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.List;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.hibernate.Session;
23  import org.hibernate.SessionFactory;
24  import org.hibernate.context.spi.CurrentSessionContext;
25  import org.springframework.batch.item.ItemWriter;
26  import org.springframework.beans.factory.InitializingBean;
27  import org.springframework.orm.hibernate3.HibernateOperations;
28  import org.springframework.util.Assert;
29  
30  /**
31   * {@link ItemWriter} that uses a Hibernate session to save or update entities
32   * that are not part of the current Hibernate session. It will also flush the
33   * session after writing (i.e. at chunk boundaries if used in a Spring Batch
34   * TaskletStep). It will also clear the session on write
35   * default (see {@link #setClearSession(boolean) clearSession} property).<br/>
36   * <br/>
37   *
38  <<<<<<< HEAD
39   * The writer is thread safe after its properties are set (normal singleton
40   * behavior), so it can be used to write in multiple concurrent transactions.
41   *
42   * @author Dave Syer
43   * @author Thomas Risberg
44  =======
45   * The writer is thread safe once properties are set (normal singleton behavior)
46   * if a {@link CurrentSessionContext} that uses only one session per thread is
47   * used.
48   *
49   * @author Dave Syer
50   * @author Thomas Risberg
51   * @author Michael Minella
52  >>>>>>> BATCH-1904: Updated to support Hibernate 4
53   *
54   */
55  public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
56  
57  	protected static final Log logger = LogFactory
58  			.getLog(HibernateItemWriter.class);
59  
60  	private HibernateOperations hibernateTemplate;
61  	private SessionFactory sessionFactory;
62  
63  	private boolean clearSession = true;
64  
65  	/**
66  	 * Flag to indicate that the session should be cleared and flushed at the
67  	 * end of the write (default true).
68  	 *
69  	 * @param clearSession
70  	 *            the flag value to set
71  	 */
72  	public void setClearSession(boolean clearSession) {
73  		this.clearSession = clearSession;
74  	}
75  
76  	/**
77  	 * Public setter for the {@link HibernateOperations} property.
78  	 *
79  	 * @param hibernateTemplate
80  	 *            the hibernateTemplate to set
81  	 * @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
82  	 */
83  	public void setHibernateTemplate(HibernateOperations hibernateTemplate) {
84  		this.hibernateTemplate = hibernateTemplate;
85  	}
86  
87  	/**
88  	 * Set the Hibernate SessionFactory to be used internally.
89  	 *
90  	 * @param sessionFactory session factory to be used by the writer
91  	 */
92  	public final void setSessionFactory(SessionFactory sessionFactory) {
93  		this.sessionFactory = sessionFactory;
94  	}
95  
96  	/**
97  	 * Check mandatory properties - there must be a hibernateTemplate.
98  	 */
99  	@Override
100 	public void afterPropertiesSet() {
101 		Assert.state(!(hibernateTemplate == null && sessionFactory == null),
102 				"Either HibernateOperations or SessionFactory must be provided");
103 	}
104 
105 	/**
106 	 * Save or update any entities not in the current hibernate session and then
107 	 * flush the hibernate session.
108 	 *
109 	 * @see org.springframework.batch.item.ItemWriter#write(java.util.List)
110 	 */
111 	@Override
112 	public final void write(List<? extends T> items) {
113 		if(sessionFactory == null) {
114 			doWrite(hibernateTemplate, items);
115 			hibernateTemplate.flush();
116 			if (clearSession) {
117 				hibernateTemplate.clear();
118 			}
119 		}
120 		else {
121 			doWrite(sessionFactory, items);
122 			sessionFactory.getCurrentSession().flush();
123 			if(clearSession) {
124 				sessionFactory.getCurrentSession().clear();
125 			}
126 		}
127 	}
128 
129 	/**
130 	 * Do perform the actual write operation using Hibernate's API.
131 	 * This can be overridden in a subclass if necessary.
132 	 *
133 	 * @param items
134 	 *            the list of items to use for the write
135 	 * @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
136 	 */
137 	protected void doWrite(SessionFactory sessionFactory, List<? extends T> items) {
138 		if (logger.isDebugEnabled()) {
139 			logger.debug("Writing to Hibernate with " + items.size()
140 					+ " items.");
141 		}
142 
143 		Session currentSession = sessionFactory.getCurrentSession();
144 
145 		if (!items.isEmpty()) {
146 			long saveOrUpdateCount = 0;
147 			for (T item : items) {
148 				if (!currentSession.contains(item)) {
149 					currentSession.saveOrUpdate(item);
150 					saveOrUpdateCount++;
151 				}
152 			}
153 			if (logger.isDebugEnabled()) {
154 				logger.debug(saveOrUpdateCount + " entities saved/updated.");
155 				logger.debug((items.size() - saveOrUpdateCount)
156 						+ " entities found in session.");
157 			}
158 		}
159 	}
160 
161 	/**
162 <<<<<<< HEAD
163 	 * Do perform the actual write operation. This can be overridden in a
164 	 * subclass if necessary.
165 =======
166 	 * Do perform the actual write operation using {@link HibernateOperations}.
167 	 * This can be overridden in a subclass if necessary.
168 >>>>>>> BATCH-1904: Updated to support Hibernate 4
169 	 *
170 	 * @param hibernateTemplate
171 	 *            the HibernateTemplate to use for the operation
172 	 * @param items
173 	 *            the list of items to use for the write
174 	 * @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
175 	 */
176 	protected void doWrite(HibernateOperations hibernateTemplate,
177 			List<? extends T> items) {
178 
179 		if (logger.isDebugEnabled()) {
180 			logger.debug("Writing to Hibernate with " + items.size()
181 					+ " items.");
182 		}
183 
184 		if (!items.isEmpty()) {
185 			long saveOrUpdateCount = 0;
186 			for (T item : items) {
187 				if (!hibernateTemplate.contains(item)) {
188 					hibernateTemplate.saveOrUpdate(item);
189 					saveOrUpdateCount++;
190 				}
191 			}
192 			if (logger.isDebugEnabled()) {
193 				logger.debug(saveOrUpdateCount + " entities saved/updated.");
194 				logger.debug((items.size() - saveOrUpdateCount)
195 						+ " entities found in session.");
196 			}
197 		}
198 
199 	}
200 
201 }