]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
a3e93d0359f04033c5e679ef8593e1f1f75f8e7d
[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.lang.reflect.Method;
27 import java.util.ArrayList;
28 import java.util.GregorianCalendar;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32
33 import javax.ws.rs.core.MultivaluedMap;
34
35 import org.collectionspace.services.client.CollectionSpaceClient;
36 import org.collectionspace.services.client.IQueryManager;
37 import org.collectionspace.services.client.IRelationsManager;
38 import org.collectionspace.services.client.PoxPayloadIn;
39 import org.collectionspace.services.client.PoxPayloadOut;
40 import org.collectionspace.services.common.ReflectionMapper;
41 import org.collectionspace.services.common.api.GregorianCalendarDateTimeUtils;
42 import org.collectionspace.services.common.api.Tools;
43 import org.collectionspace.services.common.config.ServiceConfigUtils;
44 import org.collectionspace.services.common.context.AbstractServiceContextImpl;
45 import org.collectionspace.services.common.context.ServiceContext;
46 import org.collectionspace.services.common.document.DocumentException;
47 import org.collectionspace.services.common.document.DocumentWrapper;
48 import org.collectionspace.services.common.query.QueryContext;
49 import org.collectionspace.services.common.relation.nuxeo.RelationsUtils;
50 import org.collectionspace.services.config.service.DocHandlerParams;
51 import org.collectionspace.services.config.service.ListResultField;
52 import org.collectionspace.services.jaxb.AbstractCommonList;
53 import org.collectionspace.services.nuxeo.client.java.CommonList;
54 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
55 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
56
57 import org.nuxeo.ecm.core.api.DocumentModel;
58 import org.nuxeo.ecm.core.api.DocumentModelList;
59
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 /**
64  * This class is generified by the marker type T,
65  * where T is expected to map to something like BlobCommon, MediaCommon, ObjectexitCommon, etc.,
66  * and so on for every JAXB-generated schema class.
67  *
68  * User: laramie
69  * $LastChangedRevision: $
70  * $LastChangedDate: $
71  *
72  */
73 public abstract class NuxeoDocumentModelHandler<T> extends RemoteDocumentModelHandlerImpl<T, AbstractCommonList> {
74
75         /** The logger. */
76         private final Logger logger = LoggerFactory.getLogger(this.getClass());
77
78         private AbstractCommonList commonList;
79
80         protected static final int NUM_STANDARD_LIST_RESULT_FIELDS = 5;
81         protected static final String STANDARD_LIST_CSID_FIELD = "csid";
82         protected static final String STANDARD_LIST_URI_FIELD = CollectionSpaceClient.COLLECTIONSPACE_CORE_URI;
83         protected static final String STANDARD_LIST_REFNAME_FIELD = CollectionSpaceClient.COLLECTIONSPACE_CORE_REFNAME;
84         protected static final String STANDARD_LIST_UPDATED_AT_FIELD = CollectionSpaceClient.COLLECTIONSPACE_CORE_UPDATED_AT;
85         protected static final String STANDARD_LIST_WORKFLOW_FIELD = CollectionSpaceClient.COLLECTIONSPACE_CORE_WORKFLOWSTATE;
86         protected static final String STANDARD_LIST_MARK_RT_FIELD = "related";
87
88         @Override
89         public AbstractCommonList getCommonPartList() {
90                 return commonList;
91         }
92
93         @Override
94         public void setCommonPartList(AbstractCommonList aCommonList) {
95                 this.commonList = aCommonList;
96         }
97
98         private T commonPart;
99
100         @Override
101         public T getCommonPart() {
102                 return (T) commonPart;
103         }
104
105         @Override
106         public void setCommonPart(T commonPart) {
107                 this.commonPart = commonPart;
108         }
109
110         /**
111          * Subclass DocHandlers may override this method to control exact creation of the common list.
112          * This class instantiates an AbstractCommonList from the classname returned by getDocHandlerParams().AbstractCommonListClassname.
113          * 
114          * @return
115          * @throws Exception
116          */
117         public AbstractCommonList createAbstractCommonListImpl() throws Exception {
118                 // String classname = this.commonList.getClass().getName();
119                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
120                 String classname = ServiceConfigUtils.getDocHandlerParams(ctx).getAbstractCommonListClassname();
121                 if (classname == null) {
122                         throw new Exception(
123                                         "in createAbstractCommonListImpl. getDocHandlerParams().getAbstractCommonListClassname() is null");
124                 }
125                 classname = classname.trim();
126                 return (AbstractCommonList) (ReflectionMapper.instantiate(classname));
127         }
128
129         /** DocHandlerBase calls this method with the CSID as id */
130         public Object createItemForCommonList(DocumentModel docModel, String label, String id) throws Exception {
131                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
132                 return createItemForCommonList(ServiceConfigUtils.getDocHandlerParams(ctx).getCommonListItemClassname(),
133                                 docModel, label, id, true);
134         }
135
136         public String getSummaryFields(AbstractCommonList theCommonList) throws DocumentException {
137                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
138                 return ServiceConfigUtils.getDocHandlerParams(ctx).getSummaryFields();
139         }
140
141         public void setListItemArrayExtended(boolean isExtended) throws DocumentException {
142                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
143                 ServiceConfigUtils.getDocHandlerParams(ctx).getListResultsFields().setExtended(isExtended);
144         }
145
146         public boolean isListItemArrayExtended() throws DocumentException {
147                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
148                 return ServiceConfigUtils.getDocHandlerParams(ctx).getListResultsFields().isExtended();
149         }
150
151         public List<ListResultField> getListItemsArray() throws DocumentException {
152                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
153                 return ServiceConfigUtils.getDocHandlerParams(ctx).getListResultsFields().getListResultField();
154         }
155
156         @Override
157         public T extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
158                 throw new UnsupportedOperationException();
159         }
160
161         @Override
162         public void fillCommonPart(T objectexitObject, DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
163                 throw new UnsupportedOperationException();
164         }
165
166         protected static String getRefname(DocumentModel docModel) throws Exception {
167                 String result = (String) docModel.getProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
168                                 CollectionSpaceClient.COLLECTIONSPACE_CORE_REFNAME);
169                 return result;
170         }
171
172         public static String getUpdatedAtAsString(DocumentModel docModel) throws Exception {
173                 GregorianCalendar cal = (GregorianCalendar) docModel.getProperty(
174                                 CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
175                                 CollectionSpaceClient.COLLECTIONSPACE_CORE_UPDATED_AT);
176                 String updatedAt = GregorianCalendarDateTimeUtils.formatAsISO8601Timestamp(cal);
177                 return updatedAt;
178         }
179
180         @Override
181         public AbstractCommonList extractCommonPartList(DocumentWrapper<DocumentModelList> wrapDoc) throws Exception {
182                 CommonList commonList = new CommonList();
183                 String markRtSbj = null;
184                 CoreSessionInterface repoSession = null;
185                 RepositoryClientImpl repoClient = null;
186                 boolean releaseRepoSession = false;
187
188                 AbstractServiceContextImpl ctx = (AbstractServiceContextImpl) getServiceContext();
189                 MultivaluedMap<String, String> queryParams = getServiceContext().getQueryParams();
190                 markRtSbj = queryParams.getFirst(IQueryManager.MARK_RELATED_TO_CSID_AS_SUBJECT);
191                 if (markRtSbj != null && markRtSbj.isEmpty())
192                         markRtSbj = null;
193
194                 try {
195                         if (markRtSbj != null) {
196                                 repoClient = (RepositoryClientImpl) this.getRepositoryClient(ctx);
197                                 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl) repoClient;
198                                 repoSession = this.getRepositorySession();
199                                 if (repoSession == null) {
200                                         repoSession = repoClient.getRepositorySession(ctx);
201                                         releaseRepoSession = true;
202                                 }
203                         }
204
205                         String commonSchema = getServiceContext().getCommonPartLabel();
206                         extractPagingInfo(commonList, wrapDoc);
207                         List<ListResultField> resultsFields = getListItemsArray();
208                         int nFields = resultsFields.size() + NUM_STANDARD_LIST_RESULT_FIELDS;
209                         int baseFields = NUM_STANDARD_LIST_RESULT_FIELDS;
210                         if (markRtSbj != null) {
211                                 nFields++;
212                                 baseFields++;
213                         }
214                         
215                         String fields[] = new String[nFields]; // REM - Why can't this just be a static array defined once at the top? Then there'd be no need for these hardcoded "[x]" statements and no need for NUM_STANDARD_LIST_RESULT_FIELDS constant as well.
216                         fields[0] = STANDARD_LIST_CSID_FIELD;
217                         fields[1] = STANDARD_LIST_URI_FIELD;
218                         fields[2] = STANDARD_LIST_REFNAME_FIELD;
219                         fields[3] = STANDARD_LIST_UPDATED_AT_FIELD;
220                         fields[4] = STANDARD_LIST_WORKFLOW_FIELD;
221                         
222                         if (markRtSbj != null) {
223                                 fields[5] = STANDARD_LIST_MARK_RT_FIELD;
224                         }
225                         
226                         for (int i = baseFields; i < nFields; i++) {
227                                 ListResultField field = resultsFields.get(i - baseFields);
228                                 fields[i] = field.getElement();
229                         }
230                         commonList.setFieldsReturned(fields);
231                         Iterator<DocumentModel> iter = wrapDoc.getWrappedObject().iterator();
232                         HashMap<String, Object> item = new HashMap<String, Object>();
233                         while (iter.hasNext()) {
234                                 DocumentModel docModel = iter.next();
235                                 String id = NuxeoUtils.getCsid(docModel);
236                                 item.put(STANDARD_LIST_CSID_FIELD, id);
237                                 if (markRtSbj != null) {
238                                         String relationClause = RelationsUtils.buildWhereClause(markRtSbj, null, null, id, null);
239                                         String whereClause = relationClause + IQueryManager.SEARCH_QUALIFIER_AND
240                                                         + NuxeoUtils.buildWorkflowNotDeletedWhereClause();
241                                         QueryContext queryContext = new QueryContext(ctx, whereClause);
242                                         queryContext.setDocType(IRelationsManager.DOC_TYPE);
243                                         String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
244                                         // Search for 1 relation that matches. 1 is enough to fail
245                                         // the filter
246                                         DocumentModelList docList = repoSession.query(query, null, 1, 0, false);
247                                         item.put(STANDARD_LIST_MARK_RT_FIELD, docList.isEmpty() ? "false" : "true");
248                                 }
249                                 String uri = getUri(docModel);
250                                 item.put(STANDARD_LIST_URI_FIELD, uri);
251                                 item.put(STANDARD_LIST_REFNAME_FIELD, getRefname(docModel));
252                                 item.put(STANDARD_LIST_UPDATED_AT_FIELD, getUpdatedAtAsString(docModel));
253                                 item.put(STANDARD_LIST_WORKFLOW_FIELD, docModel.getCurrentLifeCycleState());
254
255                                 for (ListResultField field : resultsFields) {
256                                         String schema = field.getSchema();
257                                         if (schema == null || schema.trim().isEmpty()) {
258                                                 schema = commonSchema;
259                                         }
260                                         Object value = getListResultValue(docModel, schema, field);
261                                         if (value != null && value instanceof String) { // If it is String that is either null or empty, we set our value to null
262                                                 String strValue = (String) value;
263                                                 if (strValue.trim().isEmpty() == true) {
264                                                         value = null; // We found an "empty" string value, so just set the value to null so we don't return anything.
265                                                 }
266                                         }
267                                         if (value != null) {
268                                                 item.put(field.getElement(), value);
269                                         }
270                                 }
271                                 commonList.addItem(item);
272                                 item.clear();
273                         }
274                 } catch (Exception e) {
275                         if (logger.isDebugEnabled()) {
276                                 logger.debug("Caught exception ", e);
277                         }
278                         throw new DocumentException(e);
279                 } finally {
280                         // If we got/aquired a new session then we're responsible for releasing it.
281                         if (releaseRepoSession && repoSession != null) {
282                                 repoClient.releaseRepositorySession(ctx, repoSession);
283                         }
284                 }
285
286                 return commonList;
287         }
288
289         // TODO - get rid of this if we can - appears to be unused.
290         @Override
291         public String getQProperty(String prop) throws DocumentException {
292                 ServiceContext ctx = this.getServiceContext();
293                 return ServiceConfigUtils.getDocHandlerParams(ctx).getSchemaName() + ":" + prop;
294         }
295
296         // ============= dublin core handling =======================================
297
298         @Override
299         public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
300                 super.fillAllParts(wrapDoc, action);
301                 fillDublinCoreObject(wrapDoc);
302         }
303
304         /**
305          * Fill dublin core object, but only if there are document handler parameters in the service
306          * bindings.
307          *
308          * @param wrapDoc
309          *            the wrap doc
310          * @throws Exception
311          *             the exception
312          */
313         // TODO - Remove this?
314         // This look like it is never used in a sensible way. It just stuffs a static
315         // String that matches the service name into a bogus field.
316         protected void fillDublinCoreObject(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
317                 DocHandlerParams.Params docHandlerParams = null;
318                 try {
319                         docHandlerParams = ServiceConfigUtils.getDocHandlerParams(getServiceContext());
320                 } catch (Exception e) {
321                         logger.warn(e.getMessage());
322                 }
323
324                 if (docHandlerParams != null) {
325                         String title = docHandlerParams.getDublinCoreTitle();
326                         if (Tools.isEmpty(title) == false) {
327                                 DocumentModel docModel = wrapDoc.getWrappedObject();
328                                 docModel.setPropertyValue("dublincore:title", title);
329                         }
330                 }
331         }
332
333         // ================== UTILITY METHODS ================================================
334         public static ReflectionMapper.STATUS callPropertySetterWithXPathValue(DocumentModel docModel, Object listItem,
335                         String setterName, String schema, String xpath) throws Exception {
336                 // Object prop = docModel.getProperty(label, elementName);
337                 String value = (String) NuxeoUtils.getXPathValue(docModel, schema, xpath);
338                 return ReflectionMapper.callSetter(listItem, setterName, value);
339         }
340
341         public static ReflectionMapper.STATUS callSimplePropertySetter(Object target, String name, Object arg) {
342                 return ReflectionMapper.callSetter(target, name, arg);
343         }
344
345         /**
346          * @param commonListClassname
347          *            is a package-qualified java classname, including inner class $ notation, such as
348          *            "org.collectionspace.services.objectexit.ObjectexitCommonList$ObjectexitListItem".
349          * @param includeStdFields
350          *            set to true to have the method set Uri and Csid automatically, based on id param.
351          */
352         public Object createItemForCommonList(String commonListClassname, DocumentModel docModel, String schema, String id,
353                         boolean includeStdFields) throws Exception {
354                 // createItemForCommonList(docModel, label, id);
355                 Object item = ReflectionMapper.instantiate(commonListClassname);
356                 List<ListResultField> resultsFields = getListItemsArray();
357                 for (ListResultField field : resultsFields) {
358                         callPropertySetterWithXPathValue(docModel, item, field.getSetter(), schema, field.getXpath());
359                 }
360                 if (includeStdFields) {
361                         callSimplePropertySetter(item, "setCsid", id);
362                         callSimplePropertySetter(item, "setUri", getServiceContextPath() + id);
363                 }
364                 
365                 return item;
366         }
367
368         /**
369          * Subclasses should override this method if they don't want to automatically
370          * call List createItemsList(AbstractCommonList commonList, String listItemMethodName)
371          * which will use introspection to create a summary list, and will find the primary
372          * field for you if specified.
373          */
374         public List createItemsList(AbstractCommonList commonList) throws Exception {
375                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
376                 return createItemsList(commonList, ServiceConfigUtils.getDocHandlerParams(ctx).getListResultsItemMethodName());
377         }
378
379         /** e.g. createItemsList(commonList, "getObjectexitListItem" */
380         public List createItemsList(AbstractCommonList commonList, String listItemMethodName) throws Exception {
381                 Class commonListClass = commonList.getClass();
382                 Class[] types = new Class[] {};
383                 try {
384                         Method m = commonListClass.getMethod(listItemMethodName, types);
385                         return (List) (ReflectionMapper.fireGetMethod(m, commonList));
386                 } catch (NoSuchMethodException nsm) {
387                         return new ArrayList();
388                 }
389         }
390
391 }