]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
533a4f7263ce50ce72b1cbe2344e8dac593a50a5
[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  *  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.nuxeo.client.java;
25
26 import java.util.Collection;
27 import java.util.List;
28
29 import javax.ws.rs.core.MultivaluedMap;
30
31 import org.collectionspace.services.client.CollectionSpaceClient;
32 import org.collectionspace.services.client.IQueryManager;
33 import org.collectionspace.services.client.IRelationsManager;
34 import org.collectionspace.services.client.PoxPayloadIn;
35 import org.collectionspace.services.client.PoxPayloadOut;
36 import org.collectionspace.services.common.authorityref.AuthorityRefList;
37 import org.collectionspace.services.common.context.ServiceContext;
38 import org.collectionspace.services.common.datetime.GregorianCalendarDateTimeUtils;
39 import org.collectionspace.services.common.document.AbstractMultipartDocumentHandlerImpl;
40 import org.collectionspace.services.common.document.DocumentFilter;
41 import org.collectionspace.services.common.document.DocumentWrapper;
42 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
43 import org.collectionspace.services.common.profile.Profiler;
44 import org.collectionspace.services.common.repository.RepositoryClient;
45 import org.collectionspace.services.common.repository.RepositoryClientFactory;
46 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthRefConfigInfo;
47 import org.collectionspace.services.lifecycle.Lifecycle;
48 import org.collectionspace.services.lifecycle.State;
49 import org.collectionspace.services.lifecycle.StateList;
50 import org.collectionspace.services.lifecycle.TransitionDef;
51 import org.collectionspace.services.lifecycle.TransitionDefList;
52 import org.collectionspace.services.lifecycle.TransitionList;
53
54 import org.nuxeo.ecm.core.NXCore;
55 import org.nuxeo.ecm.core.api.ClientException;
56 import org.nuxeo.ecm.core.api.DocumentModel;
57 import org.nuxeo.ecm.core.api.DocumentModelList;
58 import org.nuxeo.ecm.core.api.model.PropertyException;
59 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
60 import org.nuxeo.ecm.core.lifecycle.LifeCycleService;
61
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 /**
66  * DocumentModelHandler is a base abstract Nuxeo document handler
67  * using Nuxeo Java Remote APIs for CollectionSpace services
68  *
69  * $LastChangedRevision: $
70  * $LastChangedDate: $
71  */
72 public abstract class DocumentModelHandler<T, TL>
73         extends AbstractMultipartDocumentHandlerImpl<T, TL, DocumentModel, DocumentModelList> {
74
75     private final Logger logger = LoggerFactory.getLogger(DocumentModelHandler.class);
76     private RepositoryInstance repositorySession;
77
78     /*
79      * Map Nuxeo's life cycle object to our JAX-B based life cycle object
80      */
81     private Lifecycle createCollectionSpaceLifecycle(org.nuxeo.ecm.core.lifecycle.LifeCycle nuxeoLifecyle) {
82         Lifecycle result = null;
83         
84         if (nuxeoLifecyle != null) {
85                 //
86                 // Copy the life cycle's name
87                 result = new Lifecycle();
88                 result.setName(nuxeoLifecyle.getName());
89                 
90                 // We currently support only one initial state, so take the first one from Nuxeo
91                 Collection<String> initialStateNames = nuxeoLifecyle.getInitialStateNames();
92                 result.setDefaultInitial(initialStateNames.iterator().next());
93                 
94                 // Next, we copy the state and corresponding transition lists
95                 StateList stateList = new StateList();
96                 List<State> states = stateList.getState();
97                 Collection<org.nuxeo.ecm.core.lifecycle.LifeCycleState> nuxeoStates = nuxeoLifecyle.getStates();
98                 for (org.nuxeo.ecm.core.lifecycle.LifeCycleState nuxeoState : nuxeoStates) {
99                         State tempState = new State();
100                         tempState.setDescription(nuxeoState.getDescription());
101                         tempState.setInitial(nuxeoState.isInitial());
102                         tempState.setName(nuxeoState.getName());
103                         // Now get the list of transitions
104                         TransitionList transitionList = new TransitionList();
105                         List<String> transitions = transitionList.getTransition();
106                         Collection<String> nuxeoTransitions = nuxeoState.getAllowedStateTransitions();
107                         for (String nuxeoTransition : nuxeoTransitions) {
108                                 transitions.add(nuxeoTransition);
109                         }
110                         tempState.setTransitionList(transitionList);
111                         states.add(tempState);
112                 }
113                 result.setStateList(stateList);
114                 
115                 // Finally, we create the transition definitions
116                 TransitionDefList transitionDefList = new TransitionDefList();
117                 List<TransitionDef> transitionDefs = transitionDefList.getTransitionDef();
118                 Collection<org.nuxeo.ecm.core.lifecycle.LifeCycleTransition> nuxeoTransitionDefs = nuxeoLifecyle.getTransitions();
119                 for (org.nuxeo.ecm.core.lifecycle.LifeCycleTransition nuxeoTransitionDef : nuxeoTransitionDefs) {
120                         TransitionDef tempTransitionDef = new TransitionDef();
121                         tempTransitionDef.setDescription(nuxeoTransitionDef.getDescription());
122                         tempTransitionDef.setDestinationState(nuxeoTransitionDef.getDestinationStateName());
123                         tempTransitionDef.setName(nuxeoTransitionDef.getName());
124                         transitionDefs.add(tempTransitionDef);
125                 }
126                 result.setTransitionDefList(transitionDefList);
127         }
128         
129         return result;
130     }
131     
132     /*
133      * Returns the the life cycle definition of the related Nuxeo document type for this handler.
134      * (non-Javadoc)
135      * @see org.collectionspace.services.common.document.DocumentHandler#getLifecycle()
136      */
137     @Override
138     public Lifecycle getLifecycle() {
139         Lifecycle result = null;
140         
141         String docTypeName = null;
142         try {
143                 docTypeName = this.getServiceContext().getDocumentType();
144                 result = getLifecycle(docTypeName);
145         } catch (Exception e) {
146                 if (logger.isTraceEnabled() == true) {
147                         logger.trace("Could not retrieve lifecycle definition for Nuxeo doctype: " + docTypeName);
148                 }
149         }
150         
151         return result;
152     }
153     
154     /*
155      * Returns the the life cycle definition of the related Nuxeo document type for this handler.
156      * (non-Javadoc)
157      * @see org.collectionspace.services.common.document.DocumentHandler#getLifecycle(java.lang.String)
158      */
159     @Override
160     public Lifecycle getLifecycle(String docTypeName) {
161         org.nuxeo.ecm.core.lifecycle.LifeCycle nuxeoLifecyle;
162         Lifecycle result = null;
163         
164         try {
165                 LifeCycleService lifeCycleService = null;
166                         try {
167                                 lifeCycleService = NXCore.getLifeCycleService();
168                         } catch (Exception e) {
169                                 e.printStackTrace();
170                         }
171                         
172                 String lifeCycleName; 
173                 lifeCycleName = lifeCycleService.getLifeCycleNameFor(docTypeName);
174                 nuxeoLifecyle = lifeCycleService.getLifeCycleByName(lifeCycleName);
175                 
176                 result = createCollectionSpaceLifecycle(nuxeoLifecyle); 
177 //                      result = (Lifecycle)FileTools.getJaxbObjectFromFile(Lifecycle.class, "default-lifecycle.xml");
178                 } catch (Exception e) {
179                         // TODO Auto-generated catch block
180                         logger.error("Could not retreive life cycle information for Nuxeo doctype: " + docTypeName, e);
181                 }
182         
183         return result;
184     }
185     
186     /*
187      * We're using the "name" field of Nuxeo's DocumentModel to store
188      * the CSID.
189      */
190     public String getCsid(DocumentModel docModel) {
191         return NuxeoUtils.getCsid(docModel);
192     }
193
194     public String getUri(DocumentModel docModel) {
195         return getServiceContextPath()+getCsid(docModel);
196     }
197         
198     public RepositoryClient<PoxPayloadIn, PoxPayloadOut> getRepositoryClient(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
199         RepositoryClient<PoxPayloadIn, PoxPayloadOut> repositoryClient = RepositoryClientFactory.getInstance().getClient(ctx.getRepositoryClientName());
200         return repositoryClient;
201     }
202
203     /**
204      * getRepositorySession returns Nuxeo Repository Session
205      * @return
206      */
207     public RepositoryInstance getRepositorySession() {
208         
209         return repositorySession;
210     }
211
212     /**
213      * setRepositorySession sets repository session
214      * @param repoSession
215      */
216     public void setRepositorySession(RepositoryInstance repoSession) {
217         this.repositorySession = repoSession;
218     }
219
220     @Override
221     public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
222         // TODO for sub-docs - check to see if the current service context is a multipart input, 
223         // OR a docfragment, and call a variant to fill the DocModel.
224         fillAllParts(wrapDoc, Action.CREATE);
225         handleCoreValues(wrapDoc, Action.CREATE);
226     }
227     
228     // TODO for sub-docs - Add completeCreate in which we look for set-aside doc fragments 
229     // and create the subitems. We will create service contexts with the doc fragments
230     // and then call 
231
232
233     @Override
234     public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
235         // TODO for sub-docs - check to see if the current service context is a multipart input, 
236         // OR a docfragment, and call a variant to fill the DocModel.
237         fillAllParts(wrapDoc, Action.UPDATE);
238         handleCoreValues(wrapDoc, Action.UPDATE);
239     }
240
241     @Override
242     public void handleGet(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
243         extractAllParts(wrapDoc);
244     }
245
246     @Override
247     public void handleGetAll(DocumentWrapper<DocumentModelList> wrapDoc) throws Exception {
248         Profiler profiler = new Profiler(this, 2);
249         profiler.start();
250         setCommonPartList(extractCommonPartList(wrapDoc));
251         profiler.stop();
252     }
253
254     @Override
255     public abstract void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception;
256
257     @Override
258     public abstract void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception;
259
260     @Override
261     public abstract T extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc) throws Exception;
262
263     @Override
264     public abstract void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception;
265
266     @Override
267     public abstract void fillCommonPart(T obj, DocumentWrapper<DocumentModel> wrapDoc) throws Exception;
268
269     @Override
270     public abstract TL extractCommonPartList(DocumentWrapper<DocumentModelList> wrapDoc) throws Exception;
271
272     @Override
273     public abstract T getCommonPart();
274
275     @Override
276     public abstract void setCommonPart(T obj);
277
278     @Override
279     public abstract TL getCommonPartList();
280
281     @Override
282     public abstract void setCommonPartList(TL obj);
283     
284     @Override
285     public DocumentFilter createDocumentFilter() {
286         DocumentFilter filter = new NuxeoDocumentFilter(this.getServiceContext());
287         return filter;
288     }
289     
290     /**
291      * Gets the authority refs.
292      *
293      * @param docWrapper the doc wrapper
294      * @param authRefFields the auth ref fields
295      * @return the authority refs
296      * @throws PropertyException the property exception
297      */
298     abstract public AuthorityRefList getAuthorityRefs(String csid,
299                 List<AuthRefConfigInfo> authRefsInfo) throws PropertyException;    
300
301     private void handleCoreValues(DocumentWrapper<DocumentModel> docWrapper, 
302                 Action action)  throws ClientException {
303         DocumentModel documentModel = docWrapper.getWrappedObject();
304         String now = GregorianCalendarDateTimeUtils.timestampUTC();
305         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
306         String userId = ctx.getUserId();
307         if(action==Action.CREATE) {
308             //
309             // Add the tenant ID value to the new entity
310             //
311                 String tenantId = ctx.getTenantId();
312             documentModel.setProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
313                         CollectionSpaceClient.COLLECTIONSPACE_CORE_TENANTID, tenantId);
314             //
315             // Add the uri value to the new entity
316             //
317             documentModel.setProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
318                         CollectionSpaceClient.COLLECTIONSPACE_CORE_URI, getUri(documentModel));
319                 //
320                 // Add the CSID to the DublinCore title so we can see the CSID in the default
321                 // Nuxeo webapp.
322                 //
323                 try {
324                 documentModel.setProperty("dublincore", "title",
325                         documentModel.getName());
326                 } catch (Exception x) {
327                         if (logger.isWarnEnabled() == true) {
328                                 logger.warn("Could not set the Dublin Core 'title' field on document CSID:" +
329                                                 documentModel.getName());
330                         }
331                 }
332             documentModel.setProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
333                         CollectionSpaceClient.COLLECTIONSPACE_CORE_CREATED_AT, now);
334             documentModel.setProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
335                         CollectionSpaceClient.COLLECTIONSPACE_CORE_CREATED_BY, userId);
336         }
337         
338                 if (action == Action.CREATE || action == Action.UPDATE) {
339                         documentModel.setProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
340                                         CollectionSpaceClient.COLLECTIONSPACE_CORE_UPDATED_AT, now);
341                         documentModel.setProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
342                                         CollectionSpaceClient.COLLECTIONSPACE_CORE_UPDATED_BY, userId);
343                 }
344     }
345     
346     /*
347      * If we see the "rtSbj" query param then we need to perform a CMIS query.  Currently, we have only one
348      * CMIS query, but we could add more.  If we do, this method should look at the incoming request and corresponding
349      * query params to determine if we need to do a CMIS query
350      * (non-Javadoc)
351      * @see org.collectionspace.services.common.document.AbstractDocumentHandlerImpl#isCMISQuery()
352      */
353     public boolean isCMISQuery() {
354         boolean result = false;
355         
356         MultivaluedMap<String, String> queryParams = getServiceContext().getQueryParams();
357         //
358         // Look the query params to see if we need to make a CMSIS query.
359         //
360         String asSubjectCsid = (String)queryParams.getFirst(IQueryManager.SEARCH_RELATED_TO_CSID_AS_SUBJECT);           
361         String asOjectCsid = (String)queryParams.getFirst(IQueryManager.SEARCH_RELATED_TO_CSID_AS_OBJECT);      
362         String asEither = (String)queryParams.getFirst(IQueryManager.SEARCH_RELATED_TO_CSID_AS_EITHER);         
363         if (asSubjectCsid != null || asOjectCsid != null || asEither != null) {
364                 result = true;
365         }
366         
367         return result;
368     }
369     
370         /**
371          * Creates the CMIS query from the service context. Each document handler is
372          * responsible for returning (can override) a valid CMIS query using the information in the
373          * current service context -which includes things like the query parameters,
374          * etc.
375          * 
376          * This method implementation supports three mutually exclusive cases. We will build a query
377          * that can find a document(s) 'A' in a relationship with another document
378          * 'B' where document 'B' has a CSID equal to the query param passed in and:
379          *              1. Document 'B' is the subject of the relationship
380          *              2. Document 'B' is the object of the relationship
381          *              3. Document 'B' is either the object or the subject of the relationship
382          */
383     @Override
384     public String getCMISQuery() {
385         String result = null;
386         
387         if (isCMISQuery() == true) {
388                 String docType = this.getServiceContext().getDocumentType();            
389                 String selectFields = IQueryManager.CMIS_TARGET_CSID + ", "
390                                 + IQueryManager.CMIS_TARGET_TITLE + ", "
391                                 + IRelationsManager.CMIS_CSPACE_RELATIONS_TITLE + ", "
392                                 + IRelationsManager.CMIS_CSPACE_RELATIONS_OBJECT_ID + ", "
393                                 + IRelationsManager.CMIS_CSPACE_RELATIONS_SUBJECT_ID;
394                 String targetTable = docType + " " + IQueryManager.CMIS_TARGET_PREFIX;
395                 String relTable = IRelationsManager.DOC_TYPE + " " + IQueryManager.CMIS_RELATIONS_PREFIX;
396                 String relObjectCsidCol = IRelationsManager.CMIS_CSPACE_RELATIONS_OBJECT_ID;
397                 String relSubjectCsidCol = IRelationsManager.CMIS_CSPACE_RELATIONS_SUBJECT_ID;
398                 String targetCsidCol = IQueryManager.CMIS_TARGET_CSID;
399                 //
400                 // Build up the query arguments
401                 //
402                 String theOnClause = "";
403                 String theWhereClause = "";
404                 MultivaluedMap<String, String> queryParams = getServiceContext().getQueryParams();
405                 String asSubjectCsid = (String)queryParams.getFirst(IQueryManager.SEARCH_RELATED_TO_CSID_AS_SUBJECT);
406                 String asObjectCsid = (String)queryParams.getFirst(IQueryManager.SEARCH_RELATED_TO_CSID_AS_OBJECT);
407                 String asEitherCsid = (String)queryParams.getFirst(IQueryManager.SEARCH_RELATED_TO_CSID_AS_EITHER);
408
409                 //
410                 // Create the "ON" and "WHERE" query clauses based on the params passed into the HTTP request.  
411                 //
412                 // First come, first serve -the first match determines the "ON" and "WHERE" query clauses.
413                 //
414                 if (asSubjectCsid != null && !asSubjectCsid.isEmpty()) {  
415                         // Since our query param is the "subject" value, join the tables where the CSID of the document is the other side (the "object") of the relationship.
416                         theOnClause = relObjectCsidCol + " = " + targetCsidCol;
417                         theWhereClause = relSubjectCsidCol + " = " + "'" + asSubjectCsid + "'";
418                 } else if (asObjectCsid != null && !asObjectCsid.isEmpty()) {
419                         // Since our query param is the "object" value, join the tables where the CSID of the document is the other side (the "subject") of the relationship.
420                         theOnClause = relSubjectCsidCol + " = " + targetCsidCol; 
421                         theWhereClause = relObjectCsidCol + " = " + "'" + asObjectCsid + "'";
422                 } else if (asEitherCsid != null && !asEitherCsid.isEmpty()) {
423                         theOnClause = relObjectCsidCol + " = " + targetCsidCol
424                                         + " OR " + relSubjectCsidCol + " = " + targetCsidCol;
425                         theWhereClause = relSubjectCsidCol + " = " + "'" + asEitherCsid + "'"
426                                         + " OR " + relObjectCsidCol + " = " + "'" + asEitherCsid + "'";
427                 } else {
428                         //Since the call to isCMISQuery() return true, we should never get here.
429                         logger.error("Attempt to make CMIS query failed because the HTTP request was missing valid query parameters.");
430                 }
431                 
432                 // assemble the query from the string arguments
433                 result = "SELECT " + selectFields
434                                 + " FROM "      + targetTable + " JOIN " + relTable
435                                 + " ON " + theOnClause
436                                 + " WHERE " + theWhereClause;
437                 
438                 // An example:
439                 // SELECT D.cmis:name, D.dc:title, R.dc:title, R.relations_common:subjectCsid
440                 // FROM Dimension D JOIN Relation R
441                 // ON R.relations_common:objectCsid = D.cmis:name
442                 // WHERE R.relations_common:subjectCsid = '737527ec-a560-4776-99de'
443                 
444                 if (logger.isDebugEnabled() == true && result != null) {
445                         logger.debug("The CMIS query for the Movement service is: " + result);
446                 }
447         }
448         
449         return result;
450     }
451     
452 }