net.sf.jasperreports.data.cache.ColumnDataCacheHandler Maven / Gradle / Ivy
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 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;
}
}
}