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