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 }