001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028: package net.sf.jasperreports.engine.data;
029:
030: import java.util.HashMap;
031: import java.util.Map;
032:
033: import net.sf.jasperreports.engine.JRDataSource;
034: import net.sf.jasperreports.engine.JRException;
035: import net.sf.jasperreports.engine.JRField;
036: import net.sf.jasperreports.engine.JRRuntimeException;
037: import net.sf.jasperreports.engine.query.JRHibernateQueryExecuter;
038:
039: import org.apache.commons.beanutils.PropertyUtils;
040: import org.hibernate.type.Type;
041:
042: /**
043: * Base abstract Hibernate data source.
044: *
045: * @author Lucian Chirita (lucianc@users.sourceforge.net)
046: * @version $Id: JRHibernateAbstractDataSource.java 1229 2006-04-19 10:27:35Z teodord $
047: */
048: public abstract class JRHibernateAbstractDataSource implements
049: JRDataSource {
050: private final boolean useFieldDescription;
051: private final Map fieldReaders;
052: protected final JRHibernateQueryExecuter queryExecuter;
053: private Object currentReturnValue;
054:
055: /**
056: * Creates a Hibernate data source.
057: *
058: * @param queryExecuter the query executer
059: * @param useFieldDescription whether to use field descriptions for fields to results mapping
060: * @param useIndexOnSingleReturn whether to use indexed addressing even when the query has only one return column
061: */
062: protected JRHibernateAbstractDataSource(
063: JRHibernateQueryExecuter queryExecuter,
064: boolean useFieldDescription, boolean useIndexOnSingleReturn) {
065: this .useFieldDescription = useFieldDescription;
066:
067: this .queryExecuter = queryExecuter;
068:
069: fieldReaders = assignReaders(useIndexOnSingleReturn);
070: }
071:
072: /**
073: * Assigns field readers to report fields.
074: *
075: * @param useIndexOnSingleReturn whether to use indexed addressing even when the query has only one return column
076: * @return a report field name to field reader mapping
077: * @see FieldReader
078: */
079: protected Map assignReaders(boolean useIndexOnSingleReturn) {
080: Map readers = new HashMap();
081:
082: JRField[] fields = queryExecuter.getDataset().getFields();
083: Type[] returnTypes = queryExecuter.getReturnTypes();
084: String[] aliases = queryExecuter.getReturnAliases();
085:
086: Map aliasesMap = new HashMap();
087: if (aliases != null) {
088: for (int i = 0; i < aliases.length; i++) {
089: aliasesMap.put(aliases[i], new Integer(i));
090: }
091: }
092:
093: if (returnTypes.length == 1) {
094: if (returnTypes[0].isEntityType()
095: || returnTypes[0].isComponentType()) {
096: for (int i = 0; i < fields.length; i++) {
097: JRField field = fields[i];
098: readers.put(field.getName(),
099: getFieldReaderSingleReturn(aliasesMap,
100: field, useIndexOnSingleReturn));
101: }
102: } else {
103: if (fields.length > 1) {
104: throw new JRRuntimeException(
105: "The HQL query returns only one non-entity and non-component result but there are more than one fields.");
106: }
107:
108: if (fields.length == 1) {
109: JRField field = fields[0];
110: if (useIndexOnSingleReturn) {
111: readers.put(field.getName(),
112: new IndexFieldReader(0));
113: } else {
114: readers.put(field.getName(),
115: new IdentityFieldReader());
116: }
117: }
118: }
119: } else {
120: for (int i = 0; i < fields.length; i++) {
121: JRField field = fields[i];
122: readers.put(field.getName(), getFieldReader(
123: returnTypes, aliasesMap, field));
124: }
125: }
126:
127: return readers;
128: }
129:
130: protected FieldReader getFieldReaderSingleReturn(Map aliasesMap,
131: JRField field, boolean useIndex) {
132: FieldReader reader;
133:
134: String fieldMapping = getFieldMapping(field);
135: if (aliasesMap.containsKey(fieldMapping)) {
136: if (useIndex) {
137: reader = new IndexFieldReader(0);
138: } else {
139: reader = new IdentityFieldReader();
140: }
141: } else {
142: int firstNestedIdx = fieldMapping
143: .indexOf(PropertyUtils.NESTED_DELIM);
144:
145: if (firstNestedIdx >= 0
146: && aliasesMap.containsKey(fieldMapping.substring(0,
147: firstNestedIdx))) {
148: fieldMapping = fieldMapping
149: .substring(firstNestedIdx + 1);
150: }
151:
152: if (useIndex) {
153: reader = new IndexPropertyFieldReader(0, fieldMapping);
154: } else {
155: reader = new PropertyFieldReader(fieldMapping);
156: }
157: }
158:
159: return reader;
160: }
161:
162: protected FieldReader getFieldReader(Type[] returnTypes,
163: Map aliasesMap, JRField field) {
164: FieldReader reader;
165:
166: String fieldMapping = getFieldMapping(field);
167: Integer fieldIdx = (Integer) aliasesMap.get(fieldMapping);
168: if (fieldIdx == null) {
169: int firstNestedIdx = fieldMapping
170: .indexOf(PropertyUtils.NESTED_DELIM);
171:
172: if (firstNestedIdx < 0) {
173: throw new JRRuntimeException(
174: "Unknown HQL return alias \"" + fieldMapping
175: + "\".");
176: }
177:
178: String fieldAlias = fieldMapping.substring(0,
179: firstNestedIdx);
180: String fieldProperty = fieldMapping
181: .substring(firstNestedIdx + 1);
182:
183: fieldIdx = (Integer) aliasesMap.get(fieldAlias);
184: if (fieldIdx == null) {
185: throw new JRRuntimeException(
186: "The HQL query does not have a \"" + fieldAlias
187: + "\" alias.");
188: }
189:
190: Type type = returnTypes[fieldIdx.intValue()];
191: if (!type.isEntityType() && !type.isComponentType()) {
192: throw new JRRuntimeException(
193: "The HQL query does not have a \"" + fieldAlias
194: + "\" alias.");
195: }
196:
197: reader = new IndexPropertyFieldReader(fieldIdx.intValue(),
198: fieldProperty);
199: } else {
200: reader = new IndexFieldReader(fieldIdx.intValue());
201: }
202:
203: return reader;
204: }
205:
206: /**
207: * Sets the current row of the query result.
208: *
209: * @param currentReturnValue the current row value
210: */
211: protected void setCurrentRowValue(Object currentReturnValue) {
212: this .currentReturnValue = currentReturnValue;
213: }
214:
215: public Object getFieldValue(JRField jrField) throws JRException {
216: FieldReader reader = (FieldReader) fieldReaders.get(jrField
217: .getName());
218: if (reader == null) {
219: throw new JRRuntimeException("No filed reader for "
220: + jrField.getName());
221: }
222: return reader.getFieldValue(currentReturnValue);
223: }
224:
225: protected String getFieldMapping(JRField field) {
226: return (useFieldDescription ? JRAbstractBeanDataSource.FIELD_DESCRIPTION_PROPERTY_NAME_PROVIDER
227: : JRAbstractBeanDataSource.FIELD_NAME_PROPERTY_NAME_PROVIDER)
228: .getPropertyName(field);
229: }
230:
231: /**
232: * Interface used to get the value of a report field from a result row.
233: */
234: protected static interface FieldReader {
235: Object getFieldValue(Object resultValue) throws JRException;
236: }
237:
238: protected static class IdentityFieldReader implements FieldReader {
239: public Object getFieldValue(Object resultValue) {
240: return resultValue;
241: }
242: }
243:
244: protected static class IndexFieldReader implements FieldReader {
245: private final int idx;
246:
247: protected IndexFieldReader(int idx) {
248: this .idx = idx;
249: }
250:
251: public Object getFieldValue(Object resultValue) {
252: return ((Object[]) resultValue)[idx];
253: }
254: }
255:
256: protected static class PropertyFieldReader implements FieldReader {
257: private final String property;
258:
259: protected PropertyFieldReader(String property) {
260: this .property = property;
261: }
262:
263: public Object getFieldValue(Object resultValue)
264: throws JRException {
265: return JRAbstractBeanDataSource.getBeanProperty(
266: resultValue, property);
267: }
268: }
269:
270: protected static class IndexPropertyFieldReader implements
271: FieldReader {
272: private final int idx;
273: private final String property;
274:
275: protected IndexPropertyFieldReader(int idx, String property) {
276: this .idx = idx;
277: this .property = property;
278: }
279:
280: public Object getFieldValue(Object resultValue)
281: throws JRException {
282: return JRAbstractBeanDataSource.getBeanProperty(
283: ((Object[]) resultValue)[idx], property);
284: }
285: }
286: }
|