EMMA Coverage Report (generated Thu May 22 12:08:10 CDT 2014)
[all classes][org.springframework.batch.item.database]

COVERAGE SUMMARY FOR SOURCE FILE [JpaPagingItemReader.java]

nameclass, %method, %block, %line, %
JpaPagingItemReader.java100% (1/1)100% (12/12)97%  (196/202)98%  (57.9/59)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JpaPagingItemReader100% (1/1)100% (12/12)97%  (196/202)98%  (57.9/59)
doOpen (): void 100% (1/1)81%  (21/26)86%  (6/7)
afterPropertiesSet (): void 100% (1/1)95%  (20/21)98%  (5.9/6)
JpaPagingItemReader (): void 100% (1/1)100% (15/15)100% (5/5)
createQuery (): Query 100% (1/1)100% (13/13)100% (3/3)
doClose (): void 100% (1/1)100% (6/6)100% (3/3)
doJumpToPage (int): void 100% (1/1)100% (1/1)100% (1/1)
doReadPage (): void 100% (1/1)100% (100/100)100% (24/24)
setEntityManagerFactory (EntityManagerFactory): void 100% (1/1)100% (4/4)100% (2/2)
setParameterValues (Map): void 100% (1/1)100% (4/4)100% (2/2)
setQueryProvider (JpaQueryProvider): void 100% (1/1)100% (4/4)100% (2/2)
setQueryString (String): void 100% (1/1)100% (4/4)100% (2/2)
setTransacted (boolean): void 100% (1/1)100% (4/4)100% (2/2)

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 
17package org.springframework.batch.item.database;
18 
19import java.util.HashMap;
20import java.util.List;
21import java.util.Map;
22import java.util.concurrent.CopyOnWriteArrayList;
23 
24import javax.persistence.EntityManager;
25import javax.persistence.EntityManagerFactory;
26import javax.persistence.EntityTransaction;
27import javax.persistence.Query;
28 
29import org.springframework.batch.item.ExecutionContext;
30import org.springframework.batch.item.database.orm.JpaQueryProvider;
31import org.springframework.dao.DataAccessResourceFailureException;
32import org.springframework.util.Assert;
33import org.springframework.util.ClassUtils;
34 
35/**
36 * <p>
37 * {@link org.springframework.batch.item.ItemReader} for reading database
38 * records built on top of JPA.
39 * </p>
40 *
41 * <p>
42 * It executes the JPQL {@link #setQueryString(String)} to retrieve requested
43 * data. The query is executed using paged requests of a size specified in
44 * {@link #setPageSize(int)}. Additional pages are requested when needed as
45 * {@link #read()} method is called, returning an object corresponding to
46 * current position.
47 * </p>
48 *
49 * <p>
50 * The performance of the paging depends on the JPA implementation and its use
51 * of database specific features to limit the number of returned rows.
52 * </p>
53 *
54 * <p>
55 * Setting a fairly large page size and using a commit interval that matches the
56 * page size should provide better performance.
57 * </p>
58 *
59 * <p>
60 * In order to reduce the memory usage for large results the persistence context
61 * is flushed and cleared after each page is read. This causes any entities read
62 * to be detached. If you make changes to the entities and want the changes
63 * persisted then you must explicitly merge the entities.
64 * </p>
65 *
66 * <p>
67 * The reader must be configured with an
68 * {@link javax.persistence.EntityManagerFactory}. All entity access is
69 * performed within a new transaction, independent of any existing Spring
70 * managed transactions.
71 * </p>
72 *
73 * <p>
74 * The implementation is thread-safe in between calls to
75 * {@link #open(ExecutionContext)}, but remember to use
76 * <code>saveState=false</code> if used in a multi-threaded client (no restart
77 * available).
78 * </p>
79 *
80 *
81 * @author Thomas Risberg
82 * @author Dave Syer
83 * @author Will Schipp
84 * @since 2.0
85 */
86public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
87 
88        private EntityManagerFactory entityManagerFactory;
89 
90        private EntityManager entityManager;
91 
92        private final Map<String, Object> jpaPropertyMap = new HashMap<String, Object>();
93 
94        private String queryString;
95 
96        private JpaQueryProvider queryProvider;
97 
98        private Map<String, Object> parameterValues;
99        
100        private boolean transacted = true;//default value
101 
102        public JpaPagingItemReader() {
103                setName(ClassUtils.getShortName(JpaPagingItemReader.class));
104        }
105 
106        /**
107         * Create a query using an appropriate query provider (entityManager OR
108         * queryProvider).
109         */
110        private Query createQuery() {
111                if (queryProvider == null) {
112                        return entityManager.createQuery(queryString);
113                }
114                else {
115                        return queryProvider.createQuery();
116                }
117        }
118 
119        public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
120                this.entityManagerFactory = entityManagerFactory;
121        }
122 
123        /**
124         * The parameter values to be used for the query execution.
125         *
126         * @param parameterValues the values keyed by the parameter named used in
127         * the query string.
128         */
129        public void setParameterValues(Map<String, Object> parameterValues) {
130                this.parameterValues = parameterValues;
131        }
132        
133        /**
134         * By default (true) the EntityTransaction will be started and committed around the read.  
135         * Can be overridden (false) in cases where the JPA implementation doesn't support a 
136         * particular transaction.  (e.g. Hibernate with a JTA transaction).  NOTE: may cause 
137         * problems in guaranteeing the object consistency in the EntityManagerFactory.
138         * 
139         * @param transacted
140         */
141        public void setTransacted(boolean transacted) {
142                this.transacted = transacted;
143        }        
144 
145        @Override
146        public void afterPropertiesSet() throws Exception {
147                super.afterPropertiesSet();
148 
149                if (queryProvider == null) {
150                        Assert.notNull(entityManagerFactory);
151                        Assert.hasLength(queryString);
152                }
153                // making sure that the appropriate (JPA) query provider is set
154                else {
155                        Assert.isTrue(queryProvider != null, "JPA query provider must be set");
156                }
157        }
158 
159        /**
160         * @param queryString JPQL query string
161         */
162        public void setQueryString(String queryString) {
163                this.queryString = queryString;
164        }
165 
166        /**
167         * @param queryProvider JPA query provider
168         */
169        public void setQueryProvider(JpaQueryProvider queryProvider) {
170                this.queryProvider = queryProvider;
171        }
172 
173        @Override
174        protected void doOpen() throws Exception {
175                super.doOpen();
176 
177                entityManager = entityManagerFactory.createEntityManager(jpaPropertyMap);
178                if (entityManager == null) {
179                        throw new DataAccessResourceFailureException("Unable to obtain an EntityManager");
180                }
181                // set entityManager to queryProvider, so it participates
182                // in JpaPagingItemReader's managed transaction
183                if (queryProvider != null) {
184                        queryProvider.setEntityManager(entityManager);
185                }
186 
187        }
188 
189        @Override
190        @SuppressWarnings("unchecked")
191        protected void doReadPage() {
192 
193                EntityTransaction tx = null;
194                
195                if (transacted) {
196                        tx = entityManager.getTransaction();
197                        tx.begin();
198                        
199                        entityManager.flush();
200                        entityManager.clear();
201                }//end if
202 
203                Query query = createQuery().setFirstResult(getPage() * getPageSize()).setMaxResults(getPageSize());
204 
205                if (parameterValues != null) {
206                        for (Map.Entry<String, Object> me : parameterValues.entrySet()) {
207                                query.setParameter(me.getKey(), me.getValue());
208                        }
209                }
210 
211                if (results == null) {
212                        results = new CopyOnWriteArrayList<T>();
213                }
214                else {
215                        results.clear();
216                }
217                
218                if (!transacted) {
219                        List<T> queryResult = query.getResultList();
220                        for (T entity : queryResult) {
221                                entityManager.detach(entity);
222                                results.add(entity);
223                        }//end if
224                } else {
225                        results.addAll(query.getResultList());
226                        tx.commit();
227                }//end if
228        }
229 
230        @Override
231        protected void doJumpToPage(int itemIndex) {
232        }
233 
234        @Override
235        protected void doClose() throws Exception {
236                entityManager.close();
237                super.doClose();
238        }
239 
240}

[all classes][org.springframework.batch.item.database]
EMMA 2.0.5312 (C) Vladimir Roubtsov