]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
b5349389b275b0f2b60465563d1d68c95fdf03b8
[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 2009 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 package org.collectionspace.services.common.storage.jpa;
19
20 import java.util.Date;
21 import java.util.List;
22
23 import javax.persistence.RollbackException;
24
25 import java.sql.BatchUpdateException;
26
27 import javax.persistence.EntityExistsException;
28 import javax.persistence.EntityManager;
29 import javax.persistence.EntityManagerFactory;
30 import javax.persistence.Query;
31
32 import org.collectionspace.services.common.document.BadRequestException;
33 import org.collectionspace.services.common.document.DocumentException;
34 import org.collectionspace.services.common.document.DocumentFilter;
35 import org.collectionspace.services.common.document.DocumentHandler;
36 import org.collectionspace.services.common.document.DocumentNotFoundException;
37 import org.collectionspace.services.common.document.DocumentHandler.Action;
38 import org.collectionspace.services.common.document.DocumentWrapper;
39 import org.collectionspace.services.common.document.DocumentWrapperImpl;
40 import org.collectionspace.services.common.document.JaxbUtils;
41 import org.collectionspace.services.common.document.TransactionException;
42 import org.collectionspace.services.common.storage.StorageClient;
43 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
44 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
45 import org.collectionspace.services.common.context.ServiceContextProperties;
46 import org.collectionspace.services.common.authorization_mgt.AuthorizationStore;
47 import org.collectionspace.services.common.context.ServiceContext;
48 import org.collectionspace.services.common.query.QueryContext;
49 import org.collectionspace.services.lifecycle.TransitionDef;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * JpaStorageClient is used to perform CRUD operations on SQL storage using JPA.
55  * It uses @see DocumentHandler as IOHandler with the client.
56  * All the operations in this client are carried out under their own transactions.
57  * A call to any method would start and commit/rollback a transaction.
58  * 
59  * Assumption: each persistent entityReceived has the following 3 attributes
60 <xs:element name="createdAt" type="xs:dateTime">
61 <xs:annotation>
62 <xs:appinfo>
63 <hj:basic>
64 <orm:column name="created_at" nullable="false"/>
65 </hj:basic>
66 </xs:appinfo>
67 </xs:annotation>
68 </xs:element>
69 <xs:element name="updatedAt" type="xs:dateTime">
70 <xs:annotation>
71 <xs:appinfo>
72 <hj:basic>
73 <orm:column name="updated_at" />
74 </hj:basic>
75 </xs:appinfo>
76 </xs:annotation>
77 </xs:element>
78 </xs:sequence>
79 <xs:attribute name="csid" type="xs:string">
80 <xs:annotation>
81 <xs:appinfo>
82 <hj:csidReceived>
83 <orm:column name="csid" length="128" nullable="false"/>
84 </hj:csidReceived>
85 </xs:appinfo>
86 </xs:annotation>
87 </xs:attribute>
88  *
89  * $LastChangedRevision: $ $LastChangedDate: $
90  */
91 public class JpaStorageClientImpl implements StorageClient {
92
93     /** The logger. */
94     private final Logger logger = LoggerFactory.getLogger(JpaStorageClientImpl.class);
95
96     /**
97      * Instantiates a new jpa storage client.
98      */
99     public JpaStorageClientImpl() {
100         //intentionally empty
101     }
102     
103     /* (non-Javadoc)
104      * @see org.collectionspace.services.common.storage.StorageClient#create(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
105      */
106     @Override
107     public String create(ServiceContext ctx,
108             DocumentHandler handler) throws BadRequestException,
109             DocumentException {
110         if (ctx == null) {
111             throw new IllegalArgumentException(
112                     "create: ctx is missing");
113         }
114         if (handler == null) {
115             throw new IllegalArgumentException(
116                     "create: handler is missing");
117         }
118         
119         boolean rollbackTransaction = false;
120         EntityManagerFactory emf = null;
121         EntityManager em = null;
122         try {
123             handler.prepare(Action.CREATE);
124             Object entity = handler.getCommonPart();
125             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entity);
126             
127             emf = JpaStorageUtils.getEntityManagerFactory();            
128             em = emf.createEntityManager();
129             em.getTransaction().begin(); { //begin of transaction block            
130                     ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, em);
131                     try {
132                         handler.handle(Action.CREATE, wrapDoc);
133                             JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date());
134                             em.persist(entity);                 
135                     } catch (EntityExistsException ee) {
136                         //
137                         // We found an existing matching entity in the store, so we don't need to create one.  Just update the transient 'entity' instance with the existing persisted entity we found.
138                         // An entity's document handler class will throw this exception only if attempting to create (but not actually creating) duplicate is ok -e.g., Permission records.
139                         //
140                         entity = wrapDoc.getWrappedObject(); // the handler should have reset the wrapped transient object with the existing persisted entity we just found.
141                     }
142             }
143             em.getTransaction().commit();
144             handler.complete(Action.CREATE, wrapDoc);
145             return (String) JaxbUtils.getValue(entity, "getCsid");
146         } catch (BadRequestException bre) {
147                 rollbackTransaction = true;
148             throw bre;
149         } catch (DocumentException de) {
150                 rollbackTransaction = true;
151             throw de;
152         } catch (Exception e) {
153                 rollbackTransaction = true;
154             if (logger.isDebugEnabled()) {
155                 logger.debug("Caught exception ", e);
156             }
157             throw DocumentException.createDocumentException(e);
158         } finally {
159             ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, null);
160             if (em != null) {
161                 if (rollbackTransaction == true) {
162                         if (em.getTransaction().isActive() == true) {
163                                 em.getTransaction().rollback();
164                         }
165                 }
166                 // Don't call this unless "em" is not null -hence the check above.
167                 JpaStorageUtils.releaseEntityManagerFactory(emf);
168             }
169         }
170
171     }
172
173     /* (non-Javadoc)
174      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
175      */
176     @Override
177     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
178             throws DocumentNotFoundException, DocumentException {
179         throw new UnsupportedOperationException();
180     }
181
182     /* (non-Javadoc)
183      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
184      */
185     @Override
186     public void get(ServiceContext ctx, String id, DocumentHandler handler)
187             throws DocumentNotFoundException, DocumentException {
188         if (ctx == null) {
189             throw new IllegalArgumentException(
190                     "get: ctx is missing");
191         }
192         if (handler == null) {
193             throw new IllegalArgumentException(
194                     "get: handler is missing");
195         }
196         EntityManagerFactory emf = null;
197         EntityManager em = null;
198         try {
199             handler.prepare(Action.GET);
200             Object o = null;
201             o = JpaStorageUtils.getEntity(getEntityName(ctx), id, 
202                     ctx.getTenantId());
203             if (null == o) {
204                 if (em != null && em.getTransaction().isActive()) {
205                     em.getTransaction().rollback();
206                 }
207                 String msg = "could not find entity with id=" + id;
208                 throw new DocumentNotFoundException(msg);
209             }
210             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(o);
211             handler.handle(Action.GET, wrapDoc);
212             handler.complete(Action.GET, wrapDoc);
213         } catch (DocumentException de) {
214             throw de;
215         } catch (Exception e) {
216             if (logger.isDebugEnabled()) {
217                 logger.debug("Caught exception ", e);
218             }
219             throw new DocumentException(e);
220         } finally {
221             if (emf != null) {
222                 JpaStorageUtils.releaseEntityManagerFactory(emf);
223             }
224         }
225     }
226
227     /* (non-Javadoc)
228      * @see org.collectionspace.services.common.storage.StorageClient#getAll(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
229      */
230     @Override
231     public void getAll(ServiceContext ctx, DocumentHandler handler)
232             throws DocumentNotFoundException, DocumentException {
233         throw new UnsupportedOperationException("use getFiltered instead");
234     }
235
236     /* (non-Javadoc)
237      * @see org.collectionspace.services.common.storage.StorageClient#getFiltered(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.document.DocumentHandler)
238      */
239     @Override
240     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
241             throws DocumentNotFoundException, DocumentException {
242         QueryContext queryContext = new QueryContext(ctx, handler);
243         
244         DocumentFilter docFilter = handler.getDocumentFilter();
245         if (docFilter == null) {
246             docFilter = handler.createDocumentFilter();
247         }
248         EntityManagerFactory emf = null;
249         EntityManager em = null;
250         try {
251             handler.prepare(Action.GET_ALL);
252             StringBuilder queryStrBldr = new StringBuilder("SELECT a FROM ");
253             queryStrBldr.append(getEntityName(ctx));
254             queryStrBldr.append(" a");
255             
256             List<DocumentFilter.ParamBinding> params = docFilter.buildWhereForSearch(queryStrBldr);
257             emf = JpaStorageUtils.getEntityManagerFactory();
258             em = emf.createEntityManager();
259             String queryStr = queryStrBldr.toString(); //for debugging
260             Query q = em.createQuery(queryStr);
261             //bind parameters
262             for (DocumentFilter.ParamBinding p : params) {
263                 q.setParameter(p.getName(), p.getValue());
264             }
265             if (docFilter.getOffset() > 0) {
266                 q.setFirstResult(docFilter.getOffset());
267             }
268             if (docFilter.getPageSize() > 0) {
269                 q.setMaxResults(docFilter.getPageSize());
270             }
271
272             //FIXME is transaction required for get?
273             em.getTransaction().begin();
274             List list = q.getResultList();
275             long totalItems = getTotalItems(em, ctx, handler); // Find out how many items our query would find independent of the paging restrictions
276             em.getTransaction().commit();
277             
278             docFilter.setTotalItemsResult(totalItems); // Save the items total in the doc filter for later reporting
279
280             DocumentWrapper<List> wrapDoc = new DocumentWrapperImpl<List>(list);
281             handler.handle(Action.GET_ALL, wrapDoc);
282             handler.complete(Action.GET_ALL, wrapDoc);
283         } catch (DocumentException de) {
284             throw de;
285         } catch (Exception e) {
286             if (logger.isDebugEnabled()) {
287                 logger.debug("Caught exception ", e);
288             }
289             throw new DocumentException(e);
290         } finally {
291             if (emf != null) {
292                 JpaStorageUtils.releaseEntityManagerFactory(emf);
293             }
294         }
295     }
296
297     /*
298      * Return the COUNT for a query to find the total number of matches independent of the paging restrictions.
299      */
300     private long getTotalItems(EntityManager em, ServiceContext ctx, DocumentHandler handler) {
301         long result = -1;
302         
303         DocumentFilter docFilter = handler.getDocumentFilter();
304         StringBuilder queryStrBldr = new StringBuilder("SELECT COUNT(*) FROM ");
305         queryStrBldr.append(getEntityName(ctx));
306         queryStrBldr.append(" a");
307         
308         List<DocumentFilter.ParamBinding> params = docFilter.buildWhereForSearch(queryStrBldr);
309         String queryStr = queryStrBldr.toString();
310         Query q = em.createQuery(queryStr);
311         //bind parameters
312         for (DocumentFilter.ParamBinding p : params) {
313             q.setParameter(p.getName(), p.getValue());
314         }
315
316         result = (long) q.getSingleResult();
317
318         return result;
319     }
320
321         /* (non-Javadoc)
322      * @see org.collectionspace.services.common.storage.StorageClient#update(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
323      */
324     @Override
325     public void update(ServiceContext ctx, String id, DocumentHandler handler)
326             throws BadRequestException, DocumentNotFoundException,
327             DocumentException {
328         if (ctx == null) {
329             throw new IllegalArgumentException(
330                     "update: ctx is missing");
331         }
332         if (handler == null) {
333             throw new IllegalArgumentException(
334                     "update: handler is missing");
335         }
336         EntityManagerFactory emf = null;
337         EntityManager em = null;
338         try {
339             handler.prepare(Action.UPDATE);
340             Object entityReceived = handler.getCommonPart();
341             emf = JpaStorageUtils.getEntityManagerFactory();
342             em = emf.createEntityManager();
343             em.getTransaction().begin();
344             Object entityFound = getEntity(em, id, entityReceived.getClass());
345             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entityFound);
346             handler.handle(Action.UPDATE, wrapDoc);
347             JaxbUtils.setValue(entityFound, "setUpdatedAtItem", Date.class, new Date());
348             em.getTransaction().commit();
349             handler.complete(Action.UPDATE, wrapDoc);
350         } catch (BadRequestException bre) {
351             if (em != null && em.getTransaction().isActive()) {
352                 em.getTransaction().rollback();
353             }
354             throw bre;
355         } catch (DocumentException de) {
356             if (em != null && em.getTransaction().isActive()) {
357                 em.getTransaction().rollback();
358             }
359             throw de;
360         } catch (Exception e) {
361             if (logger.isDebugEnabled()) {
362                 logger.debug("Caught exception ", e);
363             }
364             throw new DocumentException(e);
365         } finally {
366             if (emf != null) {
367                 JpaStorageUtils.releaseEntityManagerFactory(emf);
368             }
369         }
370     }
371
372     /* 
373      * delete removes entity and its child entities
374      * cost: a get before delete
375      * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String)
376      */
377     @Override
378     public void delete(ServiceContext ctx, String id)
379             throws DocumentNotFoundException,
380             DocumentException {
381
382         if (logger.isDebugEnabled()) {
383             logger.debug("delete(ctx, id): deleting entity with id=" + id);
384         }
385
386         if (ctx == null) {
387             throw new IllegalArgumentException(
388                     "delete(ctx, id): ctx is missing");
389         }
390         EntityManagerFactory emf = null;
391         EntityManager em = null;
392         try {
393
394             emf = JpaStorageUtils.getEntityManagerFactory();
395             em = emf.createEntityManager();
396
397             em.getTransaction().begin();
398             Object entityFound = getEntity(ctx, em, id);
399             if (entityFound == null) {
400                 if (em != null && em.getTransaction().isActive()) {
401                     em.getTransaction().rollback();
402                 }
403                 String msg = "delete(ctx, id): could not find entity with id=" + id;
404                 logger.error(msg);
405                 throw new DocumentNotFoundException(msg);
406             }
407             em.remove(entityFound);
408             em.getTransaction().commit();
409
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, id): 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      * deleteWhere uses the where clause to delete an entityReceived represented by the csidReceived
432      * it does not delete any child entities.
433      * @param ctx
434      * @param id
435      * @throws DocumentNotFoundException
436      * @throws DocumentException
437      */
438     public void deleteWhere(ServiceContext ctx, String id)
439             throws DocumentNotFoundException,
440             DocumentException {
441
442         if (ctx == null) {
443             throw new IllegalArgumentException(
444                     "deleteWhere(ctx, id) : ctx is missing");
445         }
446
447         if (logger.isDebugEnabled()) {
448             logger.debug("deleteWhere(ctx, id): deleting entity with id=" + id);
449         }
450         EntityManagerFactory emf = null;
451         EntityManager em = null;
452         try {
453             StringBuilder deleteStr = new StringBuilder("DELETE FROM ");
454             deleteStr.append(getEntityName(ctx));
455             deleteStr.append(" WHERE csid = :csid and tenantId = :tenantId");
456             //TODO: add tenant csidReceived
457
458             emf = JpaStorageUtils.getEntityManagerFactory();
459             em = emf.createEntityManager();
460             Query q = em.createQuery(deleteStr.toString());
461             q.setParameter("csid", id);
462             q.setParameter("tenantId", ctx.getTenantId());
463
464             int rcount = 0;
465             em.getTransaction().begin();
466             rcount = q.executeUpdate();
467             if (rcount != 1) {
468                 if (em != null && em.getTransaction().isActive()) {
469                     em.getTransaction().rollback();
470                 }
471                 String msg = "deleteWhere(ctx, id) could not find entity with id=" + id;
472                 logger.error(msg);
473                 throw new DocumentNotFoundException(msg);
474             }
475             em.getTransaction().commit();
476
477         } catch (DocumentException de) {
478             if (em != null && em.getTransaction().isActive()) {
479                 em.getTransaction().rollback();
480             }
481             throw de;
482         } catch (Exception e) {
483             if (logger.isDebugEnabled()) {
484                 logger.debug("deleteWhere(ctx, id) Caught exception ", e);
485             }
486             if (em != null && em.getTransaction().isActive()) {
487                 em.getTransaction().rollback();
488             }
489             throw new DocumentException(e);
490         } finally {
491             if (emf != null) {
492                 JpaStorageUtils.releaseEntityManagerFactory(emf);
493             }
494         }
495     }
496
497     /*
498      * delete removes entity and its child entities but calls back to given handler
499      * cost: a get before delete
500      * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String)
501      */
502     @Override
503     public boolean delete(ServiceContext ctx, String id, DocumentHandler handler)
504             throws DocumentNotFoundException, DocumentException {
505         boolean result = true;
506         
507         if (ctx == null) {
508             throw new IllegalArgumentException(
509                     "delete(ctx, ix, handler): ctx is missing");
510         }
511         if (handler == null) {
512             throw new IllegalArgumentException(
513                     "delete(ctx, ix, handler): handler is missing");
514         }
515         
516         EntityManagerFactory emf = null;
517         EntityManager em = null;
518         try {
519             handler.prepare(Action.DELETE);
520
521             emf = JpaStorageUtils.getEntityManagerFactory();
522             em = emf.createEntityManager();
523
524             em.getTransaction().begin();
525             Object entityFound = getEntity(ctx, em, id);
526             if (entityFound == null) {
527                 if (em != null && em.getTransaction().isActive()) {
528                     em.getTransaction().rollback();
529                 }
530                 String msg = "delete(ctx, ix, handler) could not find entity with id=" + id;
531                 logger.error(msg);
532                 throw new DocumentNotFoundException(msg);
533             }
534             DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entityFound);
535             handler.handle(Action.DELETE, wrapDoc);
536             em.remove(entityFound);
537             em.getTransaction().commit();
538             handler.complete(Action.DELETE, wrapDoc);
539         } catch (DocumentException de) {
540             if (em != null && em.getTransaction().isActive()) {
541                 em.getTransaction().rollback();
542             }
543             throw de;
544         } catch (Exception e) {
545             if (logger.isDebugEnabled()) {
546                 logger.debug("delete(ctx, ix, handler): Caught exception ", e);
547             }
548             if (em != null && em.getTransaction().isActive()) {
549                 em.getTransaction().rollback();
550             }
551             throw new DocumentException(e);
552         } finally {
553             if (emf != null) {
554                 JpaStorageUtils.releaseEntityManagerFactory(emf);
555             }
556         }
557         
558         return result;
559     }
560
561     /**
562      * Gets the entityReceived name.
563      * 
564      * @param ctx the ctx
565      * 
566      * @return the entityReceived name
567      */
568     protected String getEntityName(ServiceContext ctx) {
569         Object o = ctx.getProperty(ServiceContextProperties.ENTITY_NAME);
570         if (o == null) {
571             throw new IllegalArgumentException(ServiceContextProperties.ENTITY_NAME
572                     + "property is missing in context "
573                     + ctx.toString());
574         }
575
576         return (String) o;
577     }
578
579     /**
580      * getEntity returns persistent entity for given id. it assumes that
581      * service context has property ServiceContextProperties.ENTITY_CLASS set
582      * rolls back the transaction if not found
583      * @param ctx service context
584      * @param em entity manager
585      * @param csid received
586      * @return
587      * @throws DocumentNotFoundException and rollsback the transaction if active
588      */
589     protected Object getEntity(ServiceContext ctx, EntityManager em, String id)
590             throws DocumentNotFoundException {
591         Class entityClazz = (Class) ctx.getProperty(ServiceContextProperties.ENTITY_CLASS);
592         if (entityClazz == null) {
593             String msg = ServiceContextProperties.ENTITY_CLASS
594                     + " property is missing in the context";
595             logger.error(msg);
596             throw new IllegalArgumentException(msg);
597         }
598         return getEntity(em, id, entityClazz);
599     }
600
601     /**
602      * getEntity retrieves the persistent entity of given class for given id
603      * rolls back the transaction if not found
604      * @param em
605      * @param id entity id
606      * @param entityClazz
607      * @return
608      * @throws DocumentNotFoundException and rollsback the transaction if active
609      */
610     protected Object getEntity(EntityManager em, String id, Class entityClazz)
611             throws DocumentNotFoundException {
612         Object entityFound = JpaStorageUtils.getEntity(em, id, entityClazz);
613         if (entityFound == null) {
614             if (em != null && em.getTransaction().isActive()) {
615                 em.getTransaction().rollback();
616             }
617             String msg = "could not find entity of type=" + entityClazz.getName()
618                     + " with id=" + id;
619             logger.error(msg);
620             throw new DocumentNotFoundException(msg);
621         }
622         return entityFound;
623     }
624
625     @Override
626     public void get(ServiceContext ctx, DocumentHandler handler)
627             throws DocumentNotFoundException, DocumentException {
628         throw new UnsupportedOperationException();
629     }
630
631         @Override
632         public void doWorkflowTransition(ServiceContext ctx, String id,
633                         DocumentHandler handler, TransitionDef transitionDef)
634                         throws BadRequestException, DocumentNotFoundException,
635                         DocumentException {
636                 // Do nothing.  JPA services do not support workflow.
637         }
638
639         @Override
640         public void deleteWithWhereClause(ServiceContext ctx, String whereClause,
641                         DocumentHandler handler) throws DocumentNotFoundException,
642                         DocumentException {
643         throw new UnsupportedOperationException();
644         }
645
646         @Override
647         public boolean synchronize(ServiceContext ctx, Object specifier,
648                         DocumentHandler handler) throws DocumentNotFoundException,
649                         TransactionException, DocumentException {
650                 // TODO Auto-generated method stub
651                 // Do nothing. Subclasses can override if they want/need to.
652                 return true;
653         }
654         
655         @Override
656         public boolean synchronizeItem(ServiceContext ctx, AuthorityItemSpecifier itemSpecifier,
657                         DocumentHandler handler) throws DocumentNotFoundException,
658                         TransactionException, DocumentException {
659                 // TODO Auto-generated method stub
660                 // Do nothing. Subclasses can override if they want/need to.
661                 return true;
662         }
663
664 }