/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package ro.nextreports.server.web.dashboard.drilldown;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ro.nextreports.server.domain.Chart;
import ro.nextreports.server.domain.DrillDownEntity;
import ro.nextreports.server.domain.DrillEntityContext;
import ro.nextreports.server.domain.Entity;
import ro.nextreports.server.domain.NextContent;
import ro.nextreports.server.domain.Report;
import ro.nextreports.server.report.next.NextUtil;
import ro.nextreports.server.service.StorageService;
import ro.nextreports.server.web.dashboard.Widget;
import ro.nextreports.server.web.dashboard.WidgetView;
import ro.nextreports.server.web.dashboard.chart.ChartRendererPanel;
import ro.nextreports.server.web.dashboard.chart.ChartWidget;
import ro.nextreports.server.web.dashboard.table.TableRendererPanel;
import ro.nextreports.engine.exporter.exception.NoDataFoundException;
import ro.nextreports.engine.queryexec.QueryParameter;
import ro.nextreports.engine.util.ParameterUtil;
public class DrillDownWidgetView extends WidgetView {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(DrillDownWidgetView.class);
private static final String URL_VAL = "${value}";
private DrillEntityContext drillContext;
private Map<String, Object> urlQueryParameters;
private boolean zoom;
private String width;
private String height;
@SpringBean
private StorageService storageService;
public DrillDownWidgetView(String id, IModel<Widget> model, boolean zoom) {
this(id, model, zoom, null, null, null);
}
public DrillDownWidgetView(String id, IModel<Widget> model, boolean zoom, String width, String height) {
this(id, model, zoom, width, height, null);
}
public DrillDownWidgetView(String id, IModel<Widget> model, boolean zoom, Map<String, Object> urlQueryParameters) {
this(id, model, zoom, null, null, urlQueryParameters);
}
public DrillDownWidgetView(String id, IModel<Widget> model, boolean zoom, String width, String height, Map<String, Object> urlQueryParameters) {
super(id, model, zoom);
this.zoom = zoom;
this.width = width;
this.height = height;
this.urlQueryParameters = urlQueryParameters;
drillContext = new DrillEntityContext();
drillContext.setSettingsValues(getModelObject().getQueryRuntime().getParametersValues());
Entity entity = getFirstEntity();
drillContext.setCurrentDrillEntityId(entity.getId());
if (entity instanceof Report) {
DrillDownEntity drillEntity = getFirstDrillDownEntity();
drillContext.setColumn(drillEntity.getColumn());
drillContext.setDrillLink(entity.getId());
}
add(new DrillDownNavigationPanel("drillDown") {
private static final long serialVersionUID = 1L;
@Override
public void onUp(AjaxRequestTarget target) {
DrillDownWidgetView.this.onUp(target);
}
@Override
public void onFirst(AjaxRequestTarget target) {
DrillDownWidgetView.this.onFirst(target);
}
@Override
public boolean isVisible() {
return isDrillDownable() && !drillContext.getDrillParameterValues().isEmpty();
}
});
add(getFirstRendererPanel());
}
private void onClick(AjaxRequestTarget target, String value, String pattern) throws Exception {
DrillDownEntity drillDownEntity = getNextDrillDownEntity();
String url = drillDownEntity.getUrl();
if (url != null) {
String drillUrl = storageService.getSettings().getIntegration().getDrillUrl();
if (!"".equals(drillUrl)) {
url = drillUrl + url;
}
url = url.replace(URL_VAL, value);
target.appendJavaScript("window.open('" + url + "')");
return;
}
Entity entity = drillDownEntity.getEntity();
String parameterName = drillDownEntity.getLinkParameter();
Object parameterValue = getParameterValue(entity, drillDownEntity.getLinkParameter(), value, pattern);
if (LOG.isDebugEnabled()) {
LOG.debug("add drill down parameter '" + parameterName + "' with value " + parameterValue);
}
drillContext.getDrillParameterValues().put(parameterName, parameterValue);
if (LOG.isDebugEnabled()) {
LOG.debug(drillContext.getDrillParameterValues().toString());
}
drillContext.setLast(!isNotLastDrillDownEntity());
if (entity instanceof Report) {
drillContext.setColumn(getNextDrillDownEntity().getColumn());
drillContext.setDrillLink(entity.getId());
}
DrillDownWidgetView.this.replace(getCurrentRendererPanel());
// must remove dragbox-content-chart (with min-height) on children because we may have a table
DrillDownWidgetView.this.add(AttributeModifier.replace("class", "dragbox-content zoom"));
target.add(DrillDownWidgetView.this);
}
private void onUp(AjaxRequestTarget target) {
DrillDownEntity drillDownEntity = getCurrentDrillDownEntity();
String parameterName = drillDownEntity.getLinkParameter();
if (LOG.isDebugEnabled()) {
LOG.debug("remove drill down parameter '" + parameterName + "'");
}
drillContext.getDrillParameterValues().remove(parameterName);
if (LOG.isDebugEnabled()) {
LOG.debug(drillContext.getDrillParameterValues().toString());
}
drillContext.setLast(!isNotLastDrillDownEntity());
Entity previousEntity = getPreviousEntity();
if (previousEntity instanceof Report) {
drillContext.setColumn(drillDownEntity.getColumn());
drillContext.setDrillLink(previousEntity.getId());
}
DrillDownWidgetView.this.replace(getCurrentRendererPanel());
// set back dragbox-content-chart class for first Chart
if (isFirstEntity() && (previousEntity instanceof Chart)) {
DrillDownWidgetView.this.add(AttributeAppender.append("class", "dragbox-content-chart zoom"));
}
target.add(DrillDownWidgetView.this);
}
private void onFirst(AjaxRequestTarget target) {
drillContext.getDrillParameterValues().clear();
drillContext.setLast(false);
Entity entity = getFirstEntity();
drillContext.setCurrentDrillEntityId(entity.getId());
if (entity instanceof Report) {
DrillDownEntity drillEntity = getFirstDrillDownEntity();
drillContext.setColumn(drillEntity.getColumn());
drillContext.setDrillLink(entity.getId());
}
DrillDownWidgetView.this.replace(getFirstRendererPanel());
if (entity instanceof Chart) {
// set back dragbox-content-chart class for first Chart
DrillDownWidgetView.this.add(AttributeAppender.append("class", "dragbox-content-chart zoom"));
}
target.add(DrillDownWidgetView.this);
}
private Panel getFirstRendererPanel() {
return getRendererPanel(getFirstEntity());
}
private Panel getCurrentRendererPanel() {
Entity entity;
if (isFirstEntity()) {
entity = getFirstEntity();
} else {
entity = getCurrentDrillDownEntity().getEntity();
}
drillContext.setCurrentDrillEntityId(entity.getId());
return getRendererPanel(entity);
}
private Panel getRendererPanel(Entity entity) {
if (entity instanceof Chart) {
ChartWidget chartWidget = getChartWidget(entity);
if (chartWidget == null) {
return new ChartRendererPanel("renderer", new Model<Chart>((Chart) entity), drillContext, zoom, width, height, urlQueryParameters) {
@Override
protected void onClickChart(AjaxRequestTarget target, String value, String pattern) throws Exception {
DrillDownWidgetView.this.onClick(target, value, pattern);
}
};
} else {
return new ChartRendererPanel("renderer", chartWidget, drillContext, zoom, width, height, urlQueryParameters) {
@Override
protected void onClickChart(AjaxRequestTarget target, String value, String pattern) throws Exception {
DrillDownWidgetView.this.onClick(target, value, pattern);
}
};
}
} else if (entity instanceof Report) {
try {
return new TableRendererPanel("renderer", new Model<Report>((Report)entity), DrillDownWidgetView.this.getModelObject().getId(), drillContext, zoom, urlQueryParameters) {
@Override
protected void onClickLink(AjaxRequestTarget target, String value, String pattern) throws Exception {
DrillDownWidgetView.this.onClick(target, value, pattern);
}
};
} catch (NoDataFoundException e) {
return new EmptyPanel("renderer");
}
} else {
//return new WidgetView(getId(), new WidgetModel(getWidget().getId()), false);
return new EmptyPanel("renderer");
}
}
public ChartWidget getChartWidget(Entity entity) {
DrillDownWidget widget = (DrillDownWidget)getWidget();
if (widget.getEntity() instanceof Chart) {
// a mock chart widget just with the fields we need on the server in getJSONData
ChartWidget chartWidget = new ChartWidget();
// we need the id to get UserWidgetParameters
chartWidget.setId(widget.getId());
chartWidget.setChartType(widget.getChartType());
chartWidget.setQueryRuntime(widget.getQueryRuntime());
chartWidget.setEntity(entity);
return chartWidget;
}
return null;
}
private Entity getPreviousEntity() {
Entity entity;
if (isFirstEntity()) {
entity = getFirstEntity();
} else {
entity = getCurrentDrillDownEntity().getEntity();
}
return entity;
}
private Entity getFirstEntity() {
DrillDownWidget widget = (DrillDownWidget) DrillDownWidgetView.this.getModelObject();
return widget.getEntity();
}
private DrillDownEntity getFirstDrillDownEntity() {
Entity parentEntity = getFirstEntity();
int drillDownEntityIndex = drillContext.getDrillParameterValues().size();
return getDrillDownEntities(parentEntity).get(0);
}
private DrillDownEntity getCurrentDrillDownEntity() {
Entity parentEntity = getFirstEntity();
int drillDownEntityIndex = drillContext.getDrillParameterValues().size();
return getDrillDownEntities(parentEntity).get(drillDownEntityIndex - 1);
}
private DrillDownEntity getNextDrillDownEntity() {
if (isNotLastDrillDownEntity()) {
Entity parentEntity = getFirstEntity();
int drillDownEntityIndex = drillContext.getDrillParameterValues().size();
return getDrillDownEntities(parentEntity).get(drillDownEntityIndex);
} else {
return getCurrentDrillDownEntity();
}
}
private boolean isDrillDownable() {
DrillDownWidget widget = (DrillDownWidget) DrillDownWidgetView.this.getModelObject();
if (widget.getEntity() instanceof Chart) {
return ((Chart)widget.getEntity()).isDrillDownable();
} else if (widget.getEntity() instanceof Report) {
return ((Report)widget.getEntity()).isDrillDownable();
} else {
return false;
}
}
private boolean isNotLastDrillDownEntity() {
DrillDownWidget widget = (DrillDownWidget) DrillDownWidgetView.this.getModelObject();
return (drillContext.getDrillParameterValues().size() < getDrillDownEntities(widget.getEntity()).size());
}
private boolean isFirstEntity() {
return drillContext.getDrillParameterValues().size() == 0;
}
private List<DrillDownEntity> getDrillDownEntities(Entity entity) {
List<DrillDownEntity> result = new ArrayList<DrillDownEntity>();
if (entity instanceof Chart) {
result = ((Chart)entity).getDrillDownEntities();
} else if (entity instanceof Report) {
result = ((Report)entity).getDrillDownEntities();
}
return result;
}
private Object getParameterValue(Entity entity, String parameterName, String value, String pattern) throws Exception {
List<QueryParameter> queryParameters = new ArrayList<QueryParameter>();
if (entity instanceof Chart) {
ro.nextreports.engine.chart.Chart nextChart = NextUtil.getChart(((Chart)entity).getContent());
queryParameters = nextChart.getReport().getParameters();
} else if (entity instanceof Report) {
ro.nextreports.engine.Report nextReport = NextUtil.getNextReport(storageService.getSettings(), (NextContent)((Report)entity).getContent());
queryParameters = nextReport.getParameters();
}
for (QueryParameter qp : queryParameters) {
if (qp.getName().equals(parameterName)) {
Object obj = ParameterUtil.getParameterValueFromStringWithPattern(qp.getValueClassName(), value, pattern);
if (QueryParameter.SINGLE_SELECTION.equals(qp.getSelection())) {
return obj;
} else {
Object[] val = new Object[1];
val[0] = obj;
return val;
}
}
}
throw new Exception("Parameter with name '" + parameterName + "' not found.");
}
public DrillEntityContext getDrillEntityContext() {
return drillContext;
}
}