net.sf.jasperreports.data.cache.ColumnDataCacheHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2022 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.data.cache;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;
import java.util.LinkedHashMap;
import net.sf.jasperreports.engine.JRField;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Report data cache handler that collects data in column stores.
*
* @author Lucian Chirita ([email protected])
*/
public class ColumnDataCacheHandler implements DataCacheHandler
{
private static final Log log = LogFactory.getLog(ColumnDataCacheHandler.class);
private final static int DEFAULT_BUFFER_STORE_SIZE = 4096;
private boolean recordingEnabled;
private volatile DataSnapshot snapshot;
private int bufferStoreSize = DEFAULT_BUFFER_STORE_SIZE;
public ColumnDataCacheHandler()
{
recordingEnabled = true;
}
@Override
public boolean isRecordingEnabled()
{
return recordingEnabled;
}
@Override
public DataRecorder createDataRecorder()
{
if (log.isDebugEnabled())
{
log.debug("creating data recorder");
}
return new DataCollector();
}
@Override
public DataSnapshot getDataSnapshot()
{
return snapshot;
}
protected void disableCaching()
{
if (log.isDebugEnabled())
{
log.debug("caching disabled");
}
this.recordingEnabled = false;
}
protected void setDataSnapshot(DataSnapshot snapshot)
{
this.snapshot = snapshot;
}
@Override
public boolean isSnapshotPopulated()
{
return snapshot != null;
}
protected ColumnStore createColumnStore(JRField field)
{
return new TypedColumnStore(this, field.getValueClass());
}
protected ColumnStore createColumnStore(Class type)
{
BufferColumnStore bufferStore = null;
if (Integer.class.equals(type))
{
bufferStore = new LongArrayStore(bufferStoreSize, NumberToIntegerTransformer.instance());
}
else if (Long.class.equals(type))
{
bufferStore = new LongArrayStore(bufferStoreSize, NumberToLongTransformer.instance());
}
else if (Short.class.equals(type))
{
bufferStore = new LongArrayStore(bufferStoreSize, NumberToShortTransformer.instance());
}
else if (Byte.class.equals(type))
{
bufferStore = new LongArrayStore(bufferStoreSize, NumberToByteTransformer.instance());
}
else if (Character.class.equals(type))
{
bufferStore = new LongArrayStore(bufferStoreSize, NumberToCharTransformer.instance());
}
else if (Double.class.equals(type))
{
bufferStore = new DoubleArrayStore(bufferStoreSize);
}
else if (Float.class.equals(type))
{
bufferStore = new FloatArrayStore(bufferStoreSize);
}
else if (String.class.equals(type))
{
bufferStore = new ObjectArrayStore(String.class, bufferStoreSize);
}
else if (java.sql.Date.class.isAssignableFrom(type))//allow subclasses
{
bufferStore = new DateStore(bufferStoreSize, NumberToSQLDateTransformer.instance());
}
else if (Timestamp.class.isAssignableFrom(type))
{
bufferStore = new TimestampStore(bufferStoreSize);
}
else if (Time.class.isAssignableFrom(type))
{
bufferStore = new DateStore(bufferStoreSize, NumberToSQLTimeTransformer.instance());
}
else if (Date.class.isAssignableFrom(type))
{
bufferStore = new DateStore(bufferStoreSize, NumberToDateTransformer.instance());
}
else if (BigInteger.class.isAssignableFrom(type))
{
bufferStore = new BigIntegerStore(bufferStoreSize);
}
else if (BigDecimal.class.isAssignableFrom(type))
{
bufferStore = new BigDecimalStore(bufferStoreSize);
}
else if (Boolean.class.equals(type))
{
bufferStore = new BooleanStore(bufferStoreSize);
}
ColumnStore store = null;
if (bufferStore != null)
{
store = new BlockColumnStore(bufferStore);
if (log.isDebugEnabled())
{
log.debug("created block store " + store + " with buffer " + bufferStore
+ ", buffer size " + bufferStoreSize);
}
}
return store;
}
class DataCollector implements DataRecorder
{
private final ColumnDataSnapshot dataSnapshot;
public DataCollector()
{
this.dataSnapshot = new ColumnDataSnapshot();
}
@Override
public DatasetRecorder createRecorder()
{
if (log.isDebugEnabled())
{
log.debug("Creating ColumnDataCollector");
}
ColumnDataCollector collector = new ColumnDataCollector();
return collector;
}
@Override
public void addRecordResult(Object key, Object result)
{
ColumnCacheData data = (ColumnCacheData) result;
if (log.isDebugEnabled())
{
log.debug("adding cached data of size " + data.size() + " for for " + key);
}
if (!data.isSerializable())
{
if (log.isDebugEnabled())
{
log.debug("cached data not serializable at key " + key);
}
// mark the snapshot as unpersistable
disablePersistence();
}
dataSnapshot.addCachedData(key, data);
}
@Override
public void setSnapshotPopulated()
{
if (isEnabled())
{
setDataSnapshot(dataSnapshot);
}
}
@Override
public void disableRecording()
{
disableCaching();
}
@Override
public void disablePersistence()
{
dataSnapshot.setPersistable(false);
}
@Override
public boolean isEnabled()
{
return isRecordingEnabled();
}
}
class ColumnDataCollector implements DatasetRecorder
{
private JRField[] fields;
private ColumnStore[] columns;
private int size;
private boolean ended;
private LinkedHashMap parameters;
public ColumnDataCollector()
{
}
@Override
public void start(JRField[] datasetFields)
{
fields = (datasetFields == null) ? new JRField[0] : datasetFields;
columns = new ColumnStore[fields.length];
for (int i = 0; i < fields.length; i++)
{
JRField field = fields[i];
ColumnStore columnStore = createColumnStore(field);
if (columnStore == null)
{
if (log.isDebugEnabled())
{
log.debug("Field " + field.getName() + " of type " + field.getValueClassName()
+ " not cacheable");
}
disableCaching();
return;
}
if (log.isDebugEnabled())
{
log.debug("created store " + columnStore + " for field " + field.getName());
}
columns[i] = columnStore;
}
size = 0;
parameters = null;
ended = false;
}
@Override
public void addParameter(String name, Object value)
{
if (parameters == null)
{
parameters = new LinkedHashMap<>();
}
parameters.put(name, value);
}
@Override
public void addRecord(Object[] values)
{
if (!isRecordingEnabled())
{
// nothing to do
return;
}
if (values == null || values.length != columns.length)
{
throw new IllegalArgumentException();
}
for (int i = 0; i < columns.length; i++)
{
columns[i].addValue(values[i]);
}
++size;
}
@Override
public Object end()
{
if (!isRecordingEnabled())
{
// nothing to do
return null;
}
if (log.isDebugEnabled())
{
log.debug("Recorded cached data source of " + size + " records");
}
ended = true;
String[] fieldNames;
if (fields == null)
{
fieldNames = new String[0];
}
else
{
fieldNames = new String[fields.length];
for (int i = 0; i < fields.length; i++)
{
fieldNames[i] = fields[i].getName();
}
}
ColumnValues[] values = new ColumnValues[columns.length];
for (int i = 0; i < columns.length; i++)
{
values[i] = columns[i].createValues();
}
StandardColumnCacheData data = new StandardColumnCacheData(fieldNames, size, values, parameters);
return data;
}
@Override
public boolean hasEnded()
{
return ended;
}
}
}