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