/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. 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 <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.data;
import java.util.HashMap;
import java.util.Map;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.query.JRHibernateQueryExecuter;
import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.type.Type;
/**
* Base abstract Hibernate data source.
*
* @author Lucian Chirita (lucianc@users.sourceforge.net)
* @version $Id: JRHibernateAbstractDataSource.java 3659 2010-03-31 10:20:49Z shertage $
*/
public abstract class JRHibernateAbstractDataSource implements JRDataSource
{
private final boolean useFieldDescription;
private final Map fieldReaders;
protected final JRHibernateQueryExecuter queryExecuter;
private Object currentReturnValue;
/**
* Creates a Hibernate data source.
*
* @param queryExecuter the query executer
* @param useFieldDescription whether to use field descriptions for fields to results mapping
* @param useIndexOnSingleReturn whether to use indexed addressing even when the query has only one return column
*/
protected JRHibernateAbstractDataSource(JRHibernateQueryExecuter queryExecuter, boolean useFieldDescription, boolean useIndexOnSingleReturn)
{
this.useFieldDescription = useFieldDescription;
this.queryExecuter = queryExecuter;
fieldReaders = assignReaders(useIndexOnSingleReturn);
}
/**
* Assigns field readers to report fields.
*
* @param useIndexOnSingleReturn whether to use indexed addressing even when the query has only one return column
* @return a report field name to field reader mapping
* @see FieldReader
*/
protected Map assignReaders(boolean useIndexOnSingleReturn)
{
Map readers = new HashMap();
JRField[] fields = queryExecuter.getDataset().getFields();
Type[] returnTypes = queryExecuter.getReturnTypes();
String[] aliases = queryExecuter.getReturnAliases();
Map aliasesMap = new HashMap();
if (aliases != null)
{
for (int i = 0; i < aliases.length; i++)
{
aliasesMap.put(aliases[i], Integer.valueOf(i));
}
}
if (returnTypes.length == 1)
{
if (returnTypes[0].isEntityType() || returnTypes[0].isComponentType())
{
for (int i = 0; i < fields.length; i++)
{
JRField field = fields[i];
readers.put(field.getName(), getFieldReaderSingleReturn(aliasesMap, field, useIndexOnSingleReturn));
}
}
else
{
if (fields.length > 1)
{
throw new JRRuntimeException("The HQL query returns only one non-entity and non-component result but there are more than one fields.");
}
if (fields.length == 1)
{
JRField field = fields[0];
if (useIndexOnSingleReturn)
{
readers.put(field.getName(), new IndexFieldReader(0));
}
else
{
readers.put(field.getName(), new IdentityFieldReader());
}
}
}
}
else
{
for (int i = 0; i < fields.length; i++)
{
JRField field = fields[i];
readers.put(field.getName(), getFieldReader(returnTypes, aliasesMap, field));
}
}
return readers;
}
protected FieldReader getFieldReaderSingleReturn(Map aliasesMap, JRField field, boolean useIndex)
{
FieldReader reader;
String fieldMapping = getFieldMapping(field);
if (aliasesMap.containsKey(fieldMapping))
{
if (useIndex)
{
reader = new IndexFieldReader(0);
}
else
{
reader = new IdentityFieldReader();
}
}
else
{
int firstNestedIdx = fieldMapping.indexOf(PropertyUtils.NESTED_DELIM);
if (firstNestedIdx >= 0 && aliasesMap.containsKey(fieldMapping.substring(0, firstNestedIdx)))
{
fieldMapping = fieldMapping.substring(firstNestedIdx + 1);
}
if (useIndex)
{
reader = new IndexPropertyFieldReader(0, fieldMapping);
}
else
{
reader = new PropertyFieldReader(fieldMapping);
}
}
return reader;
}
protected FieldReader getFieldReader(Type[] returnTypes, Map aliasesMap, JRField field)
{
FieldReader reader;
String fieldMapping = getFieldMapping(field);
Integer fieldIdx = (Integer) aliasesMap.get(fieldMapping);
if (fieldIdx == null)
{
int firstNestedIdx = fieldMapping.indexOf(PropertyUtils.NESTED_DELIM);
if (firstNestedIdx < 0)
{
throw new JRRuntimeException("Unknown HQL return alias \"" + fieldMapping + "\".");
}
String fieldAlias = fieldMapping.substring(0, firstNestedIdx);
String fieldProperty = fieldMapping.substring(firstNestedIdx + 1);
fieldIdx = (Integer) aliasesMap.get(fieldAlias);
if (fieldIdx == null)
{
throw new JRRuntimeException("The HQL query does not have a \"" + fieldAlias + "\" alias.");
}
Type type = returnTypes[fieldIdx.intValue()];
if (!type.isEntityType() && !type.isComponentType())
{
throw new JRRuntimeException("The HQL query does not have a \"" + fieldAlias + "\" alias.");
}
reader = new IndexPropertyFieldReader(fieldIdx.intValue(), fieldProperty);
}
else
{
reader = new IndexFieldReader(fieldIdx.intValue());
}
return reader;
}
/**
* Sets the current row of the query result.
*
* @param currentReturnValue the current row value
*/
protected void setCurrentRowValue(Object currentReturnValue)
{
this.currentReturnValue = currentReturnValue;
}
public Object getFieldValue(JRField jrField) throws JRException
{
FieldReader reader = (FieldReader) fieldReaders.get(jrField.getName());
if (reader == null)
{
throw new JRRuntimeException("No filed reader for " + jrField.getName());
}
return reader.getFieldValue(currentReturnValue);
}
protected String getFieldMapping(JRField field)
{
return (useFieldDescription ?
JRAbstractBeanDataSource.FIELD_DESCRIPTION_PROPERTY_NAME_PROVIDER :
JRAbstractBeanDataSource.FIELD_NAME_PROPERTY_NAME_PROVIDER)
.getPropertyName(field);
}
/**
* Interface used to get the value of a report field from a result row.
*/
protected static interface FieldReader
{
Object getFieldValue(Object resultValue) throws JRException;
}
protected static class IdentityFieldReader implements FieldReader
{
public Object getFieldValue(Object resultValue)
{
return resultValue;
}
}
protected static class IndexFieldReader implements FieldReader
{
private final int idx;
protected IndexFieldReader(int idx)
{
this.idx = idx;
}
public Object getFieldValue(Object resultValue)
{
return ((Object[]) resultValue)[idx];
}
}
protected static class PropertyFieldReader implements FieldReader
{
private final String property;
protected PropertyFieldReader(String property)
{
this.property = property;
}
public Object getFieldValue(Object resultValue) throws JRException
{
return JRAbstractBeanDataSource.getBeanProperty(resultValue, property);
}
}
protected static class IndexPropertyFieldReader implements FieldReader
{
private final int idx;
private final String property;
protected IndexPropertyFieldReader(int idx, String property)
{
this.idx = idx;
this.property = property;
}
public Object getFieldValue(Object resultValue) throws JRException
{
return JRAbstractBeanDataSource.getBeanProperty(((Object[]) resultValue)[idx], property);
}
}
}