]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
e10113d105c1fbb5ba8ad4e87303e07e0f44b810
[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 2010 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  *  Unless required by applicable law or agreed to in writing, software
19  *  distributed under the License is distributed on an "AS IS" BASIS,
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  *  See the License for the specific language governing permissions and
22  *  limitations under the License.
23  */
24 package org.collectionspace.services.common.storage.jpa;
25
26 import org.collectionspace.services.common.context.ServiceContextProperties;
27
28 import java.util.ArrayList;
29 import java.util.Date;
30 import java.util.List;
31 import java.util.UUID;
32
33 import javax.persistence.EntityManager;
34 import javax.persistence.EntityManagerFactory;
35 import javax.persistence.NoResultException;
36 import javax.persistence.PersistenceException;
37 import javax.persistence.Query;
38
39 import org.collectionspace.services.authorization.perms.Permission;
40 import org.collectionspace.services.authorization.PermissionValue;
41 import org.collectionspace.services.authorization.Role;
42 import org.collectionspace.services.authorization.RoleValue;
43 import org.collectionspace.services.authorization.AccountRoleRel;
44 import org.collectionspace.services.authorization.PermissionRoleRel;
45
46 import org.collectionspace.services.common.context.ServiceContext;
47 import org.collectionspace.services.common.document.BadRequestException;
48 import org.collectionspace.services.common.document.DocumentException;
49 import org.collectionspace.services.common.document.DocumentFilter;
50 import org.collectionspace.services.common.document.DocumentHandler;
51 import org.collectionspace.services.common.document.DocumentHandler.Action;
52 import org.collectionspace.services.common.document.DocumentNotFoundException;
53 import org.collectionspace.services.common.document.DocumentWrapper;
54 import org.collectionspace.services.common.document.DocumentWrapperImpl;
55 import org.collectionspace.services.common.document.JaxbUtils;
56
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 /**
61  * JpaRelationshipStorageClient deals with a relationship
62  * in persistent storage. This storage client deals with bulk operations, i.e.
63  * create/post inserts multiple tuples between the given object and subjects
64  * get retrieves all subjects for the given object in relationship
65  * delete deletes all subjects for the given object in relationship
66  * @author 
67  */
68 public class JpaRelationshipStorageClient<T> extends JpaStorageClientImpl {
69
70     private final Logger logger = LoggerFactory.getLogger(JpaRelationshipStorageClient.class);
71
72     public static PermissionValue createPermissionValue(Permission permission) {
73         PermissionValue result = new PermissionValue();
74         result.setPermissionId(permission.getCsid());
75         result.setResourceName(permission.getResourceName());
76         result.setActionGroup(permission.getActionGroup());
77         return result;
78     }
79     
80     public static RoleValue createRoleValue(Role role) {
81         RoleValue result = new RoleValue();
82         result.setRoleId(role.getCsid());
83         result.setRoleName(role.getRoleName());
84         return result;
85     }
86     
87     public JpaRelationshipStorageClient() {
88         //empty
89     }
90
91     /**
92      * create of a relationship creates one or more relationships between
93      * permission and role
94      * the object and subjects of the relationship is chosen (by doc handler) from
95      * the payload
96      * @param ctx
97      * @param handler
98      * @return
99      * @throws BadRequestException
100      * @throws DocumentException
101      */
102     @Override
103     public String create(ServiceContext ctx,
104             DocumentHandler handler) throws BadRequestException,
105             DocumentException {
106
107         if (ctx == null) {
108             throw new IllegalArgumentException(
109                     "create : ctx is missing");
110         }
111         if (handler == null) {
112             throw new IllegalArgumentException(
113                     "create: handler is missing");
114         }
115         EntityManagerFactory emf = null;
116         EntityManager em = null;
117         try {
118             handler.prepare(Action.CREATE);
119             List<T> rl = new ArrayList<T>();
120             DocumentWrapper<List<T>> wrapDoc =
121                     new DocumentWrapperImpl<List<T>>(rl);
122             handler.handle(Action.CREATE, wrapDoc);
123             emf = JpaStorageUtils.getEntityManagerFactory();
124             em = emf.createEntityManager();
125             em.getTransaction().begin();
126             for (T r : rl) {
127                 JaxbUtils.setValue(r, "setCreatedAtItem", Date.class, new Date());
128                 em.persist(r);
129             }
130             em.getTransaction().commit();
131             handler.complete(Action.CREATE, wrapDoc);
132             return UUID.randomUUID().toString(); //filler, not useful
133         } catch (BadRequestException bre) {
134             if (em != null && em.getTransaction().isActive()) {
135                 em.getTransaction().rollback();
136             }
137             throw bre;
138         } catch (PersistenceException pe) {
139                 throw pe;
140         } catch (Exception e) {
141             if (em != null && em.getTransaction().isActive()) {
142                 em.getTransaction().rollback();
143             }
144             if (logger.isDebugEnabled()) {
145                 logger.debug("Caught exception ", e);
146             }
147             throw new DocumentException(e);
148         } finally {
149             if (em != null) {
150                 JpaStorageUtils.releaseEntityManagerFactory(emf);
151             }
152         }
153     }
154
155     /**
156      * get retrieves all relationships for the object in the relationship
157      * identified by the id. the object could be a permission or a role
158      * @param ctx
159      * @param id of the object in the relationship
160      * @param handler
161      * @throws DocumentNotFoundException
162      * @throws DocumentException
163      */
164     @Override
165     public void get(ServiceContext ctx, String id, DocumentHandler handler)
166             throws DocumentNotFoundException, DocumentException {
167         if (ctx == null) {
168             throw new IllegalArgumentException(
169                     "get: ctx is missing");
170         }
171         if (handler == null) {
172             throw new IllegalArgumentException(
173                     "get: handler is missing");
174         }
175         if (getObject(ctx, id) == null) {
176             String msg = "get: "
177                     + "could not find the object with id=" + id;
178             logger.error(msg);
179             throw new DocumentNotFoundException(msg);
180         }
181         String objectId = getObjectId(ctx);
182         if (logger.isDebugEnabled()) {
183             logger.debug("get: using objectId=" + objectId);
184         }
185         Class objectClass = getObjectClass(ctx);
186         if (logger.isDebugEnabled()) {
187             logger.debug("get: using object class=" + objectClass.getName());
188         }
189         DocumentFilter docFilter = handler.getDocumentFilter();
190         if (docFilter == null) {
191             docFilter = handler.createDocumentFilter();
192         }
193         EntityManagerFactory emf = null;
194         EntityManager em = null;
195         try {
196             handler.prepare(Action.GET);
197             StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
198             queryStrBldr.append(getEntityName(ctx));
199             queryStrBldr.append(" a");
200
201             queryStrBldr.append(" WHERE " + objectId + " = :objectId");
202             String where = docFilter.getWhereClause();
203             if ((null != where) && (where.length() > 0)) {
204                 queryStrBldr.append(" AND " + where);
205             }
206             emf = JpaStorageUtils.getEntityManagerFactory();
207             em = emf.createEntityManager();
208             String queryStr = queryStrBldr.toString(); //for debugging
209             if (logger.isDebugEnabled()) {
210                 logger.debug("get: jql=" + queryStr.toString());
211             }
212             Query q = em.createQuery(queryStr);
213             q.setParameter("objectId", id);
214
215             List<T> rl = new ArrayList<T>();
216             try {
217                 //require transaction for get?
218                 em.getTransaction().begin();
219                 rl = q.getResultList();
220                 em.getTransaction().commit();
221             } catch (NoResultException nre) {
222                 if (em != null && em.getTransaction().isActive()) {
223                     em.getTransaction().rollback();
224                 }
225                 String msg = "get(1): "
226                         + " could not find relationships for object class="
227                         + objectClass.getName() + " id=" + id;
228                 if (logger.isDebugEnabled()) {
229                     logger.debug(msg, nre);
230                 }
231             }
232             if (rl.size() == 0) {
233                 String msg = "get(2): "
234                         + " could not find relationships for object class="
235                         + objectClass.getName() + " id=" + id;
236                 if (logger.isDebugEnabled()) {
237                     logger.debug(msg);
238                 }
239             }
240             DocumentWrapper<List<T>> wrapDoc =
241                     new DocumentWrapperImpl<List<T>>(rl);
242             handler.handle(Action.GET, wrapDoc);
243             handler.complete(Action.GET, wrapDoc);
244         } catch (DocumentException de) {
245             throw de;
246         } catch (Exception e) {
247             if (logger.isDebugEnabled()) {
248                 logger.debug("Caught exception ", e);
249             }
250             throw new DocumentException(e);
251         } finally {
252             if (emf != null) {
253                 JpaStorageUtils.releaseEntityManagerFactory(emf);
254             }
255         }
256     }
257     
258     /**
259      * Gets the id.
260      *
261      * @param relationship the relationship
262      * @return the id
263      */
264     private Long getId(T relationship) {
265         Long result = null;
266         
267         if (relationship != null) {
268                 if (relationship instanceof AccountRoleRel) {
269                         AccountRoleRel accountRoleRel = (AccountRoleRel)relationship;
270                         result = accountRoleRel.getHjid();
271                 } else if (relationship instanceof PermissionRoleRel) {
272                         PermissionRoleRel permissionRoleRel = (PermissionRoleRel)relationship;
273                         result = permissionRoleRel.getHjid();
274                 }
275         }
276         
277         return result;
278     }
279     
280     /**
281      * Gets the relationship.
282      *
283      * @param em the em
284      * @param relationship the relationship
285      * @return the relationship
286      * @throws DocumentNotFoundException the document not found exception
287      */
288     private T getRelationship(EntityManager em, T relationship)
289                 throws DocumentNotFoundException {
290         Long id = getId(relationship);
291         
292         T relationshipFound = (T)em.find(relationship.getClass(), id);
293         if (relationshipFound == null) {
294             String msg = "Could not find relationship with id=" + id;
295             if (logger.isErrorEnabled() == true) {
296                 logger.error(msg);
297             }
298             throw new DocumentNotFoundException(msg);
299         }
300         return relationshipFound;
301     }
302
303     /**
304      * delete removes all the relationships for the object in the relationship
305      * identified by the id. the object could be a permission or a role
306      * @param ctx
307      * @param id of the object in the relationship
308      * @throws DocumentNotFoundException
309      * @throws DocumentException
310      */
311     @Override
312     public void delete(ServiceContext ctx, String id)
313             throws DocumentNotFoundException,
314             DocumentException {
315
316         if (ctx == null) {
317             throw new IllegalArgumentException(
318                     "delete : ctx is missing");
319         }
320         if (getObject(ctx, id) == null) {
321             String msg = "delete : "
322                     + "could not find the object with id=" + id;
323             logger.error(msg);
324             throw new DocumentNotFoundException(msg);
325         }
326         String objectId = getObjectId(ctx);
327         if (logger.isDebugEnabled()) {
328             logger.debug("delete: using objectId=" + objectId);
329         }
330         Class objectClass = getObjectClass(ctx);
331         if (logger.isDebugEnabled()) {
332             logger.debug("delete: using object class=" + objectClass.getName());
333         }
334         EntityManagerFactory emf = null;
335         EntityManager em = null;
336         try {
337             StringBuilder deleteStr = new StringBuilder("DELETE FROM ");
338             String entityName = getEntityName(ctx);
339             deleteStr.append(entityName);
340             deleteStr.append(" WHERE " + objectId + " = :objectId");
341             emf = JpaStorageUtils.getEntityManagerFactory();
342             em = emf.createEntityManager();
343             if (logger.isDebugEnabled()) {
344                 logger.debug("delete: jql=" + deleteStr.toString());
345             }
346             Query q = em.createQuery(deleteStr.toString());
347             q.setParameter("objectId", id);
348             int rcount = 0;
349             em.getTransaction().begin();
350             if (logger.isDebugEnabled() == true) {
351                 logger.debug(q.toString());
352             }
353             rcount = q.executeUpdate();
354             if (logger.isDebugEnabled()) {
355                 logger.debug("deleted " + rcount + " relationships for entity " + entityName
356                         + " with objectId=" + objectId);
357             }
358             em.getTransaction().commit();
359
360         } catch (Exception e) {
361             if (logger.isDebugEnabled()) {
362                 logger.debug("Caught exception ", e);
363             }
364             if (em != null && em.getTransaction().isActive()) {
365                 em.getTransaction().rollback();
366             }
367             throw new DocumentException(e);
368         } finally {
369             if (emf != null) {
370                 JpaStorageUtils.releaseEntityManagerFactory(emf);
371             }
372         }
373     }
374
375     /**
376      * delete of a relationship deletes one or more relationships between
377      * permission and role
378      * the object and subjects of the relationship is chosen (by doc handler) from
379      * the payload
380      * @param ctx
381      * @param handler
382      * @return
383      * @throws DocumentNotFoundException
384      * @throws DocumentException
385      */
386     @Override
387     public void delete(ServiceContext ctx, String id, DocumentHandler handler)
388             throws DocumentNotFoundException, DocumentException {
389
390         if (ctx == null) {
391             throw new IllegalArgumentException(
392                     "delete : ctx is missing");
393         }
394         if (handler == null) {
395             throw new IllegalArgumentException(
396                     "delete : handler is missing");
397         }
398         EntityManagerFactory emf = null;
399         EntityManager em = null;
400         try {
401             handler.prepare(Action.DELETE);
402             List<T> rl = new ArrayList<T>();
403             DocumentWrapper<List<T>> wrapDoc =
404                     new DocumentWrapperImpl<List<T>>(rl);
405             handler.handle(Action.DELETE, wrapDoc);
406             emf = JpaStorageUtils.getEntityManagerFactory();
407             em = emf.createEntityManager();
408             em.getTransaction().begin();
409             //the following could be much more efficient if done with a single
410             //sql/jql
411             for (T r : rl) {
412                 em.remove(getRelationship(em, r));
413             }
414             em.getTransaction().commit();
415             handler.complete(Action.DELETE, wrapDoc);
416         } catch (DocumentException de) {
417             if (em != null && em.getTransaction().isActive()) {
418                 em.getTransaction().rollback();
419             }
420             throw de;
421         } catch (Exception e) {
422             if (logger.isDebugEnabled()) {
423                 logger.debug("delete(ctx, ix, handler): Caught exception ", e);
424             }
425             if (em != null && em.getTransaction().isActive()) {
426                 em.getTransaction().rollback();
427             }
428             throw new DocumentException(e);
429         } finally {
430             if (emf != null) {
431                 JpaStorageUtils.releaseEntityManagerFactory(emf);
432             }
433         }
434     }
435
436     /**
437      * getObjectId returns the id of the object in a relationship
438      * @param ctx
439      * @return
440      */
441     protected String getObjectId(ServiceContext ctx) {
442         String objectId = (String) ctx.getProperty(ServiceContextProperties.OBJECT_ID);
443         if (objectId == null) {
444             String msg = ServiceContextProperties.OBJECT_ID
445                     + " property is missing in the context";
446             logger.error(msg);
447             throw new IllegalArgumentException(msg);
448         }
449
450         return objectId;
451     }
452
453     /**
454      * getObjectClass returns the class of the object in a relationship
455      * @param ctx
456      * @return
457      */
458     protected Class getObjectClass(ServiceContext ctx) {
459         Class objectClass = (Class) ctx.getProperty(ServiceContextProperties.OBJECT_CLASS);
460         if (objectClass == null) {
461             String msg = ServiceContextProperties.OBJECT_CLASS
462                     + " property is missing in the context";
463             logger.error(msg);
464             throw new IllegalArgumentException(msg);
465         }
466         return objectClass;
467     }
468
469     /**
470      * getObject returns the object in the relationship
471      * @param ctx
472      * @param id
473      * @return
474      */
475     protected Object getObject(ServiceContext ctx, String id)
476                 throws DocumentNotFoundException {
477         Class objectClass = getObjectClass(ctx);
478         return JpaStorageUtils.getEntity(id, objectClass);
479     }
480 }