]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
3e8a5bf61ad87022164fec8d09d9c29d00192939
[tmp/jakarta-migration.git] /
1 /**
2  *  This document is a part of the source code and related artifacts
3  *  for CollectionSpace, an open source collections management system
4  *  for museums and related institutions:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17  */
18 package org.collectionspace.services.common.storage.jpa;
19
20 import java.util.Date;
21 import java.util.List;
22 import javax.persistence.EntityManager;
23 import javax.persistence.EntityManagerFactory;
24 import javax.persistence.Query;
25 import org.collectionspace.services.common.context.ServiceContext;
26 import org.collectionspace.services.common.document.BadRequestException;
27 import org.collectionspace.services.common.document.DocumentException;
28 import org.collectionspace.services.common.document.DocumentFilter;
29 import org.collectionspace.services.common.document.DocumentHandler;
30 import org.collectionspace.services.common.document.DocumentNotFoundException;
31 import org.collectionspace.services.common.document.DocumentHandler.Action;
32 import org.collectionspace.services.common.document.DocumentWrapper;
33 import org.collectionspace.services.common.document.DocumentWrapperImpl;
34 import org.collectionspace.services.common.document.JaxbUtils;
35 import org.collectionspace.services.common.storage.StorageClient;
36 import org.collectionspace.services.common.context.ServiceContextProperties;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * JpaStorageClient is used to perform CRUD operations on SQL storage using JPA.
42  * It uses @see DocumentHandler as IOHandler with the client.
43  * All the operations in this client are carried out under their own transactions.
44  * A call to any method would start and commit/rollback a transaction.
45  * 
46  * Assumption: each persistent entityReceived has the following 3 attributes
47 <xs:element name="createdAt" type="xs:dateTime">
48 <xs:annotation>
49 <xs:appinfo>
50 <hj:basic>
51 <orm:column name="created_at" nullable="false"/>
52 </hj:basic>
53 </xs:appinfo>
54 </xs:annotation>
55 </xs:element>
56 <xs:element name="updatedAt" type="xs:dateTime">
57 <xs:annotation>
58 <xs:appinfo>
59 <hj:basic>
60 <orm:column name="updated_at" />
61 </hj:basic>
62 </xs:appinfo>
63 </xs:annotation>
64 </xs:element>
65 </xs:sequence>
66 <xs:attribute name="csidFound" type="xs:string">
67 <xs:annotation>
68 <xs:appinfo>
69 <hj:csidReceived>
70 <orm:column name="csidFound" length="128" nullable="false"/>
71 </hj:csidReceived>
72 </xs:appinfo>
73 </xs:annotation>
74 </xs:attribute>
75  *
76  * $LastChangedRevision: $ $LastChangedDate: $
77  */
78 public class JpaStorageClientImpl implements StorageClient {
79
80     /** The logger. */
81     private final Logger logger = LoggerFactory.getLogger(JpaStorageClientImpl.class);
82
83     /**
84      * Instantiates a new jpa storage client.
85      */
86     public JpaStorageClientImpl() {
87     }
88
89     /* (non-Javadoc)
90      * @see org.collectionspace.services.common.storage.StorageClient#create(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
91      */
92     @Override
93     public String create(ServiceContext ctx,
94             DocumentHandler handler) throws BadRequestException,
95             DocumentException {
96
97         if (ctx == null) {
98             throw new IllegalArgumentException(
99                     "JpaStorageClient.create: ctx is missing");
100         }
101         if (handler == null) {
102             throw new IllegalArgumentException(
103                     "JpaStorageClient.create: handler is missing");
104         }
105         EntityManagerFactory emf = null;
106         EntityManager em = null;
107         try {
108             handler.prepare(Action.CREATE);
109             Object entity = handler.getCommonPart();
110             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entity);
111             handler.handle(Action.CREATE, wrapDoc);
112             JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date());
113             emf = JpaStorageUtils.getEntityManagerFactory();
114             em = emf.createEntityManager();
115             em.getTransaction().begin();
116             em.persist(entity);
117             em.getTransaction().commit();
118             handler.complete(Action.CREATE, wrapDoc);
119             return (String) JaxbUtils.getValue(entity, "getCsid");
120         } catch (BadRequestException bre) {
121             if (em != null && em.getTransaction().isActive()) {
122                 em.getTransaction().rollback();
123             }
124             throw bre;
125         } catch (DocumentException de) {
126             throw de;
127         } catch (Exception e) {
128             if (em != null && em.getTransaction().isActive()) {
129                 em.getTransaction().rollback();
130             }
131             if (logger.isDebugEnabled()) {
132                 logger.debug("Caught exception ", e);
133             }
134             throw new DocumentException(e);
135         } finally {
136             if (em != null) {
137                 JpaStorageUtils.releaseEntityManagerFactory(emf);
138             }
139         }
140
141     }
142
143     /* (non-Javadoc)
144      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
145      */
146     @Override
147     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
148             throws DocumentNotFoundException, DocumentException {
149         throw new UnsupportedOperationException();
150     }
151
152     /* (non-Javadoc)
153      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
154      */
155     @Override
156     public void get(ServiceContext ctx, String id, DocumentHandler handler)
157             throws DocumentNotFoundException, DocumentException {
158         if (ctx == null) {
159             throw new IllegalArgumentException(
160                     "JpaStorageClient.get: ctx is missing");
161         }
162         if (handler == null) {
163             throw new IllegalArgumentException(
164                     "JpaStorageClient.get: handler is missing");
165         }
166         DocumentFilter docFilter = handler.getDocumentFilter();
167         if (docFilter == null) {
168             docFilter = handler.createDocumentFilter();
169         }
170         EntityManagerFactory emf = null;
171         EntityManager em = null;
172         try {
173             handler.prepare(Action.GET);
174             Object o = null;
175             o = JpaStorageUtils.getEntity(getEntityName(ctx), id, docFilter);
176             if (null == o) {
177                 if (em != null && em.getTransaction().isActive()) {
178                     em.getTransaction().rollback();
179                 }
180                 String msg = "could not find entity with id=" + id;
181                 throw new DocumentNotFoundException(msg);
182             }
183             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(o);
184             handler.handle(Action.GET, wrapDoc);
185             handler.complete(Action.GET, wrapDoc);
186         } catch (DocumentException de) {
187             throw de;
188         } catch (Exception e) {
189             if (logger.isDebugEnabled()) {
190                 logger.debug("Caught exception ", e);
191             }
192             throw new DocumentException(e);
193         } finally {
194             if (emf != null) {
195                 JpaStorageUtils.releaseEntityManagerFactory(emf);
196             }
197         }
198     }
199
200     /* (non-Javadoc)
201      * @see org.collectionspace.services.common.storage.StorageClient#getAll(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
202      */
203     @Override
204     public void getAll(ServiceContext ctx, DocumentHandler handler)
205             throws DocumentNotFoundException, DocumentException {
206         throw new UnsupportedOperationException("use getFiltered instead");
207     }
208
209     /* (non-Javadoc)
210      * @see org.collectionspace.services.common.storage.StorageClient#getFiltered(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
211      */
212     @Override
213     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
214             throws DocumentNotFoundException, DocumentException {
215         if (ctx == null) {
216             throw new IllegalArgumentException(
217                     "JpaStorageClient.getFiltered: ctx is missing");
218         }
219         if (handler == null) {
220             throw new IllegalArgumentException(
221                     "JpaStorageClient.getFiltered: handler is missing");
222         }
223
224         DocumentFilter docFilter = handler.getDocumentFilter();
225         if (docFilter == null) {
226             docFilter = handler.createDocumentFilter();
227         }
228         EntityManagerFactory emf = null;
229         EntityManager em = null;
230         try {
231             handler.prepare(Action.GET_ALL);
232
233             StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
234             queryStrBldr.append(getEntityName(ctx));
235             queryStrBldr.append(" a");
236             List<DocumentFilter.ParamBinding> params = docFilter.buildWhereForSearch(queryStrBldr);
237             //TODO: add tenant csidReceived
238             emf = JpaStorageUtils.getEntityManagerFactory();
239             em = emf.createEntityManager();
240             String queryStr = queryStrBldr.toString(); //for debugging
241             Query q = em.createQuery(queryStr);
242             //bind parameters
243             for (DocumentFilter.ParamBinding p : params) {
244                 q.setParameter(p.getName(), p.getValue());
245             }
246             if (docFilter.getOffset() > 0) {
247                 q.setFirstResult(docFilter.getOffset());
248             }
249             if (docFilter.getPageSize() > 0) {
250                 q.setMaxResults(docFilter.getPageSize());
251             }
252
253             //FIXME is transaction required for get?
254             em.getTransaction().begin();
255             List list = q.getResultList();
256             em.getTransaction().commit();
257             DocumentWrapper<List> wrapDoc = new DocumentWrapperImpl<List>(list);
258             handler.handle(Action.GET_ALL, wrapDoc);
259             handler.complete(Action.GET_ALL, wrapDoc);
260         } catch (DocumentException de) {
261             throw de;
262         } catch (Exception e) {
263             if (logger.isDebugEnabled()) {
264                 logger.debug("Caught exception ", e);
265             }
266             throw new DocumentException(e);
267         } finally {
268             if (emf != null) {
269                 JpaStorageUtils.releaseEntityManagerFactory(emf);
270             }
271         }
272     }
273
274     /* (non-Javadoc)
275      * @see org.collectionspace.services.common.storage.StorageClient#update(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
276      */
277     @Override
278     public void update(ServiceContext ctx, String id, DocumentHandler handler)
279             throws BadRequestException, DocumentNotFoundException,
280             DocumentException {
281         if (ctx == null) {
282             throw new IllegalArgumentException(
283                     "JpaStorageClient.update: ctx is missing");
284         }
285         if (handler == null) {
286             throw new IllegalArgumentException(
287                     "JpaStorageClient.update: handler is missing");
288         }
289         EntityManagerFactory emf = null;
290         EntityManager em = null;
291         try {
292             handler.prepare(Action.UPDATE);
293             Object entityReceived = handler.getCommonPart();
294             emf = JpaStorageUtils.getEntityManagerFactory();
295             em = emf.createEntityManager();
296             em.getTransaction().begin();
297             Object entityFound = em.find(entityReceived.getClass(), id);
298             if (entityFound == null) {
299                 if (em != null && em.getTransaction().isActive()) {
300                     em.getTransaction().rollback();
301                 }
302                 String msg = "could not find entity with id=" + id;
303                 logger.error(msg);
304                 throw new DocumentNotFoundException(msg);
305             }
306             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entityFound);
307             handler.handle(Action.UPDATE, wrapDoc);
308             em.getTransaction().commit();
309             handler.complete(Action.UPDATE, wrapDoc);
310         } catch (BadRequestException bre) {
311             if (em != null && em.getTransaction().isActive()) {
312                 em.getTransaction().rollback();
313             }
314             throw bre;
315         } catch (DocumentException de) {
316             throw de;
317         } catch (Exception e) {
318             if (logger.isDebugEnabled()) {
319                 logger.debug("Caught exception ", e);
320             }
321             throw new DocumentException(e);
322         } finally {
323             if (emf != null) {
324                 JpaStorageUtils.releaseEntityManagerFactory(emf);
325             }
326         }
327     }
328
329     /* delete use delete to remove parent entityReceived along with child entities
330      * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String)
331      */
332     @Override
333     public void delete(ServiceContext ctx, String id)
334             throws DocumentNotFoundException,
335             DocumentException {
336
337         if (ctx == null) {
338             throw new IllegalArgumentException(
339                     "JpaStorageClient.delete: ctx is missing");
340         }
341
342         if (logger.isDebugEnabled()) {
343             logger.debug("deleting entity with id=" + id);
344         }
345         EntityManagerFactory emf = null;
346         EntityManager em = null;
347         try {
348
349             emf = JpaStorageUtils.getEntityManagerFactory();
350             em = emf.createEntityManager();
351
352             em.getTransaction().begin();
353             Object entityFound = getEntity(ctx, em, id);
354             if (entityFound == null) {
355                 if (em != null && em.getTransaction().isActive()) {
356                     em.getTransaction().rollback();
357                 }
358                 String msg = "could not find entity with id=" + id;
359                 logger.error(msg);
360                 throw new DocumentNotFoundException(msg);
361             }
362             em.remove(entityFound);
363             em.getTransaction().commit();
364
365         } catch (DocumentException de) {
366             throw de;
367         } catch (Exception e) {
368             if (logger.isDebugEnabled()) {
369                 logger.debug("Caught exception ", e);
370             }
371             if (em != null && em.getTransaction().isActive()) {
372                 em.getTransaction().rollback();
373             }
374             throw new DocumentException(e);
375         } finally {
376             if (emf != null) {
377                 JpaStorageUtils.releaseEntityManagerFactory(emf);
378             }
379         }
380     }
381
382     /**
383      * deleteWhere uses the where clause to delete an entityReceived represented by the csidReceived
384      * it does not delete any child entities.
385      * @param ctx
386      * @param csidReceived
387      * @throws DocumentNotFoundException
388      * @throws DocumentException
389      */
390     public void deleteWhere(ServiceContext ctx, String id)
391             throws DocumentNotFoundException,
392             DocumentException {
393
394         if (ctx == null) {
395             throw new IllegalArgumentException(
396                     "JpaStorageClient.deleteWhere: ctx is missing");
397         }
398
399         if (logger.isDebugEnabled()) {
400             logger.debug("deleting entity with id=" + id);
401         }
402         EntityManagerFactory emf = null;
403         EntityManager em = null;
404         try {
405             StringBuilder deleteStr = new StringBuilder("DELETE FROM ");
406             deleteStr.append(getEntityName(ctx));
407             deleteStr.append(" WHERE csid = :csid");
408             //TODO: add tenant csidReceived
409
410             emf = JpaStorageUtils.getEntityManagerFactory();
411             em = emf.createEntityManager();
412             Query q = em.createQuery(deleteStr.toString());
413             q.setParameter("csid", id);
414
415             int rcount = 0;
416             em.getTransaction().begin();
417             rcount = q.executeUpdate();
418             if (rcount != 1) {
419                 if (em != null && em.getTransaction().isActive()) {
420                     em.getTransaction().rollback();
421                 }
422                 String msg = "could not find entity with id=" + id;
423                 logger.error(msg);
424                 throw new DocumentNotFoundException(msg);
425             }
426             em.getTransaction().commit();
427
428         } catch (DocumentException de) {
429             throw de;
430         } catch (Exception e) {
431             if (logger.isDebugEnabled()) {
432                 logger.debug("Caught exception ", e);
433             }
434             if (em != null && em.getTransaction().isActive()) {
435                 em.getTransaction().rollback();
436             }
437             throw new DocumentException(e);
438         } finally {
439             if (emf != null) {
440                 JpaStorageUtils.releaseEntityManagerFactory(emf);
441             }
442         }
443     }
444
445     /**
446      * Gets the entityReceived name.
447      * 
448      * @param ctx the ctx
449      * 
450      * @return the entityReceived name
451      */
452     protected String getEntityName(ServiceContext ctx) {
453         Object o = ctx.getProperty(ServiceContextProperties.ENTITY_NAME);
454         if (o == null) {
455             throw new IllegalArgumentException(ServiceContextProperties.ENTITY_NAME +
456                     "property is missing in context "
457                     + ctx.toString());
458         }
459
460         return (String) o;
461     }
462
463     /**
464      * getEntity returns persistent entity for given id. it assumes that
465      * JpaStorageClientImpl is implemented using the JpaStorageClientImpl(entityClazz)
466      * constructor
467      * @param ctx service context
468      * @param em entity manager
469      * @param csid received
470      * @return
471      * @throws DocumentNotFoundException
472      * @throws UnsupportedOperationException if JpaStorageClientImpl is not implemented
473      * using the JpaStorageClientImpl(entityClazz)
474      * constructor
475      */
476     protected Object getEntity(ServiceContext ctx, EntityManager em, String id) throws DocumentNotFoundException {
477         Class entityClazz = (Class) ctx.getProperty(ServiceContextProperties.ENTITY_CLASS);
478         if (entityClazz == null) {
479             String msg = ServiceContextProperties.ENTITY_CLASS +
480                     " property is missing in the context";
481             logger.error(msg);
482             throw new IllegalArgumentException(msg);
483         }
484         Object entityFound = JpaStorageUtils.getEntity(em, id, entityClazz);
485         if (entityFound == null) {
486             if (em != null && em.getTransaction().isActive()) {
487                 em.getTransaction().rollback();
488             }
489             String msg = "could not find entity of type=" + entityClazz.getName()
490                     + " with id=" + id;
491             logger.error(msg);
492             throw new DocumentNotFoundException(msg);
493         }
494         return entityFound;
495     }
496
497     @Override
498     public void get(ServiceContext ctx, DocumentHandler handler)
499             throws DocumentNotFoundException, DocumentException {
500         throw new UnsupportedOperationException();
501     }
502 }