/*
* 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.table;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.IteratorUtils;
import org.apache.wicket.extensions.markup.html.repeater.data.table.filter.IFilterStateLocator;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.injection.Injector;
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.DrillEntityContext;
import ro.nextreports.server.service.DashboardService;
import ro.nextreports.server.util.ServerUtil;
import ro.nextreports.server.web.NextServerSession;
import ro.nextreports.engine.exporter.exception.NoDataFoundException;
import ro.nextreports.engine.exporter.util.TableData;
import ro.nextreports.engine.i18n.I18nLanguage;
import ro.nextreports.engine.util.ObjectCloner;
/**
* @author Decebal Suiu
*/
public class TableDataProvider extends SortableDataProvider<RowData, String> implements IFilterStateLocator<RowData> {
private static final long serialVersionUID = 1L;
public static final String SORT_PROP_POS_SUFFIX = "_sortPos";
public static final String SORT_PROP_DIR_SUFFIX = "_sortDir";
private static final Logger LOG = LoggerFactory.getLogger(TableDataProvider.class);
private transient List<RowData> cache;
private transient List<String> header;
private transient List<String> pattern;
private transient I18nLanguage language;
private String widgetId;
private DrillEntityContext drillContext;
private Map<String, Object> urlQueryParameters;
private int sortPos;
private int sortDir;
private RowData tableFilter;
@SpringBean
private DashboardService dashboardService;
public TableDataProvider() {
this(null, null);
}
public TableDataProvider(String widgetId, Map<String, Object> urlQueryParameters) {
this(widgetId, null, urlQueryParameters);
}
public TableDataProvider(String widgetId, DrillEntityContext drillContext, Map<String, Object> urlQueryParameters) {
this.widgetId = widgetId;
this.drillContext = drillContext;
this.urlQueryParameters = urlQueryParameters;
Injector.get().inject(this);
}
@SuppressWarnings("unchecked")
@Override
public Iterator<RowData> iterator(long first, long count) {
try {
List<RowData> data = getCache();
String username = ServerUtil.getUsername();
String sortPosKey = username == null ? widgetId + SORT_PROP_POS_SUFFIX : widgetId + "_" + username + SORT_PROP_POS_SUFFIX;
String sortDirKey = username == null ? widgetId + SORT_PROP_DIR_SUFFIX : widgetId + "_" + username + SORT_PROP_DIR_SUFFIX;
if (getSort() != null) {
sortDir = getSort().isAscending() ? 1 : -1;
sortPos = getPropertyPosition(getSort().getProperty());
// save these properties to be used by TableResource (save to excel)
System.setProperty(sortPosKey, String.valueOf(sortPos));
System.setProperty(sortDirKey, String.valueOf(sortDir));
Collections.sort(data, new Comparator<RowData>() {
public int compare(RowData o1, RowData o2) {
if (sortPos != -1) {
if ((o1.getCellValues(sortPos) == null) && (o2.getCellValues(sortPos) == null)) {
return 0;
} else if (o1.getCellValues(sortPos) == null) {
return sortDir;
} else if (o2.getCellValues(sortPos) == null) {
return -sortDir;
} else {
return sortDir * new TableObjectComparator().compare(o1.getCellValues(sortPos), o2.getCellValues(sortPos));
}
}
return 0;
}
});
} else {
System.clearProperty(sortPosKey);
System.clearProperty(sortDirKey);
}
return getCache().subList((int) first, (int) (first + count)).iterator();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return IteratorUtils.EMPTY_ITERATOR;
}
}
private int getPropertyPosition(String property) {
List<String> header = new ArrayList<String>();
try {
header = getHeader();
for (int i=0, size=header.size(); i<size; i++) {
if (header.get(i).equals(property)) {
return i;
}
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return -1;
}
@Override
public IModel<RowData> model(RowData object) {
return new Model<RowData>(object);
}
@Override
public long size() {
try {
return getCache().size();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return 0;
}
}
public int getColumnCount() {
try {
return getCache().get(0).getCellValues().size();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return 0;
}
}
@Override
public void detach() {
cache = null;
}
public String getWidgetId() {
return widgetId;
}
public List<String> getHeader() throws NoDataFoundException, Exception {
getCache();
return header;
}
public List<String> getPattern() throws NoDataFoundException, Exception {
getCache();
return pattern;
}
public I18nLanguage getLanguage() throws NoDataFoundException, Exception {
getCache();
return language;
}
private List<RowData> getCache() throws NoDataFoundException, Exception {
if (cache == null) {
if (widgetId != null) {
TableData td = dashboardService.getTableData(widgetId, drillContext, urlQueryParameters);
// tableData may be kept in cache (if there are cache settings set)!
// so we must use a clone here to not modify the original in case of filtering
TableData tableData = ObjectCloner.silenceDeepCopy(td);
List<List<Object>> data = tableData.getData();
List<List<Map<String, Object>>> style = tableData.getStyle();
header = tableData.getHeader();
if (data != null) {
cache = new ArrayList<RowData>();
tableFilter = NextServerSession.get().getTableFilter(widgetId);
if (tableFilter == null) {
List<Object> cellValues = new ArrayList<Object>();
if (data.size() > 0) {
for (int k=0; k<data.get(0).size(); k++) {
cellValues.add(null);
}
}
tableFilter = new RowData(cellValues);
} else {
tableData.search(tableFilter.getCellValues());
}
for (int i=0, size=data.size(); i<size; i++) {
List<Object> row = data.get(i);
RowData rowData = new RowData(row);
if (i == 0) {
pattern = tableData.getPattern();
language = tableData.getLanguage();
}
rowData.setStyles(style.get(i));
cache.add(rowData);
}
}
}
}
return cache;
}
@Override
public RowData getFilterState() {
return tableFilter;
}
@Override
public void setFilterState(RowData state) {
this.tableFilter = tableFilter;
}
}