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