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