001: package com.calipso.reportgenerator.reportcalculator;
002:
003: import com.calipso.reportgenerator.reportcalculator.SharedFloat;
004:
005: import java.io.Serializable;
006: import java.util.*;
007:
008: /**
009: * Es una consulta que se realiza sobre el pivot, cuyo resultado es un Cube
010: */
011: public class CubeQuery implements Serializable {
012: private int[] rows;
013: private int[] columns;
014: private int[] pages;
015: private int[] metrics;
016: private int[] dimensions;
017: private boolean[] ascending;
018: private int[] dimensionRank;
019: private ExpressionCubeFilter filter;
020: private EnumerationCubeFilter enumFilter;
021: private EnumerationCubeFilter rankingFilters;
022: private boolean firstFilterMatches;
023: private EnumerationCubeFilter excludeGroupFilter;
024:
025: public void setRankingFilter(EnumerationCubeFilter rankingFilters) {
026: this .rankingFilters = rankingFilters;
027: }
028:
029: public EnumerationCubeFilter getRankingFilters() {
030: return rankingFilters;
031: }
032:
033: /**
034: * Inicializa una nueva Query
035: */
036: public CubeQuery() {
037: initialize();
038: }
039:
040: /**
041: * Inicializa las estructuras que contendrán la información acerca de las dimensiones y métricas involucradas
042: */
043: private void initialize() {
044: setRows(new int[0]);
045: setColumns(new int[0]);
046: setPages(new int[0]);
047: setMetrics(new int[0]);
048: }
049:
050: /**
051: * Devuelve un array cuyos elementos son los índices de las dimensiones que agrupan por fila
052: * @return
053: */
054: public int[] getRows() {
055: return rows;
056: }
057:
058: /**
059: * Asigna un array cuyos elementos son los índices de las dimensiones que agrupan por fila
060: * @param rows
061: */
062: public void setRows(int[] rows) {
063: this .rows = rows;
064: }
065:
066: /**
067: * Devuelve un array cuyos elementos son los índices de las dimensiones que agrupan por columna
068: * @return
069: */
070: public int[] getColumns() {
071: return columns;
072: }
073:
074: /**
075: * Devuelve un array cuyos elementos son los índices de las dimensiones que agrupan por página
076: * @return
077: */
078:
079: public int[] getPages() {
080: return pages;
081: }
082:
083: /**
084: * Asigna un array cuyos elementos son los índices de las dimensiones que agrupan por columna
085: * @param columns
086: */
087:
088: public void setColumns(int[] columns) {
089: this .columns = columns;
090: }
091:
092: /**
093: * Asigna un array cuyos elementos son los índices de las dimensiones que agrupan por página
094: * @param pages
095: */
096:
097: public void setPages(int[] pages) {
098: this .pages = pages;
099: }
100:
101: /**
102: * Devuelve un array cuyos elementos son los índices de las métricas visibles
103: * @return
104: */
105: public int[] getMetrics() {
106: return metrics;
107: }
108:
109: /**
110: * Asigna un array cuyos elementos son los índices de las métricas visibles
111: * @param metrics
112: */
113: public void setMetrics(int[] metrics) {
114: this .metrics = metrics;
115: }
116:
117: /**
118: * Devuelve un array que contiene los criterios de ordenamiento para los valores de las dimensiones
119: * @return
120: */
121: public boolean[] getAscending() {
122: if (ascending == null) {
123: ascending = new boolean[dimensions.length];
124: Arrays.fill(ascending, true);
125: }
126: return ascending;
127: }
128:
129: /**
130: * Asigna un array que contiene los criterios de ordenamiento para los valores de las dimensiones
131: * @param ascending
132: */
133: public void setAscending(boolean[] ascending) {
134: this .ascending = ascending;
135: }
136:
137: /**
138: * Devuelve un array que contiene los indices de las métricas que se utilizaran para ranking (ordenamiento por valor
139: * de métrica) para cada dimensión. Si no se utiliza ranking el valor es -1, ordenando por valor de dimensión.
140: * @return
141: */
142:
143: public int[] getDimensionRank() {
144: if (dimensionRank == null) {
145: dimensionRank = new int[dimensions.length];
146: Arrays.fill(dimensionRank, -1);
147: }
148: return dimensionRank;
149: }
150:
151: /**
152: * Asigna un array que contiene los indices de las métricas para ranking
153: */
154:
155: public void setDimensionRank(int[] dimensionRank) {
156: this .dimensionRank = dimensionRank;
157: }
158:
159: /**
160: * Devuelve el filtro que se aplicará sobre las rows del pivot para llenar el Cube
161: * @return
162: */
163: public ExpressionCubeFilter getFilter() {
164: return filter;
165: }
166:
167: /**
168: * Asigna el filtro que se aplicará sobre las rows del pivot para llenar el Cube
169: * @param filter
170: */
171: public void setFilter(ExpressionCubeFilter filter) {
172: this .filter = filter;
173: }
174:
175: /**
176: * Devuelve el filtro que se aplicará sobre las rows del pivot para llenar el Cube conteniendo los valores deshabilitados
177: * @return
178: */
179:
180: public EnumerationCubeFilter getEnumFilter() {
181: return enumFilter;
182: }
183:
184: /**
185: * Asigna el filtro que se aplicará sobre las rows del pivot para llenar el Cube conteniendo los valores deshabilidados
186: * @param enumFilter
187: */
188:
189: public void setEnumFilter(EnumerationCubeFilter enumFilter) {
190: this .enumFilter = enumFilter;
191: }
192:
193: /**
194: * Determina si un array contiene un elemento
195: * @param array1
196: * @param element
197: * @return
198: */
199: private boolean arrayIncludes(int[] array1, int element) {
200: int index;
201: int lenght;
202:
203: lenght = array1.length;
204: for (index = 0; index < lenght; index++) {
205: if (array1[index] == element) {
206: return true;
207: }
208: }
209: return false;
210: }
211:
212: /**
213: * Devuelve un array cuyos elementos son los índices de las dimensiones
214: * @return
215: */
216: public int[] getDimensions() {
217: if (dimensions == null) {
218: fillDimensions();
219: }
220: return dimensions;
221: }
222:
223: /**
224: * Llena el array de dimensiones con las que agrupan por fila y por columna
225: */
226: private void fillDimensions() {
227: int rowsLenght;
228: int columnsLenght;
229: int dimensionsLenght;
230: int index;
231:
232: rowsLenght = rows.length;
233: columnsLenght = columns.length;
234: dimensionsLenght = rowsLenght + columnsLenght;
235: dimensions = new int[dimensionsLenght];
236: for (index = 0; index < rowsLenght; ++index) {
237: dimensions[index] = rows[index];
238: }
239: for (index = 0; index < columnsLenght; ++index) {
240: dimensions[index + rowsLenght] = columns[index];
241: }
242: }
243:
244: /**
245: * Aplica el filtro a una row y devuelve verdadero si cumple con la condición
246: * @param row
247: * @return
248: */
249: public boolean matches(Object[] row) {
250: firstFilterMatches = ((filter == null) || filter.matches(row))
251: && ((rankingFilters == null) || rankingFilters
252: .matches(row));
253: return firstFilterMatches
254: && ((excludeGroupFilter == null) || excludeGroupFilter
255: .matches(row));
256: }
257:
258: public boolean valuesEnabled(Object[] row) {
259: return (enumFilter == null) || enumFilter.matches(row);
260: }
261:
262: /**
263: * Determina las dimensiones que se deben agregar para resolver una consulta en forma incremental tomando como base
264: * una query previamente procesada
265: * @param otherQuery
266: * @return
267: */
268: public LinkedList newDimensionsWithRespectTo(CubeQuery otherQuery) {
269: LinkedList newDimension;
270:
271: newDimension = new LinkedList();
272: for (int i = 0; i < dimensions.length; i++) {
273: int dimension = dimensions[i];
274: if (!arrayIncludes(otherQuery.dimensions, dimension)) {
275: newDimension.add(new Integer(dimension));
276: }
277: }
278:
279: return newDimension;
280: }
281:
282: /**
283: * Devuelve el comparador apropiado para el criterio de ordenamiento de una dimensión
284: * @param dimensionIndex
285: * @return
286: */
287: public Comparator entryComparatorFor(int dimensionIndex) {
288: // Debe fijarse en la query si esta dimensión se muestra en orden ascendente
289: int cubeMetricIndex = getDimensionRank()[dimensionIndex]
290: - this .getDimensionRank().length
291: + this .getDimensions().length;
292: return new EntryComparator(getAscending()[dimensionIndex],
293: cubeMetricIndex);
294: }
295:
296: /**
297: * Devuelve el comparador apropiado para el criterio de ordenamiento de una dimensión
298: * @param dimensionIndex
299: * @return
300: */
301: public Comparator valueComparatorFor(int dimensionIndex) {
302: // Debe fijarse en la query si esta dimensión se muestra en orden ascendente
303: return new ValueComparator(getAscending()[dimensionIndex]);
304: }
305:
306: public boolean equivalentQuery(CubeQuery newQuery) {
307: return newQuery != null
308: && sameRowDimensions(newQuery.getRows())
309: && sameColumnDimensions(newQuery.getColumns())
310: && sameMetrics(newQuery.getMetrics())
311: && sameFilter(newQuery.getFilter())
312: && sameEnumFilter(newQuery.getEnumFilter())
313: && sameAscending(newQuery.getAscending())
314: && sameDimensionRank(newQuery.getDimensionRank());
315: }
316:
317: private boolean sameDimensionRank(int[] otherDimensionRank) {
318: return Arrays.equals(getDimensionRank(), otherDimensionRank);
319: }
320:
321: private boolean sameAscending(boolean[] otherAscending) {
322: return Arrays.equals(getAscending(), otherAscending);
323: }
324:
325: private boolean sameMetrics(int[] newMetrics) {
326: return Arrays.equals(getMetrics(), newMetrics);
327: }
328:
329: private boolean sameEnumFilter(EnumerationCubeFilter enumFilter) {
330: return getEnumFilter().equals(enumFilter);
331: }
332:
333: private boolean sameFilter(ExpressionCubeFilter filter) {
334: if ((getFilter() == null) && (filter == null)) {
335: return true;
336: } else {
337: if (getFilter() != null) {
338: return getFilter().equals(filter);
339: }
340: }
341: return false;
342: }
343:
344: private boolean sameColumnDimensions(int[] newColumns) {
345: return Arrays.equals(columns, newColumns);
346: }
347:
348: private boolean sameRowDimensions(int[] newRows) {
349: return Arrays.equals(rows, newRows);
350: }
351:
352: public boolean isGroupExcludedValues() {
353: return excludeGroupFilter != null;
354: }
355:
356: public boolean otherFilterMatches() {
357: return firstFilterMatches;
358: }
359:
360: public void setExcludeGroupFilter(
361: EnumerationCubeFilter excludeGroupFilter) {
362: this .excludeGroupFilter = excludeGroupFilter;
363: }
364:
365: /**
366: * Implementación del comparador para ordenar valores de dimensiones (Entry)
367: */
368: private static class EntryComparator implements Comparator {
369: boolean ascending;
370: int dimensionRank;
371:
372: public EntryComparator(boolean ascending, int dimensionRank) {
373: this .ascending = ascending;
374: this .dimensionRank = dimensionRank;
375: }
376:
377: public int compare(Object o1, Object o2) {
378: int comparison;
379: if (dimensionRank < 0) {
380: //Significa que no ordena por metrica, sino por los valores de la dimension
381: Object ok1 = ((Map.Entry) o1).getKey();
382: Object ok2 = ((Map.Entry) o2).getKey();
383: comparison = ((Comparable) ok1).compareTo(ok2);
384: } else {
385: comparison = ((SharedFloat) ((Object[]) ((Map.Entry) o1)
386: .getValue())[dimensionRank])
387: .compareTo(((Object[]) ((Map.Entry) o2)
388: .getValue())[dimensionRank]);
389: if (comparison == 0) {
390: comparison = 1;
391: }
392: }
393: if (ascending) {
394: return comparison;
395: } else {
396: return 0 - comparison;
397: }
398: }
399: }
400:
401: /**
402: * Implementación del comparador para ordenar valores de dimensiones
403: */
404: private static class ValueComparator implements Comparator {
405: boolean ascending;
406:
407: public ValueComparator(boolean ascending) {
408: this .ascending = ascending;
409: }
410:
411: public int compare(Object o1, Object o2) {
412: int comparison;
413:
414: comparison = o1.toString().compareTo(o2.toString());
415: if (ascending) {
416: return comparison;
417: } else {
418: return 0 - comparison;
419: }
420: }
421: }
422:
423: public EnumerationCubeFilter getExcludeGroupFilter() {
424: return excludeGroupFilter;
425: }
426:
427: }
|