]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
423f3a144a0c39b56a8e3427e5ede700c4d24218
[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.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.util.List;
23 import javax.persistence.EntityManager;
24 import javax.persistence.EntityManagerFactory;
25 import javax.persistence.NoResultException;
26 import javax.persistence.Persistence;
27 import javax.persistence.Query;
28 import org.collectionspace.services.common.context.ServiceContext;
29 import org.collectionspace.services.common.document.BadRequestException;
30 import org.collectionspace.services.common.document.DocumentException;
31 import org.collectionspace.services.common.document.DocumentFilter;
32 import org.collectionspace.services.common.document.DocumentHandler;
33 import org.collectionspace.services.common.document.DocumentNotFoundException;
34 import org.collectionspace.services.common.document.DocumentHandler.Action;
35 import org.collectionspace.services.common.document.DocumentWrapper;
36 import org.collectionspace.services.common.document.DocumentWrapperImpl;
37 import org.collectionspace.services.common.storage.StorageClient;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * JpaStorageClient is used to perform CRUD operations on SQL storage using JPA.
43  * It uses @see DocumentHandler as IOHandler with the client.
44  * All the operations in this client are carried out under their own transactions.
45  * A call to any method would start and commit/rollback a transaction.
46  *
47  * $LastChangedRevision: $ $LastChangedDate: $
48  */
49 public class JpaStorageClientImpl implements StorageClient {
50
51     /** The logger. */
52     private final Logger logger = LoggerFactory.getLogger(JpaStorageClientImpl.class);
53     /** The Constant CS_PERSISTENCE_UNIT. */
54     public final static String CS_PERSISTENCE_UNIT = "org.collectionspace.services";
55
56     /**
57      * Instantiates a new jpa storage client.
58      */
59     public JpaStorageClientImpl() {
60     }
61
62     /* (non-Javadoc)
63      * @see org.collectionspace.services.common.storage.StorageClient#create(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
64      */
65     @Override
66     public String create(ServiceContext ctx,
67             DocumentHandler handler) throws BadRequestException,
68             DocumentException {
69
70         String docType = ctx.getDocumentType();
71         if (docType == null) {
72             throw new DocumentNotFoundException(
73                     "Unable to find DocumentType for service " + ctx.getServiceName());
74         }
75         if (handler == null) {
76             throw new IllegalArgumentException(
77                     "JpaStorageClient.create: handler is missing");
78         }
79         EntityManagerFactory emf = null;
80         EntityManager em = null;
81         try {
82             handler.prepare(Action.CREATE);
83             Object entity = handler.getCommonPart();
84             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entity);
85             handler.handle(Action.CREATE, wrapDoc);
86             emf = getEntityManagerFactory();
87             em = emf.createEntityManager();
88             em.getTransaction().begin();
89             em.persist(entity);
90             em.getTransaction().commit();
91             handler.complete(Action.CREATE, wrapDoc);
92             return (String) getValue(entity, "getCsid");
93         } catch (DocumentException de) {
94             throw de;
95         } catch (Exception e) {
96             if (em != null && em.getTransaction().isActive()) {
97                 em.getTransaction().rollback();
98             }
99             if (logger.isDebugEnabled()) {
100                 logger.debug("Caught exception ", e);
101             }
102             throw new DocumentException(e);
103         } finally {
104             if (em != null) {
105                 releaseEntityManagerFactory(emf);
106             }
107         }
108
109     }
110
111     /* (non-Javadoc)
112      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
113      */
114     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
115             throws DocumentNotFoundException, DocumentException {
116         throw new UnsupportedOperationException();
117     }
118
119     /* (non-Javadoc)
120      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
121      */
122     @Override
123     public void get(ServiceContext ctx, String id, DocumentHandler handler)
124             throws DocumentNotFoundException, DocumentException {
125         if (handler == null) {
126             throw new IllegalArgumentException(
127                     "JpaStorageClient.get: handler is missing");
128         }
129         DocumentFilter docFilter = handler.getDocumentFilter();
130         if (docFilter == null) {
131             docFilter = handler.createDocumentFilter(ctx);
132         }
133         String docType = ctx.getDocumentType();
134         if (docType == null) {
135             throw new DocumentNotFoundException(
136                     "Unable to find DocumentType for service " + ctx.getServiceName());
137         }
138         EntityManagerFactory emf = null;
139         EntityManager em = null;
140         try {
141             handler.prepare(Action.GET);
142             StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
143             queryStrBldr.append(getEntityName(ctx));
144             queryStrBldr.append(" a");
145             queryStrBldr.append(" WHERE csid = :csid");
146             //TODO: add tenant id
147             String where = docFilter.getWhereClause();
148             if ((null != where) && (where.length() > 0)) {
149                 queryStrBldr.append(" AND " + where);
150             }
151             emf = getEntityManagerFactory();
152             em = emf.createEntityManager();
153             String queryStr = queryStrBldr.toString(); //for debugging
154             Query q = em.createQuery(queryStr);
155             q.setParameter("csid", id);
156             //TODO: add tenant id
157
158             //TODO: get page
159             if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) {
160             } else {
161             }
162             Object o = null;
163
164             try {
165                 //require transaction for get?
166                 em.getTransaction().begin();
167                 o = q.getSingleResult();
168                 em.getTransaction().commit();
169             } catch (NoResultException nre) {
170                 if (em != null && em.getTransaction().isActive()) {
171                     em.getTransaction().rollback();
172                 }
173                 String msg = "could not find entity with id=" + id;
174                 logger.error(msg, nre);
175                 throw new DocumentNotFoundException(msg, nre);
176             }
177             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(o);
178             handler.handle(Action.GET, wrapDoc);
179             handler.complete(Action.GET, wrapDoc);
180         } catch (DocumentException de) {
181             throw de;
182         } catch (Exception e) {
183             if (logger.isDebugEnabled()) {
184                 logger.debug("Caught exception ", e);
185             }
186             throw new DocumentException(e);
187         } finally {
188             if (emf != null) {
189                 releaseEntityManagerFactory(emf);
190             }
191         }
192     }
193
194     /* (non-Javadoc)
195      * @see org.collectionspace.services.common.storage.StorageClient#getAll(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
196      */
197     @Override
198     public void getAll(ServiceContext ctx, DocumentHandler handler)
199             throws DocumentNotFoundException, DocumentException {
200         throw new UnsupportedOperationException("use getFiltered instead");
201     }
202
203     /* (non-Javadoc)
204      * @see org.collectionspace.services.common.storage.StorageClient#getFiltered(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
205      */
206     @Override
207     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
208             throws DocumentNotFoundException, DocumentException {
209         if (handler == null) {
210             throw new IllegalArgumentException(
211                     "JpaStorageClient.getFiltered: handler is missing");
212         }
213         DocumentFilter docFilter = handler.getDocumentFilter();
214         if (docFilter == null) {
215             docFilter = handler.createDocumentFilter(ctx);
216         }
217         String docType = ctx.getDocumentType();
218         if (docType == null) {
219             throw new DocumentNotFoundException(
220                     "Unable to find DocumentType for service " + ctx.getServiceName());
221         }
222
223         EntityManagerFactory emf = null;
224         EntityManager em = null;
225         try {
226             handler.prepare(Action.GET_ALL);
227
228             StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
229             queryStrBldr.append(getEntityName(ctx));
230             queryStrBldr.append(" a");
231             List<DocumentFilter.ParamBinding> params = docFilter.buildWhereForSearch(queryStrBldr);
232             //TODO: add tenant id
233             emf = getEntityManagerFactory();
234             em = emf.createEntityManager();
235             String queryStr = queryStrBldr.toString(); //for debugging
236             Query q = em.createQuery(queryStr);
237             //bind parameters
238             for (DocumentFilter.ParamBinding p : params) {
239                 q.setParameter(p.getName(), p.getValue());
240             }
241             if (docFilter.getOffset() > 0) {
242                 q.setFirstResult(docFilter.getOffset());
243             }
244             if (docFilter.getPageSize() > 0) {
245                 q.setMaxResults(docFilter.getPageSize());
246             }
247
248             //FIXME is transaction required for get?
249             em.getTransaction().begin();
250             List list = q.getResultList();
251             em.getTransaction().commit();
252             DocumentWrapper<List> wrapDoc = new DocumentWrapperImpl<List>(list);
253             handler.handle(Action.GET_ALL, wrapDoc);
254             handler.complete(Action.GET_ALL, wrapDoc);
255         } catch (DocumentException de) {
256             throw de;
257         } catch (Exception e) {
258             if (logger.isDebugEnabled()) {
259                 logger.debug("Caught exception ", e);
260             }
261             throw new DocumentException(e);
262         } finally {
263             if (emf != null) {
264                 releaseEntityManagerFactory(emf);
265             }
266         }
267     }
268
269     /* (non-Javadoc)
270      * @see org.collectionspace.services.common.storage.StorageClient#update(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
271      */
272     @Override
273     public void update(ServiceContext ctx, String id, DocumentHandler handler)
274             throws BadRequestException, DocumentNotFoundException,
275             DocumentException {
276         String docType = ctx.getDocumentType();
277         if (docType == null) {
278             throw new DocumentNotFoundException(
279                     "Unable to find DocumentType for service " + ctx.getServiceName());
280         }
281         if (handler == null) {
282             throw new IllegalArgumentException(
283                     "JpaStorageClient.update: handler is missing");
284         }
285         EntityManagerFactory emf = null;
286         EntityManager em = null;
287         try {
288             handler.prepare(Action.UPDATE);
289             Object entity = handler.getCommonPart();
290             setCsid(entity, id);
291             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entity);
292             handler.handle(Action.UPDATE, wrapDoc);
293             emf = getEntityManagerFactory();
294             em = emf.createEntityManager();
295             em.getTransaction().begin();
296             Object entityFound = em.find(entity.getClass(), id);
297             if (entityFound == null) {
298                 if (em != null && em.getTransaction().isActive()) {
299                     em.getTransaction().rollback();
300                 }
301                 String msg = "could not find entity with id=" + id;
302                 logger.error(msg);
303                 throw new DocumentNotFoundException(msg);
304             }
305             em.merge(entity);
306             em.getTransaction().commit();
307             handler.complete(Action.UPDATE, wrapDoc);
308         } catch (DocumentException de) {
309             throw de;
310         } catch (Exception e) {
311             if (logger.isDebugEnabled()) {
312                 logger.debug("Caught exception ", e);
313             }
314             throw new DocumentException(e);
315         } finally {
316             if (emf != null) {
317                 releaseEntityManagerFactory(emf);
318             }
319         }
320     }
321
322     /* (non-Javadoc)
323      * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String)
324      */
325     @Override
326     public void delete(ServiceContext ctx, String id)
327             throws DocumentNotFoundException,
328             DocumentException {
329
330         if (logger.isDebugEnabled()) {
331             logger.debug("deleting entity with id=" + id);
332         }
333         String docType = ctx.getDocumentType();
334         if (docType == null) {
335             throw new DocumentNotFoundException(
336                     "Unable to find DocumentType for service " + ctx.getServiceName());
337         }
338         EntityManagerFactory emf = null;
339         EntityManager em = null;
340         try {
341             StringBuilder deleteStr = new StringBuilder("DELETE FROM ");
342             deleteStr.append(getEntityName(ctx));
343             deleteStr.append(" WHERE csid = :csid");
344             //TODO: add tenant id
345
346             emf = getEntityManagerFactory();
347             em = emf.createEntityManager();
348             Query q = em.createQuery(deleteStr.toString());
349             q.setParameter("csid", id);
350             //TODO: add tenant id
351             int rcount = 0;
352             em.getTransaction().begin();
353             rcount = q.executeUpdate();
354             if (rcount != 1) {
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.getTransaction().commit();
363
364         } catch (DocumentException de) {
365             throw de;
366         } catch (Exception e) {
367             if (logger.isDebugEnabled()) {
368                 logger.debug("Caught exception ", e);
369             }
370             if (em != null && em.getTransaction().isActive()) {
371                 em.getTransaction().rollback();
372             }
373             throw new DocumentException(e);
374         } finally {
375             if (emf != null) {
376                 releaseEntityManagerFactory(emf);
377             }
378         }
379     }
380
381     /**
382      * Gets the entity manager factory.
383      * 
384      * @return the entity manager factory
385      */
386     public EntityManagerFactory getEntityManagerFactory() {
387         return getEntityManagerFactory(CS_PERSISTENCE_UNIT);
388     }
389
390     /**
391      * Gets the entity manager factory.
392      * 
393      * @param persistenceUnit the persistence unit
394      * 
395      * @return the entity manager factory
396      */
397     public EntityManagerFactory getEntityManagerFactory(
398             String persistenceUnit) {
399         return Persistence.createEntityManagerFactory(persistenceUnit);
400
401     }
402
403     /**
404      * Release entity manager factory.
405      * 
406      * @param emf the emf
407      */
408     public void releaseEntityManagerFactory(EntityManagerFactory emf) {
409         if (emf != null) {
410             emf.close();
411         }
412
413     }
414
415     /**
416      * getValue gets invokes specified accessor method on given object. Assumption
417      * is that this is used for JavaBean pattern getXXX methods only.
418      * @param o object to return value from
419      * @param methodName of method to invoke
420      * @return value returned of invocation
421      * @throws NoSuchMethodException
422      * @throws IllegalAccessException
423      * @throws InvocationTargetException
424      */
425     protected Object getValue(Object o, String methodName)
426             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
427         if (methodName == null) {
428             String msg = methodName + " cannot be null";
429             logger.error(msg);
430             throw new IllegalArgumentException(msg);
431         }
432         Class c = o.getClass();
433         Method m = c.getMethod(methodName);
434
435         Object r = m.invoke(o);
436         if (logger.isDebugEnabled()) {
437             logger.debug("getValue returned value=" + r
438                     + " for " + c.getName());
439         }
440         return r;
441     }
442
443     /**
444      * setValue mutates the given object by invoking specified method. Assumption
445      * is that this is used for JavaBean pattern setXXX methods only.
446      * @param o object to mutate
447      * @param methodName indicates method to invoke
448      * @param argType type of the only argument (assumed) to method
449      * @param argValue value of the only argument (assumed) to method
450      * @return
451      * @throws NoSuchMethodException
452      * @throws IllegalAccessException
453      * @throws InvocationTargetException
454      */
455     protected Object setValue(Object o, String methodName, Class argType, Object argValue)
456             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
457         if (methodName == null) {
458             String msg = methodName + " cannot be null";
459             logger.error(msg);
460             throw new IllegalArgumentException(msg);
461         }
462         if (argType == null) {
463             String msg = "argType cannot be null";
464             logger.error(msg);
465             throw new IllegalArgumentException(msg);
466         }
467         Class c = o.getClass();
468         Method m = c.getMethod(methodName, argType);
469         Object r = m.invoke(o, argValue);
470         if (logger.isDebugEnabled()) {
471             logger.debug("completed invocation of " + methodName
472                     + " for " + c.getName());
473         }
474         return r;
475     }
476
477     /**
478      * Sets the csid.
479      * 
480      * @param o the o
481      * @param csid the csid
482      * 
483      * @throws Exception the exception
484      */
485     protected void setCsid(Object o, String csid) throws Exception {
486         //verify csid
487         String id = (String) getValue(o, "getCsid");
488         if (id != null) {
489             if (!id.equals(csid)) {
490                 String msg = "Csids do not match!";
491                 logger.error(msg);
492                 throw new BadRequestException(msg);
493             } else {
494                 //no need to set
495                 return;
496             }
497
498         }
499         //set csid
500         setValue(o, "setCsid", java.lang.String.class, csid);
501     }
502
503     /**
504      * Gets the entity name.
505      * 
506      * @param ctx the ctx
507      * 
508      * @return the entity name
509      */
510     protected String getEntityName(ServiceContext ctx) {
511         Object o = ctx.getProperty("entity-name");
512         if (o == null) {
513             throw new IllegalArgumentException("property entity-name missing in context "
514                     + ctx.toString());
515         }
516
517         return (String) o;
518     }
519
520     @Override
521     public void get(ServiceContext ctx, DocumentHandler handler)
522             throws DocumentNotFoundException, DocumentException {
523         throw new UnsupportedOperationException();
524     }
525 }