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;
33 import javax.ws.rs.WebApplicationException;
34 import javax.ws.rs.core.MediaType;
35 import javax.ws.rs.core.Response;
37 import org.collectionspace.services.common.authorityref.AuthorityRefList;
38 import org.collectionspace.services.common.context.MultipartServiceContext;
39 import org.collectionspace.services.common.context.ServiceContext;
40 import org.collectionspace.services.common.document.BadRequestException;
41 import org.collectionspace.services.common.document.DocumentUtils;
42 import org.collectionspace.services.common.document.DocumentWrapper;
43 import org.collectionspace.services.common.service.ObjectPartType;
44 import org.collectionspace.services.common.vocabulary.RefNameUtils;
45 import org.jboss.resteasy.plugins.providers.multipart.InputPart;
46 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
47 import org.nuxeo.ecm.core.api.DocumentModel;
48 import org.nuxeo.ecm.core.api.model.PropertyException;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.w3c.dom.Document;
54 * RemoteDocumentModelHandler
56 * $LastChangedRevision: $
59 public abstract class RemoteDocumentModelHandlerImpl<T, TL>
60 extends DocumentModelHandler<T, TL> {
62 private final Logger logger = LoggerFactory.getLogger(RemoteDocumentModelHandlerImpl.class);
65 public void setServiceContext(ServiceContext ctx) {
66 if(ctx instanceof MultipartServiceContext){
67 super.setServiceContext(ctx);
69 throw new IllegalArgumentException("setServiceContext requires instance of " +
70 MultipartServiceContext.class.getName());
75 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
76 DocumentModel docModel = wrapDoc.getWrappedObject();
77 //return at least those document part(s) that were received
78 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
79 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
80 List<InputPart> inputParts = ctx.getInput().getParts();
81 for(InputPart part : inputParts){
82 String partLabel = part.getHeaders().getFirst("label");
83 ObjectPartType partMeta = partsMetaMap.get(partLabel);
84 // extractPart(docModel, partLabel, partMeta);
85 Map<String, Object> unQObjectProperties = extractPart(docModel, partLabel, partMeta);
86 addOutputPart(unQObjectProperties, partLabel, partMeta);
90 private void addOutputPart(Map<String, Object> unQObjectProperties, String schema, ObjectPartType partMeta)
92 Document doc = DocumentUtils.buildDocument(partMeta, schema,
94 if (logger.isDebugEnabled()) {
95 DocumentUtils.writeDocument(doc, System.out);
97 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
98 ctx.addOutputPart(schema, doc, partMeta.getContent().getContentType());
102 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
105 DocumentModel docModel = wrapDoc.getWrappedObject();
106 String[] schemas = docModel.getDeclaredSchemas();
107 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
108 for (String schema : schemas) {
109 ObjectPartType partMeta = partsMetaMap.get(schema);
110 if (partMeta == null) {
111 continue; // unknown part, ignore
113 Map<String, Object> unQObjectProperties = extractPart(docModel, schema, partMeta);
114 addOutputPart(unQObjectProperties, schema, partMeta);
119 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
121 //TODO filling extension parts should be dynamic
122 //Nuxeo APIs lack to support stream/byte[] input, get/setting properties is
123 //not an ideal way of populating objects.
124 DocumentModel docModel = wrapDoc.getWrappedObject();
125 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
126 MultipartInput input = ctx.getInput();
127 if(input.getParts().isEmpty()){
128 String msg = "No payload found!";
129 logger.error(msg + "Ctx=" + getServiceContext().toString());
130 throw new BadRequestException(msg);
133 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
135 //iterate over parts received and fill those parts
136 List<InputPart> inputParts = input.getParts();
137 for(InputPart part : inputParts){
139 String partLabel = part.getHeaders().getFirst("label");
140 if (partLabel == null) {
141 String msg = "Part label is missing or empty!";
142 logger.error(msg + "Ctx=" + getServiceContext().toString());
143 throw new BadRequestException(msg);
146 //skip if the part is not in metadata
147 if(!partsMetaMap.containsKey(partLabel)){
150 ObjectPartType partMeta = partsMetaMap.get(partLabel);
151 fillPart(part, docModel, partMeta);
157 * fillPart fills an XML part into given document model
158 * @param part to fill
159 * @param docModel for the given object
160 * @param partMeta metadata for the object to fill
163 protected void fillPart(InputPart part, DocumentModel docModel, ObjectPartType partMeta)
165 InputStream payload = part.getBody(InputStream.class, null);
167 //check if this is an xml part
168 if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){
170 Document document = DocumentUtils.parseDocument(payload);
171 //TODO: callback to handler if registered to validate the
173 Map<String, Object> objectProps = DocumentUtils.parseProperties(document);
174 docModel.setProperties(partMeta.getLabel(), objectProps);
180 * extractPart extracts an XML object from given DocumentModel
182 * @param schema of the object to extract
183 * @param partMeta metadata for the object to extract
186 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
188 Map<String, Object> result = null;
190 MediaType mt = MediaType.valueOf(partMeta.getContent().getContentType());
191 if (mt.equals(MediaType.APPLICATION_XML_TYPE)){
192 Map<String, Object> objectProps = docModel.getProperties(schema);
193 //unqualify properties before sending the doc over the wire (to save bandwidh)
194 //FIXME: is there a better way to avoid duplication of a collection?
195 Map<String, Object> unQObjectProperties = new HashMap<String, Object>();
196 Set<Entry<String, Object>> qualifiedEntries = objectProps.entrySet();
197 for(Entry<String, Object> entry : qualifiedEntries){
198 String unqProp = getUnQProperty(entry.getKey());
199 unQObjectProperties.put(unqProp, entry.getValue());
201 result = unQObjectProperties;
202 } //TODO: handle other media types
209 * @param authRefFields list of schema-qualified field names
211 * @throws PropertyException
213 public AuthorityRefList getAuthorityRefs(
214 DocumentWrapper<DocumentModel> docWrapper,
215 List<String> authRefFields) throws PropertyException {
216 AuthorityRefList authRefList = new AuthorityRefList();
218 DocumentModel docModel = docWrapper.getWrappedObject();
219 List<AuthorityRefList.AuthorityRefItem> list =
220 authRefList.getAuthorityRefItem();
222 for(String field:authRefFields){
223 String refName = (String)docModel.getPropertyValue(field);
227 RefNameUtils.AuthorityTermInfo termInfo =
228 RefNameUtils.parseAuthorityTermInfo(refName);
229 AuthorityRefList.AuthorityRefItem ilistItem =
230 new AuthorityRefList.AuthorityRefItem();
231 ilistItem.setRefName(refName);
232 ilistItem.setAuthDisplayName(termInfo.inAuthority.displayName);
233 ilistItem.setItemDisplayName(termInfo.displayName);
234 ilistItem.setSourceField(field);
235 ilistItem.setUri(termInfo.getRelativeUri());
237 } catch( Exception e ) {
238 // FIXME: Do we need to throw this Exception here?
239 if (logger.isDebugEnabled()) {
240 logger.debug("Caught exception in getAuthorityRefs", e);
244 } catch (PropertyException pe) {
246 "Attempted to retrieve value for invalid or missing authority field. " +
247 "Check authority field properties in tenant bindings.";
248 logger.warn(msg, pe);
250 } catch (Exception e) {
251 if (logger.isDebugEnabled()) {
252 logger.debug("Caught exception in getAuthorityRefs", e);
254 Response response = Response.status(
255 Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to retrieve authority references").type("text/plain").build();
256 throw new WebApplicationException(response);