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:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2010 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
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.
24 package org.collectionspace.services.common.storage.jpa;
26 import org.collectionspace.services.common.context.ServiceContextProperties;
28 import java.util.ArrayList;
29 import java.util.Date;
30 import java.util.List;
31 import java.util.UUID;
33 import javax.persistence.EntityManager;
34 import javax.persistence.EntityManagerFactory;
35 import javax.persistence.NoResultException;
36 import javax.persistence.Query;
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;
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;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
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
67 public class JpaRelationshipStorageClient<T> extends JpaStorageClientImpl {
69 private final Logger logger = LoggerFactory.getLogger(JpaRelationshipStorageClient.class);
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());
79 public static RoleValue createRoleValue(Role role) {
80 RoleValue result = new RoleValue();
81 result.setRoleId(role.getCsid());
82 result.setRoleName(role.getRoleName());
86 public JpaRelationshipStorageClient() {
91 * create of a relationship creates one or more relationships between
93 * the object and subjects of the relationship is chosen (by doc handler) from
98 * @throws BadRequestException
99 * @throws DocumentException
102 public String create(ServiceContext ctx,
103 DocumentHandler handler) throws BadRequestException,
107 throw new IllegalArgumentException(
108 "create : ctx is missing");
110 if (handler == null) {
111 throw new IllegalArgumentException(
112 "create: handler is missing");
114 EntityManagerFactory emf = null;
115 EntityManager em = null;
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();
126 JaxbUtils.setValue(r, "setCreatedAtItem", Date.class, new Date());
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();
137 } catch (Exception e) {
138 if (em != null && em.getTransaction().isActive()) {
139 em.getTransaction().rollback();
141 if (logger.isDebugEnabled()) {
142 logger.debug("Caught exception ", e);
144 throw new DocumentException(e);
147 JpaStorageUtils.releaseEntityManagerFactory(emf);
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
156 * @param id of the object in the relationship
158 * @throws DocumentNotFoundException
159 * @throws DocumentException
162 public void get(ServiceContext ctx, String id, DocumentHandler handler)
163 throws DocumentNotFoundException, DocumentException {
165 throw new IllegalArgumentException(
166 "get: ctx is missing");
168 if (handler == null) {
169 throw new IllegalArgumentException(
170 "get: handler is missing");
172 if (getObject(ctx, id) == null) {
174 + "could not find the object with id=" + id;
176 throw new DocumentNotFoundException(msg);
178 String objectId = getObjectId(ctx);
179 if (logger.isDebugEnabled()) {
180 logger.debug("get: using objectId=" + objectId);
182 Class objectClass = getObjectClass(ctx);
183 if (logger.isDebugEnabled()) {
184 logger.debug("get: using object class=" + objectClass.getName());
186 DocumentFilter docFilter = handler.getDocumentFilter();
187 if (docFilter == null) {
188 docFilter = handler.createDocumentFilter();
190 EntityManagerFactory emf = null;
191 EntityManager em = null;
193 handler.prepare(Action.GET);
194 StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
195 queryStrBldr.append(getEntityName(ctx));
196 queryStrBldr.append(" a");
198 queryStrBldr.append(" WHERE " + objectId + " = :objectId");
199 String where = docFilter.getWhereClause();
200 if ((null != where) && (where.length() > 0)) {
201 queryStrBldr.append(" AND " + where);
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());
209 Query q = em.createQuery(queryStr);
210 q.setParameter("objectId", id);
212 List<T> rl = new ArrayList<T>();
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();
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);
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()) {
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) {
243 } catch (Exception e) {
244 if (logger.isDebugEnabled()) {
245 logger.debug("Caught exception ", e);
247 throw new DocumentException(e);
250 JpaStorageUtils.releaseEntityManagerFactory(emf);
258 * @param relationship the relationship
261 private Long getId(T relationship) {
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();
278 * Gets the relationship.
281 * @param relationship the relationship
282 * @return the relationship
283 * @throws DocumentNotFoundException the document not found exception
285 private T getRelationship(EntityManager em, T relationship)
286 throws DocumentNotFoundException {
287 Long id = getId(relationship);
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) {
295 throw new DocumentNotFoundException(msg);
297 return relationshipFound;
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
304 * @param id of the object in the relationship
305 * @throws DocumentNotFoundException
306 * @throws DocumentException
309 public void delete(ServiceContext ctx, String id)
310 throws DocumentNotFoundException,
314 throw new IllegalArgumentException(
315 "delete : ctx is missing");
317 if (getObject(ctx, id) == null) {
318 String msg = "delete : "
319 + "could not find the object with id=" + id;
321 throw new DocumentNotFoundException(msg);
323 String objectId = getObjectId(ctx);
324 if (logger.isDebugEnabled()) {
325 logger.debug("delete: using objectId=" + objectId);
327 Class objectClass = getObjectClass(ctx);
328 if (logger.isDebugEnabled()) {
329 logger.debug("delete: using object class=" + objectClass.getName());
331 EntityManagerFactory emf = null;
332 EntityManager em = null;
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());
343 Query q = em.createQuery(deleteStr.toString());
344 q.setParameter("objectId", id);
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);
352 em.getTransaction().commit();
354 } catch (Exception e) {
355 if (logger.isDebugEnabled()) {
356 logger.debug("Caught exception ", e);
358 if (em != null && em.getTransaction().isActive()) {
359 em.getTransaction().rollback();
361 throw new DocumentException(e);
364 JpaStorageUtils.releaseEntityManagerFactory(emf);
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
377 * @throws DocumentNotFoundException
378 * @throws DocumentException
381 public void delete(ServiceContext ctx, String id, DocumentHandler handler)
382 throws DocumentNotFoundException, DocumentException {
385 throw new IllegalArgumentException(
386 "delete : ctx is missing");
388 if (handler == null) {
389 throw new IllegalArgumentException(
390 "delete : handler is missing");
392 EntityManagerFactory emf = null;
393 EntityManager em = null;
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
406 em.remove(getRelationship(em, r));
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();
415 } catch (Exception e) {
416 if (logger.isDebugEnabled()) {
417 logger.debug("delete(ctx, ix, handler): Caught exception ", e);
419 if (em != null && em.getTransaction().isActive()) {
420 em.getTransaction().rollback();
422 throw new DocumentException(e);
425 JpaStorageUtils.releaseEntityManagerFactory(emf);
431 * getObjectId returns the id of the object in a relationship
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";
441 throw new IllegalArgumentException(msg);
448 * getObjectClass returns the class of the object in a relationship
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";
458 throw new IllegalArgumentException(msg);
464 * getObject returns the object in the relationship
469 protected Object getObject(ServiceContext ctx, String id)
470 throws DocumentNotFoundException {
471 Class objectClass = getObjectClass(ctx);
472 return JpaStorageUtils.getEntity(id, objectClass);