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.NuxeoDocumentModelHandler;
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.NuxeoBlobUtils;
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;
43 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
44 import org.nuxeo.ecm.core.api.ClientException;
45 import org.nuxeo.ecm.core.api.DocumentModel;
46 import org.nuxeo.ecm.core.api.IdRef;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import java.util.List;
53 import javax.ws.rs.core.MultivaluedMap;
55 import org.dom4j.Element;
58 * The Class BlobDocumentModelHandler.
60 public class BlobDocumentModelHandler
61 extends NuxeoDocumentModelHandler<BlobsCommon> {
64 private final Logger logger = LoggerFactory.getLogger(BlobDocumentModelHandler.class);
66 //==============================================================================
68 private String getDerivativePathBase(DocumentModel docModel) {
69 return getServiceContextPath() + docModel.getName() + "/" +
70 BlobInput.URI_DERIVATIVES_PATH + "/";
73 private BlobsCommon getCommonPartProperties(DocumentModel docModel) throws Exception {
74 String label = getServiceContext().getCommonPartLabel();
75 BlobsCommon result = new BlobsCommon();
77 result.setData((String)
78 docModel.getProperty(label, BlobJAXBSchema.data));
79 result.setDigest((String)
80 docModel.getProperty(label, BlobJAXBSchema.digest));
81 result.setEncoding((String)
82 docModel.getProperty(label, BlobJAXBSchema.encoding));
83 result.setLength((String)
84 docModel.getProperty(label, BlobJAXBSchema.length));
85 result.setMimeType((String)
86 docModel.getProperty(label, BlobJAXBSchema.mimeType));
87 result.setName((String)
88 docModel.getProperty(label, BlobJAXBSchema.name));
89 result.setRepositoryId((String)
90 docModel.getProperty(label, BlobJAXBSchema.repositoryId));
91 result.setUri(getServiceContextPath() + docModel.getName() + "/" +
92 BlobInput.URI_CONTENT_PATH);
97 private void setCommonPartProperties(DocumentModel documentModel,
98 BlobsCommon blobsCommon) throws ClientException {
100 String schemaName = getServiceContext().getCommonPartLabel();
101 PayloadOutputPart outputPart = new PayloadOutputPart(schemaName, blobsCommon);
102 Element element = outputPart.asElement();
103 Map<String, Object> propertyMap = DocumentUtils.parseProperties(schemaName, element, getServiceContext());
104 documentModel.setProperties(schemaName, propertyMap);
105 } catch (Exception e) {
106 throw new ClientException(e);
110 private void extractMetadata(String nuxeoImageID, String metadataLabel) {
111 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
112 ObjectPartType partMeta = partsMetaMap.get(metadataLabel);
114 if (partMeta != null) {
115 CoreSessionInterface repoSession = this.getRepositorySession();
116 if (nuxeoImageID != null && nuxeoImageID.isEmpty() == false) try {
117 IdRef documentRef = new IdRef(nuxeoImageID);
118 DocumentModel docModel = repoSession.getDocument(documentRef);
119 Map<String, Object> unQObjectProperties = extractPart(docModel, metadataLabel);
120 if (unQObjectProperties != null) {
121 addOutputPart(unQObjectProperties, metadataLabel, partMeta);
123 } catch (Exception e) {
124 logger.warn("Metadata extraction failed: " + e.getMessage());
127 logger.warn("Metadata extraction failed: Could not find tenant binding for schema type = " + metadataLabel);
132 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#extractAllParts(org.collectionspace.services.common.document.DocumentWrapper)
135 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
137 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
138 BlobInput blobInput = BlobUtil.getBlobInput(ctx); // the blobInput was set by the Blob JAX-RS resource code and put into the service context
139 CoreSessionInterface repoSession = this.getRepositorySession();
140 DocumentModel docModel = wrapDoc.getWrappedObject();
141 BlobsCommon blobsCommon = this.getCommonPartProperties(docModel);
142 String blobRepositoryId = blobsCommon.getRepositoryId(); //cache the value to pass to the blob retriever
144 // 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).
146 if (blobInput.isDerivativeListRequested() == true) {
147 List<ListResultField> resultsFields = getListItemsArray();
148 CommonList blobsCommonList = NuxeoBlobUtils.getBlobDerivatives( //FIXME: REM - Need to replace "NuxeoImageUtils" with something more general like "BlobUtils" since we may support other blob types.
149 repoSession, blobRepositoryId, resultsFields, getDerivativePathBase(docModel));
150 // ctx.setProperty(BlobInput.BLOB_DERIVATIVE_LIST_KEY, blobsCommonList);
151 blobInput.setDerivativeList(blobsCommonList);
152 return; //FIXME: REM - Don't like this exit point. Perhaps derivatives should be a sub-resource with its own DerivativeDocumentHandler doc handler?
155 String derivativeTerm = blobInput.getDerivativeTerm();
156 Boolean getContentFlag = blobInput.isContentRequested();
158 // If we're being asked for either the content of the blob, the content of a derivative, or the payload for a derivative then
159 // fall into this block of code. Otherwise, we'll just call our parent to deal with a plain-old-blob payload.
161 if (derivativeTerm != null || getContentFlag == true) {
162 StringBuffer mimeTypeBuffer = new StringBuffer();
163 BlobOutput blobOutput = NuxeoBlobUtils.getBlobOutput(ctx, repoSession,
164 blobRepositoryId, derivativeTerm, getContentFlag, mimeTypeBuffer);
165 if (getContentFlag == true) {
166 if (blobOutput != null) {
167 blobInput.setContentStream(blobOutput.getBlobInputStream());
169 blobInput.setContentStream(null);
173 if (derivativeTerm != null) {
174 // reset 'blobsCommon' if we have a derivative request
175 blobsCommon = blobOutput.getBlobsCommon();
176 blobsCommon.setUri(getDerivativePathBase(docModel) +
177 derivativeTerm + "/" + BlobInput.URI_CONTENT_PATH);
180 String mimeType = mimeTypeBuffer.toString();
181 if (mimeType != null && !mimeType.isEmpty()) { // MIME type for derivatives might be different from original
182 blobInput.setMimeType(mimeType);
183 blobsCommon.setMimeType(mimeType);
185 blobInput.setMimeType(blobsCommon.getMimeType()); // Set the MIME type to the one in blobsCommon
188 blobsCommon.setRepositoryId(null); //hide the repository id from the GET results payload since it is private
189 this.setCommonPartProperties(docModel, blobsCommon);
190 // finish extracting the other parts by calling the parent
192 extractMetadata(blobRepositoryId, NuxeoBlobUtils.SCHEMA_IMAGE_METADATA);
193 extractMetadata(blobRepositoryId, NuxeoBlobUtils.SCHEMA_IPTC);
197 // Hide the Nuxeo repository ID of the Nuxeo blob since this is private
199 docModel.setProperty(ctx.getCommonPartLabel(), BlobJAXBSchema.repositoryId, null);
200 super.extractAllParts(wrapDoc);
204 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
205 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
206 BlobInput blobInput = BlobUtil.getBlobInput(ctx); // The blobInput should have been put into the context by the Blob or Media resource
207 if (blobInput != null && blobInput.getBlobFile() != null) {
208 boolean purgeOriginal = false;
209 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
210 String purgeOriginalStr = queryParams.getFirst(BlobClient.BLOB_PURGE_ORIGINAL);
211 if (purgeOriginalStr != null && purgeOriginalStr.isEmpty() == false) { // Find our if the caller wants us to purge/delete the original
212 purgeOriginal = true;
215 // If blobInput has a file then we just received a multipart/form-data file post or a URI query parameter
217 DocumentModel documentModel = wrapDoc.getWrappedObject();
218 CoreSessionInterface repoSession = this.getRepositorySession();
220 BlobsCommon blobsCommon = NuxeoBlobUtils.createBlobInRepository(ctx, repoSession, blobInput, purgeOriginal, true);
221 blobInput.setBlobCsid(documentModel.getName()); //Assumption here is that the documentModel "name" field is storing a CSID
223 PoxPayloadIn input = ctx.getInput();
225 // If the input payload is null, then we're creating a new blob from a post or a uri. This means there
226 // is no "input" payload for our framework to process. Therefore we need to synthesize a payload from
227 // the BlobsCommon instance we just filled out.
230 PoxPayloadOut output = new PoxPayloadOut(BlobClient.SERVICE_PAYLOAD_NAME);
231 PayloadOutputPart commonPart = new PayloadOutputPart(BlobClient.SERVICE_COMMON_PART_NAME, blobsCommon);
232 output.addPart(commonPart);
233 input = new PoxPayloadIn(output.toXML());
236 // 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
237 // that to populate the resource record. However, since the "input" var is not null the requester provided their own resource record data
238 // so we'll use it rather than deriving one from the blob.
239 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." +
240 " The data in blob resource record fields may not correspond completely with the persisted blob binary file.");
244 super.fillAllParts(wrapDoc, action);