![JAR search and dependency download from the Maven repository](/logo.png)
com.day.cq.reporting.Data Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* Copyright 1997-2010 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.reporting;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.io.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class represents the data of a report.
*
* Instances of this class may be used concurrently (through caches), so the following
* policy must be followed:
*
*
* - During the creation of a report, the class must only be used from a single thread.
*
* - After the data has been completely retrieved (and before adding it to a cache), it
* must be "compacted" (using {@link #compact}).
* - After being compacted, the data object is considered immutable. All methods
* that change state are then considered to throw {@link IllegalStateException}s.
*
*/
public abstract class Data {
/**
* Logger
*/
protected static final Logger log = LoggerFactory.getLogger(Data.class);
/**
* The report
*/
protected Report report;
/**
* Data rows
*/
protected final List rows;
/**
* Column totals
*/
protected final Map columnTotals;
/**
* Flag that determines if the data has grouped columns
*/
protected final boolean hasGroupedColumns;
/**
* Flag that determines if the data has already been compacted.
*/
protected boolean isCompacted;
/**
* List of the report's column (available after compacting)
*/
protected List columns;
/**
* Version of report data (0 - CQ 5.4; 1 - CQ 5.5)
*/
protected int reportingVersion;
public Data(Report report) {
this.report = report;
this.hasGroupedColumns = this.report.hasGroupedColumns();
this.columnTotals = new HashMap();
this.rows = new ArrayList(16);
this.isCompacted = false;
this.reportingVersion = (report instanceof ReportExtensions
? ((ReportExtensions) report).getReportingVersion() : 0);
}
/**
* Ensures that the data is still mutable. Throws an {@link IllegalStateException}
* otherwise.
*/
protected void ensureMutable() {
if (this.isCompacted) {
throw new IllegalStateException(
"Report data is already compacted and therefore immutable.");
}
}
/**
* Ensures that the report data is immutable; throws an {@link IllegalStateException}
* otherwise.
*/
protected void ensureImmutable() {
if (!this.isCompacted) {
throw new IllegalStateException(
"Report data must be compacted before writing to JSON");
}
}
/**
* Determines if the report data has of grouped columns.
*
* @return true
if the report contains data from grouped columns
*/
public boolean hasGroupedColumns() {
return this.hasGroupedColumns;
}
/**
* Adds the specified row of data.
*
* @param rowToAdd The row to add
*/
public void addRow(DataRow rowToAdd) {
this.ensureMutable();
log.debug("Adding row; value: {}", rowToAdd);
this.rows.add(rowToAdd);
}
/**
* Gets a row by its index.
*
* @param rowIndex The index
* @return The row
*/
public DataRow getRowAt(int rowIndex) {
return this.rows.get(rowIndex);
}
/**
* Gets the number of rows.
*
* @return Number of rows
*/
public int getRowCnt() {
return this.rows.size();
}
/**
* Gets an iterator over the columns of the report data.
*
* @return The iterator
*/
public Iterator getColumns() {
this.ensureImmutable();
return this.columns.iterator();
}
/**
* Adds the specified column total.
*
* @param col The column
* @param total The total value
*/
public void addColumnTotal(Column col, CellValue total) {
this.ensureMutable();
this.columnTotals.put(col, total);
}
/**
* Gets the total value of the specified column.
*
* @param col The (aggregated) column to determine the total value for
* @return The total value of the specified column
*/
public CellValue getColumnTotal(Column col) {
return this.columnTotals.get(col);
}
/**
* This class must called after the data has been calculated completely, no further
* changes have to be made and the
*/
public void compact() {
this.ensureMutable();
this.isCompacted = true;
Iterator cols = this.report.getColumnIterator();
this.columns = new ArrayList();
while (cols.hasNext()) {
this.columns.add(cols.next());
}
((ArrayList) this.columns).trimToSize();
this.report = null;
((ArrayList) this.rows).trimToSize();
for (DataRow row : this.rows) {
row.compact();
}
}
/**
* Use this method to process each data row with the specified {@link Processor}s.
*
* @param processors The array of processing modules to execute. Note that if one of the
* modules declares a row to be deleted, the modules specified at
* higher array indices will not be executed on that row.
*/
public void postProcess(Processor[] processors) {
this.ensureMutable();
log.debug("Postprocessing result data");
for (int r = this.getRowCnt() - 1; r >= 0; r--) {
log.debug("Postprocessing row #{}", r);
DataRow row = this.rows.get(r);
for (Processor processor : processors) {
log.debug("Applying processor {}", processor.getClass().getSimpleName());
if (processor.processRow(row)) {
log.debug("Processor requested removal of record {}; removing record",
row);
this.rows.remove(r);
}
}
}
}
/**
* Sorts the result data by the specified column.
*
* @param sortingColumn The column to sort by
* @param sortingDirection The sorting direction
*/
public void sortByColumn(final Column sortingColumn,
Sorting.Direction sortingDirection) {
this.ensureMutable();
final boolean isAscending = (sortingDirection == Sorting.Direction.ASCENDING);
log.debug("Sorting result for column {}", sortingColumn.getName());
Collections.sort(this.rows, new Comparator() {
public int compare(DataRow o1, DataRow o2) {
int cmpResult;
String resultProp = sortingColumn.getName();
CellValue val1 = o1.get(resultProp);
CellValue val2 = o2.get(resultProp);
if (val1 == null) {
if (val2 == null) {
cmpResult = 0;
} else {
cmpResult = -1;
}
} else if (val2 == null) {
cmpResult = 1;
} else {
// TODO ugly hack, please help (cause: page titles can be Longs)!!!
try {
cmpResult = val1.compareTo(val2);
} catch (IllegalStateException e) {
return val1.toString().compareTo(val2.toString());
}
}
if (!isAscending) {
cmpResult = -cmpResult;
}
return cmpResult;
}
});
}
/**
* Use this method to process each data row with the specified {@link Processor}.
*
* @param processor The processing module
*/
public void postProcess(Processor processor) {
this.ensureMutable();
this.postProcess(new Processor[] { processor } );
}
/**
* Gets the interal reporting version the report was created for.
*
* This can be used to ensure backwards compatibility with reports that were created
* for different CQ versions if some default behaviour had to be changed.
*
* @return The version of reporting the report has been created for (0 - CQ 5.4; 1 - CQ
* 5.5)
* @since 5.5
*/
public int getReportingVersion() {
return this.reportingVersion;
}
/**
* Creates a suitable {@link ChartData} object for this report data.
*
* @param limit Number of data to be returned for the chart
* @return The corresponding chart data
*/
public abstract ChartData createChartData(int limit);
/**
* Writes the type definition for each column to the specified {@link JSONWriter}.
*
* @param writer The writer to stream the data to
* @throws JSONException if writing the type definition has failed
*/
public abstract void writeTypesJSON(JSONWriter writer) throws JSONException;
/**
* Writes the sort information for the report to the specified {@link JSONWriter}.
*
* @param writer The writer to stream the data to
* @throws JSONException if writing the sort info has failed
*/
public abstract void writeSortInfoJSON(JSONWriter writer) throws JSONException;
/**
* Writes the result to the specified {@link JSONWriter}.
*
* @param writer The writer to stream the data to
* @param locale The locale to be used for formatting data
* @param start The first record to be streamed; null
to stream from the
* beginning
* @param limit The maximum number of records to be streamed; null
to
* stream to the end
* @throws JSONException if writing the result has failed
*/
public abstract void writeDataJSON(JSONWriter writer, Locale locale, Integer start,
Integer limit) throws JSONException;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy