]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
656ccc5a044c81cf2cf21b79fb9f447b6dbf02d9
[tmp/jakarta-migration.git] /
1 /**     \r
2  * NuxeoImageUtils.java\r
3  *\r
4  * {Purpose of This Class}\r
5  *\r
6  * {Other Notes Relating to This Class (Optional)}\r
7  *\r
8  * $LastChangedBy: $\r
9  * $LastChangedRevision: $\r
10  * $LastChangedDate: $\r
11  *\r
12  * This document is a part of the source code and related artifacts\r
13  * for CollectionSpace, an open source collections management system\r
14  * for museums and related institutions:\r
15  *\r
16  * http://www.collectionspace.org\r
17  * http://wiki.collectionspace.org\r
18  *\r
19  * Copyright © 2009 {Contributing Institution}.\r
20  *\r
21  * Licensed under the Educational Community License (ECL), Version 2.0.\r
22  * You may not use this file except in compliance with this License.\r
23  *\r
24  * You may obtain a copy of the ECL 2.0 License at\r
25  * https://source.collectionspace.org/collection-space/LICENSE.txt\r
26  */\r
27 package org.collectionspace.services.common.imaging.nuxeo;\r
28 \r
29 import java.io.File;\r
30 import java.io.ByteArrayOutputStream;\r
31 import java.io.InputStream;\r
32 import java.io.BufferedInputStream;\r
33 import java.io.IOException;\r
34 import java.math.BigDecimal;\r
35 import java.math.BigInteger;\r
36 import java.util.HashMap;\r
37 import java.util.List;\r
38 import java.util.Map;\r
39 \r
40 import org.nuxeo.runtime.api.Framework;\r
41 //import org.nuxeo.runtime.api.ServiceManager;\r
42 //import org.nuxeo.runtime.api.ServiceDescriptor;\r
43 \r
44 //import org.nuxeo.common.utils.FileUtils;\r
45 \r
46 import org.nuxeo.ecm.platform.picture.api.ImageInfo;\r
47 import org.nuxeo.ecm.platform.picture.api.ImagingService;\r
48 import org.nuxeo.ecm.platform.picture.api.PictureView;\r
49 \r
50 import org.nuxeo.ecm.platform.mimetype.MimetypeDetectionException;\r
51 import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;\r
52 import org.nuxeo.ecm.platform.picture.api.adapters.PictureBlobHolder;\r
53 import org.nuxeo.ecm.platform.filemanager.api.FileManager;\r
54 import org.nuxeo.ecm.platform.types.TypeManager;\r
55 \r
56 import org.nuxeo.ecm.core.repository.RepositoryDescriptor;\r
57 import org.nuxeo.ecm.core.repository.RepositoryManager;\r
58 \r
59 import org.nuxeo.ecm.core.repository.RepositoryService;\r
60 //import org.nuxeo.runtime.model.ComponentManager;\r
61 //import org.nuxeo.runtime.model.impl.ComponentManagerImpl;\r
62 //import org.nuxeo.ecm.core.api.ejb.DocumentManagerBean;\r
63 //import org.nuxeo.ecm.core.storage.sql.RepositoryImpl;\r
64 //import org.nuxeo.ecm.core.storage.sql.Repository;\r
65 import org.nuxeo.ecm.core.storage.sql.DefaultBinaryManager;\r
66 import org.nuxeo.ecm.core.storage.sql.coremodel.SQLRepository;\r
67 //import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor;\r
68 \r
69 //import org.nuxeo.ecm.core.api.DocumentResolver;\r
70 import org.nuxeo.ecm.core.api.IdRef;\r
71 import org.nuxeo.ecm.core.api.blobholder.BlobHolder;\r
72 import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder;\r
73 import org.nuxeo.ecm.core.api.impl.blob.FileBlob;\r
74 import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob;\r
75 import org.nuxeo.ecm.core.api.impl.blob.ByteArrayBlob;\r
76 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;\r
77 import org.nuxeo.ecm.core.api.repository.Repository;\r
78 import org.nuxeo.ecm.core.api.Blob;\r
79 import org.nuxeo.ecm.core.api.ClientException;\r
80 import org.nuxeo.ecm.core.api.DocumentModel;\r
81 import org.nuxeo.ecm.core.api.DocumentRef;\r
82 \r
83 import org.nuxeo.ecm.core.schema.SchemaManager;\r
84 import org.nuxeo.ecm.core.schema.types.Schema;\r
85 \r
86 import org.slf4j.Logger;\r
87 import org.slf4j.LoggerFactory;\r
88 //import org.nuxeo.ecm.core.repository.jcr.testing.RepositoryOSGITestCase;\r
89 \r
90 import org.collectionspace.services.common.blob.BlobInput;\r
91 import org.collectionspace.services.common.context.ServiceContext;\r
92 import org.collectionspace.services.common.datetime.GregorianCalendarDateTimeUtils;\r
93 import org.collectionspace.services.common.service.ListResultField;\r
94 import org.collectionspace.services.blob.BlobsCommon;\r
95 import org.collectionspace.services.blob.DimensionSubGroup;\r
96 import org.collectionspace.services.blob.DimensionSubGroupList;\r
97 import org.collectionspace.services.blob.MeasuredPartGroup;\r
98 import org.collectionspace.services.blob.MeasuredPartGroupList;\r
99 //import org.collectionspace.services.blob.BlobsCommonList;\r
100 //import org.collectionspace.services.blob.BlobsCommonList.BlobListItem;\r
101 import org.collectionspace.services.jaxb.BlobJAXBSchema;\r
102 import org.collectionspace.services.nuxeo.client.java.CommonList;\r
103 import org.collectionspace.services.common.blob.BlobOutput;\r
104 \r
105 //import org.collectionspace.ecm.platform.quote.api.QuoteManager;\r
106 \r
107 // TODO: Auto-generated Javadoc\r
108 /**\r
109  * The Class NuxeoImageUtils.\r
110  */\r
111 public class NuxeoImageUtils {\r
112         /** The Constant logger. */\r
113         private static final Logger logger = LoggerFactory\r
114                         .getLogger(NuxeoImageUtils.class);\r
115 \r
116         /*\r
117          * FIXME: REM - These constants should be coming from configuration and NOT\r
118          * hard coded.\r
119          */\r
120         public static final String DERIVATIVE_ORIGINAL = "Original";\r
121         public static final String DERIVATIVE_ORIGINAL_TAG = DERIVATIVE_ORIGINAL\r
122                         + "_";\r
123 \r
124         public static final String DERIVATIVE_ORIGINAL_JPEG = "OriginalJpeg";\r
125         public static final String DERIVATIVE_ORIGINAL_JPEG_TAG = DERIVATIVE_ORIGINAL_JPEG\r
126                         + "_";\r
127 \r
128         public static final String DERIVATIVE_MEDIUM = "Medium";\r
129         public static final String DERIVATIVE_MEDIUM_TAG = DERIVATIVE_MEDIUM + "_";\r
130 \r
131         public static final String DERIVATIVE_THUMBNAIL = "Thumbnail";\r
132         public static final String DERIVATIVE_THUMBNAIL_TAG = DERIVATIVE_THUMBNAIL\r
133                         + "_";\r
134 \r
135         public static final String DERIVATIVE_UNKNOWN = "_UNKNOWN_DERIVATIVE_NAME_";\r
136 \r
137         //\r
138         // Image Dimension fields\r
139         //\r
140         public static final String PART_IMAGE = "digitalImage";\r
141         public static final String PART_SUMMARY = "The dimensions of a digital image -width, height, and pixel depth.";\r
142         public static final String WIDTH = "width";\r
143         public static final String HEIGHT = "height";\r
144         public static final String DEPTH = "depth";\r
145         public static final String UNIT_PIXELS = "pixels";\r
146         public static final String UNIT_BITS = "bits";\r
147         //\r
148         // Image Metadata schemas - These are Nuxeo defined schemas\r
149         //\r
150         public static final String SCHEMA_IPTC = "iptc";\r
151         public static final String SCHEMA_IMAGE_METADATA = "image_metadata";\r
152 \r
153         // static DefaultBinaryManager binaryManager = new DefaultBinaryManager();\r
154         // //can we get this from Nuxeo? i.e.,\r
155         // Framework.getService(BinaryManger.class)\r
156 \r
157         // /** The temp file name. */\r
158         // static String tempFileName = "sunset.jpg";\r
159         //\r
160         // /** The file separator. */\r
161         // static String fileSeparator = System.getProperty("file.separator");\r
162         //\r
163         // /** The cur dir. */\r
164         // static String curDir = System.getProperty("user.dir");\r
165 \r
166         /**\r
167          * Instantiates a new nuxeo image utils.\r
168          */\r
169         NuxeoImageUtils() {\r
170                 // empty constructor\r
171         }\r
172 \r
173         private static String toStringPictureView(PictureView pictureView) {\r
174                 StringBuffer strBuffer = new StringBuffer();\r
175                 strBuffer.append("Description: " + pictureView.getDescription() + '\n');\r
176                 strBuffer.append("FileName: " + pictureView.getFilename() + '\n');\r
177                 strBuffer.append("Height: " + pictureView.getHeight() + '\n');\r
178                 strBuffer.append("Width: " + pictureView.getWidth() + '\n');\r
179                 strBuffer.append("Tag: " + pictureView.getTag() + '\n');\r
180                 strBuffer.append("Title: " + pictureView.getTitle() + '\n');\r
181                 return strBuffer.toString();\r
182         }\r
183 \r
184         // FIXME: REM - This needs to be configuration-bases and NOT hard coded!\r
185         // FIXME: REM - Use MultiviewPicture adapter to get some of this information\r
186         static private String getDerivativeUri(String uri, String derivativeName) {\r
187                 String result = DERIVATIVE_UNKNOWN;\r
188 \r
189                 if (derivativeName.startsWith(DERIVATIVE_ORIGINAL_TAG) == true) {\r
190                         result = DERIVATIVE_ORIGINAL;\r
191                 } else if (derivativeName.startsWith(DERIVATIVE_ORIGINAL_JPEG_TAG) == true) {\r
192                         result = DERIVATIVE_ORIGINAL_JPEG;\r
193                 } else if (derivativeName.startsWith(DERIVATIVE_MEDIUM_TAG) == true) {\r
194                         result = DERIVATIVE_MEDIUM;\r
195                 } else if (derivativeName.startsWith(DERIVATIVE_THUMBNAIL_TAG) == true) {\r
196                         result = DERIVATIVE_THUMBNAIL;\r
197                 }\r
198 \r
199                 return uri + result + "/" + BlobInput.URI_CONTENT_PATH;\r
200         }\r
201 \r
202         static private HashMap<String, String> createBlobListItem(Blob blob,\r
203                         String uri) {\r
204                 HashMap<String, String> item = new HashMap<String, String>();\r
205 \r
206                 String value = blob.getEncoding();\r
207                 if (value != null && !value.trim().isEmpty()) {\r
208                         item.put(BlobJAXBSchema.encoding, value);\r
209                 }\r
210                 value = Long.toString(blob.getLength());\r
211                 if (value != null && !value.trim().isEmpty()) {\r
212                         item.put(BlobJAXBSchema.length, value);\r
213                 }\r
214                 value = blob.getMimeType();\r
215                 if (value != null && !value.trim().isEmpty()) {\r
216                         item.put(BlobJAXBSchema.mimeType, value);\r
217                 }\r
218                 value = blob.getFilename();\r
219                 if (value != null && !value.trim().isEmpty()) {\r
220                         item.put(BlobJAXBSchema.name, value);\r
221                 }\r
222                 value = getDerivativeUri(uri, blob.getFilename());\r
223                 if (value != null && !value.trim().isEmpty()) {\r
224                         item.put(BlobJAXBSchema.uri, value);\r
225                 }\r
226 \r
227                 return item;\r
228         }\r
229 \r
230         static public CommonList getBlobDerivatives(RepositoryInstance repoSession,\r
231                         String repositoryId, List<ListResultField> resultsFields, String uri)\r
232                         throws Exception {\r
233                 CommonList commonList = new CommonList();\r
234                 int nFields = resultsFields.size() + 2;\r
235                 String fields[] = new String[nFields];// FIXME: REM - Patrick needs to fix this hack.  It is a "common list" issue\r
236                 fields[0] = "csid";\r
237                 fields[1] = "uri";\r
238                 for (int i = 2; i < nFields; i++) {\r
239                         ListResultField field = resultsFields.get(i - 2);\r
240                         fields[i] = field.getElement();\r
241                 }\r
242                 commonList.setFieldsReturned(fields);\r
243 \r
244                 IdRef documentRef = new IdRef(repositoryId);\r
245                 DocumentModel documentModel = repoSession.getDocument(documentRef);\r
246                 DocumentBlobHolder docBlobHolder = (DocumentBlobHolder) documentModel\r
247                                 .getAdapter(BlobHolder.class);\r
248                 List<Blob> docBlobs = docBlobHolder.getBlobs();\r
249                 // List<BlobListItem> blobListItems = result.getBlobListItem();\r
250                 HashMap<String, String> item = null;\r
251                 for (Blob blob : docBlobs) {\r
252                         item = createBlobListItem(blob, uri);\r
253                         commonList.addItem(item);\r
254                 }\r
255 \r
256                 return commonList;\r
257         }\r
258 \r
259         /*\r
260          * [dublincore, uid, picture, iptc, common, image_metadata]\r
261          */\r
262         static private Map<String, Object> getMetadata(Blob nuxeoBlob)\r
263                         throws Exception {\r
264                 ImagingService service = Framework.getService(ImagingService.class);\r
265                 Map<String, Object> metadataMap = service.getImageMetadata(nuxeoBlob);\r
266                 return metadataMap;\r
267         }\r
268 \r
269         static private MeasuredPartGroupList getDimensions(\r
270                         DocumentModel documentModel, Blob nuxeoBlob) {\r
271                 MeasuredPartGroupList result = null;\r
272                 try {\r
273                         ImagingService service = Framework.getService(ImagingService.class);\r
274                         ImageInfo imageInfo = service.getImageInfo(nuxeoBlob);\r
275                         Map<String, Object> metadataMap = getMetadata(nuxeoBlob);\r
276 \r
277                         if (imageInfo != null) {\r
278                                 //\r
279                                 // Create a timestamp to add to all the image's dimensions\r
280                                 //\r
281                                 String valueDate = GregorianCalendarDateTimeUtils\r
282                                                 .timestampUTC();\r
283                                 \r
284                                 result = new MeasuredPartGroupList();\r
285                                 List<MeasuredPartGroup> measuredPartGroupList = \r
286                                                 (result).getMeasuredPartGroup();\r
287                                 //\r
288                                 // Create a new measured part for the "image"\r
289                                 //\r
290                                 MeasuredPartGroup mpGroup = new MeasuredPartGroup();\r
291                                 mpGroup.setMeasuredPart(PART_IMAGE);\r
292                                 mpGroup.setDimensionSummary(PART_SUMMARY);\r
293                                 mpGroup.setDimensionSubGroupList(new DimensionSubGroupList());\r
294                                 List<DimensionSubGroup> dimensionSubGroupList = mpGroup.getDimensionSubGroupList()\r
295                                                 .getDimensionSubGroup();\r
296 \r
297                                 //\r
298                                 // Set the width\r
299                                 //\r
300                                 DimensionSubGroup widthDimension = new DimensionSubGroup();\r
301                                 widthDimension.setDimension(WIDTH);\r
302                                 widthDimension.setMeasurementUnit(UNIT_PIXELS);\r
303                                 widthDimension.setValue(intToBigDecimal(imageInfo.getWidth()));\r
304                                 widthDimension.setValueDate(valueDate);\r
305                                 dimensionSubGroupList.add(widthDimension);\r
306                                 //\r
307                                 // Set the height\r
308                                 //\r
309                                 DimensionSubGroup heightDimension = new DimensionSubGroup();\r
310                                 heightDimension.setDimension(HEIGHT);\r
311                                 heightDimension.setMeasurementUnit(UNIT_PIXELS);\r
312                                 heightDimension\r
313                                                 .setValue(intToBigDecimal(imageInfo.getHeight()));\r
314                                 heightDimension.setValueDate(valueDate);\r
315                                 dimensionSubGroupList.add(heightDimension);\r
316                                 //\r
317                                 // Set the depth\r
318                                 //\r
319                                 DimensionSubGroup depthDimension = new DimensionSubGroup();\r
320                                 depthDimension.setDimension(DEPTH);\r
321                                 depthDimension.setMeasurementUnit(UNIT_BITS);\r
322                                 depthDimension.setValue(intToBigDecimal(imageInfo.getDepth()));\r
323                                 depthDimension.setValueDate(valueDate);\r
324                                 dimensionSubGroupList.add(depthDimension);\r
325                                 //\r
326                                 // Now set out result\r
327                                 //\r
328                                 measuredPartGroupList.add(mpGroup);\r
329                         } else {\r
330                                 if (logger.isWarnEnabled() == true) {\r
331                                         logger.warn("Could not synthesize a dimension list of the blob: "\r
332                                                         + documentModel.getName());\r
333                                 }\r
334                         }\r
335                 } catch (Exception e) {\r
336                         logger.warn("Could not extract image information for blob: "\r
337                                         + documentModel.getName(), e);\r
338                 }\r
339 \r
340                 return result;\r
341         }\r
342 \r
343         // FIXME: Add error checking here, as none of these calls return an\r
344         // Exception\r
345         static private BigDecimal intToBigDecimal(int i) {\r
346                 BigInteger bigint = BigInteger.valueOf(i);\r
347                 BigDecimal bigdec = new BigDecimal(bigint);\r
348                 return bigdec;\r
349         }\r
350 \r
351         static private BlobsCommon createBlobsCommon(DocumentModel documentModel,\r
352                         Blob nuxeoBlob) {\r
353                 BlobsCommon result = new BlobsCommon();\r
354 \r
355                 if (documentModel != null) {\r
356                         result.setMimeType(nuxeoBlob.getMimeType());\r
357                         result.setName(nuxeoBlob.getFilename());\r
358                         result.setLength(Long.toString(nuxeoBlob.getLength()));\r
359                         result.setRepositoryId(documentModel.getId());\r
360                         MeasuredPartGroupList measuredPartGroupList = getDimensions(\r
361                                         documentModel, nuxeoBlob);\r
362                         if (measuredPartGroupList != null) {\r
363                                 result.setMeasuredPartGroupList(measuredPartGroupList);\r
364                         }\r
365                 }\r
366 \r
367                 return result;\r
368         }\r
369 \r
370         /*\r
371          * This is a prototype method that is not currently used as of 1/1/2012.  However,\r
372          * it may be useful now that we've transitioned to using an embedded Nuxeo server.\r
373          */\r
374         static private File getBlobFile(RepositoryInstance ri,\r
375                         DocumentModel documentModel, Blob blob) {\r
376                 DefaultBinaryManager binaryManager = null;\r
377                 RepositoryDescriptor descriptor = null;\r
378 \r
379                 try {\r
380                         RepositoryService repositoryService1 = (RepositoryService) Framework\r
381                                         .getRuntime().getComponent(RepositoryService.NAME);\r
382 \r
383                         String repositoryName = documentModel.getRepositoryName();\r
384                         RepositoryManager repositoryManager = repositoryService1\r
385                                         .getRepositoryManager();\r
386                         descriptor = repositoryManager.getDescriptor(repositoryName);\r
387 \r
388 //                      binaryManager = new DefaultBinaryManager();\r
389 //\r
390 //                      File storageDir = binaryManager.getStorageDir();\r
391 //                      // SQLBlob blob = (SQLBlob)\r
392 //                      // doc.getPropertyValue("schema:blobField");\r
393 //                      File file = binaryManager.getFileForDigest(blob.getDigest(), false);\r
394 \r
395                 } catch (Exception e) {\r
396                         e.printStackTrace();\r
397                 }\r
398 \r
399                 try {\r
400                         binaryManager.initialize(SQLRepository.getDescriptor(descriptor));\r
401                 } catch (IOException e) {\r
402                         // TODO Auto-generated catch block\r
403                         e.printStackTrace();\r
404                 } catch (Exception e) {\r
405                         // TODO Auto-generated catch block\r
406                         e.printStackTrace();\r
407                 }\r
408 \r
409                 File storageDir = binaryManager.getStorageDir();\r
410                 // SQLBlob blob = (SQLBlob)\r
411                 // documentModel.getPropertyValue("schema:blobField");\r
412                 File file = binaryManager.getFileForDigest(blob.getDigest(), false);\r
413 \r
414                 return file;\r
415         }\r
416 \r
417         /**\r
418          * Returns a schema, given the name of a schema.\r
419          * \r
420          * @param schemaName\r
421          *            a schema name.\r
422          * @return a schema.\r
423          */\r
424         private static Schema getSchemaFromName(String schemaName) {\r
425                 SchemaManager schemaManager = null;\r
426                 try {\r
427                         schemaManager = Framework.getService(SchemaManager.class);\r
428                 } catch (Exception e) {\r
429                         // TODO Auto-generated catch block\r
430                         e.printStackTrace();\r
431                 }\r
432                 return schemaManager != null ? schemaManager.getSchema(schemaName)\r
433                                 : null;\r
434         }\r
435 \r
436         /**\r
437          * Gets the blob.\r
438          * \r
439          * @param nuxeoSession\r
440          *            the nuxeo session\r
441          * @param id\r
442          *            the id\r
443          * @return the blob\r
444          */\r
445         static private Blob getBlob(RepositoryInstance nuxeoSession, String id) {\r
446                 Blob result = null;\r
447 \r
448                 try {\r
449                         Repository repository = nuxeoSession.getRepository();\r
450                         // binaryManager.initialize(new RepositoryDescriptor());\r
451                         // binaryManager.getBinary("a4cac052ae0281979f2dcf5ab2e61a6c");\r
452                         // DocumentResolver.resolveReference(nuxeoSession, documentRef);\r
453                         // binaryManager = repository.getBinaryManager();\r
454                         // documentModel.getr\r
455                 } catch (Exception x) {\r
456                         x.printStackTrace();\r
457                 }\r
458 \r
459                 return result;\r
460         }\r
461 \r
462         /**\r
463          * Gets the type service.\r
464          * \r
465          * @return the type service\r
466          * @throws ClientException\r
467          *             the client exception\r
468          */\r
469         private static TypeManager getTypeService() throws ClientException {\r
470                 TypeManager typeService = null;\r
471                 try {\r
472                         typeService = Framework.getService(TypeManager.class);\r
473                 } catch (Exception e) {\r
474                         throw new ClientException(e);\r
475                 }\r
476                 return typeService;\r
477         }\r
478 \r
479         /**\r
480          * Gets the bytes.\r
481          * \r
482          * @param fis\r
483          *            the fis\r
484          * @return the bytes\r
485          */\r
486         private static byte[] getBytes(InputStream fis) {\r
487                 ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
488                 byte[] buf = new byte[128 * 1024];\r
489                 try {\r
490                         for (int readNum; (readNum = fis.read(buf)) != -1;) {\r
491                                 bos.write(buf, 0, readNum);\r
492                                 // no doubt here is 0\r
493                                 /*\r
494                                  * Writes len bytes from the specified byte array starting at\r
495                                  * offset off to this byte array output stream.\r
496                                  */\r
497                                 System.out.println("read " + readNum + " bytes,");\r
498                         }\r
499                 } catch (IOException ex) {\r
500                         logger.error(ex.getMessage(), ex);\r
501                 }\r
502                 byte[] bytes = bos.toByteArray();\r
503                 // bytes is the ByteArray we need\r
504                 return bytes;\r
505         }\r
506 \r
507         /**\r
508          * Creates the serializable blob.\r
509          * \r
510          * @param fileInputStream\r
511          *            the file input stream\r
512          * @param filename\r
513          *            the filename\r
514          * @param mimeType\r
515          *            the mime type\r
516          * @return the blob\r
517          */\r
518         private static Blob createSerializableBlob(InputStream fileInputStream,\r
519                         String filename, String mimeType) {\r
520                 Blob blob = null;\r
521                 try {\r
522                         // persisting the blob makes it possible to read the binary content\r
523                         // of the request stream several times (mimetype sniffing, digest\r
524                         // computation, core binary storage)\r
525                         byte[] bytes = getBytes(fileInputStream);\r
526                         blob = new ByteArrayBlob(bytes);\r
527                         // filename\r
528                         if (filename != null) {\r
529                                 filename = getCleanFileName(filename);\r
530                         }\r
531                         blob.setFilename(filename);\r
532                         // mimetype detection\r
533                         MimetypeRegistry mimeService = Framework\r
534                                         .getService(MimetypeRegistry.class);\r
535                         String detectedMimeType = mimeService\r
536                                         .getMimetypeFromFilenameAndBlobWithDefault(filename, blob,\r
537                                                         null);\r
538                         if (detectedMimeType == null) {\r
539                                 if (mimeType != null) {\r
540                                         detectedMimeType = mimeType;\r
541                                 } else {\r
542                                         // default\r
543                                         detectedMimeType = "application/octet-stream";\r
544                                 }\r
545                         }\r
546                         blob.setMimeType(detectedMimeType);\r
547                 } catch (MimetypeDetectionException e) {\r
548                         logger.error(String.format("could not fetch mimetype for file %s",\r
549                                         filename), e);\r
550                 } catch (Exception e) {\r
551                         logger.error("", e);\r
552                 }\r
553                 return blob;\r
554         }\r
555 \r
556         /**\r
557          * Creates a serializable blob from a stream, with filename and mimetype\r
558          * detection.\r
559          * \r
560          * <p>\r
561          * Creates an in-memory blob if data is under 64K, otherwise constructs a\r
562          * serializable FileBlob which stores data in a temporary file on the hard\r
563          * disk.\r
564          * </p>\r
565          * \r
566          * @param file\r
567          *            the input stream holding data\r
568          * @param filename\r
569          *            the file name. Will be set on the blob and will used for\r
570          *            mimetype detection.\r
571          * @param mimeType\r
572          *            the detected mimetype at upload. Can be null. Will be verified\r
573          *            by the mimetype service.\r
574          * @return the blob\r
575          */\r
576         private static Blob createStreamingBlob(File file, String filename,\r
577                         String mimeType) {\r
578                 Blob blob = null;\r
579                 try {\r
580                         // persisting the blob makes it possible to read the binary content\r
581                         // of the request stream several times (mimetype sniffing, digest\r
582                         // computation, core binary storage)\r
583                         blob = StreamingBlob.createFromFile(file, mimeType).persist();\r
584                         // filename\r
585                         if (filename != null) {\r
586                                 filename = getCleanFileName(filename);\r
587                         }\r
588                         blob.setFilename(filename);\r
589                         // mimetype detection\r
590                         MimetypeRegistry mimeService = Framework\r
591                                         .getService(MimetypeRegistry.class);\r
592                         String detectedMimeType = mimeService\r
593                                         .getMimetypeFromFilenameAndBlobWithDefault(filename, blob,\r
594                                                         null);\r
595                         if (detectedMimeType == null) {\r
596                                 if (mimeType != null) {\r
597                                         detectedMimeType = mimeType;\r
598                                 } else {\r
599                                         // default\r
600                                         detectedMimeType = "application/octet-stream";\r
601                                 }\r
602                         }\r
603                         blob.setMimeType(detectedMimeType);\r
604                 } catch (MimetypeDetectionException e) {\r
605                         logger.error(String.format("could not fetch mimetype for file %s",\r
606                                         filename), e);\r
607                 } catch (IOException e) {\r
608                         logger.error("", e);\r
609                 } catch (Exception e) {\r
610                         logger.error("", e);\r
611                 }\r
612                 return blob;\r
613         }\r
614 \r
615         private static Blob createFileBlob(File file) {\r
616                 Blob result = null;\r
617 \r
618                 result = new FileBlob(file);\r
619                 return result;\r
620         }\r
621 \r
622         /**\r
623          * Returns a clean filename, stripping upload path on client side.\r
624          * <p>\r
625          * Fixes NXP-544\r
626          * </p>\r
627          * \r
628          * @param filename\r
629          *            the filename\r
630          * @return the clean file name\r
631          */\r
632         private static String getCleanFileName(String filename) {\r
633                 String res = null;\r
634                 int lastWinSeparator = filename.lastIndexOf('\\');\r
635                 int lastUnixSeparator = filename.lastIndexOf('/');\r
636                 int lastSeparator = Math.max(lastWinSeparator, lastUnixSeparator);\r
637                 if (lastSeparator != -1) {\r
638                         res = filename.substring(lastSeparator + 1, filename.length());\r
639                 } else {\r
640                         res = filename;\r
641                 }\r
642                 return res;\r
643         }\r
644 \r
645         /**\r
646          * Gets Nuxeo's file manager service.\r
647          * \r
648          * @return the file manager service\r
649          * @throws ClientException\r
650          *             the client exception\r
651          */\r
652         private static FileManager getFileManagerService() throws ClientException {\r
653                 FileManager result = null;\r
654                 try {\r
655                         result = Framework.getService(FileManager.class);\r
656                 } catch (Exception e) {\r
657                         String msg = "Unable to get Nuxeo's FileManager service.";\r
658                         logger.error(msg, e);\r
659                         throw new ClientException("msg", e);\r
660                 }\r
661                 return result;\r
662         }\r
663 \r
664         /**\r
665          * Creates the picture.\r
666          * \r
667          * @param ctx\r
668          *            the ctx\r
669          * @param repoSession\r
670          *            the repo session\r
671          * @param filePath\r
672          *            the file path\r
673          * @return the string\r
674          */\r
675         public static BlobsCommon createPicture(ServiceContext ctx,\r
676                         RepositoryInstance repoSession, BlobInput blobInput) {\r
677                 BlobsCommon result = null;\r
678 \r
679                 try {\r
680                         File blobFile = blobInput.getBlobFile();\r
681                         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();\r
682                         DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);\r
683                         DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);\r
684 \r
685                         // FileInputStream inputStream = new FileInputStream(blobFile);\r
686                         // //FIXME: REM - With an embedded Nuxeo server, we may no longer\r
687                         // need to pass in a stream but instead just pass them the File\r
688                         // instance\r
689                         // if (inputStream != null) {\r
690                         result = createImage(repoSession, wspaceDoc,\r
691                         /* inputStream, */blobFile, null);\r
692                         // }\r
693                 } catch (Exception e) {\r
694                         logger.error("Could not create image blob", e); //FIXME: REM - We should probably be re-throwing the exception?\r
695                 }\r
696 \r
697                 return result;\r
698         }\r
699 \r
700         /**\r
701          * Creates the image blob.\r
702          * \r
703          * @param nuxeoSession\r
704          *            the nuxeo session\r
705          * @param blobLocation\r
706          *            the blob location\r
707          * @param file\r
708          *            the file\r
709          * @param fileName\r
710          *            the file name\r
711          * @param mimeType\r
712          *            the mime type\r
713          * @return the string\r
714          */\r
715         static public BlobsCommon createImage(RepositoryInstance nuxeoSession,\r
716                         DocumentModel blobLocation,\r
717                         // InputStream file,\r
718                         File file, String mimeType) {\r
719                 BlobsCommon result = null;\r
720 \r
721                 try {\r
722                         // Blob fileBlob = createStreamingBlob(blobFile, blobFile.getName(),\r
723                         // mimeType);\r
724                         Blob fileBlob = createFileBlob(file);\r
725                         String digestAlgorithm = getFileManagerService()\r
726                                         .getDigestAlgorithm(); // Need some way on initializing the\r
727                                                                                         // FileManager with a call.\r
728                         \r
729                         logger.debug("Start --> Calling Nuxeo to create an image blob.");\r
730                         DocumentModel documentModel = getFileManagerService()\r
731                                         .createDocumentFromBlob(nuxeoSession, fileBlob,\r
732                                                         blobLocation.getPathAsString(), true,\r
733                                                         file.getName());\r
734                         logger.debug("Stop --> Calling Nuxeo to create an image blob.");\r
735                         \r
736                         result = createBlobsCommon(documentModel, fileBlob);\r
737                 } catch (Exception e) {\r
738                         result = null;\r
739                         logger.error("Could not create new image blob", e); //FIXME: REM - This should probably be re-throwing the exception?\r
740                 }\r
741 \r
742                 return result;\r
743         }\r
744 \r
745         // /*\r
746         // * This is an alternate approach to getting information about an image\r
747         // * and its corresponding derivatives.\r
748         // */\r
749         // // MultiviewPictureAdapter multiviewPictureAdapter =\r
750         // documentModel.getAdapter(MultiviewPictureAdapter.class);\r
751         // MultiviewPictureAdapterFactory multiviewPictureAdapterFactory = new\r
752         // MultiviewPictureAdapterFactory();\r
753         // MultiviewPictureAdapter multiviewPictureAdapter =\r
754         // (MultiviewPictureAdapter)multiviewPictureAdapterFactory.getAdapter(documentModel,\r
755         // null);\r
756         // if (multiviewPictureAdapter != null) {\r
757         // PictureView[] pictureViewArray = multiviewPictureAdapter.getViews();\r
758         // for (PictureView pictureView : pictureViewArray) {\r
759         // if (logger.isDebugEnabled() == true) {\r
760         // logger.debug("-------------------------------------");\r
761         // logger.debug(toStringPictureView(pictureView));\r
762         // }\r
763         // }\r
764         // }\r
765 \r
766         /**\r
767          * Gets the image.\r
768          * \r
769          * @param repoSession\r
770          *            the repo session\r
771          * @param repositoryId\r
772          *            the repository id\r
773          * @param derivativeTerm\r
774          *            the derivative term\r
775          * @return the image\r
776          */\r
777         static public BlobOutput getBlobOutput(ServiceContext ctx,\r
778                         RepositoryInstance repoSession, String repositoryId,\r
779                         String derivativeTerm, Boolean getContentFlag) {\r
780                 BlobOutput result = new BlobOutput();\r
781 \r
782                 if (repositoryId != null && repositoryId.isEmpty() == false)\r
783                         try {\r
784                                 IdRef documentRef = new IdRef(repositoryId);\r
785                                 DocumentModel documentModel = repoSession\r
786                                                 .getDocument(documentRef);\r
787 \r
788                                 Blob docBlob = null;\r
789                                 DocumentBlobHolder docBlobHolder = (DocumentBlobHolder) documentModel\r
790                                                 .getAdapter(BlobHolder.class);\r
791                                 if (docBlobHolder instanceof PictureBlobHolder) { // if it is a\r
792                                                                                                                                         // PictureDocument\r
793                                                                                                                                         // then it\r
794                                                                                                                                         // has these\r
795                                                                                                                                         // Nuxeo\r
796                                                                                                                                         // schemas:\r
797                                                                                                                                         // [dublincore,\r
798                                                                                                                                         // uid,\r
799                                                                                                                                         // picture,\r
800                                                                                                                                         // iptc,\r
801                                                                                                                                         // common,\r
802                                                                                                                                         // image_metadata]\r
803                                         //\r
804                                         // Need to add the "MultiviewPictureAdapter" support here to\r
805                                         // get the view data, see above.\r
806                                         //\r
807                                         PictureBlobHolder pictureBlobHolder = (PictureBlobHolder) docBlobHolder;\r
808                                         if (derivativeTerm != null) {\r
809                                                 docBlob = pictureBlobHolder.getBlob(derivativeTerm);\r
810                                         } else {\r
811                                                 docBlob = pictureBlobHolder.getBlob();\r
812                                         }\r
813                                 } else {\r
814                                         docBlob = docBlobHolder.getBlob();\r
815                                 }\r
816 \r
817                                 //\r
818                                 // Create the result instance that will contain the blob\r
819                                 // metadata\r
820                                 // and an InputStream with the bits if the 'getContentFlag' is\r
821                                 // set\r
822                                 //\r
823                                 BlobsCommon blobsCommon = createBlobsCommon(documentModel,\r
824                                                 docBlob);\r
825                                 result.setBlobsCommon(blobsCommon);\r
826                                 if (getContentFlag == true) {\r
827                                         InputStream remoteStream = docBlob.getStream();\r
828                                         BufferedInputStream bufferedInputStream = new BufferedInputStream(\r
829                                                         remoteStream); // FIXME: REM - To improve\r
830                                                                                         // performance, try\r
831                                                                                         // BufferedInputStream(InputStream\r
832                                                                                         // in, int size)\r
833                                         result.setBlobInputStream(bufferedInputStream); // the input\r
834                                                                                                                                         // stream of\r
835                                                                                                                                         // blob bits\r
836                                 }\r
837 \r
838                         } catch (Exception e) {\r
839                                 if (logger.isErrorEnabled() == true) {\r
840                                         logger.error(e.getMessage(), e);\r
841                                 }\r
842                                 result = null;\r
843                         }\r
844 \r
845                 return result;\r
846         }\r
847 }\r
848 \r
849 /*\r
850  * Notes and code snippets about Nuxeo's support for binaries and image\r
851  * documents.\r
852  */\r
853 \r
854 /*\r
855  * \r
856  * \r
857  * MultiviewPictureAdapter org.nuxeo.ecm.platform.picture.api.adapters\r
858  * PictureResourceAdapter pictureResourceAdapter = (PictureResourceAdapter)\r
859  * documentModel.getAdapter(PictureResourceAdapter.class); String thumbnailPath\r
860  * = pictureResourceAdapter.getViewXPath("Thumbnail");\r
861  * \r
862  * Map<String,Serializable> blobHolderProps = docBlobHolder.getProperties();\r
863  * String filePath = docBlobHolder.getFilePath(); List<Blob> docBlobs =\r
864  * docBlobHolder.getBlobs();\r
865  * \r
866  * stream = new FileInputStream(fileUploadHolder.getTempFile());\r
867  * \r
868  * public String addFile(InputStream fileUpload, String fileName) fileName =\r
869  * FileUtils.getCleanFileName(fileName); DocumentModel currentDocument =\r
870  * navigationContext.getCurrentDocument(); String path =\r
871  * currentDocument.getPathAsString(); Blob blob =\r
872  * FileUtils.createSerializableBlob(fileUpload, fileName, null);\r
873  * \r
874  * DocumentModel createdDoc = getFileManagerService().createDocumentFromBlob(\r
875  * documentManager, blob, path, true, fileName);\r
876  * eventManager.raiseEventsOnDocumentSelected(createdDoc);\r
877  * \r
878  * protected FileManager fileManager;\r
879  * \r
880  * protected FileManager getFileManagerService() throws ClientException { if\r
881  * (fileManager == null) { try { fileManager =\r
882  * Framework.getService(FileManager.class); } catch (Exception e) {\r
883  * log.error("Unable to get FileManager service ", e); throw new\r
884  * ClientException("Unable to get FileManager service ", e); } } return\r
885  * fileManager; }\r
886  */\r
887 \r
888 /*\r
889  * RepositoryService repositoryService = (RepositoryService)\r
890  * Framework.getRuntime().getComponent( RepositoryService.NAME);\r
891  * RepositoryManager repositoryManager =\r
892  * repositoryService.getRepositoryManager(); RepositoryDescriptor descriptor =\r
893  * repositoryManager.getDescriptor(repositoryName); DefaultBinaryManager\r
894  * binaryManager = new DefaultBinaryManager(\r
895  * SQLRepository.getDescriptor(descriptor)));\r
896  * \r
897  * File storageDir = binaryManager.getStorageDir(); SQLBlob blob = (SQLBlob)\r
898  * doc.getPropertyValue("schema:blobField"); File file =\r
899  * binaryManager.getFileForDigest( blob.getBinary().getDigest(), false);\r
900  */\r
901 \r
902 /*\r
903  * RepositoryInstance.getStreamURI()\r
904  * \r
905  * String getStreamURI(String blobPropertyId) throws ClientException\r
906  * \r
907  * Returns an URI identifying the stream given the blob property id. This method\r
908  * should be used by a client to download the data of a blob property.\r
909  * \r
910  * The blob is fetched from the repository and the blob stream is registered\r
911  * against the streaming service so the stream will be available remotely\r
912  * through stream service API.\r
913  * \r
914  * After the client has called this method, it will be able to download the\r
915  * stream using streaming server API.\r
916  * \r
917  * Returns: an URI identifying the remote stream Throws: ClientException\r
918  */\r
919 \r
920 /*\r
921  * A blob contains usually large data.\r
922  * \r
923  * Document fields holding Blob data are by default fetched in a lazy manner.\r
924  * \r
925  * A Blob object hides the data source and it also describes data properties\r
926  * like the encoding or mime-type.\r
927  * \r
928  * The encoding is used to decode Unicode text content that was stored in an\r
929  * encoded form. If not encoding is specified, the default java encoding is\r
930  * used. The encoding is ignored for binary content.\r
931  * \r
932  * When retrieving the content from a document, it will be returned as source\r
933  * content instead of returning the content bytes.\r
934  * \r
935  * The same is true when setting the content for a document: you set a content\r
936  * source and not directly the content bytes. Ex:\r
937  * \r
938  * File file = new File("/tmp/index.html"); FileBlob fb = new FileBlob(file);\r
939  * fb.setMimeType("text/html"); fb.setEncoding("UTF-8"); // this specifies that\r
940  * content bytes will be stored as UTF-8 document.setProperty("file", "content",\r
941  * fb);\r
942  * \r
943  * \r
944  * Then you may want to retrieve the content as follow:\r
945  * \r
946  * Blob blob = document.getProperty("file:content"); htmlDoc = blob.getString();\r
947  * // the content is decoded from UTF-8 into a java string\r
948  */\r