View Javadoc

1   /*
2    * Copyright 2006-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.batch.item.database;
17  
18  import java.util.Map;
19  import java.util.concurrent.CopyOnWriteArrayList;
20  
21  import org.hibernate.Session;
22  import org.hibernate.SessionFactory;
23  import org.hibernate.StatelessSession;
24  import org.springframework.batch.item.ExecutionContext;
25  import org.springframework.batch.item.ItemReader;
26  import org.springframework.batch.item.ItemStream;
27  import org.springframework.batch.item.database.orm.HibernateQueryProvider;
28  import org.springframework.beans.factory.InitializingBean;
29  import org.springframework.util.Assert;
30  import org.springframework.util.ClassUtils;
31  
32  /**
33   * {@link ItemReader} for reading database records built on top of Hibernate and
34   * reading only up to a fixed number of items at a time. It executes an HQL
35   * query when initialized is paged as the {@link #read()} method is called. The
36   * query can be set directly using {@link #setQueryString(String)}, a named
37   * query can be used by {@link #setQueryName(String)}, or a query provider
38   * strategy can be supplied via
39   * {@link #setQueryProvider(HibernateQueryProvider)}.
40   *
41   * <p>
42   * The reader can be configured to use either {@link StatelessSession}
43   * sufficient for simple mappings without the need to cascade to associated
44   * objects or standard hibernate {@link Session} for more advanced mappings or
45   * when caching is desired. When stateful session is used it will be cleared in
46   * the {@link #update(ExecutionContext)} method without being flushed (no data
47   * modifications are expected).
48   * </p>
49   *
50   * <p>
51   * The implementation is thread-safe in between calls to
52   * {@link #open(ExecutionContext)}, but remember to use
53   * <code>saveState=false</code> if used in a multi-threaded client (no restart
54   * available).
55   * </p>
56   *
57   * @author Dave Syer
58   *
59   * @since 2.1
60   */
61  public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T> implements ItemStream, InitializingBean {
62  
63  	private HibernateItemReaderHelper<T> helper = new HibernateItemReaderHelper<T>();
64  
65  	private Map<String, Object> parameterValues;
66  
67  	private int fetchSize;
68  
69  	public HibernatePagingItemReader() {
70  		setName(ClassUtils.getShortName(HibernatePagingItemReader.class));
71  	}
72  
73  	/**
74  	 * The parameter values to apply to a query (map of name:value).
75  	 *
76  	 * @param parameterValues the parameter values to set
77  	 */
78  	public void setParameterValues(Map<String, Object> parameterValues) {
79  		this.parameterValues = parameterValues;
80  	}
81  
82  	/**
83  	 * A query name for an externalized query. Either this or the {
84  	 * {@link #setQueryString(String) query string} or the {
85  	 * {@link #setQueryProvider(HibernateQueryProvider) query provider} should
86  	 * be set.
87  	 *
88  	 * @param queryName name of a hibernate named query
89  	 */
90  	public void setQueryName(String queryName) {
91  		helper.setQueryName(queryName);
92  	}
93  
94  	/**
95  	 * Fetch size used internally by Hibernate to limit amount of data fetched
96  	 * from database per round trip.
97  	 *
98  	 * @param fetchSize the fetch size to pass down to Hibernate
99  	 */
100 	public void setFetchSize(int fetchSize) {
101 		this.fetchSize = fetchSize;
102 	}
103 
104 	/**
105 	 * A query provider. Either this or the {{@link #setQueryString(String)
106 	 * query string} or the {{@link #setQueryName(String) query name} should be
107 	 * set.
108 	 *
109 	 * @param queryProvider Hibernate query provider
110 	 */
111 	public void setQueryProvider(HibernateQueryProvider queryProvider) {
112 		helper.setQueryProvider(queryProvider);
113 	}
114 
115 	/**
116 	 * A query string in HQL. Either this or the {
117 	 * {@link #setQueryProvider(HibernateQueryProvider) query provider} or the {
118 	 * {@link #setQueryName(String) query name} should be set.
119 	 *
120 	 * @param queryString HQL query string
121 	 */
122 	public void setQueryString(String queryString) {
123 		helper.setQueryString(queryString);
124 	}
125 
126 	/**
127 	 * The Hibernate SessionFactory to use the create a session.
128 	 *
129 	 * @param sessionFactory the {@link SessionFactory} to set
130 	 */
131 	public void setSessionFactory(SessionFactory sessionFactory) {
132 		helper.setSessionFactory(sessionFactory);
133 	}
134 
135 	/**
136 	 * Can be set only in uninitialized state.
137 	 *
138 	 * @param useStatelessSession <code>true</code> to use
139 	 * {@link StatelessSession} <code>false</code> to use standard hibernate
140 	 * {@link Session}
141 	 */
142 	public void setUseStatelessSession(boolean useStatelessSession) {
143 		helper.setUseStatelessSession(useStatelessSession);
144 	}
145 
146 	@Override
147 	public void afterPropertiesSet() throws Exception {
148 		super.afterPropertiesSet();
149 		Assert.state(fetchSize >= 0, "fetchSize must not be negative");
150 		helper.afterPropertiesSet();
151 	}
152 
153 	@Override
154 	protected void doOpen() throws Exception {
155 		super.doOpen();
156 	}
157 
158 	@Override
159 	protected void doReadPage() {
160 
161 		if (results == null) {
162 			results = new CopyOnWriteArrayList<T>();
163 		}
164 		else {
165 			results.clear();
166 		}
167 
168 		results.addAll(helper.readPage(getPage(), getPageSize(), fetchSize, parameterValues));
169 
170 	}
171 
172 	@Override
173 	protected void doJumpToPage(int itemIndex) {
174 	}
175 
176 	@Override
177 	protected void doClose() throws Exception {
178 		helper.close();
179 		super.doClose();
180 	}
181 
182 }