]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
25efd1c35bd9f740abce1aff4c44989de223bbfb
[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.io.InputStream;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.Set;
32
33 import javax.ws.rs.WebApplicationException;
34 import javax.ws.rs.core.MediaType;
35 import javax.ws.rs.core.Response;
36
37 import org.collectionspace.services.jaxb.AbstractCommonList;
38 import org.collectionspace.services.common.authorityref.AuthorityRefList;
39 import org.collectionspace.services.common.context.MultipartServiceContext;
40 import org.collectionspace.services.common.context.ServiceContext;
41 import org.collectionspace.services.common.document.BadRequestException;
42 import org.collectionspace.services.common.document.DocumentUtils;
43 import org.collectionspace.services.common.document.DocumentWrapper;
44 import org.collectionspace.services.common.document.DocumentFilter;
45 import org.collectionspace.services.common.document.DocumentHandler.Action;
46 import org.collectionspace.services.common.service.ObjectPartType;
47 import org.collectionspace.services.common.vocabulary.RefNameUtils;
48
49 import org.jboss.resteasy.plugins.providers.multipart.InputPart;
50 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
51 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
52 import org.nuxeo.ecm.core.api.DocumentModel;
53 import org.nuxeo.ecm.core.api.DocumentModelList;
54 import org.nuxeo.ecm.core.api.model.PropertyException;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.w3c.dom.Document;
58
59 /**
60  * RemoteDocumentModelHandler
61  *
62  * $LastChangedRevision: $
63  * $LastChangedDate: $
64  * @param <T> 
65  * @param <TL> 
66  */
67 public abstract class RemoteDocumentModelHandlerImpl<T, TL>
68         extends DocumentModelHandler<T, TL> {
69
70     /** The logger. */
71     private final Logger logger = LoggerFactory.getLogger(RemoteDocumentModelHandlerImpl.class);
72
73     /* (non-Javadoc)
74      * @see org.collectionspace.services.common.document.AbstractDocumentHandlerImpl#setServiceContext(org.collectionspace.services.common.context.ServiceContext)
75      */
76     @Override
77     public void setServiceContext(ServiceContext ctx) {  //FIXME: Apply proper generics to ServiceContext<MultipartInput, MultipartOutput>
78         if(ctx instanceof MultipartServiceContext){
79             super.setServiceContext(ctx);
80         }else{
81             throw new IllegalArgumentException("setServiceContext requires instance of " +
82                     MultipartServiceContext.class.getName());
83         }
84     }
85
86     /* (non-Javadoc)
87      * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#completeUpdate(org.collectionspace.services.common.document.DocumentWrapper)
88      */
89     @Override
90     public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
91         DocumentModel docModel = wrapDoc.getWrappedObject();
92         //return at least those document part(s) that were received
93         Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
94         MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
95         List<InputPart> inputParts = ctx.getInput().getParts();
96         for(InputPart part : inputParts){
97             String partLabel = part.getHeaders().getFirst("label");
98             ObjectPartType partMeta = partsMetaMap.get(partLabel);
99 //            extractPart(docModel, partLabel, partMeta);
100                         Map<String, Object> unQObjectProperties = extractPart(docModel, partLabel, partMeta);
101                         addOutputPart(unQObjectProperties, partLabel, partMeta);
102         }
103     }
104
105     /**
106      * Adds the output part.
107      *
108      * @param unQObjectProperties the un q object properties
109      * @param schema the schema
110      * @param partMeta the part meta
111      * @throws Exception the exception
112      */
113     private void addOutputPart(Map<String, Object> unQObjectProperties, String schema, ObjectPartType partMeta)
114                 throws Exception {
115                 Document doc = DocumentUtils.buildDocument(partMeta, schema,
116                                 unQObjectProperties);
117                 if (logger.isDebugEnabled() == true) {                  
118                         logger.debug(DocumentUtils.xmlToString(doc));
119                 }
120                 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
121                 ctx.addOutputPart(schema, doc, partMeta.getContent().getContentType());
122     }    
123     
124     /**
125      * Extract paging info.
126      *
127      * @param commonsList the commons list
128      * @return the tL
129      * @throws Exception the exception
130      */
131     protected TL extractPagingInfo(TL theCommonList, DocumentWrapper<DocumentModelList> wrapDoc)
132         throws Exception {
133         AbstractCommonList commonList = (AbstractCommonList)theCommonList;
134         
135         DocumentFilter docFilter = this.getDocumentFilter();
136         long pageSize = docFilter.getPageSize();
137         long pageNum = pageSize != 0 ? docFilter.getOffset() / pageSize : pageSize;
138         // set the page size and page number
139         commonList.setPageNum(pageNum);
140         commonList.setPageSize(pageSize);
141         DocumentModelList docList = wrapDoc.getWrappedObject();
142         // Set num of items in list. this is useful to our testing framework.
143         commonList.setItemsInPage(docList.size());
144         // set the total result size
145         commonList.setTotalItems(docList.totalSize());
146         
147         return (TL)commonList;
148     }
149     
150     
151         /* (non-Javadoc)
152          * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#extractAllParts(org.collectionspace.services.common.document.DocumentWrapper)
153          */
154         @Override
155         public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
156                         throws Exception {
157
158                 DocumentModel docModel = wrapDoc.getWrappedObject();
159                 String[] schemas = docModel.getDeclaredSchemas();
160                 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
161                 for (String schema : schemas) {
162                         ObjectPartType partMeta = partsMetaMap.get(schema);
163                         if (partMeta == null) {
164                                 continue; // unknown part, ignore
165                         }
166                         Map<String, Object> unQObjectProperties = extractPart(docModel, schema, partMeta);
167                         addOutputPart(unQObjectProperties, schema, partMeta);
168                 }
169         }
170
171     /* (non-Javadoc)
172      * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#fillAllParts(org.collectionspace.services.common.document.DocumentWrapper)
173      */
174     @Override
175     public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
176
177         //TODO filling extension parts should be dynamic
178         //Nuxeo APIs lack to support stream/byte[] input, get/setting properties is
179         //not an ideal way of populating objects.
180         DocumentModel docModel = wrapDoc.getWrappedObject();
181         MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
182         MultipartInput input = ctx.getInput();
183         if(input.getParts().isEmpty()){
184             String msg = "No payload found!";
185             logger.error(msg + "Ctx=" + getServiceContext().toString());
186             throw new BadRequestException(msg);
187         }
188
189         Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
190
191         //iterate over parts received and fill those parts
192         List<InputPart> inputParts = input.getParts();
193         for(InputPart part : inputParts){
194
195             String partLabel = part.getHeaders().getFirst("label");
196             if (partLabel == null) {
197                 String msg = "Part label is missing or empty!";
198                 logger.error(msg + "Ctx=" + getServiceContext().toString());
199                 throw new BadRequestException(msg);
200             }
201             
202             //skip if the part is not in metadata
203             ObjectPartType partMeta = partsMetaMap.get(partLabel);
204             if(partMeta==null){
205                 continue;
206             }
207             fillPart(part, docModel, partMeta, action);
208         }//rof
209
210     }
211
212     /**
213      * fillPart fills an XML part into given document model
214      * @param part to fill
215      * @param docModel for the given object
216      * @param partMeta metadata for the object to fill
217      * @throws Exception
218      */
219     protected void fillPart(InputPart part, DocumentModel docModel, ObjectPartType partMeta, Action action)
220             throws Exception {
221         InputStream payload = part.getBody(InputStream.class, null);
222         
223 // TODO for sub-docs - after we parse the doc, we need to look for elements that are configured as 
224 // subitem lists, for this part (schema), pull them out, and set them aside for later processing.
225
226         //check if this is an xml part
227         if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){
228             if(payload != null){
229                 Document document = DocumentUtils.parseDocument(payload, partMeta);
230                 //TODO: callback to handler if registered to validate the
231                 //document
232                 Map<String, Object> objectProps = DocumentUtils.parseProperties(document.getFirstChild());
233                 if(action==Action.UPDATE) {
234                         this.filterReadOnlyPropertiesForPart(objectProps, partMeta);
235                 }
236                 docModel.setProperties(partMeta.getLabel(), objectProps);
237             }
238         }
239     }
240
241     /**
242      * Filters out read only properties, so they cannot be set on update.
243      * TODO: add configuration support to do this generally
244      * @param objectProps the properties parsed from the update payload
245      * @param partMeta metadata for the object to fill
246      */
247     public void filterReadOnlyPropertiesForPart(
248                 Map<String, Object> objectProps, ObjectPartType partMeta) {
249         // Currently a no-op, but can be overridden in Doc handlers.
250     }
251
252     /**
253      * extractPart extracts an XML object from given DocumentModel
254      * @param docModel
255      * @param schema of the object to extract
256      * @param partMeta metadata for the object to extract
257      * @throws Exception
258      */
259     protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
260             throws Exception {
261         return extractPart( docModel, schema, partMeta, null );
262     }
263     
264     /**
265      * extractPart extracts an XML object from given DocumentModel
266      * @param docModel
267      * @param schema of the object to extract
268      * @param partMeta metadata for the object to extract
269      * @throws Exception
270      */
271     protected Map<String, Object> extractPart(
272                 DocumentModel docModel, String schema, ObjectPartType partMeta,
273                 Map<String, Object> addToMap)
274             throws Exception {
275         Map<String, Object> result = null;
276         
277         MediaType mt = MediaType.valueOf(partMeta.getContent().getContentType());
278         if (mt.equals(MediaType.APPLICATION_XML_TYPE)){
279             Map<String, Object> objectProps = docModel.getProperties(schema);
280             //unqualify properties before sending the doc over the wire (to save bandwidh)
281             //FIXME: is there a better way to avoid duplication of a collection?
282             Map<String, Object> unQObjectProperties = 
283                 (addToMap!=null)? addToMap:(new HashMap<String, Object>());
284             Set<Entry<String, Object>> qualifiedEntries = objectProps.entrySet();
285             for(Entry<String, Object> entry : qualifiedEntries){
286                 String unqProp = getUnQProperty(entry.getKey());
287                 unQObjectProperties.put(unqProp, entry.getValue());
288             }
289             result = unQObjectProperties;
290         } //TODO: handle other media types
291         
292         return result;
293     }
294     
295     /* (non-Javadoc)
296      * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#getAuthorityRefs(org.collectionspace.services.common.document.DocumentWrapper, java.util.List)
297      */
298     @Override
299     public AuthorityRefList getAuthorityRefs(
300                 DocumentWrapper<DocumentModel> docWrapper,
301                 List<String> authRefFields) throws PropertyException {
302         AuthorityRefList authRefList = new AuthorityRefList();
303         try {
304                 DocumentModel docModel = docWrapper.getWrappedObject();
305                 List<AuthorityRefList.AuthorityRefItem> list = authRefList.getAuthorityRefItem();
306
307                 for (String field : authRefFields) {
308                         String refName = (String) docModel.getPropertyValue(field);
309                         if (refName == null)
310                                 continue;
311                         try {
312                                 RefNameUtils.AuthorityTermInfo termInfo = RefNameUtils
313                                 .parseAuthorityTermInfo(refName);
314                                 AuthorityRefList.AuthorityRefItem ilistItem = new AuthorityRefList.AuthorityRefItem();
315                                 ilistItem.setRefName(refName);
316                                 ilistItem.setAuthDisplayName(termInfo.inAuthority.displayName);
317                                 ilistItem.setItemDisplayName(termInfo.displayName);
318                                 ilistItem.setSourceField(field);
319                                 ilistItem.setUri(termInfo.getRelativeUri());
320                                 list.add(ilistItem);
321                         } catch (Exception e) {
322                                 // FIXME: Do we need to throw this Exception here?
323                                 if (logger.isDebugEnabled()) {
324                                         logger.debug("Caught exception in getAuthorityRefs", e);
325                                 }
326                         }
327                 }
328         } catch (PropertyException pe) {
329                 String msg = "Attempted to retrieve value for invalid or missing authority field. "
330                         + "Check authority field properties in tenant bindings.";
331                 logger.warn(msg, pe);
332                 throw pe;
333         } catch (Exception e) {
334                 if (logger.isDebugEnabled()) {
335                         logger.debug("Caught exception in getAuthorityRefs", e);
336                 }
337                 Response response = Response.status(
338                                 Response.Status.INTERNAL_SERVER_ERROR).entity(
339                                 "Failed to retrieve authority references").type(
340                                 "text/plain").build();
341                 throw new WebApplicationException(response);
342         }
343         return authRefList;
344     }
345 }