package org.openswing.swing.pivottable.server; import org.openswing.swing.pivottable.java.*; import org.openswing.swing.pivottable.tablemodelreaders.server.Reader; import org.openswing.swing.message.receive.java.*; import java.util.*; import org.openswing.swing.pivottable.functions.java.GenericFunction; /** * <p>Title: OpenSwing Framework</p> * <p>Description: Engine used to generate a PivotTableModel, starting from a PivotTableParameters.</p> * <p>Copyright: Copyright (C) 2006 Mauro Carniel</p> * * <p> This file is part of OpenSwing Framework. * This library is free software; you can redistribute it and/or * modify it under the terms of the (LGPL) Lesser General Public * License as published by the Free Software Foundation; * * GNU LESSER GENERAL PUBLIC LICENSE * Version 2.1, February 1999 * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author may be contacted at: * maurocarniel@tin.it</p> * * @author Mauro Carniel * @version 1.0 */ public class PivotTableEngine { /** data model reader */ private Reader reader = null; /** * @param reader Data model reader */ public PivotTableEngine(Reader reader) { this.reader = reader; } /** * @param pars parameters used in PivotTableEngine to generate the PivotTableModel * @return VOResponse that contains a PivotTableModel generated starting from PivotTableParameters; ErrorResponse in case of errors on analyzing data */ public final Response getPivotTableModel(PivotTableParameters pars) { if (!reader.initializeScrolling(pars.getInputFilter())) return new ErrorResponse("Error on reading data on input."); HashSet cols = new HashSet(); for(int i=0;i<reader.getColumnCount();i++) cols.add(reader.getColumnName(i)); // check whether some row/column/data fields are unknown... for(int i=0;i<pars.getRowFields().size();i++) if (!cols.contains(((RowField)pars.getRowFields().get(i)).getColumnName())) { return new ErrorResponse( ((RowField)pars.getRowFields().get(i)).getColumnName()+"' row field is not defined in data model: Pivot Table cannot be created." ); } for(int i=0;i<pars.getColumnFields().size();i++) if (!cols.contains(((ColumnField)pars.getColumnFields().get(i)).getColumnName())) { return new ErrorResponse( ((ColumnField)pars.getColumnFields().get(i)).getColumnName()+"' column field is not defined in data model: Pivot Table cannot be created." ); } for(int i=0;i<pars.getDataFields().size();i++) if (!cols.contains(((DataField)pars.getDataFields().get(i)).getColumnName())) { return new ErrorResponse( ((DataField)pars.getDataFields().get(i)).getColumnName()+"' data field is not defined in data model: Pivot Table cannot be created." ); } if (pars.getRowFields().size()==0) { return new ErrorResponse("At least one field must be defined as row field: Pivot Table cannot be created."); } if (pars.getColumnFields().size()==0) { return new ErrorResponse("At least one field must be defined as column field: Pivot Table cannot be created."); } if (pars.getDataFields().size()==0) { return new ErrorResponse("At least one field must be defined as data field: Pivot Table cannot be created."); } // index input data model column names... HashMap indexes = new HashMap(); for(int j=0;j<reader.getColumnCount();j++) { indexes.put(reader.getColumnName(j),new Integer(j)); } // index row fields indexes... int[] rowFieldsIndexes = new int[pars.getRowFields().size()]; for(int j=0;j<pars.getRowFields().size();j++) { rowFieldsIndexes[j] = ((Integer)indexes.get(((RowField)pars.getRowFields().get(j)).getColumnName())).intValue(); } // index data fields indexes... int[] dataFieldsIndexes = new int[pars.getDataFields().size()]; for(int j=0;j<pars.getDataFields().size();j++) { dataFieldsIndexes[j] = ((Integer)indexes.get(((DataField)pars.getDataFields().get(j)).getColumnName())).intValue(); } // index column fields indexes... int[] colFieldsIndexes = new int[pars.getColumnFields().size()]; for(int j=0;j<pars.getColumnFields().size();j++) { colFieldsIndexes[j] = ((Integer)indexes.get(((ColumnField)pars.getColumnFields().get(j)).getColumnName())).intValue(); } // create Pivot TableModel... RowGenericNode hroot = new RowGenericNode(); GlobalColGenericNode vroot = new GlobalColGenericNode(); PivotTableModel model = new PivotTableModel(hroot,vroot); // read all data in input... // StringBuffer hpath = new StringBuffer(); GenericNodeKey hpath = null; RowGenericNode hnode = null; ColGenericNode vnode = null; GlobalColGenericNode globalvnode = null; RowGenericNode hparentNode = null; ColGenericNode vparentNode = null; GlobalColGenericNode globalvparentNode = null; RowField rowField = null; ColumnField colField = null; Object hvalue = null; Object vvalue = null; HashMap htreeNodes = new HashMap(); HashMap vtreeNodes = null; HashMap globalvtreeNodes = new HashMap(); GenericFunction[] gf = null; GenericNodeKey vpath = null; while(reader.nextRow(pars.getInputFilter())) { // read row... hparentNode = hroot; hpath = new GenericNodeKey(); // for each row: parse row data, along row fields... for(int j=0;j<pars.getRowFields().size();j++) { rowField = (RowField)pars.getRowFields().get(j); hvalue = rowField.getAggregator().decodeValue(reader.getValueAt(rowFieldsIndexes[j])); if (hvalue==null) hvalue = ""; hpath = hpath.appendKey(hvalue); hnode = (RowGenericNode)htreeNodes.get(hpath); if (hnode==null) { hnode = new RowGenericNode(hpath); htreeNodes.put(hpath,hnode); hparentNode.add(hnode); } vtreeNodes = hnode.getVtreeNodes(); // for each row field node, parse row data, along column fields and calculate data field values... vparentNode = null; globalvparentNode = vroot; vpath = new GenericNodeKey(); for(int y=0;y<pars.getColumnFields().size();y++) { colField = (ColumnField)pars.getColumnFields().get(y); vvalue = colField.getAggregator().decodeValue(reader.getValueAt(colFieldsIndexes[y])); if (vvalue==null) vvalue = ""; vpath = vpath.appendKey(vvalue); vnode = (ColGenericNode)vtreeNodes.get(vpath); if (vnode==null) { gf = new GenericFunction[dataFieldsIndexes.length]; for (int u = 0; u < dataFieldsIndexes.length; u++) try { gf[u] = (GenericFunction) ( (DataField) pars.getDataFields().get(u)).getFunction().getClass().newInstance(); } catch (Throwable ex) { return new ErrorResponse("Error while analyzing data."); } vnode = new ColGenericNode(vpath,gf); vtreeNodes.put(vpath,vnode); if (vparentNode!=null) vparentNode.add(vnode); else hnode.setColsParentNode(vnode); } else gf = (GenericFunction[])vnode.getGenericFunctions(); fillRow(pars,dataFieldsIndexes,gf); vparentNode = vnode; // moreover, create a global column fields hierarchy, without associating data field values... globalvnode = (GlobalColGenericNode)globalvtreeNodes.get(vpath); if (globalvnode==null) { globalvnode = new GlobalColGenericNode(vpath); globalvtreeNodes.put(vpath,globalvnode); globalvparentNode.add(globalvnode); } globalvparentNode = globalvnode; } // end for on colFields hparentNode = hnode; } // end for on rowFields } // end while return new VOResponse(model); } private void fillRow(PivotTableParameters pars,int[] dataFieldsIndexes,GenericFunction[] gf) { Number n = null; for(int j=0;j<pars.getDataFields().size();j++) { n = (Number)reader.getValueAt(dataFieldsIndexes[j]); gf[j].processValue(reader.getValueAt(dataFieldsIndexes[j])); } } }