2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.nuxeo.client.java;
26 import java.io.InputStream;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Map.Entry;
32 import javax.ws.rs.core.MediaType;
33 import org.collectionspace.services.common.context.RemoteServiceContext;
34 import org.collectionspace.services.common.context.ServiceContext;
35 import org.collectionspace.services.common.document.BadRequestException;
36 import org.collectionspace.services.common.document.DocumentUtils;
37 import org.collectionspace.services.common.document.DocumentWrapper;
38 import org.collectionspace.services.common.service.ObjectPartType;
39 import org.jboss.resteasy.plugins.providers.multipart.InputPart;
40 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
41 import org.nuxeo.ecm.core.api.DocumentModel;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.w3c.dom.Document;
47 * RemoteDocumentModelHandler
49 * $LastChangedRevision: $
52 public abstract class RemoteDocumentModelHandler<T, TL>
53 extends DocumentModelHandler<T, TL> {
55 private final Logger logger = LoggerFactory.getLogger(RemoteDocumentModelHandler.class);
58 public void setServiceContext(ServiceContext ctx) {
59 if(ctx instanceof RemoteServiceContext){
60 super.setServiceContext(ctx);
62 throw new IllegalArgumentException("setServiceContext requires instance of " +
63 RemoteServiceContext.class.getName());
68 public abstract String getDocumentType();
71 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
72 DocumentModel docModel = wrapDoc.getWrappedObject();
73 //return at least those document part(s) that were received
74 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
75 RemoteServiceContext ctx = (RemoteServiceContext) getServiceContext();
76 List<InputPart> inputParts = ctx.getInput().getParts();
77 for(InputPart part : inputParts){
78 String partLabel = part.getHeaders().getFirst("label");
79 ObjectPartType partMeta = partsMetaMap.get(partLabel);
80 extractPart(docModel, partLabel, partMeta);
85 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
87 DocumentModel docModel = wrapDoc.getWrappedObject();
88 String[] schemas = docModel.getDeclaredSchemas();
89 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
90 for(String schema : schemas){
91 ObjectPartType partMeta = partsMetaMap.get(schema);
93 continue; //unknown part, ignore
95 extractPart(docModel, schema, partMeta);
100 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
102 //TODO filling extension parts should be dynamic
103 //Nuxeo APIs lack to support stream/byte[] input, get/setting properties is
104 //not an ideal way of populating objects.
105 DocumentModel docModel = wrapDoc.getWrappedObject();
106 RemoteServiceContext ctx = (RemoteServiceContext) getServiceContext();
107 MultipartInput input = ctx.getInput();
108 if(input.getParts().isEmpty()){
109 String msg = "No payload found!";
110 logger.error(msg + "Ctx=" + getServiceContext().toString());
111 throw new BadRequestException(msg);
114 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
116 //iterate over parts received and fill those parts
117 List<InputPart> inputParts = input.getParts();
118 for(InputPart part : inputParts){
120 String partLabel = part.getHeaders().getFirst("label");
121 if (partLabel == null) {
122 String msg = "Part label is missing or empty!";
123 logger.error(msg + "Ctx=" + getServiceContext().toString());
124 throw new BadRequestException(msg);
127 //skip if the part is not in metadata
128 if(!partsMetaMap.containsKey(partLabel)){
131 ObjectPartType partMeta = partsMetaMap.get(partLabel);
132 fillPart(part, docModel, partMeta);
138 * fillPart fills an XML part into given document model
139 * @param part to fill
140 * @param docModel for the given object
141 * @param partMeta metadata for the object to fill
144 protected void fillPart(InputPart part, DocumentModel docModel, ObjectPartType partMeta)
146 InputStream payload = part.getBody(InputStream.class, null);
148 //check if this is an xml part
149 if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){
151 Document document = DocumentUtils.parseDocument(payload);
152 //TODO: callback to handler if registered to validate the
154 Map<String, Object> objectProps = DocumentUtils.parseProperties(document);
155 docModel.setProperties(partMeta.getLabel(), objectProps);
161 * extractPart extracts an XML object from given DocumentModel
163 * @param schema of the object to extract
164 * @param partMeta metadata for the object to extract
167 protected void extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
169 MediaType mt = MediaType.valueOf(partMeta.getContent().getContentType());
170 if(mt.equals(MediaType.APPLICATION_XML_TYPE)){
171 Map<String, Object> objectProps = docModel.getProperties(schema);
172 //unqualify properties before sending the doc over the wire (to save bandwidh)
173 //FIXME: is there a better way to avoid duplication of a collection?
174 Map<String, Object> unQObjectProperties = new HashMap<String, Object>();
175 Set<Entry<String, Object>> qualifiedEntries = objectProps.entrySet();
176 for(Entry<String, Object> entry : qualifiedEntries){
177 String unqProp = getUnQProperty(entry.getKey());
178 unQObjectProperties.put(unqProp, entry.getValue());
180 Document doc = DocumentUtils.buildDocument(partMeta, schema, unQObjectProperties);
181 if(logger.isDebugEnabled()){
182 DocumentUtils.writeDocument(doc, System.out);
184 RemoteServiceContext ctx = (RemoteServiceContext) getServiceContext();
185 ctx.addOutputPart(schema, doc, partMeta.getContent().getContentType());
186 } //TODO: handle other media types