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.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.service.ObjectPartType;
46 import org.collectionspace.services.common.vocabulary.RefNameUtils;
47 //import org.collectionspace.services.vocabulary.VocabulariesCommonList;
48 import org.jboss.resteasy.plugins.providers.multipart.InputPart;
49 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
50 import org.nuxeo.ecm.core.api.DocumentModel;
51 import org.nuxeo.ecm.core.api.DocumentModelList;
52 import org.nuxeo.ecm.core.api.model.PropertyException;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.w3c.dom.Document;
58 * RemoteDocumentModelHandler
60 * $LastChangedRevision: $
63 public abstract class RemoteDocumentModelHandlerImpl<T, TL>
64 extends DocumentModelHandler<T, TL> {
66 private final Logger logger = LoggerFactory.getLogger(RemoteDocumentModelHandlerImpl.class);
69 public void setServiceContext(ServiceContext ctx) {
70 if(ctx instanceof MultipartServiceContext){
71 super.setServiceContext(ctx);
73 throw new IllegalArgumentException("setServiceContext requires instance of " +
74 MultipartServiceContext.class.getName());
79 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
80 DocumentModel docModel = wrapDoc.getWrappedObject();
81 //return at least those document part(s) that were received
82 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
83 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
84 List<InputPart> inputParts = ctx.getInput().getParts();
85 for(InputPart part : inputParts){
86 String partLabel = part.getHeaders().getFirst("label");
87 ObjectPartType partMeta = partsMetaMap.get(partLabel);
88 // extractPart(docModel, partLabel, partMeta);
89 Map<String, Object> unQObjectProperties = extractPart(docModel, partLabel, partMeta);
90 addOutputPart(unQObjectProperties, partLabel, partMeta);
94 private void addOutputPart(Map<String, Object> unQObjectProperties, String schema, ObjectPartType partMeta)
96 Document doc = DocumentUtils.buildDocument(partMeta, schema,
98 if (logger.isDebugEnabled()) {
99 DocumentUtils.writeDocument(doc, System.out);
101 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
102 ctx.addOutputPart(schema, doc, partMeta.getContent().getContentType());
107 * Extract paging info.
109 * @param commonsList the commons list
111 * @throws Exception the exception
113 protected TL extractPagingInfo(TL theCommonList, DocumentWrapper<DocumentModelList> wrapDoc)
115 AbstractCommonList commonList = (AbstractCommonList)theCommonList;
117 DocumentFilter docFilter = this.getDocumentFilter();
118 long pageSize = docFilter.getPageSize();
119 long pageNum = docFilter.getOffset() / pageSize;
120 // set the page size and page numer
121 commonList.setPageNum(pageNum);
122 commonList.setPageSize(pageSize);
123 // set the total result size
124 DocumentModelList docList = wrapDoc.getWrappedObject();
125 commonList.setTotalItems(docList.totalSize());
127 return (TL)commonList;
132 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
135 DocumentModel docModel = wrapDoc.getWrappedObject();
136 String[] schemas = docModel.getDeclaredSchemas();
137 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
138 for (String schema : schemas) {
139 ObjectPartType partMeta = partsMetaMap.get(schema);
140 if (partMeta == null) {
141 continue; // unknown part, ignore
143 Map<String, Object> unQObjectProperties = extractPart(docModel, schema, partMeta);
144 addOutputPart(unQObjectProperties, schema, partMeta);
149 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
151 //TODO filling extension parts should be dynamic
152 //Nuxeo APIs lack to support stream/byte[] input, get/setting properties is
153 //not an ideal way of populating objects.
154 DocumentModel docModel = wrapDoc.getWrappedObject();
155 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
156 MultipartInput input = ctx.getInput();
157 if(input.getParts().isEmpty()){
158 String msg = "No payload found!";
159 logger.error(msg + "Ctx=" + getServiceContext().toString());
160 throw new BadRequestException(msg);
163 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
165 //iterate over parts received and fill those parts
166 List<InputPart> inputParts = input.getParts();
167 for(InputPart part : inputParts){
169 String partLabel = part.getHeaders().getFirst("label");
170 if (partLabel == null) {
171 String msg = "Part label is missing or empty!";
172 logger.error(msg + "Ctx=" + getServiceContext().toString());
173 throw new BadRequestException(msg);
176 //skip if the part is not in metadata
177 if(!partsMetaMap.containsKey(partLabel)){
180 ObjectPartType partMeta = partsMetaMap.get(partLabel);
181 fillPart(part, docModel, partMeta);
187 * fillPart fills an XML part into given document model
188 * @param part to fill
189 * @param docModel for the given object
190 * @param partMeta metadata for the object to fill
193 protected void fillPart(InputPart part, DocumentModel docModel, ObjectPartType partMeta)
195 InputStream payload = part.getBody(InputStream.class, null);
197 //check if this is an xml part
198 if(part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)){
200 Document document = DocumentUtils.parseDocument(payload);
201 //TODO: callback to handler if registered to validate the
203 Map<String, Object> objectProps = DocumentUtils.parseProperties(document);
204 docModel.setProperties(partMeta.getLabel(), objectProps);
210 * extractPart extracts an XML object from given DocumentModel
212 * @param schema of the object to extract
213 * @param partMeta metadata for the object to extract
216 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
218 Map<String, Object> result = null;
220 MediaType mt = MediaType.valueOf(partMeta.getContent().getContentType());
221 if (mt.equals(MediaType.APPLICATION_XML_TYPE)){
222 Map<String, Object> objectProps = docModel.getProperties(schema);
223 //unqualify properties before sending the doc over the wire (to save bandwidh)
224 //FIXME: is there a better way to avoid duplication of a collection?
225 Map<String, Object> unQObjectProperties = new HashMap<String, Object>();
226 Set<Entry<String, Object>> qualifiedEntries = objectProps.entrySet();
227 for(Entry<String, Object> entry : qualifiedEntries){
228 String unqProp = getUnQProperty(entry.getKey());
229 unQObjectProperties.put(unqProp, entry.getValue());
231 result = unQObjectProperties;
232 } //TODO: handle other media types
238 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#getAuthorityRefs(org.collectionspace.services.common.document.DocumentWrapper, java.util.List)
241 public AuthorityRefList getAuthorityRefs(
242 DocumentWrapper<DocumentModel> docWrapper,
243 List<String> authRefFields) throws PropertyException {
244 AuthorityRefList authRefList = new AuthorityRefList();
246 DocumentModel docModel = docWrapper.getWrappedObject();
247 List<AuthorityRefList.AuthorityRefItem> list = authRefList.getAuthorityRefItem();
249 for (String field : authRefFields) {
250 String refName = (String) docModel.getPropertyValue(field);
254 RefNameUtils.AuthorityTermInfo termInfo = RefNameUtils
255 .parseAuthorityTermInfo(refName);
256 AuthorityRefList.AuthorityRefItem ilistItem = new AuthorityRefList.AuthorityRefItem();
257 ilistItem.setRefName(refName);
258 ilistItem.setAuthDisplayName(termInfo.inAuthority.displayName);
259 ilistItem.setItemDisplayName(termInfo.displayName);
260 ilistItem.setSourceField(field);
261 ilistItem.setUri(termInfo.getRelativeUri());
263 } catch (Exception e) {
264 // FIXME: Do we need to throw this Exception here?
265 if (logger.isDebugEnabled()) {
266 logger.debug("Caught exception in getAuthorityRefs", e);
270 } catch (PropertyException pe) {
271 String msg = "Attempted to retrieve value for invalid or missing authority field. "
272 + "Check authority field properties in tenant bindings.";
273 logger.warn(msg, pe);
275 } catch (Exception e) {
276 if (logger.isDebugEnabled()) {
277 logger.debug("Caught exception in getAuthorityRefs", e);
279 Response response = Response.status(
280 Response.Status.INTERNAL_SERVER_ERROR).entity(
281 "Failed to retrieve authority references").type(
282 "text/plain").build();
283 throw new WebApplicationException(response);