001: ///////////////////////////////
002: // Makumba, Makumba tag library
003: // Copyright (C) 2000-2003 http://www.makumba.org
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: //
019: // -------------
020: // $Id: Grouper.java 1704 2007-09-28 12:35:31Z manuel_gay $
021: // $Name$
022: /////////////////////////////////////
023:
024: package org.makumba.list.engine;
025:
026: import java.util.Date;
027: import java.util.Enumeration;
028: import java.util.Hashtable;
029: import java.util.Vector;
030:
031: import org.makumba.commons.ArrayMap;
032: import org.makumba.commons.MultipleKey;
033:
034: /**
035: * This class groups data coming in an Enumeration of Dictionaries. Grouping is done in more levels, each level is
036: * defined by a set of keys of the dictionary. Elements of each group come in a Vector that is guaranteed to respect the
037: * order in the original enumeration.
038: *
039: * @author Cristian Bogdan
040: */
041: public class Grouper extends Hashtable {
042:
043: private static final long serialVersionUID = 1L;
044:
045: Vector keyNameSets;
046:
047: /**
048: * Groups the given data according to the given key sets.
049: *
050: * @param keyNameSets
051: * a Vector of Vectors of Strings that represents key names
052: * @param e
053: * the Enumeration of dictionaries containing the data
054: */
055: public Grouper(Vector keyNameSets, Enumeration e) {
056: this .keyNameSets = keyNameSets;
057: long l = new Date().getTime();
058:
059: // for all read records
060: while (e.hasMoreElements()) {
061: ArrayMap data = (ArrayMap) e.nextElement();
062: Hashtable h = this ;
063: Hashtable h1;
064: int i = 0;
065: int _max = keyNameSets.size() - 1;
066: MultipleKey mk;
067:
068: // find the subresult where this record has to be inserted
069: for (; i < _max; i++) {
070: // make a keyset value
071: mk = getKey(i, data.data);
072:
073: // get the subresult associated with it, make a new one if none exists
074: h1 = (Hashtable) h.get(mk);
075: if (h1 == null) {
076: h1 = new Hashtable();
077: h.put(mk, h1);
078: }
079: h = h1;
080: }
081:
082: // insert the data in the subresult
083: mk = getKey(i, data.data);
084: Vector v = (Vector) h.get(mk);
085: if (v == null) {
086: v = new Vector();
087: h.put(mk, v);
088: }
089: v.addElement(data);
090: }
091:
092: max = keyNameSets.size() - 1;
093: stack = new Hashtable[max + 1];
094: keyStack = new Object[max];
095: stack[0] = this ;
096:
097: long diff = (new Date().getTime() - l);
098:
099: // if(diff>20)
100: java.util.logging.Logger.getLogger(
101: "org.makumba." + "db.query.performance.grouping").fine(
102: "grouping " + diff + " ms");
103: }
104:
105: int max;
106:
107: Hashtable[] stack;
108:
109: Object[] keyStack;
110:
111: /**
112: * Gets the Vector associated with the given keysets. The returned data is deleted from the Grouper.
113: *
114: * @param keyData
115: * a Vector of Dictionaries representing a set of key values each
116: * @return A Vector associated with the given keysets
117: */
118: public Vector getData(Vector keyData) {
119: int i = 0;
120: for (; i < max; i++) {
121: keyStack[i] = getKey(i,
122: ((ArrayMap) keyData.elementAt(i)).data);
123: stack[i + 1] = (Hashtable) stack[i].get(keyStack[i]);
124: if (stack[i + 1] == null)
125: return null;
126: }
127: Vector v = (Vector) stack[i].remove(getKey(i,
128: ((ArrayMap) keyData.elementAt(i)).data));
129: for (; i > 0 && stack[i].isEmpty(); i--)
130: stack[i - 1].remove(keyStack[i - 1]);
131: return v;
132: }
133:
134: /**
135: * Get the bunch of values associated with the keyset with the given index
136: *
137: * @param n
138: * the index
139: * @param data
140: * an object array containing the interesting data
141: * @return A MultipleKey holding the values
142: */
143: protected MultipleKey getKey(int n, Object[] data) {
144: return new MultipleKey((Vector) keyNameSets.elementAt(n), data);
145: }
146: }
|