KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > toplink > TopLinkTemplate


1 /*
2  * Copyright 2002-2007 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
17 package org.springframework.orm.toplink;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.Arrays JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 import oracle.toplink.exceptions.TopLinkException;
27 import oracle.toplink.expressions.Expression;
28 import oracle.toplink.queryframework.Call;
29 import oracle.toplink.queryframework.DatabaseQuery;
30 import oracle.toplink.queryframework.ReadObjectQuery;
31 import oracle.toplink.sessions.ObjectCopyingPolicy;
32 import oracle.toplink.sessions.Session;
33 import oracle.toplink.sessions.UnitOfWork;
34
35 import org.springframework.dao.DataAccessException;
36 import org.springframework.dao.InvalidDataAccessApiUsageException;
37 import org.springframework.orm.ObjectRetrievalFailureException;
38 import org.springframework.util.Assert;
39 import org.springframework.util.StringUtils;
40
41 /**
42  * Helper class that simplifies TopLink data access code, and converts
43  * TopLinkExceptions into unchecked DataAccessExceptions, following the
44  * <code>org.springframework.dao</code> exception hierarchy.
45  * Uses the same SQLExceptionTranslator mechanism as JdbcTemplate.
46  *
47  * <p>Typically used to implement data access or business logic services that use
48  * TopLink within their implementation but are TopLink-agnostic in their interface.
49  * The latter or code calling the latter only have to deal with business
50  * objects, query objects, and <code>org.springframework.dao</code> exceptions.
51  *
52  * <p>The central method is <code>execute</code>, supporting TopLink access code
53  * implementing the {@link TopLinkCallback} interface. It provides TopLink Session
54  * handling such that neither the TopLinkCallback implementation nor the calling
55  * code needs to explicitly care about retrieving/closing TopLink Sessions,
56  * or handling Session lifecycle exceptions. For typical single step actions,
57  * there are various convenience methods (read, readAll, merge, delete, etc).
58  *
59  * <p>Can be used within a service implementation via direct instantiation
60  * with a SessionFactory reference, or get prepared in an application context
61  * and given to services as bean reference. Note: The SessionFactory should
62  * always be configured as bean in the application context, in the first case
63  * given to the service directly, in the second case to the prepared template.
64  *
65  * <p>This class can be considered as direct alternative to working with the raw
66  * TopLink Session API (through <code>SessionFactoryUtils.getSession()</code>).
67  * The major advantage is its automatic conversion to DataAccessExceptions, the
68  * major disadvantage that no checked application exceptions can get thrown from
69  * within data access code. Corresponding checks and the actual throwing of such
70  * exceptions can often be deferred to after callback execution, though.
71  *
72  * <p>Note that even if {@link TopLinkTransactionManager} is used for transaction
73  * demarcation in higher-level services, all those services above the data
74  * access layer don't need to be TopLink-aware. Setting such a special
75  * PlatformTransactionManager is a configuration issue, without introducing
76  * code dependencies. For example, switching to JTA is just a matter of Spring
77  * configuration (use JtaTransactionManager instead) and TopLink session
78  * configuration, neither affecting application code.
79  *
80  * <p>{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference
81  * to a specific TopLink SessionFactory. It will usually be configured to
82  * create ClientSessions for a ServerSession held by it, allowing for seamless
83  * multi-threaded execution. The Spring application context will manage its lifecycle,
84  * initializing and shutting down the factory as part of the application.
85  *
86  * <p>Thanks to Slavik Markovich for implementing the initial TopLink support prototype!
87  *
88  * @author Juergen Hoeller
89  * @author <a HREF="mailto:james.x.clark@oracle.com">James Clark</a>
90  * @since 1.2
91  * @see #setSessionFactory
92  * @see TopLinkCallback
93  * @see oracle.toplink.sessions.Session
94  * @see TopLinkInterceptor
95  * @see LocalSessionFactoryBean
96  * @see TopLinkTransactionManager
97  * @see org.springframework.transaction.jta.JtaTransactionManager
98  */

99 public class TopLinkTemplate extends TopLinkAccessor implements TopLinkOperations {
100
101     private boolean allowCreate = true;
102
103
104     /**
105      * Create a new TopLinkTemplate instance.
106      */

107     public TopLinkTemplate() {
108     }
109
110     /**
111      * Create a new TopLinkTemplate instance.
112      */

113     public TopLinkTemplate(SessionFactory sessionFactory) {
114         setSessionFactory(sessionFactory);
115         afterPropertiesSet();
116     }
117
118     /**
119      * Create a new TopLinkTemplate instance.
120      * @param allowCreate if a new Session should be created if no thread-bound found
121      */

122     public TopLinkTemplate(SessionFactory sessionFactory, boolean allowCreate) {
123         setSessionFactory(sessionFactory);
124         setAllowCreate(allowCreate);
125         afterPropertiesSet();
126     }
127
128     /**
129      * Set if a new Session should be created when no transactional Session
130      * can be found for the current thread.
131      * <p>TopLinkTemplate is aware of a corresponding Session bound to the
132      * current thread, for example when using TopLinkTransactionManager.
133      * If allowCreate is true, a new non-transactional Session will be created
134      * if none found, which needs to be closed at the end of the operation.
135      * If false, an IllegalStateException will get thrown in this case.
136      * @see SessionFactoryUtils#getSession(SessionFactory, boolean)
137      */

138     public void setAllowCreate(boolean allowCreate) {
139         this.allowCreate = allowCreate;
140     }
141
142     /**
143      * Return if a new Session should be created if no thread-bound found.
144      */

145     public boolean isAllowCreate() {
146         return allowCreate;
147     }
148
149
150     public Object JavaDoc execute(TopLinkCallback action) throws DataAccessException {
151         Assert.notNull(action, "Callback object must not be null");
152
153         Session session = SessionFactoryUtils.getSession(getSessionFactory(), this.allowCreate);
154         try {
155             return action.doInTopLink(session);
156         }
157         catch (TopLinkException ex) {
158             throw convertTopLinkAccessException(ex);
159         }
160         catch (RuntimeException JavaDoc ex) {
161             // callback code threw application exception
162
throw ex;
163         }
164         finally {
165             SessionFactoryUtils.releaseSession(session, getSessionFactory());
166         }
167     }
168
169     public List JavaDoc executeFind(TopLinkCallback action) throws DataAccessException {
170         Object JavaDoc result = execute(action);
171         if (result != null && !(result instanceof List JavaDoc)) {
172             throw new InvalidDataAccessApiUsageException(
173                     "Result object returned from TopLinkCallback isn't a List: [" + result + "]");
174         }
175         return (List JavaDoc) result;
176     }
177
178
179     //-------------------------------------------------------------------------
180
// Convenience methods for executing generic queries
181
//-------------------------------------------------------------------------
182

183     public Object JavaDoc executeNamedQuery(Class JavaDoc entityClass, String JavaDoc queryName) throws DataAccessException {
184         return executeNamedQuery(entityClass, queryName, null, false);
185     }
186
187     public Object JavaDoc executeNamedQuery(Class JavaDoc entityClass, String JavaDoc queryName, boolean enforceReadOnly)
188             throws DataAccessException {
189
190         return executeNamedQuery(entityClass, queryName, null, enforceReadOnly);
191     }
192
193     public Object JavaDoc executeNamedQuery(Class JavaDoc entityClass, String JavaDoc queryName, Object JavaDoc[] args)
194             throws DataAccessException {
195
196         return executeNamedQuery(entityClass, queryName, args, false);
197     }
198
199     public Object JavaDoc executeNamedQuery(
200             final Class JavaDoc entityClass, final String JavaDoc queryName, final Object JavaDoc[] args, final boolean enforceReadOnly)
201             throws DataAccessException {
202
203         return execute(new SessionReadCallback(enforceReadOnly) {
204             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
205                 if (args != null) {
206                     return session.executeQuery(queryName, entityClass, new Vector JavaDoc(Arrays.asList(args)));
207                 }
208                 else {
209                     return session.executeQuery(queryName, entityClass, new Vector JavaDoc());
210                 }
211             }
212         });
213     }
214
215     public Object JavaDoc executeQuery(DatabaseQuery query) throws DataAccessException {
216         return executeQuery(query, null, false);
217     }
218
219     public Object JavaDoc executeQuery(DatabaseQuery query, boolean enforceReadOnly) throws DataAccessException {
220         return executeQuery(query, null, enforceReadOnly);
221     }
222
223     public Object JavaDoc executeQuery(DatabaseQuery query, Object JavaDoc[] args) throws DataAccessException {
224         return executeQuery(query, args, false);
225     }
226
227     public Object JavaDoc executeQuery(final DatabaseQuery query, final Object JavaDoc[] args, final boolean enforceReadOnly)
228             throws DataAccessException {
229
230         return execute(new SessionReadCallback(enforceReadOnly) {
231             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
232                 if (args != null) {
233                     return session.executeQuery(query, new Vector JavaDoc(Arrays.asList(args)));
234                 }
235                 else {
236                     return session.executeQuery(query);
237                 }
238             }
239         });
240     }
241
242
243     //-------------------------------------------------------------------------
244
// Convenience methods for reading a specific set of objects
245
//-------------------------------------------------------------------------
246

247     public List JavaDoc readAll(Class JavaDoc entityClass) throws DataAccessException {
248         return readAll(entityClass, false);
249     }
250
251     public List JavaDoc readAll(final Class JavaDoc entityClass, final boolean enforceReadOnly) throws DataAccessException {
252         return executeFind(new SessionReadCallback(enforceReadOnly) {
253             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
254                 return session.readAllObjects(entityClass);
255             }
256         });
257     }
258
259     public List JavaDoc readAll(Class JavaDoc entityClass, Expression expression) throws DataAccessException {
260         return readAll(entityClass, expression, false);
261     }
262
263     public List JavaDoc readAll(final Class JavaDoc entityClass, final Expression expression, final boolean enforceReadOnly)
264             throws DataAccessException {
265
266         return executeFind(new SessionReadCallback(enforceReadOnly) {
267             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
268                 return session.readAllObjects(entityClass, expression);
269             }
270         });
271     }
272
273     public List JavaDoc readAll(Class JavaDoc entityClass, Call call) throws DataAccessException {
274         return readAll(entityClass, call, false);
275     }
276
277     public List JavaDoc readAll(final Class JavaDoc entityClass, final Call call, final boolean enforceReadOnly)
278             throws DataAccessException {
279
280         return executeFind(new SessionReadCallback(enforceReadOnly) {
281             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
282                 return session.readAllObjects(entityClass, call);
283             }
284         });
285     }
286
287     public Object JavaDoc read(Class JavaDoc entityClass, Expression expression) throws DataAccessException {
288         return read(entityClass, expression, false);
289     }
290
291     public Object JavaDoc read(final Class JavaDoc entityClass, final Expression expression, final boolean enforceReadOnly)
292             throws DataAccessException {
293
294         return execute(new SessionReadCallback(enforceReadOnly) {
295             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
296                 return session.readObject(entityClass, expression);
297             }
298         });
299     }
300
301     public Object JavaDoc read(Class JavaDoc entityClass, Call call) throws DataAccessException {
302         return read(entityClass, call, false);
303     }
304
305     public Object JavaDoc read(final Class JavaDoc entityClass, final Call call, final boolean enforceReadOnly)
306             throws DataAccessException {
307
308         return execute(new SessionReadCallback(enforceReadOnly) {
309             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
310                 return session.readObject(entityClass, call);
311             }
312         });
313     }
314
315
316     //-------------------------------------------------------------------------
317
// Convenience methods for reading an individual object by id
318
//-------------------------------------------------------------------------
319

320     public Object JavaDoc readById(Class JavaDoc entityClass, Object JavaDoc id) throws DataAccessException {
321         return readById(entityClass, id, false);
322     }
323
324     public Object JavaDoc readById(Class JavaDoc entityClass, Object JavaDoc id, boolean enforceReadOnly) throws DataAccessException {
325         return readById(entityClass, new Object JavaDoc[] {id}, enforceReadOnly);
326     }
327
328     public Object JavaDoc readById(Class JavaDoc entityClass, Object JavaDoc[] keys) throws DataAccessException {
329         return readById(entityClass, keys, false);
330     }
331
332     public Object JavaDoc readById(final Class JavaDoc entityClass, final Object JavaDoc[] keys, final boolean enforceReadOnly)
333             throws DataAccessException {
334
335         Assert.isTrue(keys != null && keys.length > 0, "Non-empty keys or id is required");
336
337         ReadObjectQuery query = new ReadObjectQuery(entityClass);
338         query.setSelectionKey(new Vector JavaDoc(Arrays.asList(keys)));
339         Object JavaDoc result = executeQuery(query, enforceReadOnly);
340
341         if (result == null) {
342             Object JavaDoc identifier = (keys.length == 1 ? keys[0] : StringUtils.arrayToCommaDelimitedString(keys));
343             throw new ObjectRetrievalFailureException(entityClass, identifier);
344         }
345         return result;
346     }
347
348     public Object JavaDoc readAndCopy(Class JavaDoc entityClass, Object JavaDoc id) throws DataAccessException {
349         return readAndCopy(entityClass, id, false);
350     }
351
352     public Object JavaDoc readAndCopy(Class JavaDoc entityClass, Object JavaDoc id, boolean enforceReadOnly)
353             throws DataAccessException {
354
355         Object JavaDoc entity = readById(entityClass, id, enforceReadOnly);
356         return copy(entity);
357     }
358
359     public Object JavaDoc readAndCopy(Class JavaDoc entityClass, Object JavaDoc[] keys) throws DataAccessException {
360         return readAndCopy(entityClass, keys, false);
361     }
362
363     public Object JavaDoc readAndCopy(Class JavaDoc entityClass, Object JavaDoc[] keys, boolean enforceReadOnly)
364             throws DataAccessException {
365
366         Object JavaDoc entity = readById(entityClass, keys, enforceReadOnly);
367         return copy(entity);
368     }
369
370
371     //-------------------------------------------------------------------------
372
// Convenience methods for copying and refreshing objects
373
//-------------------------------------------------------------------------
374

375     public Object JavaDoc copy(Object JavaDoc entity) throws DataAccessException {
376         ObjectCopyingPolicy copyingPolicy = new ObjectCopyingPolicy();
377         copyingPolicy.cascadeAllParts();
378         copyingPolicy.setShouldResetPrimaryKey(false);
379         return copy(entity, copyingPolicy);
380     }
381
382     public Object JavaDoc copy(final Object JavaDoc entity, final ObjectCopyingPolicy copyingPolicy)
383             throws DataAccessException {
384
385         return execute(new TopLinkCallback() {
386             public Object JavaDoc doInTopLink(Session session) throws TopLinkException {
387                 return session.copyObject(entity, copyingPolicy);
388             }
389         });
390     }
391
392     public List JavaDoc copyAll(Collection JavaDoc entities) throws DataAccessException {
393         ObjectCopyingPolicy copyingPolicy = new ObjectCopyingPolicy();
394         copyingPolicy.cascadeAllParts();
395         copyingPolicy.setShouldResetPrimaryKey(false);
396         return copyAll(entities, copyingPolicy);
397     }
398
399     public List JavaDoc copyAll(final Collection JavaDoc entities, final ObjectCopyingPolicy copyingPolicy)
400             throws DataAccessException {
401
402         return (List JavaDoc) execute(new TopLinkCallback() {
403             public Object JavaDoc doInTopLink(Session session) throws TopLinkException {
404                 List JavaDoc result = new ArrayList JavaDoc(entities.size());
405                 for (Iterator JavaDoc it = entities.iterator(); it.hasNext();) {
406                     Object JavaDoc entity = it.next();
407                     result.add(session.copyObject(entity, copyingPolicy));
408                 }
409                 return result;
410             }
411         });
412     }
413
414     public Object JavaDoc refresh(Object JavaDoc entity) throws DataAccessException {
415         return refresh(entity, false);
416     }
417
418     public Object JavaDoc refresh(final Object JavaDoc entity, final boolean enforceReadOnly) throws DataAccessException {
419         return execute(new SessionReadCallback(enforceReadOnly) {
420             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
421                 return session.refreshObject(entity);
422             }
423         });
424     }
425
426     public List JavaDoc refreshAll(Collection JavaDoc entities) throws DataAccessException {
427         return refreshAll(entities, false);
428     }
429
430     public List JavaDoc refreshAll(final Collection JavaDoc entities, final boolean enforceReadOnly) throws DataAccessException {
431         return (List JavaDoc) execute(new SessionReadCallback(enforceReadOnly) {
432             protected Object JavaDoc readFromSession(Session session) throws TopLinkException {
433                 List JavaDoc result = new ArrayList JavaDoc(entities.size());
434                 for (Iterator JavaDoc it = entities.iterator(); it.hasNext();) {
435                     Object JavaDoc entity = it.next();
436                     result.add(session.refreshObject(entity));
437                 }
438                 return result;
439             }
440         });
441     }
442
443
444     //-------------------------------------------------------------------------
445
// Convenience methods for persisting and deleting objects
446
//-------------------------------------------------------------------------
447

448     public Object JavaDoc register(final Object JavaDoc entity) {
449         return execute(new UnitOfWorkCallback() {
450             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
451                 return unitOfWork.registerObject(entity);
452             }
453         });
454     }
455
456     public List JavaDoc registerAll(final Collection JavaDoc entities) {
457         return (List JavaDoc) execute(new UnitOfWorkCallback() {
458             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
459                 return unitOfWork.registerAllObjects(entities);
460             }
461         });
462     }
463
464     public void registerNew(final Object JavaDoc entity) {
465         execute(new UnitOfWorkCallback() {
466             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
467                 return unitOfWork.registerNewObject(entity);
468             }
469         });
470     }
471
472     public Object JavaDoc registerExisting(final Object JavaDoc entity) {
473         return execute(new UnitOfWorkCallback() {
474             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
475                 return unitOfWork.registerExistingObject(entity);
476             }
477         });
478     }
479
480     public Object JavaDoc merge(final Object JavaDoc entity) throws DataAccessException {
481         return execute(new UnitOfWorkCallback() {
482             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
483                 return unitOfWork.mergeClone(entity);
484             }
485         });
486     }
487
488     public Object JavaDoc deepMerge(final Object JavaDoc entity) throws DataAccessException {
489         return execute(new UnitOfWorkCallback() {
490             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
491                 return unitOfWork.deepMergeClone(entity);
492             }
493         });
494     }
495
496     public Object JavaDoc shallowMerge(final Object JavaDoc entity) throws DataAccessException {
497         return execute(new UnitOfWorkCallback() {
498             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
499                 return unitOfWork.shallowMergeClone(entity);
500             }
501         });
502     }
503
504     public Object JavaDoc mergeWithReferences(final Object JavaDoc entity) throws DataAccessException {
505         return execute(new UnitOfWorkCallback() {
506             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
507                 return unitOfWork.mergeCloneWithReferences(entity);
508             }
509         });
510     }
511
512     public void delete(final Object JavaDoc entity) throws DataAccessException {
513         execute(new UnitOfWorkCallback() {
514             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
515                 return unitOfWork.deleteObject(entity);
516             }
517         });
518     }
519
520     public void deleteAll(final Collection JavaDoc entities) throws DataAccessException {
521         execute(new UnitOfWorkCallback() {
522             protected Object JavaDoc doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException {
523                 unitOfWork.deleteAllObjects(entities);
524                 return null;
525             }
526         });
527     }
528
529 }
530
Popular Tags