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.query;
029:
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Map;
036: import java.util.Set;
037:
038: import net.sf.jasperreports.engine.JRDataSource;
039: import net.sf.jasperreports.engine.JRDataset;
040: import net.sf.jasperreports.engine.JRException;
041: import net.sf.jasperreports.engine.JRParameter;
042: import net.sf.jasperreports.engine.JRPropertiesMap;
043: import net.sf.jasperreports.engine.JRRuntimeException;
044: import net.sf.jasperreports.engine.JRValueParameter;
045: import net.sf.jasperreports.engine.data.JRHibernateIterateDataSource;
046: import net.sf.jasperreports.engine.data.JRHibernateListDataSource;
047: import net.sf.jasperreports.engine.data.JRHibernateScrollDataSource;
048: import net.sf.jasperreports.engine.util.JRProperties;
049: import net.sf.jasperreports.engine.util.JRStringUtil;
050:
051: import org.apache.commons.logging.Log;
052: import org.apache.commons.logging.LogFactory;
053: import org.hibernate.Hibernate;
054: import org.hibernate.Query;
055: import org.hibernate.ScrollMode;
056: import org.hibernate.ScrollableResults;
057: import org.hibernate.Session;
058: import org.hibernate.type.Type;
059:
060: /**
061: * HQL query executer that uses Hibernate 3.
062: *
063: * @author Lucian Chirita (lucianc@users.sourceforge.net)
064: * @version $Id: JRHibernateQueryExecuter.java 1719 2007-05-07 08:54:24Z lucianc $
065: */
066: public class JRHibernateQueryExecuter extends JRAbstractQueryExecuter {
067: private static final Log log = LogFactory
068: .getLog(JRHibernateQueryExecuter.class);
069:
070: private static final Map hibernateTypeMap;
071:
072: static {
073: hibernateTypeMap = new HashMap();
074: hibernateTypeMap.put(Boolean.class, Hibernate.BOOLEAN);
075: hibernateTypeMap.put(Byte.class, Hibernate.BYTE);
076: hibernateTypeMap.put(Double.class, Hibernate.DOUBLE);
077: hibernateTypeMap.put(Float.class, Hibernate.FLOAT);
078: hibernateTypeMap.put(Integer.class, Hibernate.INTEGER);
079: hibernateTypeMap.put(Long.class, Hibernate.LONG);
080: hibernateTypeMap.put(Short.class, Hibernate.SHORT);
081: hibernateTypeMap.put(java.math.BigDecimal.class,
082: Hibernate.BIG_DECIMAL);
083: hibernateTypeMap.put(java.math.BigInteger.class,
084: Hibernate.BIG_INTEGER);
085: hibernateTypeMap.put(Character.class, Hibernate.CHARACTER);
086: hibernateTypeMap.put(String.class, Hibernate.STRING);
087: hibernateTypeMap.put(java.util.Date.class, Hibernate.DATE);
088: hibernateTypeMap.put(java.sql.Timestamp.class,
089: Hibernate.TIMESTAMP);
090: hibernateTypeMap.put(java.sql.Time.class, Hibernate.TIME);
091: }
092:
093: private final Integer reportMaxCount;
094:
095: private Session session;
096: private Query query;
097: private boolean queryRunning;
098: private ScrollableResults scrollableResults;
099: private boolean isClearCache;
100:
101: public JRHibernateQueryExecuter(JRDataset dataset, Map parameters) {
102: super (dataset, parameters);
103:
104: session = (Session) getParameterValue(JRHibernateQueryExecuterFactory.PARAMETER_HIBERNATE_SESSION);
105: reportMaxCount = (Integer) getParameterValue(JRParameter.REPORT_MAX_COUNT);
106: isClearCache = JRProperties
107: .getBooleanProperty(
108: dataset.getPropertiesMap(),
109: JRHibernateQueryExecuterFactory.PROPERTY_HIBERNATE_CLEAR_CACHE,
110: false);
111:
112: if (session == null) {
113: log
114: .warn("The supplied org.hibernate.Session object is null.");
115: }
116:
117: parseQuery();
118: }
119:
120: /**
121: * Creates an instance of {@link JRHibernateListDataSource JRHibernateListDataSource},
122: * {@link JRHibernateIterateDataSource JRHibernateIterateDataSource} or
123: * {@link JRHibernateScrollDataSource JRHibernateScrollDataSource}, depending on the
124: */
125: public JRDataSource createDatasource() throws JRException {
126: JRDataSource datasource = null;
127: String queryString = getQueryString();
128:
129: if (session != null && queryString != null
130: && queryString.trim().length() > 0) {
131: createQuery(queryString);
132:
133: datasource = createResultDatasource();
134: }
135:
136: return datasource;
137: }
138:
139: /**
140: * Creates a data source out of the query result.
141: *
142: * @return the data source
143: */
144: protected JRDataSource createResultDatasource() {
145: JRDataSource resDatasource;
146:
147: JRPropertiesMap datasetProperties = dataset.getPropertiesMap();
148:
149: String runType = JRProperties
150: .getProperty(
151: datasetProperties,
152: JRHibernateQueryExecuterFactory.PROPERTY_HIBERNATE_QUERY_RUN_TYPE);
153: boolean useFieldDescriptions = JRProperties
154: .getBooleanProperty(
155: datasetProperties,
156: JRHibernateQueryExecuterFactory.PROPERTY_HIBERNATE_FIELD_MAPPING_DESCRIPTIONS,
157: true);
158:
159: if (runType == null
160: || runType
161: .equals(JRHibernateQueryExecuterFactory.VALUE_HIBERNATE_QUERY_RUN_TYPE_LIST)) {
162: try {
163: int pageSize = JRProperties
164: .getIntegerProperty(
165: datasetProperties,
166: JRHibernateQueryExecuterFactory.PROPERTY_HIBERNATE_QUERY_LIST_PAGE_SIZE,
167: 0);
168:
169: resDatasource = new JRHibernateListDataSource(this ,
170: useFieldDescriptions, pageSize);
171: } catch (NumberFormatException e) {
172: throw new JRRuntimeException(
173: "The "
174: + JRHibernateQueryExecuterFactory.PROPERTY_HIBERNATE_QUERY_LIST_PAGE_SIZE
175: + " property must be numerical.");
176: }
177: } else if (runType
178: .equals(JRHibernateQueryExecuterFactory.VALUE_HIBERNATE_QUERY_RUN_TYPE_ITERATE)) {
179: resDatasource = new JRHibernateIterateDataSource(this ,
180: useFieldDescriptions);
181: } else if (runType
182: .equals(JRHibernateQueryExecuterFactory.VALUE_HIBERNATE_QUERY_RUN_TYPE_SCROLL)) {
183: resDatasource = new JRHibernateScrollDataSource(this ,
184: useFieldDescriptions);
185: } else {
186: throw new JRRuntimeException(
187: "Unknown value for the "
188: + JRHibernateQueryExecuterFactory.PROPERTY_HIBERNATE_QUERY_RUN_TYPE
189: + " property. Possible values are "
190: + JRHibernateQueryExecuterFactory.VALUE_HIBERNATE_QUERY_RUN_TYPE_LIST
191: + ", "
192: + JRHibernateQueryExecuterFactory.VALUE_HIBERNATE_QUERY_RUN_TYPE_ITERATE
193: + " and "
194: + JRHibernateQueryExecuterFactory.VALUE_HIBERNATE_QUERY_RUN_TYPE_SCROLL
195: + ".");
196: }
197:
198: return resDatasource;
199: }
200:
201: /**
202: * Creates the Hibernate query object.
203: * <p/>
204: * If the value of the {@link JRHibernateQueryExecuterFactory#PARAMETER_HIBERNATE_FILTER_COLLECTION PARAMETER_HIBERNATE_FILTER_COLLECTION}
205: * is not null, then a filter query is created using the value of the paramter as the collection.
206: *
207: * @param queryString the query string
208: */
209: protected synchronized void createQuery(String queryString) {
210: if (log.isDebugEnabled()) {
211: log.debug("HQL query: " + queryString);
212: }
213:
214: Object filterCollection = getParameterValue(JRHibernateQueryExecuterFactory.PARAMETER_HIBERNATE_FILTER_COLLECTION);
215: if (filterCollection == null) {
216: query = session.createQuery(queryString);
217: } else {
218: query = session.createFilter(filterCollection, queryString);
219: }
220: query.setReadOnly(true);
221:
222: int fetchSize = JRProperties.getIntegerProperty(dataset
223: .getPropertiesMap(),
224: JRJdbcQueryExecuterFactory.PROPERTY_JDBC_FETCH_SIZE, 0);
225: if (fetchSize != 0) {
226: query.setFetchSize(fetchSize);
227: }
228:
229: setParameters();
230: }
231:
232: /**
233: * Binds values for all the query paramters.
234: */
235: protected void setParameters() {
236: List parameterNames = getCollectedParameterNames();
237:
238: if (!parameterNames.isEmpty()) {
239: Set namesSet = new HashSet();
240:
241: for (Iterator iter = parameterNames.iterator(); iter
242: .hasNext();) {
243: String parameterName = (String) iter.next();
244: if (namesSet.add(parameterName)) {
245: JRValueParameter parameter = getValueParameter(parameterName);
246: setParameter(parameter);
247: }
248: }
249: }
250: }
251:
252: /**
253: * Binds a paramter value to a query paramter.
254: *
255: * @param parameter the report parameter
256: */
257: protected void setParameter(JRValueParameter parameter) {
258: String hqlParamName = getHqlParameterName(parameter.getName());
259: Class clazz = parameter.getValueClass();
260: Object parameterValue = parameter.getValue();
261:
262: if (log.isDebugEnabled()) {
263: log.debug("Parameter " + hqlParamName + " of type "
264: + clazz.getName() + ": " + parameterValue);
265: }
266:
267: Type type = (Type) hibernateTypeMap.get(clazz);
268:
269: if (type != null) {
270: query.setParameter(hqlParamName, parameterValue, type);
271: } else if (Collection.class.isAssignableFrom(clazz)) {
272: query.setParameterList(hqlParamName,
273: (Collection) parameterValue);
274: } else {
275: if (session.getSessionFactory().getClassMetadata(clazz) != null) //param type is a hibernate mapped entity
276: {
277: query.setEntity(hqlParamName, parameterValue);
278: } else //let hibernate try to guess the type
279: {
280: query.setParameter(hqlParamName, parameterValue);
281: }
282: }
283: }
284:
285: /**
286: * Closes the scrollable result when <em>scroll</em> execution type is used.
287: */
288: public synchronized void close() {
289: closeScrollableResults();
290:
291: query = null;
292: }
293:
294: /**
295: * Closes the scrollable results of the query.
296: */
297: public void closeScrollableResults() {
298: if (scrollableResults != null) {
299: try {
300: scrollableResults.close();
301: } finally {
302: scrollableResults = null;
303: }
304: }
305: }
306:
307: public synchronized boolean cancelQuery() throws JRException {
308: if (queryRunning) {
309: session.cancelQuery();
310: return true;
311: }
312:
313: return false;
314: }
315:
316: protected String getParameterReplacement(String parameterName) {
317: return ':' + getHqlParameterName(parameterName);
318: }
319:
320: protected String getHqlParameterName(String parameterName) {
321: return '_' + JRStringUtil.getLiteral(parameterName);
322: }
323:
324: /**
325: * Returns the return types of the HQL query.
326: *
327: * @return the return types of the HQL query
328: */
329: public Type[] getReturnTypes() {
330: return query.getReturnTypes();
331: }
332:
333: /**
334: * Returns the aliases of the HQL query.
335: *
336: * @return the aliases of the HQL query
337: */
338: public String[] getReturnAliases() {
339: return query.getReturnAliases();
340: }
341:
342: /**
343: * Returns the dataset for which the query executer has been created.
344: *
345: * @return the dataset for which the query executer has been created
346: */
347: public JRDataset getDataset() {
348: return dataset;
349: }
350:
351: /**
352: * Runs the query by calling <code>org.hibernate.Query.list()</code>.
353: * <p/>
354: * All the result rows are returned.
355: *
356: * @return the result of the query as a list
357: */
358: public List list() {
359: setMaxCount();
360:
361: setQueryRunning(true);
362: try {
363: return query.list();
364: } finally {
365: setQueryRunning(false);
366: }
367: }
368:
369: protected synchronized void setQueryRunning(boolean queryRunning) {
370: this .queryRunning = queryRunning;
371: }
372:
373: private void setMaxCount() {
374: if (reportMaxCount != null) {
375: query.setMaxResults(reportMaxCount.intValue());
376: }
377: }
378:
379: /**
380: * Returns a page of the query results by calling <code>org.hibernate.Query.iterate()</code>.
381: *
382: * @param firstIndex the index of the first row to return
383: * @param resultCount the number of rows to return
384: * @return result row list
385: */
386: public List list(int firstIndex, int resultCount) {
387: if (reportMaxCount != null
388: && firstIndex + resultCount > reportMaxCount.intValue()) {
389: resultCount = reportMaxCount.intValue() - firstIndex;
390: }
391:
392: query.setFirstResult(firstIndex);
393: query.setMaxResults(resultCount);
394: if (isClearCache)
395: clearCache();
396:
397: return query.list();
398: }
399:
400: /**
401: * Runs the query by calling <code>org.hibernate.Query.iterate()</code>.
402: *
403: * @return query iterator
404: */
405: public Iterator iterate() {
406: setMaxCount();
407:
408: setQueryRunning(true);
409: try {
410: return query.iterate();
411: } finally {
412: setQueryRunning(false);
413: }
414: }
415:
416: /**
417: * Runs the query by calling <code>org.hibernate.Query.scroll()</code>.
418: *
419: * @return scrollable results of the query
420: */
421: public ScrollableResults scroll() {
422: setMaxCount();
423:
424: setQueryRunning(true);
425: try {
426: scrollableResults = query.scroll(ScrollMode.FORWARD_ONLY);
427: } finally {
428: setQueryRunning(false);
429: }
430:
431: return scrollableResults;
432: }
433:
434: public void clearCache() {
435: session.flush();
436: session.clear();
437: }
438: }
|