From: Michael Ritter Date: Fri, 5 Jan 2024 01:13:16 +0000 (-0700) Subject: DRYD-1250: UCB Blob contributions (#372) X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=82a60d5ef438dfcf59eb8b7c9a9cd5ad3558ed9c;p=tmp%2Fjakarta-migration.git DRYD-1250: UCB Blob contributions (#372) Co-authored-by: Richard Millet --- diff --git a/3rdparty/nuxeo/nuxeo-server/9.10-HF30/bundles/nuxeo-binary-metadata-9.10.jar b/3rdparty/nuxeo/nuxeo-server/9.10-HF30/bundles/nuxeo-binary-metadata-9.10.jar new file mode 100644 index 000000000..dfa81772e Binary files /dev/null and b/3rdparty/nuxeo/nuxeo-server/9.10-HF30/bundles/nuxeo-binary-metadata-9.10.jar differ diff --git a/services/blob/service/src/main/java/org/collectionspace/services/blob/BlobResource.java b/services/blob/service/src/main/java/org/collectionspace/services/blob/BlobResource.java index 578373c0e..d51f80327 100644 --- a/services/blob/service/src/main/java/org/collectionspace/services/blob/BlobResource.java +++ b/services/blob/service/src/main/java/org/collectionspace/services/blob/BlobResource.java @@ -70,10 +70,10 @@ import java.util.regex.Pattern; @Consumes("application/xml") @Produces("application/xml") public class BlobResource extends NuxeoBasedResource { - + private static final int DEFAULT_MAX_CACHE_AGE = 86400; // 1 day of seconds. private static final String DERIVATIVES_REGEX = "(\\w+)(/blobs/\\*/derivatives/)(\\w+)(/content)"; // matches things like 'GET/blobs/*/derivatives/Medium/content' - + @Override public String getServiceName(){ return BlobClient.SERVICE_NAME; @@ -99,11 +99,11 @@ public class BlobResource extends NuxeoBasedResource { // protected CommonList search(MultivaluedMap queryParams,String keywords) { // return (CommonList) super.search(queryParams, keywords); // } - + private CommonList getDerivativeList(ServiceContext ctx, String csid) throws Exception { CommonList result = null; - + BlobInput blobInput = new BlobInput(); blobInput.setDerivativeListRequested(true); BlobUtil.setBlobInput(ctx, blobInput); @@ -117,21 +117,21 @@ public class BlobResource extends NuxeoBasedResource { // blobInput instance // result = BlobUtil.getBlobInput(ctx).getDerivativeList(); - + return result; } - + public InputStream getBlobContent(ServiceContext ctx, - String csid, - String derivativeTerm, + String csid, + String derivativeTerm, StringBuffer outMimeType) throws CSWebApplicationException { InputStream result = null; - + try { BlobInput blobInput = BlobUtil.getBlobInput(ctx); blobInput.setDerivativeTerm(derivativeTerm); blobInput.setContentRequested(true); - + PoxPayloadOut response = this.get(csid, ctx); if (logger.isDebugEnabled() == true) { logger.debug(response.toString()); @@ -140,7 +140,7 @@ public class BlobResource extends NuxeoBasedResource { // The result of a successful get should have put the results in the // blobInput instance // - + String mimeType = blobInput.getMimeType(); if (mimeType != null) { outMimeType.append(mimeType); // blobInput's mime type was set on call to "get" above by the doc handler @@ -149,7 +149,7 @@ public class BlobResource extends NuxeoBasedResource { } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); } - + if (result == null) { String errMsg = String.format("Index failed. Could not get the contents for the Blob with CSID = '%s'.", csid); @@ -157,10 +157,52 @@ public class BlobResource extends NuxeoBasedResource { Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).type("text/plain").build(); throw new CSWebApplicationException(response); } - + return result; } - + + /** + * Create a response for the Blob content. Depending on how the Blob is stored by Nuxeo, this may or may not support + * the Range HTTP header. If a Blob is backed by a File it will support Range, otherwise we can only use the input + * stream which RESTEasy won't apply the header to. + * + * @param ctx the service context + * @param csid the csid of the blob to get + * @return the http response builder for the Blob + * @throws CSWebApplicationException if the Blob or its content can't be retrieved + */ + private ResponseBuilder getBlobContentResponse(ServiceContext ctx, String csid) { + ResponseBuilder response = null; + + try { + BlobInput blobInput = BlobUtil.getBlobInput(ctx); + blobInput.setDerivativeTerm(null); + blobInput.setContentRequested(true); + + // refresh the BlobInput + PoxPayloadOut poxPayloadOut = this.get(csid, ctx); + + if (blobInput.getBlobFile() != null) { + response = Response.ok(blobInput.getBlobFile(), blobInput.getMimeType()); + } else if (blobInput.getContentStream() != null) { + response = Response.ok(blobInput.getContentStream(), blobInput.getMimeType()); + } + } catch (Exception e) { + throw bigReThrow(e, ServiceMessages.GET_FAILED); + } + + if (response == null) { + String errMsg = String.format("Index failed. Could not get the contents for the Blob with CSID = '%s'.", + csid); + Response errorResponse = Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(errMsg) + .type(MediaType.TEXT_PLAIN).build(); + throw new CSWebApplicationException(errorResponse); + } + + return response; + } + /* * This method can replace the 'createBlob' -specifically, this JAX-RS technique can replace the call to * the BlobInput.createBlobFile() method. In theory, this should reduce by 1 the number of times we need to copy @@ -175,15 +217,15 @@ public class BlobResource extends NuxeoBasedResource { @Context HttpServletRequest req, @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri, MultipartFormDataInput partFormData) { - Response response = null; + Response response = null; try { InputStream fileStream = null; String preamble = partFormData.getPreamble(); System.out.println("Preamble type is:" + preamble); - + Map> partsMap = partFormData.getFormDataMap(); List fileParts = partsMap.get("file"); - + for (InputPart part : fileParts) { String mediaType = part.getMediaType().toString(); @@ -191,23 +233,23 @@ public class BlobResource extends NuxeoBasedResource { fileStream = part.getBody(InputStream.class, null); FileUtilities.createTmpFile(fileStream, getServiceName() + "_"); } - + ResponseBuilder rb = Response.ok(); rb.entity("Goodbye, world!"); response = rb.build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); } - + return response; - } - + } + @POST @Consumes("multipart/form-data") @Produces("application/xml") public Response createBlob(@Context HttpServletRequest req, @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri) { - Response response = null; + Response response = null; try { ServiceContext ctx = createServiceContext(); BlobInput blobInput = BlobUtil.getBlobInput(ctx); @@ -216,20 +258,20 @@ public class BlobResource extends NuxeoBasedResource { } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); } - + return response; } - + @POST @Override public Response create( - @Context ResourceMap resourceMap, + @Context ResourceMap resourceMap, @Context UriInfo ui, String xmlPayload) { Response response = null; MultivaluedMap queryParams = ui.getQueryParameters(); String blobUri = queryParams.getFirst(BlobClient.BLOB_URI_PARAM); - + try { if (blobUri != null) { // If we were passed a URI than try to create a blob from it ServiceContext ctx = createServiceContext(); @@ -243,10 +285,10 @@ public class BlobResource extends NuxeoBasedResource { } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); } - + return response; - } - + } + /** * If there is no explicit setting in the Blobs service binding, we'll ask the HTTP client to cache blobs for 1 full day. * @param ctx @@ -256,7 +298,7 @@ public class BlobResource extends NuxeoBasedResource { @Override protected CacheControl getCacheControl(ServiceContext ctx, String cacheKey) { CacheControl result = null; - + if (cacheKey.matches(DERIVATIVES_REGEX)) { Pattern p = Pattern.compile(DERIVATIVES_REGEX); Matcher m = p.matcher(cacheKey); @@ -264,16 +306,16 @@ public class BlobResource extends NuxeoBasedResource { cacheKey = String.format("%s%s*%s", m.group(1), m.group(2), m.group(4)); // Converts something like this "GET/blobs/*/derivatives/Medium/content" into this "GET/blobs/*/derivatives/*/content" } } - + result = super.getCacheControl(ctx, cacheKey); if (result == null) { result = new CacheControl(); result.setMaxAge(DEFAULT_MAX_CACHE_AGE); } - + return result; } - + @GET @Path("{csid}/content") public Response getBlobContent( @@ -281,18 +323,15 @@ public class BlobResource extends NuxeoBasedResource { @Context Request jaxRsRequest, @Context UriInfo uriInfo) { Response result = null; - ServiceContext ctx = null; - + ServiceContext ctx = null; + try { ctx = createServiceContext(jaxRsRequest, uriInfo); BlobsCommon blobsCommon = getBlobsCommon(csid); - StringBuffer mimeType = new StringBuffer(); - InputStream contentStream = getBlobContent(ctx, csid, null /*derivative term*/, mimeType /*will get set*/); - - Response.ResponseBuilder responseBuilder = Response.ok(contentStream, mimeType.toString()); + + Response.ResponseBuilder responseBuilder = getBlobContentResponse(ctx, csid); setCacheControl(ctx, responseBuilder); - responseBuilder = responseBuilder.header("Content-Disposition","inline;filename=\"" - + blobsCommon.getName() +"\""); + responseBuilder.header("Content-Disposition","inline;filename=\"" + blobsCommon.getName() + "\""); result = responseBuilder.build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); @@ -300,18 +339,18 @@ public class BlobResource extends NuxeoBasedResource { return result; } - + private BlobsCommon getBlobsCommon(String csid) throws Exception { BlobsCommon result = null; - + ServiceContext ctx = createServiceContext(); PoxPayloadOut ppo = this.get(csid, ctx); PayloadPart blobsCommonPart = ppo.getPart(BlobClient.SERVICE_COMMON_PART_NAME); result = (BlobsCommon)blobsCommonPart.getBody(); - + return result; } - + /* * Publish the blob content. */ @@ -323,45 +362,45 @@ public class BlobResource extends NuxeoBasedResource { @PathParam("csid") String csid) { Response result = null; ServiceContext ctx = null; - + try { - ctx = createServiceContext(); + ctx = createServiceContext(); BlobsCommon blobsCommon = getBlobsCommon(csid); StringBuffer mimeType = new StringBuffer(); - InputStream contentStream = getBlobContent(ctx, csid, null /*derivative term*/, mimeType /*will get set*/); - result = PublicItemUtil.publishToRepository((PublicitemsCommon)null, resourceMap, uriInfo, + InputStream contentStream = getBlobContent(ctx, csid, null /*derivative term*/, mimeType /*will get set*/); + result = PublicItemUtil.publishToRepository((PublicitemsCommon)null, resourceMap, uriInfo, getRepositoryClient(ctx), ctx, contentStream, blobsCommon.getName()); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.PUT_FAILED); } - + return result; } - + @POST @Path("{csid}/derivatives/{derivativeTerm}/content/publish") public Response publishDerivativeContent( @Context ResourceMap resourceMap, - @Context UriInfo uriInfo, + @Context UriInfo uriInfo, @PathParam("csid") String csid, @PathParam("derivativeTerm") String derivativeTerm) { Response result = null; ServiceContext ctx = null; - + try { ctx = createServiceContext(); BlobsCommon blobsCommon = getBlobsCommon(csid); StringBuffer mimeType = new StringBuffer(); InputStream contentStream = getBlobContent(ctx, csid, derivativeTerm, mimeType); - result = PublicItemUtil.publishToRepository((PublicitemsCommon)null, resourceMap, uriInfo, + result = PublicItemUtil.publishToRepository((PublicitemsCommon)null, resourceMap, uriInfo, getRepositoryClient(ctx), ctx, contentStream, blobsCommon.getName()); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); } - + return result; } - + @GET @Path("{csid}/derivatives/{derivativeTerm}/content") public Response getDerivativeContent( @@ -371,7 +410,7 @@ public class BlobResource extends NuxeoBasedResource { @Context UriInfo uriInfo) { Response result = null; ServiceContext ctx = null; - + try { // Setup the call to get the blob derivative ctx = createServiceContext(jaxRsRequest, uriInfo); @@ -391,13 +430,13 @@ public class BlobResource extends NuxeoBasedResource { return result; } - + @GET @Path("{csid}/derivatives/{derivativeTerm}") public String getDerivative(@PathParam("csid") String csid, @PathParam("derivativeTerm") String derivativeTerm) { PoxPayloadOut result = null; - + ensureCSID(csid, READ); try { ServiceContext ctx = createServiceContext(); @@ -412,10 +451,10 @@ public class BlobResource extends NuxeoBasedResource { } catch (Exception e) { throw bigReThrow(e, ServiceMessages.READ_FAILED, csid); } - + return result.toXML(); } - + @GET @Path("{csid}/derivatives") public CommonList getDerivatives(@PathParam("csid") String csid) { @@ -433,8 +472,8 @@ public class BlobResource extends NuxeoBasedResource { } catch (Exception e) { throw bigReThrow(e, ServiceMessages.READ_FAILED, csid); } - + return result; } - + } diff --git a/services/blob/service/src/main/java/org/collectionspace/services/blob/nuxeo/BlobDocumentModelHandler.java b/services/blob/service/src/main/java/org/collectionspace/services/blob/nuxeo/BlobDocumentModelHandler.java index a9475b49a..dc0f4d981 100644 --- a/services/blob/service/src/main/java/org/collectionspace/services/blob/nuxeo/BlobDocumentModelHandler.java +++ b/services/blob/service/src/main/java/org/collectionspace/services/blob/nuxeo/BlobDocumentModelHandler.java @@ -166,6 +166,7 @@ extends NuxeoDocumentModelHandler { if (getContentFlag == true) { if (blobOutput != null) { blobInput.setContentStream(blobOutput.getBlobInputStream()); + blobInput.setBlobFile(blobOutput.getBlobFile()); } else { blobInput.setContentStream(null); } diff --git a/services/common/pom.xml b/services/common/pom.xml index 73ff2f71d..b72827120 100644 --- a/services/common/pom.xml +++ b/services/common/pom.xml @@ -234,6 +234,11 @@ provided + + org.nuxeo.binary.metadata + nuxeo-binary-metadata + ${nuxeo.platform.version} + org.nuxeo.lib.runtime nuxeo-runtime-launcher diff --git a/services/common/src/main/java/org/collectionspace/services/common/blob/BlobOutput.java b/services/common/src/main/java/org/collectionspace/services/common/blob/BlobOutput.java index 6acb2a327..a2c9043f7 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/blob/BlobOutput.java +++ b/services/common/src/main/java/org/collectionspace/services/common/blob/BlobOutput.java @@ -1,5 +1,6 @@ package org.collectionspace.services.common.blob; +import java.io.File; import java.io.InputStream; import org.collectionspace.services.blob.BlobsCommon; @@ -7,6 +8,7 @@ public class BlobOutput { private String mimeType; private BlobsCommon blobsCommon; private InputStream blobInputStream; + private File blobFile; public BlobsCommon getBlobsCommon() { return blobsCommon; @@ -26,4 +28,12 @@ public class BlobOutput { public void setMimeType(String mimeType) { this.mimeType = mimeType; } + + public void setBlobFile(File file) { + this.blobFile = file; + } + + public File getBlobFile() { + return this.blobFile; + } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/imaging/nuxeo/NuxeoBlobUtils.java b/services/common/src/main/java/org/collectionspace/services/common/imaging/nuxeo/NuxeoBlobUtils.java index 905c379b8..2b638550d 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/imaging/nuxeo/NuxeoBlobUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/imaging/nuxeo/NuxeoBlobUtils.java @@ -1,4 +1,4 @@ -/** +/** * NuxeoImageUtils.java * * {Purpose of This Class} @@ -59,6 +59,7 @@ import org.nuxeo.ecm.core.api.blobholder.BlobHolder; import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder; import org.nuxeo.ecm.core.api.impl.blob.FileBlob; import org.nuxeo.ecm.core.api.model.Property; +import org.nuxeo.binary.metadata.api.BinaryMetadataService; import org.nuxeo.ecm.core.api.Blob; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.DocumentModel; @@ -104,7 +105,7 @@ import org.collectionspace.services.config.service.ListResultField; */ class CSpaceFileBlob extends FileBlob { /** - * + * */ private static final long serialVersionUID = 1L; @@ -118,23 +119,22 @@ class CSpaceFileBlob extends FileBlob { * The Class NuxeoBlobUtils. */ public class NuxeoBlobUtils { - + /** The Constant logger. */ - private static final Logger logger = LoggerFactory - .getLogger(NuxeoBlobUtils.class); - + private static final Logger logger = LoggerFactory.getLogger(NuxeoBlobUtils.class); + private static final String VIEWS_PROPERTY = "picture:views"; private static final String TITLE_PROPERTY = "title"; private static final String FILENAME_PROPERTY = "filename"; - // - // A maximum byte size for the byte array used to hold an image. Images larger than this will - // be returned as FileInputStreams rather than ByteArrayInputStreams - // - private static final int MAX_IMAGE_BUFFER = 256 * 1024; // REM: 11/26/2013 - This should be set in a config/property file. - + /** + * A maximum byte size for the byte array used to hold an image. Images larger than this will + * be returned as FileInputStreams rather than ByteArrayInputStreams + *

+ * REM: 11/26/2013 - This should be set in a config/property file. + */ + private static final int MAX_IMAGE_BUFFER = 256 * 1024; - // // File name constants // @@ -143,7 +143,7 @@ public class NuxeoBlobUtils { public static final String DOCUMENT_PLACEHOLDER_IMAGE = "documentImage.jpg"; public static final String DOCUMENT_MISSING_PLACEHOLDER_IMAGE = "documentImageMissing.jpg"; - + public static final String DOCUMENT_PLACEHOLDER_CSV = "documentCSV.jpg"; public static final String DOCUMENT_PLACEHOLDER_DOC = "documentDOC.jpg"; public static final String DOCUMENT_PLACEHOLDER_DOCX = "documentDOC.jpg"; @@ -174,8 +174,7 @@ public class NuxeoBlobUtils { * hard coded. */ public static final String DERIVATIVE_ORIGINAL = "Original"; - public static final String DERIVATIVE_ORIGINAL_TAG = DERIVATIVE_ORIGINAL - + "_"; + public static final String DERIVATIVE_ORIGINAL_TAG = DERIVATIVE_ORIGINAL + "_"; public static final String DERIVATIVE_ORIGINAL_JPEG = "OriginalJpeg"; public static final String DERIVATIVE_ORIGINAL_JPEG_TAG = DERIVATIVE_ORIGINAL_JPEG + "_"; @@ -263,17 +262,17 @@ public class NuxeoBlobUtils { return item; } - + static public String getSanizitedFilename(File srcFile) throws Exception { return getSanizitedFilename(srcFile.getName()); } - + /* * Valid Nuxeo file names are a subset of *nix and Windows filenames, so we need to check. */ static public String getSanizitedFilename(String fileName) throws Exception { String result = fileName; - + if (fileName != null && fileName.matches(NUXEO_FILENAME_VALID_STRING) == false) { String fixedString = fileName.replaceAll(NUXEO_FILENAME_BAD_CHARS, "_"); // Replace "bad" chars with underscore character if (fixedString.matches(NUXEO_FILENAME_VALID_STRING) == true) { @@ -283,7 +282,7 @@ public class NuxeoBlobUtils { throw new Exception(errMsg); } } - + if (result != null && logger.isDebugEnabled() == true) { if (result.equals(fileName) == false) { logger.debug(String.format("The file name '%s' was sanizitized to '%s'.", fileName, result)); @@ -293,9 +292,9 @@ public class NuxeoBlobUtils { return result; } - static private void handleGenericBlobs(DocumentBlobHolder docBlobHolder, CommonList commonList, String uri) { + private static void handleGenericBlobs(DocumentBlobHolder docBlobHolder, CommonList commonList, String uri) { int total = 0; - List docBlobs = docBlobHolder.getBlobs(); + List docBlobs = docBlobHolder.getBlobs(); // List blobListItems = result.getBlobListItem(); HashMap item = null; for (Blob blob : docBlobs) { @@ -311,8 +310,8 @@ public class NuxeoBlobUtils { commonList.setTotalItems(total); commonList.setItemsInPage(total); } - - static private void handlePictureViewBlobs(PictureBlobHolder pictureBlobHolder, + + private static void handlePictureViewBlobs(PictureBlobHolder pictureBlobHolder, CoreSessionInterface repoSession, String repositoryId, CommonList commonList, @@ -359,111 +358,97 @@ public class NuxeoBlobUtils { } else { handleGenericBlobs(docBlobHolder, commonList, uri); } - + return commonList; } - /* - * [dublincore, uid, picture, iptc, common, image_metadata] - */ - static private Map getMetadata(Blob nuxeoBlob) - throws Exception { - ImagingService service = Framework.getService(ImagingService.class); - Map metadataMap = service.getImageMetadata(nuxeoBlob); - return metadataMap; - } + public static boolean isBlobAnImage(Blob input) { + boolean result = false; + + FileImporter importer = getFileManagerService().getPluginByName("Imageplugin"); + + String normalizedMimeType = getMimeService().getMimetypeEntryByMimeType(input.getMimeType()).getNormalized(); + if (importer.isEnabled() && (importer.matches(normalizedMimeType) || importer.matches(input.getMimeType()))) { + result = true; + } + + return result; + } + + /* + * [dublincore, uid, picture, iptc, common, image_metadata] + */ + private static Map getMetadata(Blob nuxeoBlob) throws Exception { + BinaryMetadataService binaryMetadataService = Framework.getService(BinaryMetadataService.class); + return binaryMetadataService.readMetadata(nuxeoBlob, false); + } - private static String[] imageTypes = {"jpeg", "bmp", "gif", "png", "tiff", "octet-stream"}; - static private boolean isImageMedia(Blob nuxeoBlob) { - boolean result = false; - - String mimeType = nuxeoBlob.getMimeType(); - if (mimeType != null) { - mimeType = mimeType.toLowerCase().trim(); - String[] parts = mimeType.split("/"); // split strings like "application/xml" into an array of two strings - if (parts.length == 2) { - for (String type : imageTypes) { - if (parts[1].equalsIgnoreCase(type)) { - result = true; - break; - } - } - } - } - - return result; - } - static private MeasuredPartGroupList getDimensions( DocumentModel documentModel, Blob nuxeoBlob) { MeasuredPartGroupList result = null; - - if (isImageMedia(nuxeoBlob) == true) try { - ImagingService service = Framework.getService(ImagingService.class); - ImageInfo imageInfo = service.getImageInfo(nuxeoBlob); - Map metadataMap = getMetadata(nuxeoBlob); - if (imageInfo != null) { - // - // Create a timestamp to add to all the image's dimensions - // - String valueDate = GregorianCalendarDateTimeUtils - .timestampUTC(); - - result = new MeasuredPartGroupList(); - List measuredPartGroupList = - (result).getMeasuredPartGroup(); - // - // Create a new measured part for the "image" - // - MeasuredPartGroup mpGroup = new MeasuredPartGroup(); - mpGroup.setMeasuredPart(PART_IMAGE); - mpGroup.setDimensionSummary(PART_SUMMARY); - mpGroup.setDimensionSubGroupList(new DimensionSubGroupList()); - List dimensionSubGroupList = mpGroup.getDimensionSubGroupList() - .getDimensionSubGroup(); + if (isBlobAnImage(nuxeoBlob)) { + try { + ImagingService service = Framework.getService(ImagingService.class); + ImageInfo imageInfo = service.getImageInfo(nuxeoBlob); + Map metadataMap = getMetadata(nuxeoBlob); - // - // Set the width - // - DimensionSubGroup widthDimension = new DimensionSubGroup(); - widthDimension.setDimension(WIDTH); - widthDimension.setMeasurementUnit(UNIT_PIXELS); - widthDimension.setValue(intToBigDecimal(imageInfo.getWidth())); - widthDimension.setValueDate(valueDate); - dimensionSubGroupList.add(widthDimension); - // - // Set the height - // - DimensionSubGroup heightDimension = new DimensionSubGroup(); - heightDimension.setDimension(HEIGHT); - heightDimension.setMeasurementUnit(UNIT_PIXELS); - heightDimension - .setValue(intToBigDecimal(imageInfo.getHeight())); - heightDimension.setValueDate(valueDate); - dimensionSubGroupList.add(heightDimension); - // - // Set the depth - // - DimensionSubGroup depthDimension = new DimensionSubGroup(); - depthDimension.setDimension(DEPTH); - depthDimension.setMeasurementUnit(UNIT_BITS); - depthDimension.setValue(intToBigDecimal(imageInfo.getDepth())); - depthDimension.setValueDate(valueDate); - dimensionSubGroupList.add(depthDimension); - // - // Now set out result - // - measuredPartGroupList.add(mpGroup); - } else { - if (logger.isWarnEnabled() == true) { - logger.warn("Could not synthesize a dimension list of the blob: " - + documentModel.getName()); + if (imageInfo != null) { + // + // Create a timestamp to add to all the image's dimensions + // + String valueDate = GregorianCalendarDateTimeUtils.timestampUTC(); + + result = new MeasuredPartGroupList(); + List measuredPartGroupList = (result).getMeasuredPartGroup(); + + // + // Create a new measured part for the "image" + // + MeasuredPartGroup mpGroup = new MeasuredPartGroup(); + mpGroup.setMeasuredPart(PART_IMAGE); + mpGroup.setDimensionSummary(PART_SUMMARY); + mpGroup.setDimensionSubGroupList(new DimensionSubGroupList()); + List dimensionSubGroupList = + mpGroup.getDimensionSubGroupList().getDimensionSubGroup(); + + // + // Set the width + // + DimensionSubGroup widthDimension = new DimensionSubGroup(); + widthDimension.setDimension(WIDTH); + widthDimension.setMeasurementUnit(UNIT_PIXELS); + widthDimension.setValue(intToBigDecimal(imageInfo.getWidth())); + widthDimension.setValueDate(valueDate); + dimensionSubGroupList.add(widthDimension); + // + // Set the height + // + DimensionSubGroup heightDimension = new DimensionSubGroup(); + heightDimension.setDimension(HEIGHT); + heightDimension.setMeasurementUnit(UNIT_PIXELS); + heightDimension.setValue(intToBigDecimal(imageInfo.getHeight())); + heightDimension.setValueDate(valueDate); + dimensionSubGroupList.add(heightDimension); + // + // Set the depth + // + DimensionSubGroup depthDimension = new DimensionSubGroup(); + depthDimension.setDimension(DEPTH); + depthDimension.setMeasurementUnit(UNIT_BITS); + depthDimension.setValue(intToBigDecimal(imageInfo.getDepth())); + depthDimension.setValueDate(valueDate); + dimensionSubGroupList.add(depthDimension); + // + // Now set out result + // + measuredPartGroupList.add(mpGroup); + } else { + logger.warn("Could not synthesize a dimension list of the blob: {}", documentModel.getName()); } + } catch (Exception e) { + logger.warn("Could not extract image information for blob: {}", documentModel.getName(), e); } - } catch (Exception e) { - logger.warn("Could not extract image information for blob: " - + documentModel.getName(), e); } return result; @@ -481,7 +466,7 @@ public class NuxeoBlobUtils { Blob nuxeoBlob) { return createBlobsCommon(ctx, documentModel, nuxeoBlob, false); } - + static private BlobsCommon createBlobsCommon(ServiceContext ctx, DocumentModel documentModel, Blob nuxeoBlob, Boolean getContentFlag) { BlobsCommon result = new BlobsCommon(); @@ -503,7 +488,7 @@ public class NuxeoBlobUtils { } } result.setDigest(digest); - + // // If getContentFlag is true then we're being asked for the blob's content, so we don't // need the measurement info. Getting the measurement info requires a call to Nuxeo which in turn @@ -559,29 +544,29 @@ public class NuxeoBlobUtils { } return blob; } - + /** * Gets the type service. Not in use, but please keep for future reference - * + * * @return the type service * @throws ClientException * the client exception */ private static TypeManager getTypeService() throws ClientException { TypeManager typeService = null; - + try { typeService = Framework.getService(TypeManager.class); } catch (Exception e) { throw new ClientException(e); } - + return typeService; } /** * Create a temporary Nuxeo FileBlob instance for processing. Nuxeo will clean this up for us. - * + * * @param file * @return * @throws Exception @@ -592,14 +577,14 @@ public class NuxeoBlobUtils { /** * Gets Nuxeo's file manager service. - * + * * @return the file manager service * @throws ClientException * the client exception */ private static FileManager getFileManager() throws ClientException { FileManager result = null; - + try { result = Framework.getService(FileManager.class); } catch (Exception e) { @@ -607,20 +592,20 @@ public class NuxeoBlobUtils { logger.error(msg, e); throw new ClientException("msg", e); } - + return result; } - + /** * Gets Nuxeo's file manager service. - * + * * @return the file manager service * @throws ClientException * the client exception */ private static FileManagerService getFileManagerService() throws ClientException { FileManagerService result = null; - + try { result = (FileManagerService)getFileManager(); } catch (Exception e) { @@ -628,54 +613,54 @@ public class NuxeoBlobUtils { logger.error(msg, e); throw new ClientException("msg", e); } - + return result; - } - - + } + + static private CoreSessionInterface getRepositorySession(ServiceContext ctx, RepositoryClient repositoryClient) { - CoreSessionInterface result = null; + CoreSessionInterface result = null; NuxeoRepositoryClientImpl nuxeoClient = (NuxeoRepositoryClientImpl)repositoryClient; - + try { result = nuxeoClient.getRepositorySession(ctx); } catch (Exception e) { logger.error("Could not get a repository session to the Nuxeo repository", e); } - + return result; } - + static private void releaseRepositorySession(ServiceContext ctx, RepositoryClient repositoryClient, CoreSessionInterface repoSession) throws TransactionException { NuxeoRepositoryClientImpl nuxeoClient = (NuxeoRepositoryClientImpl)repositoryClient; nuxeoClient.releaseRepositorySession(ctx, repoSession); } - + static private MimetypeRegistry getMimeService() throws ClientException { MimetypeRegistry result = null; - + try { result = Framework.getService(MimetypeRegistry.class); } catch (Exception e) { throw new ClientException(e); } - + return result; } - + private static DocumentModel createDocumentFromBlob( CoreSessionInterface repoSession, - Blob inputStreamBlob, - String blobLocation, - boolean overwrite, - String blobName, + Blob inputStreamBlob, + String blobLocation, + boolean overwrite, + String blobName, boolean useNuxeoAdaptors) throws Exception { DocumentModel result = null; - - boolean createdFromAdaptor = false; + + boolean createdFromAdaptor = false; if (useNuxeoAdaptors == true) try { // // Use Nuxeo's high-level create method which looks for plugin adapters that match the MIME type. For example, @@ -689,25 +674,25 @@ public class NuxeoBlobUtils { logger.warn(String.format("Tried but failed to use Nuxeo import adaptor to download '%s'. Falling back to generic file importer", blobName)); } - + if (createdFromAdaptor == false) { // // User Nuxeo's default file importer/adapter explicitly. This avoids specialized functionality from happening like // image derivative creation. // String digestAlgorithm = getFileManager().getDigestAlgorithm(); // Only call this because we seem to need some way of initializing Nuxeo's FileManager with a call. - + FileManagerService fileManagerService = getFileManagerService(); inputStreamBlob = checkMimeType(inputStreamBlob, blobName); FileImporter defaultFileImporter = fileManagerService.getPluginByName("DefaultFileImporter"); result = defaultFileImporter.create( - repoSession.getCoreSession(), inputStreamBlob, blobLocation, overwrite, blobName, getTypeService()); + repoSession.getCoreSession(), inputStreamBlob, blobLocation, overwrite, blobName, getTypeService()); } - + return result; } - + static public BlobsCommon createBlobInRepository( ServiceContext ctx, RepositoryClient repositoryClient, @@ -722,19 +707,19 @@ public class NuxeoBlobUtils { repoSession = getRepositorySession(ctx, repositoryClient); repoSessionCleanup = true; } - + try { // We'll store the blob inside the workspace directory of the calling service String nuxeoWspaceId = ctx.getRepositoryWorkspaceId(); DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId); DocumentModel blobLocation = repoSession.getDocument(nuxeoWspace); - + Blob inputStreamBlob = new FileBlob(inputStream); // creates a temp file to hold the stream DocumentModel documentModel = createDocumentFromBlob( repoSession, - inputStreamBlob, - blobLocation.getPathAsString(), - false, + inputStreamBlob, + blobLocation.getPathAsString(), + false, blobName, useNuxeoAdaptors); result = createBlobsCommon(ctx, documentModel, inputStreamBlob); // Now create the metadata about the Nuxeo blob document @@ -746,13 +731,13 @@ public class NuxeoBlobUtils { releaseRepositorySession(ctx, repositoryClient, repoSession); } } - + return result; } - + /** * Creates the picture. - * + * * @param ctx * the ctx * @param repoSession @@ -760,7 +745,7 @@ public class NuxeoBlobUtils { * @param filePath * the file path * @return the string - * @throws Exception + * @throws Exception */ public static BlobsCommon createBlobInRepository( ServiceContext ctx, @@ -786,11 +771,11 @@ public class NuxeoBlobUtils { logger.debug(String.format("The file '%s''s name has characters that Nuxeo can't deal with. Rather than renaming the file, we created a new temp file at '%s'", originalFile.getName(), targetFile.getAbsolutePath())); } - } - + } + DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace); DocumentModel newBlobFolder = NuxeoUtils.createFolder(wspaceDoc, UUID.randomUUID().toString()); - + result = createBlobInRepository(ctx, repoSession, newBlobFolder, @@ -807,7 +792,7 @@ public class NuxeoBlobUtils { if (targetFile.equals(originalFile) == false) { result.setName(originalFile.getName()); } - + } catch (Exception e) { logger.error("Could not create image blob.", e); throw e; @@ -824,24 +809,24 @@ public class NuxeoBlobUtils { return result; } - + /* * Find out if this document's blob/file-contents are allowed to be purged. For instance, we currently - * only want to allow the purging the contents of Nuxeo "Picture" documents. + * only want to allow the purging the contents of Nuxeo "Picture" documents. */ static private boolean isPurgeAllowed(DocumentModel docModel) { boolean result = false; - + if (docModel.hasFacet(ImagingDocumentConstants.PICTURE_FACET) == true) { result = true; // Yes, delete/purge the original content } - + return result; } - + /** * Creates the image blob. - * + * * @param nuxeoSession * the nuxeo session * @param blobLocation @@ -877,10 +862,10 @@ public class NuxeoBlobUtils { // If the requester wants us to generate only derivatives, we need to purge/clear the original image file if (purgeOriginal == true && isPurgeAllowed(documentModel) == true) { - + // Empty the document model's "content" property -this does not delete the actual file/blob //documentModel.setPropertyValue("file:content", (Serializable) null); - + if (documentModel.hasFacet(ImagingDocumentConstants.PICTURE_FACET)) { // // We're going to use the "source" property field of the Dublin Core schema as a way of indicating to @@ -897,14 +882,14 @@ public class NuxeoBlobUtils { } documentModel.setProperty(CommonAPI.NUXEO_DUBLINCORE_SCHEMANAME, CommonAPI.NUXEO_DUBLINCORE_SOURCE, CommonAPI.URL_SOURCED_PICTURE); - + // Now with no content, the derivative listener wants to update the derivatives. So to // prevent the listener, we remove the "Picture" facet from the document //NuxeoUtils.removeFacet(documentModel, ImagingDocumentConstants.PICTURE_FACET); // Removing this facet ensures the original derivatives are unchanged. // Now that we've emptied the document model's content field, we can add back the Picture facet //NuxeoUtils.addFacet(documentModel, ImagingDocumentConstants.PICTURE_FACET); } - + //nuxeoSession.saveDocument(documentModel); // Next, we need to remove the actual file from Nuxeo's data directory // Blob blob = docBlobHolder.getBlob(); @@ -915,7 +900,7 @@ public class NuxeoBlobUtils { // boolean deleteSuccess = NuxeoUtils.deleteFileOfBlob(docBlobHolder.getBlob()); // } } - + // // Persist/save any changes. // @@ -950,16 +935,16 @@ public class NuxeoBlobUtils { // } // } // } - + public static InputStream getResource(String resourceName) { InputStream result = null; - + try { result = ServiceMain.getInstance().getResourceAsStream(resourceName); } catch (FileNotFoundException e) { logger.error("Missing Services resource: " + resourceName, e); } - + return result; } @@ -968,21 +953,21 @@ public class NuxeoBlobUtils { String repositoryId, StringBuffer outMimeType) throws TransactionException, DocumentNotFoundException { BlobOutput result = null; - + boolean repoSessionCleanup = false; CoreSessionInterface repoSession = (CoreSessionInterface)ctx.getCurrentRepositorySession(); if (repoSession == null) { repoSession = getRepositorySession(ctx, repositoryClient); repoSessionCleanup = true; } - + try { result = getBlobOutput(ctx, repoSession, repositoryId, null, true, outMimeType); if (outMimeType.length() == 0) { BlobsCommon blobsCommon = result.getBlobsCommon(); String mimeType = blobsCommon.getMimeType(); outMimeType.append(mimeType); - } + } } catch (DocumentException e) { if (logger.isDebugEnabled()) { logger.debug(e.getMessage(), e); @@ -994,17 +979,17 @@ public class NuxeoBlobUtils { releaseRepositorySession(ctx, repositoryClient, repoSession); } } - + return result; } - + // // If the blob is not too big, we return a ByteArrayInputStream. Otherwise, we return Nuxeo's InputStream // which is usually a FileInputStream. // static private InputStream getInputStream(BlobsCommon blobsCommon, Blob blob) { InputStream result = null; - + if (blob != null) { try { InputStream blobStream = blob.getStream(); // By default, the result will be whatever stream Nuxeo returns to us. @@ -1025,16 +1010,16 @@ public class NuxeoBlobUtils { } catch (Exception x) { logger.debug(String.format("Exception encountered during InputStream cleanup of file %s", blobsCommon.getName()), x); } - } + } } } - + return result; } - + static public Set getPictureViewNameSet(CoreSessionInterface repoSession, String repositoryId) throws PropertyException { Set result = null; - + DocumentModel docModel = repoSession.getDocument(new IdRef(repositoryId)); Collection views = docModel.getProperty(VIEWS_PROPERTY).getChildren(); if (views != null) { @@ -1043,13 +1028,13 @@ public class NuxeoBlobUtils { result.add((String)property.getValue(TITLE_PROPERTY)); } } - + return result; } - + /** * Gets the image. - * + * * @param repoSession * the repo session * @param repositoryId @@ -1057,7 +1042,7 @@ public class NuxeoBlobUtils { * @param derivativeTerm * the derivative term * @return the image - * @throws DocumentNotFoundException + * @throws DocumentNotFoundException */ static public BlobOutput getBlobOutput(ServiceContext ctx, CoreSessionInterface repoSession, @@ -1103,16 +1088,16 @@ public class NuxeoBlobUtils { isNonImageDerivative = true; } } - + if (docBlob == null && logger.isWarnEnabled()) { String msg = String.format("Could not retrieve document blob from Nuxeo document ID='%s' type='%s' name='%s'", repositoryId, documentModel.getType(), documentModel.getName()); - + if (docBlob == null && docBlobHolder instanceof PictureBlobHolder && derivativeTerm != null) { msg = String.format("Could not retrieve image blob for derivative '%s' of Picture document with Nuxeo ID='%s' and name='%s'", derivativeTerm, repositoryId, documentModel.getName()); } - + if (msg != null) { logger.warn(msg); } @@ -1171,10 +1156,8 @@ public class NuxeoBlobUtils { } outMimeType.append(MIME_JPEG); } -// BufferedInputStream bufferedInputStream = new BufferedInputStream( -// remoteStream); -// result.setBlobInputStream(bufferedInputStream); result.setBlobInputStream(remoteStream); + result.setBlobFile(docBlob.getFile()); } } catch (DocumentNotFoundException d) { throw d; @@ -1187,7 +1170,7 @@ public class NuxeoBlobUtils { return result; } - + } /* @@ -1196,31 +1179,31 @@ public class NuxeoBlobUtils { */ /* - * - * + * + * * MultiviewPictureAdapter org.nuxeo.ecm.platform.picture.api.adapters * PictureResourceAdapter pictureResourceAdapter = (PictureResourceAdapter) * documentModel.getAdapter(PictureResourceAdapter.class); String thumbnailPath * = pictureResourceAdapter.getViewXPath("Thumbnail"); - * + * * Map blobHolderProps = docBlobHolder.getProperties(); * String filePath = docBlobHolder.getFilePath(); List docBlobs = * docBlobHolder.getBlobs(); - * + * * stream = new FileInputStream(fileUploadHolder.getTempFile()); - * + * * public String addFile(InputStream fileUpload, String fileName) fileName = * FileUtils.getCleanFileName(fileName); DocumentModel currentDocument = * navigationContext.getCurrentDocument(); String path = * currentDocument.getPathAsString(); Blob blob = * FileUtils.createSerializableBlob(fileUpload, fileName, null); - * + * * DocumentModel createdDoc = getFileManagerService().createDocumentFromBlob( * documentManager, blob, path, true, fileName); * eventManager.raiseEventsOnDocumentSelected(createdDoc); - * + * * protected FileManager fileManager; - * + * * protected FileManager getFileManagerService() throws ClientException { if * (fileManager == null) { try { fileManager = * Framework.getService(FileManager.class); } catch (Exception e) { @@ -1237,7 +1220,7 @@ public class NuxeoBlobUtils { * repositoryManager.getDescriptor(repositoryName); DefaultBinaryManager * binaryManager = new DefaultBinaryManager( * SQLRepository.getDescriptor(descriptor))); - * + * * File storageDir = binaryManager.getStorageDir(); SQLBlob blob = (SQLBlob) * doc.getPropertyValue("schema:blobField"); File file = * binaryManager.getFileForDigest( blob.getBinary().getDigest(), false); @@ -1245,49 +1228,48 @@ public class NuxeoBlobUtils { /* * RepositoryInstance.getStreamURI() - * + * * String getStreamURI(String blobPropertyId) throws ClientException - * + * * 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. - * + * * 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. - * + * * After the client has called this method, it will be able to download the * stream using streaming server API. - * + * * Returns: an URI identifying the remote stream Throws: ClientException */ /* * A blob contains usually large data. - * + * * Document fields holding Blob data are by default fetched in a lazy manner. - * + * * A Blob object hides the data source and it also describes data properties * like the encoding or mime-type. - * + * * 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. - * + * * When retrieving the content from a document, it will be returned as source * content instead of returning the content bytes. - * + * * The same is true when setting the content for a document: you set a content * source and not directly the content bytes. Ex: - * + * * File file = new File("/tmp/index.html"); FileBlob fb = new FileBlob(file); * fb.setMimeType("text/html"); fb.setEncoding("UTF-8"); // this specifies that * content bytes will be stored as UTF-8 document.setProperty("file", "content", * fb); - * - * + * + * * Then you may want to retrieve the content as follow: - * + * * Blob blob = document.getProperty("file:content"); htmlDoc = blob.getString(); * // the content is decoded from UTF-8 into a java string */ -