package org.ff4j.web.controller;
/*
* #%L
* ff4j-sample-web
* %%
* Copyright (C) 2013 - 2016 FF4J
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.ff4j.web.bean.WebConstants.CONTENT_TYPE_JSON;
import static org.ff4j.web.bean.WebConstants.GRAPH_BAR_HITRATIO;
import static org.ff4j.web.bean.WebConstants.GRAPH_PIE_HITRATIO;
import static org.ff4j.web.bean.WebConstants.GRAPH_PIE_HOST;
import static org.ff4j.web.bean.WebConstants.GRAPH_PIE_SOURCE;
import static org.ff4j.web.bean.WebConstants.GRAPH_PIE_USER;
import static org.ff4j.web.bean.WebConstants.OP_AUDIT;
import static org.ff4j.web.bean.WebConstants.OP_EXPORT;
import static org.ff4j.web.bean.WebConstants.OP_FEATURES;
import static org.ff4j.web.bean.WebConstants.OP_FEATUREUSAGE;
import static org.ff4j.web.bean.WebConstants.OP_PROPERTIES;
import static org.ff4j.web.bean.WebConstants.OP_TIMESERIES;
import static org.ff4j.web.embedded.ConsoleOperations.exportFile;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.ff4j.FF4j;
import org.ff4j.audit.Event;
import org.ff4j.audit.EventQueryDefinition;
import org.ff4j.audit.chart.BarChart;
import org.ff4j.audit.chart.PieChart;
import org.ff4j.audit.chart.TimeSeriesChart;
import org.ff4j.core.Feature;
import org.ff4j.property.Property;
import org.ff4j.web.bean.WebConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
/**
* Mini API to get informations through AJAX in JSON.
*
* @author Cedrick LUNVEN (@clunven)
*/
public class OperationsController extends AbstractController {
/** Logger for this class. */
public static final Logger LOGGER = LoggerFactory.getLogger(OperationsController.class);
/** {@inheritDoc} */
public OperationsController(FF4j ff4j, TemplateEngine te) {
super(ff4j, null, te);
}
/** {@inheritDoc} */
public void post(HttpServletRequest req, HttpServletResponse res, WebContext ctx)
throws IOException {
}
/** {@inheritDoc} */
public void get(HttpServletRequest req, HttpServletResponse res, WebContext ctx)
throws IOException {
String[] pathParts = req.getPathInfo().split("/");
String operation = pathParts[2];
if (OP_EXPORT.equalsIgnoreCase(operation)) {
exportFile(ff4j, res);
return;
} else if (OP_FEATURES.equalsIgnoreCase(operation)) {
featuresAsJson(req, res);
return;
} else if (OP_PROPERTIES.equalsIgnoreCase(operation)) {
propertiesAsJson(req, res);
return;
} else if (OP_FEATUREUSAGE.equalsIgnoreCase(operation)) {
graphFeatureUsageHitCountasJson(req, res);
return;
} else if (OP_TIMESERIES.equalsIgnoreCase(operation)) {
graphTimeSeriesasJson(req, res);
return;
} else if (OP_AUDIT.equalsIgnoreCase(operation)) {
auditEventasJson(req, res);
return;
} else {
res.setStatus(WebConstants.STATUS_BADREQUEST);
res.getWriter().println("Invalid request please check URL");
return;
}
}
/**
* Generation of JSON to render Features.
*
* @param req
* current request
* @param res
* current response
* @throws IOException
*/
private void auditEventasJson(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType(CONTENT_TYPE_JSON);
String[] pathParts = req.getPathInfo().split("/");
if (pathParts.length > 3) {
String eventUUId = pathParts[3];
Long eventTime = null;
if (isValidParam(req, WebConstants.KEY_DATE)) {
eventTime = Long.valueOf(req.getParameter(WebConstants.KEY_DATE));
}
Event event = getFf4j().getEventRepository().getEventByUUID(eventUUId, eventTime);
if (event != null) {
res.getWriter().println(event.toString());
} else {
res.setStatus(WebConstants.STATUS_NOT_FOUND);
res.getWriter().println("Event " + eventUUId + " does not exist in event repository." );
}
}
}
/**
* Generation of JSON to render Features.
*
* @param req
* current request
* @param res
* current response
* @throws IOException
*/
private void graphTimeSeriesasJson(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType(CONTENT_TYPE_JSON);
EventQueryDefinition query = parseQuery(req);
TimeSeriesChart tsc = getFf4j().getEventRepository().getFeatureUsageHistory(query, TimeUnit.HOURS);
res.getWriter().println(tsc.toString());
}
/**
* Generation of JSON to render Features.
*
* @param req
* current request
* @param res
* current response
* @throws IOException
*/
private void graphFeatureUsageHitCountasJson(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType(CONTENT_TYPE_JSON);
String[] pathParts = req.getPathInfo().split("/");
EventQueryDefinition query = parseQuery(req);
if (pathParts.length > 3) {
String graphName = pathParts[3];
if (GRAPH_PIE_HITRATIO.equalsIgnoreCase(graphName)) {
PieChart pc = getFf4j().getEventRepository().getFeatureUsagePieChart(query);
res.getWriter().println(pc.toJson());
} else if (GRAPH_BAR_HITRATIO.equalsIgnoreCase(graphName)) {
BarChart bc = getFf4j().getEventRepository().getFeatureUsageBarChart(query);
res.getWriter().println(bc.toJson());
} else if (GRAPH_PIE_HOST.equalsIgnoreCase(graphName)) {
PieChart pc = getFf4j().getEventRepository().getHostPieChart(query);
res.getWriter().println(pc.toJson());
} else if (GRAPH_PIE_SOURCE.equalsIgnoreCase(graphName)) {
PieChart pc = getFf4j().getEventRepository().getSourcePieChart(query);
res.getWriter().println(pc.toJson());
} else if (GRAPH_PIE_USER.equalsIgnoreCase(graphName)) {
PieChart pc = getFf4j().getEventRepository().getUserPieChart(query);
res.getWriter().println(pc.toJson());
}
}
}
/**
* Generation of JSON to render Features.
*
* @param req
* current request
* @param res
* current response
* @throws IOException
*/
private void featuresAsJson(HttpServletRequest req, HttpServletResponse res)
throws IOException {
String[] pathParts = req.getPathInfo().split("/");
res.setContentType(CONTENT_TYPE_JSON);
if (pathParts.length > 3) {
String featureId = pathParts[3];
if (getFf4j().getFeatureStore().exist(featureId)) {
Feature f = getFf4j().getFeatureStore().read(featureId);
res.getWriter().println(f.toJson());
} else {
res.setStatus(WebConstants.STATUS_NOT_FOUND);
res.getWriter().println("Feature " + featureId + " does not exist in feature store." );
}
} else {
Map< String, Feature > mapOfFeatures = getFf4j().getFeatureStore().readAll();
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Feature feature : mapOfFeatures.values()) {
if (!first) {
sb.append(",");
}
sb.append(feature.toJson());
first = false;
}
sb.append("]");
res.getWriter().println(sb.toString());
}
}
/**
* Generation of JSON to render Properties.
*
* @param req
* current request
* @param res
* current response
*/
private void propertiesAsJson(HttpServletRequest req, HttpServletResponse res)
throws IOException {
String[] pathParts = req.getPathInfo().split("/");
res.setContentType(CONTENT_TYPE_JSON);
if (pathParts.length > 3) {
String propertyName = pathParts[3];
if (getFf4j().getPropertiesStore().existProperty(propertyName)) {
Property<?> p = getFf4j().getPropertiesStore().readProperty(propertyName);
res.getWriter().println(p.toJson());
} else {
res.setStatus(WebConstants.STATUS_NOT_FOUND);
res.getWriter().println("Property " + propertyName + " does not exist in property store." );
}
} else {
Map< String, Property<?> > mapOfFeatures = getFf4j().getPropertiesStore().readAllProperties();
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Property<?> myProperty : mapOfFeatures.values()) {
if (!first) {
sb.append(",");
}
sb.append(myProperty.toJson());
first = false;
}
sb.append("]");
res.getWriter().println(sb.toString());
}
return;
}
}