2 * NuxeoImageUtils.java
\r
4 * {Purpose of This Class}
\r
6 * {Other Notes Relating to This Class (Optional)}
\r
9 * $LastChangedRevision: $
\r
10 * $LastChangedDate: $
\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
16 * http://www.collectionspace.org
\r
17 * http://wiki.collectionspace.org
\r
19 * Copyright © 2009 {Contributing Institution}
\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
24 * You may obtain a copy of the ECL 2.0 License at
\r
25 * https://source.collectionspace.org/collection-space/LICENSE.txt
\r
27 package org.collectionspace.services.common.imaging.nuxeo;
\r
29 import java.io.File;
\r
30 import java.io.ByteArrayOutputStream;
\r
31 import java.io.IOException;
\r
32 import java.io.InputStream;
\r
33 import java.io.FileInputStream;
\r
34 import java.io.Serializable;
\r
35 import java.util.ArrayList;
\r
36 import java.util.HashMap;
\r
37 import java.util.List;
\r
38 import java.util.Map;
\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
44 import org.nuxeo.common.utils.FileUtils;
\r
46 import org.nuxeo.ecm.platform.picture.api.adapters.PictureResourceAdapter;
\r
47 import org.nuxeo.ecm.platform.mimetype.MimetypeDetectionException;
\r
48 import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;
\r
49 import org.nuxeo.ecm.platform.picture.api.adapters.PictureBlobHolder;
\r
50 import org.nuxeo.ecm.platform.picture.extension.ImagePlugin;
\r
51 import org.nuxeo.ecm.platform.filemanager.api.FileManager;
\r
52 import org.nuxeo.ecm.platform.filemanager.service.FileManagerService;
\r
53 import org.nuxeo.ecm.platform.types.TypeManager;
\r
54 import org.nuxeo.ecm.platform.picture.api.adapters.PictureBlobHolderFactory;
\r
55 import org.nuxeo.ecm.platform.picture.api.adapters.PictureBlobHolder;
\r
57 import org.nuxeo.ecm.core.repository.RepositoryDescriptor;
\r
58 import org.nuxeo.ecm.core.repository.RepositoryManager;
\r
60 //import org.nuxeo.ecm.core.api.repository.RepositoryManager;
\r
61 //import org.nuxeo.ecm.core.api.repository.Repository;
\r
64 import org.nuxeo.ecm.core.repository.RepositoryService;
\r
65 import org.nuxeo.runtime.model.ComponentManager;
\r
66 import org.nuxeo.runtime.model.ComponentInstance;
\r
67 import org.nuxeo.runtime.model.impl.ComponentManagerImpl;
\r
68 //import org.nuxeo.ecm.core.api.ejb.DocumentManagerBean;
\r
69 //import org.nuxeo.ecm.core.storage.sql.RepositoryImpl;
\r
70 //import org.nuxeo.ecm.core.storage.sql.Repository;
\r
71 import org.nuxeo.ecm.core.storage.sql.BinaryManager;
\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.coremodel.SQLBlob;
\r
75 //import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor;
\r
77 //import org.nuxeo.ecm.core.api.DocumentResolver;
\r
78 import org.nuxeo.ecm.core.api.IdRef;
\r
79 import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
\r
80 import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder;
\r
81 import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
\r
82 import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob;
\r
83 import org.nuxeo.ecm.core.api.impl.blob.ByteArrayBlob;
\r
84 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
\r
85 import org.nuxeo.ecm.core.api.repository.Repository;
\r
86 import org.nuxeo.ecm.core.api.Blob;
\r
87 import org.nuxeo.ecm.core.api.ClientException;
\r
88 import org.nuxeo.ecm.core.api.DocumentModel;
\r
89 import org.nuxeo.ecm.core.api.DocumentRef;
\r
90 import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
\r
91 import org.nuxeo.ecm.core.api.blobholder.BlobHolderAdapterService;
\r
92 import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
\r
93 import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
\r
95 import org.nuxeo.ecm.core.model.Document;
\r
96 import org.nuxeo.ecm.core.schema.SchemaManager;
\r
97 import org.nuxeo.ecm.core.schema.types.Schema;
\r
99 import org.slf4j.Logger;
\r
100 import org.slf4j.LoggerFactory;
\r
101 //import org.nuxeo.ecm.core.repository.jcr.testing.RepositoryOSGITestCase;
\r
103 import org.collectionspace.services.common.ServiceMain;
\r
104 import org.collectionspace.services.common.context.ServiceContext;
\r
105 import org.collectionspace.services.common.document.DocumentUtils;
\r
107 // TODO: Auto-generated Javadoc
\r
109 * The Class NuxeoImageUtils.
\r
111 public class NuxeoImageUtils {
\r
112 /** The Constant logger. */
\r
113 private static final Logger logger = LoggerFactory.getLogger(NuxeoImageUtils.class);
\r
115 // static DefaultBinaryManager binaryManager = new DefaultBinaryManager(); //can we get this from Nuxeo? i.e., Framework.getService(BinaryManger.class)
\r
117 // /** The temp file name. */
\r
118 //static String tempFileName = "sunset.jpg";
\r
120 // /** The file separator. */
\r
121 // static String fileSeparator = System.getProperty("file.separator");
\r
123 // /** The cur dir. */
\r
124 // static String curDir = System.getProperty("user.dir");
\r
127 * Instantiates a new nuxeo image utils.
\r
129 NuxeoImageUtils() {
\r
130 //empty constructor
\r
136 public static void loggerSetup() {
\r
140 static private File getBlobFile(RepositoryInstance ri, DocumentModel documentModel, Blob blob) {
\r
141 DefaultBinaryManager binaryManager = null;
\r
142 RepositoryDescriptor descriptor = null;
\r
146 ServiceManager sm = (ServiceManager) Framework.getService(ServiceManager.class);
\r
147 ServiceDescriptor[] sd = sm.getServiceDescriptors();
\r
149 RepositoryService repositoryService1 = (RepositoryService) Framework.getRuntime().getComponent(
\r
150 RepositoryService.NAME);
\r
151 RepositoryService repositoryService2 = (RepositoryService) Framework.getRuntime().getService(
\r
152 RepositoryService.class);
\r
153 RepositoryService repositoryService3 = (RepositoryService) Framework.getService(
\r
154 RepositoryService.class);
\r
155 RepositoryService repositoryService4 = (RepositoryService) Framework.getLocalService(
\r
156 RepositoryService.class);
\r
157 ComponentManager componentManager1 = (ComponentManager) Framework.getService(ComponentManager.class);
\r
158 ComponentManager componentManager2 = (ComponentManager) Framework.getService(ComponentManagerImpl.class);
\r
161 // RepositoryManager repositoryManager2 = (RepositoryManager) Framework.getService(RepositoryManager.class);
\r
162 // Repository repository = repositoryManager2.getDefaultRepository();
\r
163 // Map<String, String> repositoryMap = repository.getProperties();
\r
164 // String streamURI = ri.getStreamURI(arg0)
\r
166 String repositoryName = documentModel.getRepositoryName();
\r
167 // RepositoryManager repositoryManager2 = (RepositoryManager) Framework.getService(RepositoryManager.class);
\r
168 RepositoryManager repositoryManager = repositoryService1.getRepositoryManager();
\r
169 descriptor = repositoryManager.getDescriptor(repositoryName);
\r
171 binaryManager = new DefaultBinaryManager();
\r
173 File storageDir = binaryManager.getStorageDir();
\r
174 // SQLBlob blob = (SQLBlob) doc.getPropertyValue("schema:blobField");
\r
175 File file = binaryManager.getFileForDigest(
\r
176 blob.getDigest(), false);
\r
178 // binaryManager = new DefaultBinaryManager();
\r
179 } catch (Exception e) {
\r
180 e.printStackTrace();
\r
184 binaryManager.initialize(
\r
185 SQLRepository.getDescriptor(descriptor));
\r
186 } catch (IOException e) {
\r
187 // TODO Auto-generated catch block
\r
188 e.printStackTrace();
\r
189 } catch (Exception e) {
\r
190 // TODO Auto-generated catch block
\r
191 e.printStackTrace();
\r
194 File storageDir = binaryManager.getStorageDir();
\r
195 // SQLBlob blob = (SQLBlob) documentModel.getPropertyValue("schema:blobField");
\r
196 File file = binaryManager.getFileForDigest(
\r
197 blob.getDigest(), false);
\r
203 * Returns a schema, given the name of a schema.
\r
205 * @param schemaName a schema name.
\r
206 * @return a schema.
\r
208 private static Schema getSchemaFromName(String schemaName) {
\r
209 SchemaManager schemaManager = null;
\r
211 schemaManager = Framework.getService(SchemaManager.class);
\r
212 } catch (Exception e) {
\r
213 // TODO Auto-generated catch block
\r
214 e.printStackTrace();
\r
216 return schemaManager != null ? schemaManager.getSchema(schemaName) : null;
\r
222 * @param nuxeoSession the nuxeo session
\r
226 static private Blob getBlob(RepositoryInstance nuxeoSession, String id) {
\r
227 Blob result = null;
\r
230 Repository repository = nuxeoSession.getRepository();
\r
231 // binaryManager.initialize(new RepositoryDescriptor());
\r
232 // binaryManager.getBinary("a4cac052ae0281979f2dcf5ab2e61a6c");
\r
233 // DocumentResolver.resolveReference(nuxeoSession, documentRef);
\r
234 //binaryManager = repository.getBinaryManager();
\r
235 // documentModel.getr
\r
236 } catch (Exception x) {
\r
237 x.printStackTrace();
\r
244 * Gets the type service.
\r
246 * @return the type service
\r
247 * @throws ClientException the client exception
\r
249 private static TypeManager getTypeService() throws ClientException {
\r
250 TypeManager typeService = null;
\r
252 typeService = Framework.getService(TypeManager.class);
\r
253 } catch (Exception e) {
\r
254 throw new ClientException(e);
\r
256 return typeService;
\r
262 * @param fis the fis
\r
263 * @return the bytes
\r
265 private static byte[] getBytes(InputStream fis) {
\r
266 ByteArrayOutputStream bos = new ByteArrayOutputStream();
\r
267 byte[] buf = new byte[128 * 1024];
\r
269 for (int readNum; (readNum = fis.read(buf)) != -1;) {
\r
270 bos.write(buf, 0, readNum);
\r
271 //no doubt here is 0
\r
272 /*Writes len bytes from the specified byte array starting at offset
\r
273 off to this byte array output stream.*/
\r
274 System.out.println("read " + readNum + " bytes,");
\r
276 } catch (IOException ex) {
\r
277 logger.error(ex.getMessage(), ex);
\r
279 byte[] bytes = bos.toByteArray();
\r
280 //bytes is the ByteArray we need
\r
285 * Creates the serializable blob.
\r
287 * @param fileInputStream the file input stream
\r
288 * @param filename the filename
\r
289 * @param mimeType the mime type
\r
292 private static Blob createSerializableBlob(InputStream fileInputStream,
\r
293 String filename, String mimeType) {
\r
296 // persisting the blob makes it possible to read the binary content
\r
297 // of the request stream several times (mimetype sniffing, digest
\r
298 // computation, core binary storage)
\r
299 byte[] bytes = getBytes(fileInputStream);
\r
300 blob = new ByteArrayBlob(bytes);
\r
302 if (filename != null) {
\r
303 filename = getCleanFileName(filename);
\r
305 blob.setFilename(filename);
\r
306 // mimetype detection
\r
307 MimetypeRegistry mimeService = Framework.getService(MimetypeRegistry.class);
\r
308 String detectedMimeType = mimeService.getMimetypeFromFilenameAndBlobWithDefault(
\r
309 filename, blob, null);
\r
310 if (detectedMimeType == null) {
\r
311 if (mimeType != null) {
\r
312 detectedMimeType = mimeType;
\r
315 detectedMimeType = "application/octet-stream";
\r
318 blob.setMimeType(detectedMimeType);
\r
319 } catch (MimetypeDetectionException e) {
\r
320 logger.error(String.format("could not fetch mimetype for file %s",
\r
322 } catch (Exception e) {
\r
323 logger.error("", e);
\r
329 * Creates a serializable blob from a stream, with filename and mimetype
\r
333 * Creates an in-memory blob if data is under 64K, otherwise constructs a
\r
334 * serializable FileBlob which stores data in a temporary file on the hard
\r
338 * @param file the input stream holding data
\r
339 * @param filename the file name. Will be set on the blob and will used for
\r
340 * mimetype detection.
\r
341 * @param mimeType the detected mimetype at upload. Can be null. Will be
\r
342 * verified by the mimetype service.
\r
345 private static Blob createStreamingBlob(InputStream file,
\r
346 String filename, String mimeType) {
\r
349 // persisting the blob makes it possible to read the binary content
\r
350 // of the request stream several times (mimetype sniffing, digest
\r
351 // computation, core binary storage)
\r
352 blob = StreamingBlob.createFromStream(file, mimeType).persist();
\r
354 if (filename != null) {
\r
355 filename = getCleanFileName(filename);
\r
357 blob.setFilename(filename);
\r
358 // mimetype detection
\r
359 MimetypeRegistry mimeService = Framework.getService(MimetypeRegistry.class);
\r
360 String detectedMimeType = mimeService.getMimetypeFromFilenameAndBlobWithDefault(
\r
361 filename, blob, null);
\r
362 if (detectedMimeType == null) {
\r
363 if (mimeType != null) {
\r
364 detectedMimeType = mimeType;
\r
367 detectedMimeType = "application/octet-stream";
\r
370 blob.setMimeType(detectedMimeType);
\r
371 } catch (MimetypeDetectionException e) {
\r
372 logger.error(String.format("could not fetch mimetype for file %s",
\r
374 } catch (IOException e) {
\r
375 logger.error("", e);
\r
376 } catch (Exception e) {
\r
377 logger.error("", e);
\r
383 * Returns a clean filename, stripping upload path on client side.
\r
388 * @param filename the filename
\r
389 * @return the clean file name
\r
391 private static String getCleanFileName(String filename) {
\r
393 int lastWinSeparator = filename.lastIndexOf('\\');
\r
394 int lastUnixSeparator = filename.lastIndexOf('/');
\r
395 int lastSeparator = Math.max(lastWinSeparator, lastUnixSeparator);
\r
396 if (lastSeparator != -1) {
\r
397 res = filename.substring(lastSeparator + 1, filename.length());
\r
405 * Gets Nuxeo's file manager service.
\r
407 * @return the file manager service
\r
408 * @throws ClientException the client exception
\r
410 private static FileManager getFileManagerService() throws ClientException {
\r
411 FileManager result = null;
\r
413 result = Framework.getService(FileManager.class);
\r
414 } catch (Exception e) {
\r
415 String msg = "Unable to get Nuxeo's FileManager service.";
\r
416 logger.error(msg, e);
\r
417 throw new ClientException("msg", e);
\r
423 * Creates the picture.
\r
425 * @param ctx the ctx
\r
426 * @param repoSession the repo session
\r
427 * @param filePath the file path
\r
428 * @return the string
\r
430 public static String createPicture(ServiceContext ctx,
\r
431 RepositoryInstance repoSession,
\r
433 String result = null;
\r
436 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
\r
437 DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
\r
438 DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
\r
440 FileInputStream inputStream = new FileInputStream(blobFile);
\r
441 if (inputStream != null) {
\r
442 result = createImage(repoSession, wspaceDoc,
\r
443 inputStream, blobFile.getName(), null);
\r
445 } catch (Exception e) {
\r
446 logger.error("Could not create image blob", e);
\r
453 * Creates the image blob.
\r
455 * @param nuxeoSession the nuxeo session
\r
456 * @param blobLocation the blob location
\r
457 * @param file the file
\r
458 * @param fileName the file name
\r
459 * @param mimeType the mime type
\r
460 * @return the string
\r
462 static public String createImage(RepositoryInstance nuxeoSession,
\r
463 DocumentModel blobLocation,
\r
467 String result = null;
\r
470 Blob fileBlob = createStreamingBlob(file, fileName, mimeType);
\r
471 String digestAlgorithm = getFileManagerService().getDigestAlgorithm(); //Need some way on initializing the FileManager with a call.
\r
472 // List<String> permissions = nuxeoSession.getAvailableSecurityPermissions();
\r
473 DocumentModel documentModel = getFileManagerService().createDocumentFromBlob(nuxeoSession,
\r
474 fileBlob, blobLocation.getPathAsString(), true, fileName);
\r
475 result = documentModel.getId();
\r
476 } catch (Exception e) {
\r
477 logger.error("Could not create new image blob", e);
\r
485 * Gets the picture.
\r
487 * @param ctx the ctx
\r
488 * @param repoSession the repo session
\r
489 * @param blobId the blob id
\r
490 * @param derivativeTerm the derivative term
\r
491 * @return the picture
\r
493 public static InputStream getPicture(ServiceContext ctx, RepositoryInstance repoSession,
\r
494 String blobId, String derivativeTerm) {
\r
495 return getImage(repoSession, blobId, derivativeTerm);
\r
501 * @param repoSession the repo session
\r
502 * @param repositoryId the repository id
\r
503 * @param derivativeTerm the derivative term
\r
504 * @return the image
\r
506 static public InputStream getImage(RepositoryInstance repoSession,
\r
507 String repositoryId, String derivativeTerm) {
\r
508 InputStream result = null;
\r
511 IdRef documentRef = new IdRef(repositoryId);
\r
512 DocumentModel documentModel = repoSession.getDocument(documentRef);
\r
514 // documentModel.getAdapter(PictureResourceAdapter.class);
\r
515 // DocumentBlobHolder docBlobHolder = (DocumentBlobHolder)documentModel.getAdapter(BlobHolder.class);
\r
516 // Blob docBlob = docBlobHolder.getBlob();
\r
517 // Map<String,Serializable> blobHolderProps = docBlobHolder.getProperties();
\r
518 // String filePath = docBlobHolder.getFilePath();
\r
519 // List<Blob> docBlobs = docBlobHolder.getBlobs();
\r
521 PictureBlobHolderFactory blobHolderFactory = new PictureBlobHolderFactory();
\r
522 PictureBlobHolder pictureBlobHolder = (PictureBlobHolder) blobHolderFactory.getBlobHolder(documentModel);
\r
523 Blob pictureBlob = null;
\r
524 if (derivativeTerm != null) {
\r
525 pictureBlob = pictureBlobHolder.getBlob(derivativeTerm);
\r
527 pictureBlob = pictureBlobHolder.getBlob();
\r
530 result = pictureBlob.getStream();
\r
531 } catch (Exception e) {
\r
532 logger.error(e.getMessage(), e);
\r
540 stream = new FileInputStream(fileUploadHolder.getTempFile());
\r
542 public String addFile(InputStream fileUpload, String fileName)
\r
543 fileName = FileUtils.getCleanFileName(fileName);
\r
544 DocumentModel currentDocument = navigationContext.getCurrentDocument();
\r
545 String path = currentDocument.getPathAsString();
\r
546 Blob blob = FileUtils.createSerializableBlob(fileUpload, fileName,
\r
549 DocumentModel createdDoc = getFileManagerService().createDocumentFromBlob(
\r
550 documentManager, blob, path, true, fileName);
\r
551 eventManager.raiseEventsOnDocumentSelected(createdDoc);
\r
553 protected FileManager fileManager;
\r
555 protected FileManager getFileManagerService() throws ClientException {
\r
556 if (fileManager == null) {
\r
558 fileManager = Framework.getService(FileManager.class);
\r
559 } catch (Exception e) {
\r
560 log.error("Unable to get FileManager service ", e);
\r
561 throw new ClientException("Unable to get FileManager service ",
\r
565 return fileManager;
\r
570 RepositoryService repositoryService = (RepositoryService) Framework.getRuntime().getComponent(
\r
571 RepositoryService.NAME);
\r
572 RepositoryManager repositoryManager = repositoryService.getRepositoryManager();
\r
573 RepositoryDescriptor descriptor = repositoryManager.getDescriptor(repositoryName);
\r
574 DefaultBinaryManager binaryManager = new DefaultBinaryManager(
\r
575 SQLRepository.getDescriptor(descriptor)));
\r
577 File storageDir = binaryManager.getStorageDir();
\r
578 SQLBlob blob = (SQLBlob) doc.getPropertyValue("schema:blobField");
\r
579 File file = binaryManager.getFileForDigest(
\r
580 blob.getBinary().getDigest(), false);
\r
584 RepositoryInstance.getStreamURI()
\r
586 String getStreamURI(String blobPropertyId)
\r
587 throws ClientException
\r
589 Returns an URI identifying the stream given the blob property id. This method should be used by a client to download the data of a blob property.
\r
591 The blob is fetched from the repository and the blob stream is registered against the streaming service so the stream will be available remotely through stream service API.
\r
593 After the client has called this method, it will be able to download the stream using streaming server API.
\r
596 an URI identifying the remote stream
\r
603 A blob contains usually large data.
\r
605 Document fields holding Blob data are by default fetched in a lazy manner.
\r
607 A Blob object hides the data source and it also describes data properties like the encoding or mime-type.
\r
609 The encoding is used to decode Unicode text content that was stored in an encoded form. If not encoding is specified, the default java encoding is used. The encoding is ignored for binary content.
\r
611 When retrieving the content from a document, it will be returned as source content instead of returning the content bytes.
\r
613 The same is true when setting the content for a document: you set a content source and not directly the content bytes. Ex:
\r
615 File file = new File("/tmp/index.html");
\r
616 FileBlob fb = new FileBlob(file);
\r
617 fb.setMimeType("text/html");
\r
618 fb.setEncoding("UTF-8"); // this specifies that content bytes will be stored as UTF-8
\r
619 document.setProperty("file", "content", fb);
\r
622 Then you may want to retrieve the content as follow:
\r
624 Blob blob = document.getProperty("file:content");
\r
625 htmlDoc = blob.getString(); // the content is decoded from UTF-8 into a java string
\r