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;
27 import java.util.ArrayList;
28 import java.util.Date;
29 import java.util.List;
30 import java.util.UUID;
31 import javax.persistence.EntityManager;
32 import javax.persistence.EntityManagerFactory;
33 import javax.persistence.NoResultException;
34 import javax.persistence.Query;
35 import org.collectionspace.services.common.context.ServiceContext;
36 import org.collectionspace.services.common.document.BadRequestException;
37 import org.collectionspace.services.common.document.DocumentException;
38 import org.collectionspace.services.common.document.DocumentFilter;
39 import org.collectionspace.services.common.document.DocumentHandler;
40 import org.collectionspace.services.common.document.DocumentHandler.Action;
41 import org.collectionspace.services.common.document.DocumentNotFoundException;
42 import org.collectionspace.services.common.document.DocumentWrapper;
43 import org.collectionspace.services.common.document.DocumentWrapperImpl;
44 import org.collectionspace.services.common.document.JaxbUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * JpaRelationshipStorageClient deals with a relationship
51 * in persistent storage. This storage client deals with bulk operations, i.e.
52 * create/post inserts multiple tuples between the given object and subjects
53 * get retrieves all subjects for the given object in relationship
54 * delete deletes all subjects for the given object in relationship
57 public class JpaRelationshipStorageClient<T> extends JpaStorageClientImpl {
59 private final Logger logger = LoggerFactory.getLogger(JpaRelationshipStorageClient.class);
61 public JpaRelationshipStorageClient() {
65 * create of a relationship creates one or more relationships between
67 * the object and subjects of the relationship is chosen (by doc handler) from
72 * @throws BadRequestException
73 * @throws DocumentException
76 public String create(ServiceContext ctx,
77 DocumentHandler handler) throws BadRequestException,
81 throw new IllegalArgumentException(
82 "create : ctx is missing");
84 if (handler == null) {
85 throw new IllegalArgumentException(
86 "create: handler is missing");
88 EntityManagerFactory emf = null;
89 EntityManager em = null;
91 handler.prepare(Action.CREATE);
92 List<T> rl = new ArrayList<T>();
93 DocumentWrapper<List<T>> wrapDoc =
94 new DocumentWrapperImpl<List<T>>(rl);
95 handler.handle(Action.CREATE, wrapDoc);
96 emf = JpaStorageUtils.getEntityManagerFactory();
97 em = emf.createEntityManager();
98 em.getTransaction().begin();
100 JaxbUtils.setValue(r, "setCreatedAtItem", Date.class, new Date());
103 em.getTransaction().commit();
104 handler.complete(Action.CREATE, wrapDoc);
105 return UUID.randomUUID().toString(); //filler, not useful
106 } catch (BadRequestException bre) {
107 if (em != null && em.getTransaction().isActive()) {
108 em.getTransaction().rollback();
111 } catch (Exception e) {
112 if (em != null && em.getTransaction().isActive()) {
113 em.getTransaction().rollback();
115 if (logger.isDebugEnabled()) {
116 logger.debug("Caught exception ", e);
118 throw new DocumentException(e);
121 JpaStorageUtils.releaseEntityManagerFactory(emf);
127 * get retrieves all relationships for the object in the relationship
128 * identified by the id. the object could be a permission or a role
130 * @param id of the object in the relationship
132 * @throws DocumentNotFoundException
133 * @throws DocumentException
136 public void get(ServiceContext ctx, String id, DocumentHandler handler)
137 throws DocumentNotFoundException, DocumentException {
139 throw new IllegalArgumentException(
140 "get: ctx is missing");
142 if (handler == null) {
143 throw new IllegalArgumentException(
144 "get: handler is missing");
146 if (getObject(ctx, id) == null) {
148 + "could not find the object with id=" + id;
150 throw new DocumentNotFoundException(msg);
152 String objectId = getObjectId(ctx);
153 if (logger.isDebugEnabled()) {
154 logger.debug("get: using objectId=" + objectId);
156 Class objectClass = getObjectClass(ctx);
157 if (logger.isDebugEnabled()) {
158 logger.debug("get: using object class=" + objectClass.getName());
160 DocumentFilter docFilter = handler.getDocumentFilter();
161 if (docFilter == null) {
162 docFilter = handler.createDocumentFilter();
164 EntityManagerFactory emf = null;
165 EntityManager em = null;
167 handler.prepare(Action.GET);
168 StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
169 queryStrBldr.append(getEntityName(ctx));
170 queryStrBldr.append(" a");
172 queryStrBldr.append(" WHERE " + objectId + " = :objectId");
173 String where = docFilter.getWhereClause();
174 if ((null != where) && (where.length() > 0)) {
175 queryStrBldr.append(" AND " + where);
177 emf = JpaStorageUtils.getEntityManagerFactory();
178 em = emf.createEntityManager();
179 String queryStr = queryStrBldr.toString(); //for debugging
180 if (logger.isDebugEnabled()) {
181 logger.debug("get: jql=" + queryStr.toString());
183 Query q = em.createQuery(queryStr);
184 q.setParameter("objectId", id);
186 List<T> rl = new ArrayList<T>();
188 //require transaction for get?
189 em.getTransaction().begin();
190 rl = q.getResultList();
191 em.getTransaction().commit();
192 } catch (NoResultException nre) {
193 if (em != null && em.getTransaction().isActive()) {
194 em.getTransaction().rollback();
196 String msg = "get(1): "
197 + " could not find relationships for object class="
198 + objectClass.getName() + " id=" + id;
199 if (logger.isDebugEnabled()) {
200 logger.debug(msg, nre);
203 if (rl.size() == 0) {
204 String msg = "get(2): "
205 + " could not find relationships for object class="
206 + objectClass.getName() + " id=" + id;
207 if (logger.isDebugEnabled()) {
211 DocumentWrapper<List<T>> wrapDoc =
212 new DocumentWrapperImpl<List<T>>(rl);
213 handler.handle(Action.GET, wrapDoc);
214 handler.complete(Action.GET, wrapDoc);
215 } catch (DocumentException de) {
217 } catch (Exception e) {
218 if (logger.isDebugEnabled()) {
219 logger.debug("Caught exception ", e);
221 throw new DocumentException(e);
224 JpaStorageUtils.releaseEntityManagerFactory(emf);
230 * delete removes all the relationships for the object in the relationship
231 * identified by the id. the object could be a permission or a role
233 * @param id of the object in the relationship
234 * @throws DocumentNotFoundException
235 * @throws DocumentException
238 public void delete(ServiceContext ctx, String id)
239 throws DocumentNotFoundException,
243 throw new IllegalArgumentException(
244 "delete : ctx is missing");
246 if (getObject(ctx, id) == null) {
247 String msg = "delete : "
248 + "could not find the object with id=" + id;
250 throw new DocumentNotFoundException(msg);
252 String objectId = getObjectId(ctx);
253 if (logger.isDebugEnabled()) {
254 logger.debug("delete: using objectId=" + objectId);
256 Class objectClass = getObjectClass(ctx);
257 if (logger.isDebugEnabled()) {
258 logger.debug("delete: using object class=" + objectClass.getName());
260 EntityManagerFactory emf = null;
261 EntityManager em = null;
263 StringBuilder deleteStr = new StringBuilder("DELETE FROM ");
264 String entityName = getEntityName(ctx);
265 deleteStr.append(entityName);
266 deleteStr.append(" WHERE " + objectId + " = :objectId");
267 emf = JpaStorageUtils.getEntityManagerFactory();
268 em = emf.createEntityManager();
269 if (logger.isDebugEnabled()) {
270 logger.debug("delete: jql=" + deleteStr.toString());
272 Query q = em.createQuery(deleteStr.toString());
273 q.setParameter("objectId", id);
275 em.getTransaction().begin();
276 rcount = q.executeUpdate();
277 if (logger.isDebugEnabled()) {
278 logger.debug("deleted " + rcount + " relationships for entity " + entityName
279 + " with objectId=" + objectId);
281 em.getTransaction().commit();
283 } catch (Exception e) {
284 if (logger.isDebugEnabled()) {
285 logger.debug("Caught exception ", e);
287 if (em != null && em.getTransaction().isActive()) {
288 em.getTransaction().rollback();
290 throw new DocumentException(e);
293 JpaStorageUtils.releaseEntityManagerFactory(emf);
299 * delete of a relationship deletes one or more relationships between
300 * permission and role
301 * the object and subjects of the relationship is chosen (by doc handler) from
306 * @throws DocumentNotFoundException
307 * @throws DocumentException
310 public void delete(ServiceContext ctx, String id, DocumentHandler handler)
311 throws DocumentNotFoundException, DocumentException {
314 throw new IllegalArgumentException(
315 "delete : ctx is missing");
317 if (handler == null) {
318 throw new IllegalArgumentException(
319 "delete : handler is missing");
321 EntityManagerFactory emf = null;
322 EntityManager em = null;
324 handler.prepare(Action.DELETE);
325 List<T> rl = new ArrayList<T>();
326 DocumentWrapper<List<T>> wrapDoc =
327 new DocumentWrapperImpl<List<T>>(rl);
328 handler.handle(Action.DELETE, wrapDoc);
329 emf = JpaStorageUtils.getEntityManagerFactory();
330 em = emf.createEntityManager();
331 em.getTransaction().begin();
332 //the following could be much more efficient if done with a single
337 em.getTransaction().commit();
338 handler.complete(Action.DELETE, wrapDoc);
339 } catch (DocumentException de) {
340 if (em != null && em.getTransaction().isActive()) {
341 em.getTransaction().rollback();
344 } catch (Exception e) {
345 if (logger.isDebugEnabled()) {
346 logger.debug("delete(ctx, ix, handler): Caught exception ", e);
348 if (em != null && em.getTransaction().isActive()) {
349 em.getTransaction().rollback();
351 throw new DocumentException(e);
354 JpaStorageUtils.releaseEntityManagerFactory(emf);
360 * getObjectId returns the id of the object in a relationship
364 protected String getObjectId(ServiceContext ctx) {
365 String objectId = (String) ctx.getProperty(ServiceContextProperties.OBJECT_ID);
366 if (objectId == null) {
367 String msg = ServiceContextProperties.OBJECT_ID
368 + " property is missing in the context";
370 throw new IllegalArgumentException(msg);
377 * getObjectClass returns the class of the object in a relationship
381 protected Class getObjectClass(ServiceContext ctx) {
382 Class objectClass = (Class) ctx.getProperty(ServiceContextProperties.OBJECT_CLASS);
383 if (objectClass == null) {
384 String msg = ServiceContextProperties.OBJECT_CLASS
385 + " property is missing in the context";
387 throw new IllegalArgumentException(msg);
393 * getObject returns the object in the relationship
398 protected Object getObject(ServiceContext ctx, String id) {
399 Class objectClass = getObjectClass(ctx);
400 return JpaStorageUtils.getEntity(id, objectClass);