]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
cb6c26659149e1dfedd6f4688894bc5577d4be31
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.blob.nuxeo;
25
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;
49
50 import java.util.List;
51 import java.util.Map;
52
53 import javax.ws.rs.core.MultivaluedMap;
54
55 import org.dom4j.Element;
56
57 /**
58  * The Class BlobDocumentModelHandler.
59  */
60 public class BlobDocumentModelHandler
61 extends NuxeoDocumentModelHandler<BlobsCommon> {
62
63         /** The logger. */
64         private final Logger logger = LoggerFactory.getLogger(BlobDocumentModelHandler.class);
65
66     //==============================================================================
67
68         private String getDerivativePathBase(DocumentModel docModel) {
69                 return getServiceContextPath() + docModel.getName() + "/" +
70                         BlobInput.URI_DERIVATIVES_PATH + "/";
71         }
72
73         private BlobsCommon getCommonPartProperties(DocumentModel docModel) throws Exception {
74                 String label = getServiceContext().getCommonPartLabel();
75                 BlobsCommon result = new BlobsCommon();
76                 
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);
93                 
94                 return result;
95         }
96         
97         private void setCommonPartProperties(DocumentModel documentModel,
98                         BlobsCommon blobsCommon) throws ClientException {
99                 try {
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);
107                 }               
108         }
109         
110         private void extractMetadata(String nuxeoImageID, String metadataLabel) {               
111         Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
112         ObjectPartType partMeta = partsMetaMap.get(metadataLabel);
113
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);
122                     }
123                         } catch (Exception e) {
124                                 logger.warn("Metadata extraction failed: " + e.getMessage());
125                         }
126         } else {
127                 logger.warn("Metadata extraction failed: Could not find tenant binding for schema type = " + metadataLabel);
128         }
129         }
130
131         /* (non-Javadoc)
132          * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#extractAllParts(org.collectionspace.services.common.document.DocumentWrapper)
133          */
134         @Override
135         public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
136                         throws Exception {
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
143                 //
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).
145                 //
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?
153                 }               
154
155                 String derivativeTerm = blobInput.getDerivativeTerm();
156                 Boolean getContentFlag = blobInput.isContentRequested();
157                 //
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.
160                 //
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());
168                                 } else {
169                                         // If we can't find the blob's content, we'll return a "missing document" image
170                                         blobInput.setContentStream(NuxeoBlobUtils.getResource(NuxeoBlobUtils.DOCUMENT_MISSING_PLACEHOLDER_IMAGE));
171                                         mimeTypeBuffer.append(NuxeoBlobUtils.MIME_JPEG);
172                                 }
173                         }
174         
175                         if (derivativeTerm != null) {
176                                 // reset 'blobsCommon' if we have a derivative request
177                                 blobsCommon = blobOutput.getBlobsCommon();
178                                 blobsCommon.setUri(getDerivativePathBase(docModel) +
179                                                 derivativeTerm + "/" + BlobInput.URI_CONTENT_PATH);                             
180                         }
181                         
182                         String mimeType = mimeTypeBuffer.toString();
183                         if (mimeType != null && !mimeType.isEmpty()) { // MIME type for derivatives might be different from original
184                                 blobInput.setMimeType(mimeType);
185                                 blobsCommon.setMimeType(mimeType);
186                         } else {
187                                 blobInput.setMimeType(blobsCommon.getMimeType());  // Set the MIME type to the one in blobsCommon
188                         }
189                         
190                         blobsCommon.setRepositoryId(null); //hide the repository id from the GET results payload since it is private
191                         this.setCommonPartProperties(docModel, blobsCommon);
192                         // finish extracting the other parts by calling the parent
193                 } else {
194                         extractMetadata(blobRepositoryId, NuxeoBlobUtils.SCHEMA_IMAGE_METADATA);
195                         extractMetadata(blobRepositoryId, NuxeoBlobUtils.SCHEMA_IPTC);
196                 }
197                 
198                 //
199                 // Hide the Nuxeo repository ID of the Nuxeo blob since this is private
200                 //
201                 docModel.setProperty(ctx.getCommonPartLabel(), BlobJAXBSchema.repositoryId, null);      
202                 super.extractAllParts(wrapDoc);
203         }
204
205         @Override
206         public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
207                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
208                 BlobInput blobInput = BlobUtil.getBlobInput(ctx); // The blobInput should have been put into the context by the Blob or Media resource
209                 if (blobInput != null && blobInput.getBlobFile() != null) {             
210                         boolean purgeOriginal = false;
211                         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
212                         String purgeOriginalStr = queryParams.getFirst(BlobClient.BLOB_PURGE_ORIGINAL);
213                         if (purgeOriginalStr != null && purgeOriginalStr.isEmpty() == false) { // Find our if the caller wants us to purge/delete the original
214                                 purgeOriginal = true;
215                         }
216                         //
217                         // If blobInput has a file then we just received a multipart/form-data file post or a URI query parameter
218                         //
219                         DocumentModel documentModel = wrapDoc.getWrappedObject();
220                         CoreSessionInterface repoSession = this.getRepositorySession();
221                 
222                         BlobsCommon blobsCommon = NuxeoBlobUtils.createBlobInRepository(ctx, repoSession, blobInput, purgeOriginal, true);
223                         blobInput.setBlobCsid(documentModel.getName()); //Assumption here is that the documentModel "name" field is storing a CSID
224
225                 PoxPayloadIn input = ctx.getInput();
226                 //
227                 // If the input payload is null, then we're creating a new blob from a post or a uri.  This means there
228                 // is no "input" payload for our framework to process.  Therefore we need to synthesize a payload from
229                 // the BlobsCommon instance we just filled out.
230                 //
231                 if (input == null) {
232                         PoxPayloadOut output = new PoxPayloadOut(BlobClient.SERVICE_PAYLOAD_NAME);
233                         PayloadOutputPart commonPart = new PayloadOutputPart(BlobClient.SERVICE_COMMON_PART_NAME, blobsCommon);
234                         output.addPart(commonPart);
235                         input = new PoxPayloadIn(output.toXML());
236                         ctx.setInput(input);
237                 } else {
238                         // 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
239                         // that to populate the resource record.  However, since the "input" var is not null the requester provided their own resource record data
240                         // so we'll use it rather than deriving one from the blob.
241                         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." +
242                                         " The data in blob resource record fields may not correspond completely with the persisted blob binary file.");
243                 }               
244                 }
245
246                 super.fillAllParts(wrapDoc, action);
247         }
248
249         @Override
250         public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
251                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
252                 BlobInput blobInput = BlobUtil.getBlobInput(ctx); // The blobInput should have been put into the context by the Blob or Media resource
253                 if (blobInput != null && blobInput.getBlobFile() != null) {             
254                         boolean purgeOriginal = false;
255                         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
256                         String purgeOriginalStr = queryParams.getFirst(BlobClient.BLOB_PURGE_ORIGINAL);
257                         if (purgeOriginalStr != null && purgeOriginalStr.isEmpty() == false) { // Find our if the caller wants us to purge/delete the original
258                                 purgeOriginal = true;
259                         }
260                         //
261                         // If blobInput has a file then we just received a multipart/form-data file post or a URI query parameter
262                         //
263                         DocumentModel documentModel = wrapDoc.getWrappedObject();
264                         CoreSessionInterface repoSession = this.getRepositorySession();
265                 
266                         BlobsCommon blobsCommon = NuxeoBlobUtils.createBlobInRepository(ctx, repoSession, blobInput, purgeOriginal, true);
267                         blobInput.setBlobCsid(documentModel.getName()); //Assumption here is that the documentModel "name" field is storing a CSID
268         
269                 PoxPayloadIn input = ctx.getInput();
270                 //
271                 // If the input payload is null, then we're creating a new blob from a post or a uri.  This means there
272                 // is no "input" payload for our framework to process.  Therefore we need to synthesize a payload from
273                 // the BlobsCommon instance we just filled out.
274                 //
275                 if (input == null) {
276                         PoxPayloadOut output = new PoxPayloadOut(BlobClient.SERVICE_PAYLOAD_NAME);
277                         PayloadOutputPart commonPart = new PayloadOutputPart(BlobClient.SERVICE_COMMON_PART_NAME, blobsCommon);
278                         output.addPart(commonPart);
279                         input = new PoxPayloadIn(output.toXML());
280                         ctx.setInput(input);
281                 } else {
282                         // 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
283                         // that to populate the resource record.  However, since the "input" var is not null the requester provided their own resource record data
284                         // so we'll use it rather than deriving one from the blob.
285                         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." +
286                                         " The data in blob resource record fields may not correspond completely with the persisted blob binary file.");
287                 }               
288                 }
289         
290                 super.fillAllParts(wrapDoc, action);
291         }    
292 }
293