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.blob.nuxeo;
26 import org.collectionspace.services.blob.BlobsCommon;
27 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
28 import org.collectionspace.services.client.BlobClient;
29 import org.collectionspace.services.client.PayloadOutputPart;
30 import org.collectionspace.services.client.PoxPayloadIn;
31 import org.collectionspace.services.client.PoxPayloadOut;
32 import org.collectionspace.services.common.blob.BlobInput;
33 import org.collectionspace.services.common.blob.BlobOutput;
34 import org.collectionspace.services.common.blob.BlobUtil;
35 import org.collectionspace.services.common.context.ServiceContext;
36 import org.collectionspace.services.common.document.DocumentUtils;
37 import org.collectionspace.services.common.document.DocumentWrapper;
38 import org.collectionspace.services.common.imaging.nuxeo.NuxeoImageUtils;
39 import org.collectionspace.services.config.service.ListResultField;
40 import org.collectionspace.services.config.service.ObjectPartType;
41 import org.collectionspace.services.jaxb.BlobJAXBSchema;
42 import org.collectionspace.services.nuxeo.client.java.CommonList;
45 import org.nuxeo.ecm.core.api.ClientException;
46 import org.nuxeo.ecm.core.api.DocumentModel;
47 import org.nuxeo.ecm.core.api.IdRef;
48 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 import java.util.List;
56 import org.dom4j.Element;
59 * The Class BlobDocumentModelHandler.
61 public class BlobDocumentModelHandler
62 extends DocHandlerBase<BlobsCommon> {
65 private final Logger logger = LoggerFactory.getLogger(BlobDocumentModelHandler.class);
67 //==============================================================================
69 private String getDerivativePathBase(DocumentModel docModel) {
70 return getServiceContextPath() + docModel.getName() + "/" +
71 BlobInput.URI_DERIVATIVES_PATH + "/";
74 private BlobsCommon getCommonPartProperties(DocumentModel docModel) throws Exception {
75 String label = getServiceContext().getCommonPartLabel();
76 BlobsCommon result = new BlobsCommon();
78 result.setData((String)
79 docModel.getProperty(label, BlobJAXBSchema.data));
80 result.setDigest((String)
81 docModel.getProperty(label, BlobJAXBSchema.digest));
82 result.setEncoding((String)
83 docModel.getProperty(label, BlobJAXBSchema.encoding));
84 result.setLength((String)
85 docModel.getProperty(label, BlobJAXBSchema.length));
86 result.setMimeType((String)
87 docModel.getProperty(label, BlobJAXBSchema.mimeType));
88 result.setName((String)
89 docModel.getProperty(label, BlobJAXBSchema.name));
90 result.setRepositoryId((String)
91 docModel.getProperty(label, BlobJAXBSchema.repositoryId));
92 result.setUri(getServiceContextPath() + docModel.getName() + "/" +
93 BlobInput.URI_CONTENT_PATH);
98 private void setCommonPartProperties(DocumentModel documentModel,
99 BlobsCommon blobsCommon) throws ClientException {
101 String schemaName = getServiceContext().getCommonPartLabel();
102 PayloadOutputPart outputPart = new PayloadOutputPart(schemaName, blobsCommon);
103 Element element = outputPart.asElement();
104 Map<String, Object> propertyMap = DocumentUtils.parseProperties(schemaName, element, getServiceContext());
105 documentModel.setProperties(schemaName, propertyMap);
106 } catch (Exception e) {
107 throw new ClientException(e);
111 private void extractMetadata(String nuxeoImageID, String metadataLabel) {
112 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
113 ObjectPartType partMeta = partsMetaMap.get(metadataLabel);
115 if (partMeta != null) {
116 RepositoryInstance repoSession = this.getRepositorySession();
117 if (nuxeoImageID != null && nuxeoImageID.isEmpty() == false) try {
118 IdRef documentRef = new IdRef(nuxeoImageID);
119 DocumentModel docModel = repoSession.getDocument(documentRef);
120 Map<String, Object> unQObjectProperties = extractPart(docModel, metadataLabel);
121 if (unQObjectProperties != null) {
122 addOutputPart(unQObjectProperties, metadataLabel, partMeta);
124 } catch (Exception e) {
125 logger.warn("Metadata extraction failed: " + e.getMessage());
128 logger.warn("Metadata extraction failed: Could not find tenant binding for schema type = " + metadataLabel);
133 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#extractAllParts(org.collectionspace.services.common.document.DocumentWrapper)
136 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
138 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
139 BlobInput blobInput = BlobUtil.getBlobInput(ctx); // the blobInput was set by the Blob JAX-RS resource code and put into the service context
140 RepositoryInstance repoSession = this.getRepositorySession();
141 DocumentModel docModel = wrapDoc.getWrappedObject();
142 BlobsCommon blobsCommon = this.getCommonPartProperties(docModel);
143 String blobRepositoryId = blobsCommon.getRepositoryId(); //cache the value to pass to the blob retriever
145 // We're being asked for a list of blob derivatives, not the payload for a blob record. FIXME: REM - This should be handled in a class called DerivativeDocumentHandler (need to create).
147 if (blobInput.isDerivativeListRequested() == true) {
148 List<ListResultField> resultsFields = getListItemsArray();
149 CommonList blobsCommonList = NuxeoImageUtils.getBlobDerivatives( //FIXME: REM - Need to replace "NuxeoImageUtils" with something more general like "BlobUtils" since we may support other blob types.
150 repoSession, blobRepositoryId, resultsFields, getDerivativePathBase(docModel));
151 // ctx.setProperty(BlobInput.BLOB_DERIVATIVE_LIST_KEY, blobsCommonList);
152 blobInput.setDerivativeList(blobsCommonList);
153 return; //FIXME: REM - Don't like this exit point. Perhaps derivatives should be a sub-resource with its own DerivativeDocumentHandler doc handler?
156 String derivativeTerm = blobInput.getDerivativeTerm();
157 Boolean getContentFlag = blobInput.isContentRequested();
159 // If we're being asked for either the content of the blob, the content of a derivative, or the payload for a derivative then
160 // fall into this block of code. Otherwise, we'll just call our parent to deal with a plain-old-blob payload.
162 if (derivativeTerm != null || getContentFlag == true) {
163 StringBuffer mimeTypeBuffer = new StringBuffer();
164 BlobOutput blobOutput = NuxeoImageUtils.getBlobOutput(ctx, repoSession, //FIXME: REM - If the blob's binary has been removed from the file system, then this call will return null. We need to at least spit out a meaningful error/warning message
165 blobRepositoryId, derivativeTerm, getContentFlag, mimeTypeBuffer);
166 if (getContentFlag == true) {
167 blobInput.setContentStream(blobOutput.getBlobInputStream());
170 if (derivativeTerm != null) {
171 // reset 'blobsCommon' if we have a derivative request
172 blobsCommon = blobOutput.getBlobsCommon();
173 blobsCommon.setUri(getDerivativePathBase(docModel) +
174 derivativeTerm + "/" + BlobInput.URI_CONTENT_PATH);
177 String mimeType = mimeTypeBuffer.toString();
178 if (mimeType != null && !mimeType.isEmpty()) { // MIME type for derivatives might be different from original
179 blobInput.setMimeType(mimeType);
180 blobsCommon.setMimeType(mimeType);
182 blobInput.setMimeType(blobsCommon.getMimeType());
185 blobsCommon.setRepositoryId(null); //hide the repository id from the GET results payload since it is private
186 this.setCommonPartProperties(docModel, blobsCommon);
187 // finish extracting the other parts by calling the parent
189 extractMetadata(blobRepositoryId, NuxeoImageUtils.SCHEMA_IMAGE_METADATA);
190 extractMetadata(blobRepositoryId, NuxeoImageUtils.SCHEMA_IPTC);
194 // Hide the Nuxeo repository ID of the Nuxeo blob since this is private
196 docModel.setProperty(ctx.getCommonPartLabel(), BlobJAXBSchema.repositoryId, null);
197 super.extractAllParts(wrapDoc);
201 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
202 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
203 BlobInput blobInput = BlobUtil.getBlobInput(ctx); // The blobInput should have been put into the context by the Blob or Media resource
204 if (blobInput != null && blobInput.getBlobFile() != null) {
206 // If blobInput has a file then we just received a multipart/form-data file post or a URI query parameter
208 DocumentModel documentModel = wrapDoc.getWrappedObject();
209 RepositoryInstance repoSession = this.getRepositorySession();
210 BlobsCommon blobsCommon = NuxeoImageUtils.createBlobInRepository(ctx, repoSession, blobInput);
211 blobInput.setBlobCsid(documentModel.getName()); //Assumption here is that the documentModel "name" field is storing a CSID
213 PoxPayloadIn input = ctx.getInput();
215 // If the input payload is null, then we're creating a new blob from a post or a uri. This means there
216 // is no "input" payload for our framework to process. Therefore we need to synthesize a payload from
217 // the BlobsCommon instance we just filled out.
220 PoxPayloadOut output = new PoxPayloadOut(BlobClient.SERVICE_PAYLOAD_NAME);
221 PayloadOutputPart commonPart = new PayloadOutputPart(BlobClient.SERVICE_COMMON_PART_NAME, blobsCommon);
222 output.addPart(commonPart);
223 input = new PoxPayloadIn(output.toXML());
226 // At this point, we've created a blob document in the Nuxeo repository. Usually, we use the blob to create and instance of BlobsCommon and use
227 // that to populate the resource record. However, since the "input" var is not null the requester provided their own resource record data
228 // so we'll use it rather than deriving one from the blob.
229 logger.warn("A resource record payload was provided along with the actually blob binary file. This payload is usually derived from the blob binary. Since a payload was provided, we're creating the resource record from the payload and not from the corresponding blob binary." +
230 " The data in blob resource record fields may not correspond completely with the persisted blob binary file.");
234 super.fillAllParts(wrapDoc, action);