/* * RHQ Management Platform * Copyright (C) 2009-2010 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.core.gui.model; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; import javax.faces.context.FacesContext; import javax.faces.model.DataModelListener; import org.ajax4jsf.model.DataVisitor; import org.ajax4jsf.model.ExtendedDataModel; import org.ajax4jsf.model.Range; import org.ajax4jsf.model.SequenceRange; import org.ajax4jsf.model.SerializableDataModel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.richfaces.model.DataProvider; import org.richfaces.model.ExtendedTableDataModel; import org.richfaces.model.Field; import org.richfaces.model.FilterField; import org.richfaces.model.LocaleAware; import org.richfaces.model.Modifiable; import org.richfaces.model.SortField2; import org.richfaces.model.impl.expressive.JavaBeanWrapper; import org.richfaces.model.impl.expressive.ObjectWrapperFactory; import org.richfaces.model.impl.expressive.WrappedBeanComparator2; import org.richfaces.model.impl.expressive.WrappedBeanFilter; /** * @author Konstantin Mishin * */ public class AbstractPagedDataModel2<T> extends ExtendedDataModel implements Modifiable, LocaleAware { protected class RowKeyWrapperFactory extends ObjectWrapperFactory { private class ExtendedJavaBeanWrapper extends JavaBeanWrapper { private Object key; public ExtendedJavaBeanWrapper(Object key, Object o, Map<Object, Object> props) { super(o, props); this.key = key; } public Object getKey() { return key; } } public RowKeyWrapperFactory(FacesContext context, String var, List<? extends Field> sortOrder) { super(context, var, sortOrder); } @Override public JavaBeanWrapper wrapObject(Object key) { originalModel.setRowKey(key); JavaBeanWrapper wrapObject = super.wrapObject(originalModel.getRowData()); return new ExtendedJavaBeanWrapper(key, wrapObject.getWrappedObject(), wrapObject.getProperties()); } @Override public Object unwrapObject(Object wrapper) { return ((ExtendedJavaBeanWrapper) wrapper).getKey(); } } private static final Log log = LogFactory.getLog(AbstractPagedDataModel2.class); private ExtendedTableDataModel<T> originalModel; protected List<Object> rowKeys; protected String var; protected Locale locale; private boolean sortNeeded = true; private boolean filterNeeded = true; @SuppressWarnings("unchecked") public AbstractPagedDataModel2(DataProvider<T> dataProvider, String var) { this(new ExtendedTableDataModel<T>(dataProvider), var); } public AbstractPagedDataModel2(DataProvider<T> dataProvider) { this(dataProvider, null); } @SuppressWarnings("unchecked") public AbstractPagedDataModel2(ExtendedTableDataModel<T> dataModel, String var) { this.originalModel = dataModel; this.var = var; } @Override public void addDataModelListener(DataModelListener listener) { originalModel.addDataModelListener(listener); } @Override public DataModelListener[] getDataModelListeners() { return originalModel.getDataModelListeners(); } public Locale getLocale() { return locale; } public void setLocale(Locale locale) { this.locale = locale; } @Override public Object getRowKey() { return originalModel.getRowKey(); } @Override public void setRowKey(Object key) { originalModel.setRowKey(key); } @Override public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException { final SequenceRange seqRange = (SequenceRange) range; int rows = seqRange.getRows(); int rowCount = getRowCount(); int currentRow = seqRange.getFirstRow(); if(rows > 0){ rows += currentRow; rows = Math.min(rows, rowCount); } else { rows = rowCount; } for (; currentRow < rows; currentRow++) { visitor.process(context, rowKeys.get(currentRow), argument); } } /** * Resets internal cached data. Call this method to reload data from data * provider on first access for data. */ public void reset(){ originalModel.reset(); rowKeys = null; sortNeeded = true; filterNeeded = true; } public Object getKey(T o) { return originalModel.getKey(o); } public T getObjectByKey(Object key) { return originalModel.getObjectByKey(key); } @Override public int getRowCount() { if (rowKeys == null) { return -1; } else { return rowKeys.size(); } } @Override public Object getRowData() { return originalModel.getRowData(); } @Override public int getRowIndex() { return rowKeys.indexOf(originalModel.getRowKey()); } @Override public Object getWrappedData() { return originalModel.getWrappedData(); } @Override public boolean isRowAvailable() { return originalModel.isRowAvailable(); } @Override public void setRowIndex(int rowIndex) { Object originalKey = null; if (rowIndex >= 0 && rowIndex < rowKeys.size()) { originalKey = rowKeys.get(rowIndex); } originalModel.setRowKey(originalKey); } @Override public void setWrappedData(Object data) { originalModel.setWrappedData(data); } @Override public SerializableDataModel getSerializableModel(Range range) { return originalModel.getSerializableModel(range); } @Override public void removeDataModelListener(DataModelListener listener) { originalModel.removeDataModelListener(listener); } public void modify(List<FilterField> filterFields, List<SortField2> sortFields) { if (sortNeeded || filterNeeded){ if (var == null){ throw new IllegalStateException("\"var\" model attribute cannot be null."); } int rowCount = originalModel.getRowCount(); if (rowCount > 0) { rowKeys = new ArrayList<Object>(rowCount); } else { rowKeys = new ArrayList<Object>(); } FacesContext context = FacesContext.getCurrentInstance(); try { originalModel.walk(context, new DataVisitor() { public void process(FacesContext context, Object rowKey, Object argument) throws IOException { originalModel.setRowKey(rowKey); if (originalModel.isRowAvailable()) { rowKeys.add(rowKey); } } }, new SequenceRange(0, -1), null); } catch (IOException e) { log.error(e.getMessage(), e); } filter(filterFields); filterNeeded = false; sort(sortFields); sortNeeded = false; } } public void resetSort(){ this.sortNeeded = true; } public void resetFilter(){ this.filterNeeded = true; } public void setVar(String var){ this.var = var; } protected List<Object> filter(List<FilterField> filterFields) { if (filterFields != null && !filterFields.isEmpty()) { FacesContext context = FacesContext.getCurrentInstance(); List <Object> filteredCollection = new ArrayList<Object>(); ObjectWrapperFactory wrapperFactory = new RowKeyWrapperFactory(context, var, filterFields); WrappedBeanFilter wrappedBeanFilter = new WrappedBeanFilter(filterFields, locale); wrapperFactory.wrapList(rowKeys); for (Object object : rowKeys) { if(wrappedBeanFilter.accept((JavaBeanWrapper)object)) { filteredCollection.add(object); } } rowKeys = filteredCollection; wrapperFactory.unwrapList(rowKeys); } return rowKeys; } protected void sort(List<SortField2> sortFields) { if (sortFields != null && !sortFields.isEmpty()) { FacesContext context = FacesContext.getCurrentInstance(); ObjectWrapperFactory wrapperFactory = new RowKeyWrapperFactory( context, var, sortFields); WrappedBeanComparator2 wrappedBeanComparator = new WrappedBeanComparator2( sortFields, locale); wrapperFactory.wrapList(rowKeys); Collections.sort(rowKeys, wrappedBeanComparator); wrapperFactory.unwrapList(rowKeys); } } }