]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5466: See JIRA issue for full description. In short, media from originating...
authorRichard Millet <remillet@berkeley.edu>
Tue, 21 Aug 2012 07:33:44 +0000 (00:33 -0700)
committerRichard Millet <remillet@berkeley.edu>
Tue, 21 Aug 2012 07:33:44 +0000 (00:33 -0700)
15 files changed:
services/blob/client/pom.xml
services/blob/client/src/main/java/org/collectionspace/services/client/BlobClient.java
services/blob/service/src/main/java/org/collectionspace/services/blob/nuxeo/BlobDocumentModelHandler.java
services/client/src/main/java/org/collectionspace/services/client/test/BaseServiceTest.java
services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java
services/common/src/main/java/org/collectionspace/services/common/config/TenantBindingConfigReaderImpl.java
services/common/src/main/java/org/collectionspace/services/common/imaging/nuxeo/NuxeoImageUtils.java
services/common/src/main/java/org/collectionspace/services/nuxeo/util/NuxeoUtils.java
services/common/src/main/resources/documentImage.jpg [deleted file]
services/config/src/main/java/org/collectionspace/services/common/config/AbstractConfigReaderImpl.java
services/config/src/main/java/org/collectionspace/services/common/config/ConfigReader.java
services/media/client/src/main/java/org/collectionspace/services/client/MediaClient.java
services/media/client/src/main/java/org/collectionspace/services/client/MediaProxy.java
services/media/client/src/test/java/org/collectionspace/services/client/test/MediaServiceTest.java
services/media/service/src/main/java/org/collectionspace/services/media/MediaResource.java

index 8223e96a3b5631f92d588b2a76533e5d936edbbc..3e8888d039ca35646845c068cd398a012dd63b35 100644 (file)
     <name>services.blob.client</name>
     
     <dependencies>
+        <dependency>
+                       <groupId>org.nuxeo.ecm.core</groupId>
+                       <artifactId>nuxeo-core-storage-sql-management</artifactId>
+                       <version>5.5.0-HF07</version>
+        </dependency>
+               
         <!-- keep slf4j dependencies on the top -->
         <dependency>
             <groupId>org.slf4j</groupId>
index 4033f33de9cbf00721ccd0bdcbb3b58a980702cc..5788d17cf5d1c47de69e915322d164b0c30d45ea 100644 (file)
@@ -38,6 +38,7 @@ public class BlobClient extends AbstractCommonListPoxServiceClientImpl<BlobProxy
        //HTTP query param string for specifying a URI source to blob bits.
        public static final String BLOB_URI_PARAM = "blobUri";
        public static final String BLOB_CSID_PARAM = "blobCsid";
+       public static final String BLOB_PURGE_ORIGINAL = "blobPurgeOrig";
        
        //Image blob metadata labels
        public static final String IMAGE_MEASURED_PART_LABEL = "digitalImage";
index aa4bf816cf67ebb69e08b59e0f206fb4b1de31b9..fc0ed020bf67c0433607808c209862b59d8fef16 100644 (file)
@@ -53,6 +53,8 @@ import org.slf4j.LoggerFactory;
 import java.util.List;
 import java.util.Map;
 
+import javax.ws.rs.core.MultivaluedMap;
+
 import org.dom4j.Element;
 
 /**
@@ -161,10 +163,16 @@ extends DocHandlerBase<BlobsCommon> {
                //
                if (derivativeTerm != null || getContentFlag == true) {
                        StringBuffer mimeTypeBuffer = new StringBuffer();
-                       BlobOutput blobOutput = NuxeoImageUtils.getBlobOutput(ctx, repoSession, //FIXME: REM - If the blob's binary has been removed from the file system, then this call will return null.  We need to at least spit out a meaningful error/warning message
+                       BlobOutput blobOutput = NuxeoImageUtils.getBlobOutput(ctx, repoSession,
                                        blobRepositoryId, derivativeTerm, getContentFlag, mimeTypeBuffer);
                        if (getContentFlag == true) {
-                               blobInput.setContentStream(blobOutput.getBlobInputStream());
+                               if (blobOutput != null) {
+                                       blobInput.setContentStream(blobOutput.getBlobInputStream());
+                               } else {
+                                       // If we can't find the blob's content, we'll return a "missing document" image
+                                       blobInput.setContentStream(NuxeoImageUtils.getResource(NuxeoImageUtils.DOCUMENT_MISSING_PLACEHOLDER_IMAGE));
+                                       mimeTypeBuffer.append(NuxeoImageUtils.MIME_JPEG);
+                               }
                        }
        
                        if (derivativeTerm != null) {
@@ -179,7 +187,7 @@ extends DocHandlerBase<BlobsCommon> {
                                blobInput.setMimeType(mimeType);
                                blobsCommon.setMimeType(mimeType);
                        } else {
-                               blobInput.setMimeType(blobsCommon.getMimeType());
+                               blobInput.setMimeType(blobsCommon.getMimeType());  // Set the MIME type to the one in blobsCommon
                        }
                        
                        blobsCommon.setRepositoryId(null); //hide the repository id from the GET results payload since it is private
@@ -202,12 +210,19 @@ extends DocHandlerBase<BlobsCommon> {
                ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
                BlobInput blobInput = BlobUtil.getBlobInput(ctx); // The blobInput should have been put into the context by the Blob or Media resource
                if (blobInput != null && blobInput.getBlobFile() != null) {             
+                       boolean purgeOriginal = false;
+                       MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
+                       String purgeOriginalStr = queryParams.getFirst(BlobClient.BLOB_PURGE_ORIGINAL);
+                       if (purgeOriginalStr != null && purgeOriginalStr.isEmpty() == false) { // Find our if the caller wants us to purge/delete the original
+                               purgeOriginal = true;
+                       }
                        //
                        // If blobInput has a file then we just received a multipart/form-data file post or a URI query parameter
                        //
                        DocumentModel documentModel = wrapDoc.getWrappedObject();
-                       RepositoryInstance repoSession = this.getRepositorySession();           
-                       BlobsCommon blobsCommon = NuxeoImageUtils.createBlobInRepository(ctx, repoSession, blobInput);
+                       RepositoryInstance repoSession = this.getRepositorySession();
+               
+                       BlobsCommon blobsCommon = NuxeoImageUtils.createBlobInRepository(ctx, repoSession, blobInput, purgeOriginal);
                        blobInput.setBlobCsid(documentModel.getName()); //Assumption here is that the documentModel "name" field is storing a CSID
 
                PoxPayloadIn input = ctx.getInput();
index a729108fd8916558473e2de1201aa5014c0c8b3d..03e4267f46f1352c23dc13dca22a648dcfc7d4dd 100644 (file)
@@ -25,7 +25,6 @@ package org.collectionspace.services.client.test;
 \r
 import java.io.ByteArrayInputStream;\r
 import java.io.File;\r
-import java.io.InputStream;\r
 import java.io.StringWriter;\r
 import java.lang.reflect.Method;\r
 import java.util.ArrayList;\r
index 3a93a231b7fbc7160dca77c8bb9359a9df6879a8..43bdcdad08f1c5ee30f9e817388334843d85f249 100644 (file)
@@ -3,6 +3,10 @@
  */\r
 package org.collectionspace.services.common;\r
 \r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.InputStream;\r
 import java.sql.Connection;\r
 import java.sql.PreparedStatement;\r
 import java.sql.ResultSet;\r
@@ -18,6 +22,7 @@ import org.collectionspace.authentication.AuthN;
 \r
 import org.collectionspace.services.config.service.InitHandler;\r
 import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon;\r
+import org.collectionspace.services.common.config.ConfigReader;\r
 import org.collectionspace.services.common.config.ServicesConfigReaderImpl;\r
 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;\r
 import org.collectionspace.services.common.init.AddIndices;\r
@@ -321,6 +326,15 @@ public class ServiceMain {
     public String getServerRootDir() {\r
         return serverRootDir;\r
     }\r
+    \r
+    public InputStream getResourceAsStream(String resourceName) throws FileNotFoundException {\r
+       InputStream result = null;\r
+       \r
+       String resourcePath = getServerRootDir() + File.separator + ConfigReader.RESOURCES_DIR_PATH + File.separator + resourceName;\r
+       result = new FileInputStream(new File(resourcePath));\r
+       \r
+       return result;\r
+    }\r
 \r
     /*\r
      * Save a copy of the DataSource instances that exist in our initial JNDI context.  For some reason, after starting up\r
index f6a4295d2f8aa6ba4cd44ba5c6276d37af69af84..e218427dd7528db5b9a0cb8cda61040197ed382d 100644 (file)
@@ -470,6 +470,6 @@ public class TenantBindingConfigReaderImpl
     }
 
     public String getResourcesDir(){
-        return getConfigRootDir() + File.separator + "resources";
+        return getConfigRootDir() + File.separator + RESOURCES_DIR_NAME;
     }
 }
index 704aefff3aced306bda791133618b357331a1705..67af453bcd539202bdd34f8a99b5ed435e8a0dfd 100644 (file)
@@ -30,17 +30,24 @@ import java.awt.Color;
 import java.awt.Font;\r
 import java.awt.Graphics;\r
 import java.awt.image.BufferedImage;\r
+import java.io.ByteArrayInputStream;\r
 import java.io.File;\r
 import java.io.ByteArrayOutputStream;\r
+import java.io.FileDescriptor;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
 import java.io.InputStream;\r
 import java.io.BufferedInputStream;\r
 import java.io.IOException;\r
+import java.io.Serializable;\r
 import java.math.BigDecimal;\r
 import java.math.BigInteger;\r
 import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Random;\r
+import java.util.Set;\r
+import java.lang.reflect.Field;\r
 \r
 import javax.imageio.ImageIO;\r
 \r
@@ -51,6 +58,7 @@ import org.nuxeo.runtime.api.Framework;
 //import org.nuxeo.common.utils.FileUtils;\r
 \r
 import org.nuxeo.ecm.platform.picture.api.ImageInfo;\r
+import org.nuxeo.ecm.platform.picture.api.ImagingDocumentConstants;\r
 import org.nuxeo.ecm.platform.picture.api.ImagingService;\r
 import org.nuxeo.ecm.platform.picture.api.PictureView;\r
 \r
@@ -69,7 +77,12 @@ import org.nuxeo.ecm.core.repository.RepositoryService;
 //import org.nuxeo.ecm.core.api.ejb.DocumentManagerBean;\r
 //import org.nuxeo.ecm.core.storage.sql.RepositoryImpl;\r
 //import org.nuxeo.ecm.core.storage.sql.Repository;\r
+import org.nuxeo.ecm.core.storage.sql.Binary;\r
+import org.nuxeo.ecm.core.storage.sql.BinaryManager;\r
 import org.nuxeo.ecm.core.storage.sql.DefaultBinaryManager;\r
+import org.nuxeo.ecm.core.storage.sql.RepositoryImpl;\r
+import org.nuxeo.ecm.core.storage.sql.RepositoryResolver;\r
+import org.nuxeo.ecm.core.storage.sql.coremodel.SQLBlob;\r
 import org.nuxeo.ecm.core.storage.sql.coremodel.SQLRepository;\r
 //import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor;\r
 \r
@@ -77,6 +90,7 @@ import org.nuxeo.ecm.core.storage.sql.coremodel.SQLRepository;
 import org.nuxeo.ecm.core.api.IdRef;\r
 import org.nuxeo.ecm.core.api.blobholder.BlobHolder;\r
 import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder;\r
+import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;\r
 import org.nuxeo.ecm.core.api.impl.blob.FileBlob;\r
 import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob;\r
 import org.nuxeo.ecm.core.api.impl.blob.ByteArrayBlob;\r
@@ -95,6 +109,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;\r
 //import org.nuxeo.ecm.core.repository.jcr.testing.RepositoryOSGITestCase;\r
 \r
+import org.collectionspace.services.common.ServiceMain;\r
 import org.collectionspace.services.common.blob.BlobInput;\r
 import org.collectionspace.services.common.context.ServiceContext;\r
 import org.collectionspace.services.common.datetime.GregorianCalendarDateTimeUtils;\r
@@ -108,22 +123,24 @@ import org.collectionspace.services.blob.MeasuredPartGroupList;
 import org.collectionspace.services.jaxb.BlobJAXBSchema;\r
 import org.collectionspace.services.nuxeo.client.java.CommonList;\r
 import org.collectionspace.services.nuxeo.extension.thumbnail.ThumbnailConstants;\r
+import org.collectionspace.services.nuxeo.util.NuxeoUtils;\r
 import org.collectionspace.services.common.blob.BlobOutput;\r
 \r
 import org.collectionspace.services.config.service.ListResultField;\r
 \r
-//import org.collectionspace.ecm.platform.quote.api.QuoteManager;\r
 \r
-// TODO: Auto-generated Javadoc\r
 /**\r
  * The Class NuxeoImageUtils.\r
  */\r
 public class NuxeoImageUtils {\r
+               \r
        /** The Constant logger. */\r
        private static final Logger logger = LoggerFactory\r
                        .getLogger(NuxeoImageUtils.class);\r
 \r
-       private static final String MIME_JPEG = "image/jpeg";\r
+       public static final String DOCUMENT_PLACEHOLDER_IMAGE = "documentImage.jpg";\r
+       public static final String DOCUMENT_MISSING_PLACEHOLDER_IMAGE = "documentImageMissing.jpg";\r
+       public static final String MIME_JPEG = "image/jpeg";\r
        /*\r
         * FIXME: REM - These constants should be coming from configuration and NOT\r
         * hard coded.\r
@@ -267,8 +284,10 @@ public class NuxeoImageUtils {
                // List<BlobListItem> blobListItems = result.getBlobListItem();\r
                HashMap<String, Object> item = null;\r
                for (Blob blob : docBlobs) {\r
-                       item = createBlobListItem(blob, uri);\r
-                       commonList.addItem(item);\r
+                       if (blob != null) {\r
+                               item = createBlobListItem(blob, uri);\r
+                               commonList.addItem(item);\r
+                       }\r
                }\r
 \r
                return commonList;\r
@@ -724,6 +743,19 @@ public class NuxeoImageUtils {
                }\r
                return result;\r
        }\r
+       \r
+       private static BinaryManager getBinaryManagerService() throws ClientException {\r
+               BinaryManager result = null;\r
+               try {\r
+                       result = Framework.getService(BinaryManager.class);\r
+               } catch (Exception e) {\r
+                       String msg = "Unable to get Nuxeo's BinaryManager service.";\r
+                       logger.error(msg, e);\r
+                       throw new ClientException("msg", e);\r
+               }\r
+               return result;\r
+       }\r
+       \r
 \r
        /**\r
         * Creates the picture.\r
@@ -738,7 +770,9 @@ public class NuxeoImageUtils {
         * @throws Exception \r
         */\r
        public static BlobsCommon createBlobInRepository(ServiceContext ctx,\r
-                       RepositoryInstance repoSession, BlobInput blobInput) throws Exception {\r
+                       RepositoryInstance repoSession,\r
+                       BlobInput blobInput,\r
+                       boolean purgeOriginal) throws Exception {\r
                BlobsCommon result = null;\r
 \r
                try {\r
@@ -756,7 +790,7 @@ public class NuxeoImageUtils {
                    }\r
             }                  \r
 \r
-                       result = createBlobInRepository(repoSession, wspaceDoc, blobFile, null /*mime type*/);\r
+                       result = createBlobInRepository(repoSession, wspaceDoc, purgeOriginal, blobFile, null /*mime type*/);\r
                } catch (Exception e) {\r
                        logger.error("Could not create image blob", e);\r
                        throw e;\r
@@ -782,8 +816,9 @@ public class NuxeoImageUtils {
         */\r
        static public BlobsCommon createBlobInRepository(RepositoryInstance nuxeoSession,\r
                        DocumentModel blobLocation,\r
-                       // InputStream file,\r
-                       File file, String mimeType) {\r
+                       boolean purgeOriginal,\r
+                       File file,\r
+                       String mimeType) {\r
                BlobsCommon result = null;\r
 \r
                try {\r
@@ -799,8 +834,29 @@ public class NuxeoImageUtils {
                                                        blobLocation.getPathAsString(), true,\r
                                                        file.getName());\r
                        logger.debug("Stop --> Finished calling Nuxeo to create the blob document.");\r
-                       \r
+\r
                        result = createBlobsCommon(documentModel, fileBlob); // Now create our metadata resource document\r
+\r
+                       // If the sender only wanted use to generate derivatives, we need to clear the original content\r
+                       if (purgeOriginal == true) {\r
+                               // Empty the document model's "content" property -this does not delete the actual file/blob\r
+                               documentModel.setPropertyValue("file:content", (Serializable) null);\r
+                               \r
+                               if (documentModel.hasFacet(ImagingDocumentConstants.PICTURE_FACET)) {\r
+                                       // Now with no content, the derivative listener wants to update the derivatives. So to\r
+                                       // prevent the listener, we remove the "Picture" facet from the document\r
+                                       NuxeoUtils.removeFacet(documentModel, ImagingDocumentConstants.PICTURE_FACET); // Removing this facet ensures the original derivatives are unchanged.\r
+                                       nuxeoSession.saveDocument(documentModel);\r
+                                       // Now that we've emptied the document model's content field, we can add back the Picture facet\r
+                                       NuxeoUtils.addFacet(documentModel, ImagingDocumentConstants.PICTURE_FACET);\r
+                               }\r
+                               \r
+                               nuxeoSession.saveDocument(documentModel);\r
+                               // Next, we need to remove the actual file from Nuxeo's data directory\r
+                               DocumentBlobHolder docBlobHolder = (DocumentBlobHolder) documentModel\r
+                                               .getAdapter(BlobHolder.class);\r
+                               boolean deleteSuccess = NuxeoUtils.deleteFileOfBlob(docBlobHolder.getBlob());\r
+                       }\r
                } catch (Exception e) {\r
                        result = null;\r
                        logger.error("Could not create new Nuxeo blob document.", e); //FIXME: REM - This should probably be re-throwing the exception?\r
@@ -829,6 +885,18 @@ public class NuxeoImageUtils {
        // }\r
        // }\r
        // }\r
+       \r
+       public static InputStream getResource(String resourceName) {\r
+               InputStream result = null;\r
+               \r
+               try {\r
+                       result = ServiceMain.getInstance().getResourceAsStream(resourceName);\r
+               } catch (FileNotFoundException e) {\r
+                       logger.error("Missing Services resource: " + resourceName, e);\r
+               }\r
+        \r
+               return result;\r
+       }\r
 \r
        /**\r
         * Gets the image.\r
@@ -869,7 +937,7 @@ public class NuxeoImageUtils {
                                        if (derivativeTerm != null) {\r
                                                docBlob = pictureBlobHolder.getBlob(derivativeTerm);\r
                                                // Nuxeo derivatives are all JPEG\r
-                                               outMimeType.append(docBlob.getMimeType());\r
+                                               outMimeType.append(MIME_JPEG); // All Nuxeo image derivatives are JPEG images.\r
                                        } else {\r
                                                docBlob = pictureBlobHolder.getBlob();\r
                                        }\r
@@ -890,15 +958,13 @@ public class NuxeoImageUtils {
                                if (getContentFlag == true) {\r
                                        InputStream remoteStream = null;\r
                                        if (isNonImageDerivative == false) {\r
-                                               remoteStream = docBlob.getStream();\r
+                                               remoteStream = docBlob.getStream(); // This will fail if the blob's file has been deleted. FileNotFoundException thrown.\r
                                        } else {\r
-                                               remoteStream = NuxeoImageUtils.class.getClassLoader() // for now, non-image derivatives are just placeholder document images\r
-                                                   .getResourceAsStream("documentImage.jpg");\r
+                                               remoteStream = getResource(DOCUMENT_PLACEHOLDER_IMAGE);\r
                                                outMimeType.append(MIME_JPEG);\r
                                        }\r
                                        BufferedInputStream bufferedInputStream = new BufferedInputStream(\r
-                                                       remoteStream);  // FIXME: REM - To improve performance, try\r
-                                                                                       // BufferedInputStream(InputStream in, int size)?\r
+                                                       remoteStream);  \r
                                        result.setBlobInputStream(bufferedInputStream);\r
                                }\r
                        } catch (Exception e) {\r
index a3ed9fb36b76fe24bbe5c085fb26db79424295cf..aa525b748852d0ed863e31d778c1143b348bd8c7 100644 (file)
@@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.File;
+import java.lang.reflect.Field;
 
 import java.util.GregorianCalendar;
 import java.util.List;
@@ -49,6 +50,7 @@ import org.nuxeo.ecm.core.api.DocumentModel;
 import org.nuxeo.ecm.core.api.DocumentModelList;
 import org.nuxeo.ecm.core.api.ClientException;
 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
+import org.nuxeo.ecm.core.api.Blob;
 import org.nuxeo.ecm.core.api.CoreSession;
 import org.nuxeo.ecm.core.api.DocumentRef;
 import org.nuxeo.ecm.core.api.IdRef;
@@ -64,6 +66,8 @@ import org.nuxeo.ecm.core.io.impl.plugins.XMLDocumentWriter;
 
 import org.nuxeo.ecm.core.schema.SchemaManager;
 import org.nuxeo.ecm.core.search.api.client.querymodel.descriptor.QueryModelDescriptor;
+import org.nuxeo.ecm.core.storage.sql.Binary;
+import org.nuxeo.ecm.core.storage.sql.coremodel.SQLBlob;
 import org.nuxeo.runtime.api.Framework;
 
 
@@ -91,7 +95,94 @@ public class NuxeoUtils {
     //private static final String ORDER_BY_CLAUSE_REGEX = "\\w+(_\\w+)?:\\w+( ASC| DESC)?(, \\w+(_\\w+)?:\\w+( ASC| DESC)?)*";    
                // Allow paths so can sort on complex fields. CSPACE-4601
     private static final String ORDER_BY_CLAUSE_REGEX = "\\w+(_\\w+)?:\\w+(/(\\*|\\w+))*( ASC| DESC)?(, \\w+(_\\w+)?:\\w+(/(\\*|\\w+))*( ASC| DESC)?)*";
+       
+    /* 
+     * Keep this method private.  This method uses reflection to gain access to a protected field in Nuxeo's "Binary" class.  Once we learn how
+     * to locate the "file" field of a Binary instance without breaking our "contract" with this class, we should minimize
+     * our use of this method.
+     */
+    private static File getFileOfBlob(Blob blob) {
+       File result = null;
+       
+       if (blob instanceof SQLBlob) {
+               SQLBlob sqlBlob = (SQLBlob)blob;
+               Binary binary = sqlBlob.getBinary();
+               try {
+                       Field fileField = binary.getClass().getDeclaredField("file");
+                       boolean accessibleState = fileField.isAccessible();
+                       if (accessibleState == false) {
+                               fileField.setAccessible(true);
+                       }
+                       result = (File)fileField.get(binary);
+                       fileField.setAccessible(accessibleState); // set it back to its original access state
+               } catch (Exception e) {
+                       logger.error("Was not able to find the 'file' field", e);
+               }               
+       }
+       
+       return result;
+    }
+    
+    static public boolean deleteFileOfBlob(Blob blob) {
+       boolean result = false;
+       
+       File fileToDelete = getFileOfBlob(blob);
+       result = fileToDelete.delete();
+               if (result == false) {
+                       logger.warn("Could not delete the blob file at: " + fileToDelete.getAbsolutePath());
+               }
+       
+       return result;
+    }
+    
+    /*
+     * This method will fail to return a facet list if non exist or if Nuxeo changes the
+     * DocumentModelImpl class "facets" field to be of a different type or if they remove it altogether.
+     */
+    public static Set<String> getFacets(DocumentModel docModel) {
+       Set<String> result = null;
+       
+       try {
+                       Field f = docModel.getClass().getDeclaredField("facets");
+                       f.setAccessible(true);
+                       result = (Set<String>) f.get(docModel);
+                       f.setAccessible(false);
+       } catch (Exception e) {
+               logger.error("Could not remove facet from DocumentModel instance: " + docModel.getId(), e);
+       }
+       
+       return result;
+    }
+    
+    /*
+     * Remove a Nuxeo facet from a document model instance
+     */
+    public static boolean removeFacet(DocumentModel docModel, String facet) {
+       boolean result = false;
+       
+       Set<String> facets = getFacets(docModel);
+       if (facets != null && facets.contains(facet)) {
+               facets.remove(facet);
+               result = true;
+       }
+               
+               return result;
+    }
+    
+    /*
+     * Adds a Nuxeo facet to a document model instance
+     */
+    public static boolean addFacet(DocumentModel docModel, String facet) {
+       boolean result = false;
+       
+       Set<String> facets = getFacets(docModel);
+       if (facets != null && !facets.contains(facet)) {
+               facets.add(facet);
+               result = true;
+       }
                
+               return result;
+    }    
 
     public static void exportDocModel(DocumentModel src) {
        DocumentReader reader = null;
diff --git a/services/common/src/main/resources/documentImage.jpg b/services/common/src/main/resources/documentImage.jpg
deleted file mode 100644 (file)
index 89d5066..0000000
Binary files a/services/common/src/main/resources/documentImage.jpg and /dev/null differ
index 54269fdd7e10ef7b691b603fb4bcb5c400f349a0..eb3439c2b0cb908d0231116f20cb60eb957c39d9 100644 (file)
@@ -144,7 +144,7 @@ public abstract class AbstractConfigReaderImpl<T>
     protected String getAbsoluteFileName(String configFileName) {
         return serverRootDir
                 + File.separator + CSPACE_DIR_NAME
-                + File.separator + CONFIG_DIR_NAME
+                + File.separator + CONFIG_DIR_PATH
                 + File.separator + configFileName;
     }
 
@@ -155,6 +155,6 @@ public abstract class AbstractConfigReaderImpl<T>
     protected String getConfigRootDir() {
         return serverRootDir
         + File.separator + CSPACE_DIR_NAME
-        + File.separator + CONFIG_DIR_NAME;
+        + File.separator + CONFIG_DIR_PATH;
     }
 }
index 74bf767d2bdde499692850d29b029c079ac57464..0ba485543e6edab5456c5f76ab7460ff725f8a50 100644 (file)
@@ -31,7 +31,9 @@ import java.io.File;
 public interface ConfigReader<T> {
 
     final public static String CSPACE_DIR_NAME = "cspace";
-    final public static String CONFIG_DIR_NAME = "config" + File.separator + "services";
+    final public static String CONFIG_DIR_PATH = "config" + File.separator + "services";
+    final public static String RESOURCES_DIR_NAME = "resources";
+    final public static String RESOURCES_DIR_PATH = CSPACE_DIR_NAME + File.separator + CONFIG_DIR_PATH + File.separator + RESOURCES_DIR_NAME;
 
     /**
      * getFileName - get configuration file name
index 7943c13dff8705105ad569a5c0cd5b773652ed21..0a28ffc57825e6e2f7e76f73daa0438aff0ee460 100644 (file)
@@ -78,8 +78,8 @@ public class MediaClient extends AbstractCommonListPoxServiceClientImpl<MediaPro
     /*
      * Create both a new media record
      */
-    public ClientResponse<Response> createMediaAndBlobWithUri(PoxPayloadOut xmlPayload, String blobUri) {
-       return getProxy().createMediaAndBlobWithUri(xmlPayload.getBytes(), blobUri);
+    public ClientResponse<Response> createMediaAndBlobWithUri(PoxPayloadOut xmlPayload, String blobUri, boolean purgeOriginal) {
+       return getProxy().createMediaAndBlobWithUri(xmlPayload.getBytes(), blobUri, purgeOriginal);
     }
         
     /**
index d91b08ecb13dc33befdcb287b5612cf2964785bd..9d39f503e7e05e18f64731420d4fda62a67fcd1f 100644 (file)
@@ -39,5 +39,6 @@ public interface MediaProxy extends CollectionSpaceCommonListPoxProxy {
        @Produces("application/xml")
        @Consumes("application/xml")
     ClientResponse<Response>createMediaAndBlobWithUri(byte[] xmlPayload,
-               @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri);    
+               @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri,
+               @QueryParam(BlobClient.BLOB_PURGE_ORIGINAL) boolean purgeOriginal);    
 }
index b6c3318d2f8919f4d2b9e0302e93074135f5cea4..d491d90d683024693286f01204edcc93aff4ae2c 100644 (file)
@@ -206,11 +206,12 @@ public class MediaServiceTest extends AbstractPoxServiceTestImpl<AbstractCommonL
     public void createMediaAndBlobWithUri(String testName) throws Exception {
                MediaClient client = new MediaClient();
                PoxPayloadOut multipart = createMediaInstance(createIdentifier());
-               ClientResponse<Response> mediaRes = client.createMediaAndBlobWithUri(multipart, PUBLIC_URL_DECK);
+               ClientResponse<Response> mediaRes = client.createMediaAndBlobWithUri(multipart, PUBLIC_URL_DECK, true); // purge the original
                String mediaCsid = null;
                try {
                        assertStatusCode(mediaRes, testName);
                        mediaCsid = extractId(mediaRes);
+//                     allResourceIdsCreated.add(mediaCsid); // Re-enable this and also add code to delete the associated blob
                } finally {
                        if (mediaRes != null) {
                                mediaRes.releaseConnection();
index 0afbf1717fdbcf3b3e81d9f9caac56e6c5614bc9..eaa97f7c0f40e9a449262aa02c448c0e0637b5ac 100644 (file)
@@ -124,9 +124,11 @@ public class MediaResource extends ResourceBase {
        Response response = null;
        
        try {
-               ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(BlobClient.SERVICE_NAME, (PoxPayloadIn)null); // The blobUri argument is our payload
+            MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
+               ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(BlobClient.SERVICE_NAME,
+                               queryParams);
                BlobInput blobInput = BlobUtil.getBlobInput(ctx); // the blob doc handler will look for this in the context
-               blobInput.createBlobFile(blobUri);
+               blobInput.createBlobFile(blobUri); // The blobUri argument is our payload
                response = this.create((PoxPayloadIn)null, ctx); // By now the binary bits have been created and we just need to create the metadata blob record -this info is in the blobInput var
        } catch (Exception e) {
                throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
@@ -136,7 +138,7 @@ public class MediaResource extends ResourceBase {
     }
     
     /*
-     * Looks for a blobUri query param from a POST.  If it finds one then it creates a blob and a media resource and associates them.
+     * Looks for a blobUri query param from a POST.  If it finds one then it creates a blob AND a media resource and associates them.
      * (non-Javadoc)
      * @see org.collectionspace.services.common.ResourceBase#create(org.collectionspace.services.common.context.ServiceContext, org.collectionspace.services.common.ResourceMap, javax.ws.rs.core.UriInfo, java.lang.String)
      */
@@ -153,7 +155,7 @@ public class MediaResource extends ResourceBase {
         MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
         String blobUri = queryParams.getFirst(BlobClient.BLOB_URI_PARAM);
         if (blobUri != null && blobUri.isEmpty() == false) {
-               result = createBlobWithUri(resourceMap, ui, xmlPayload, blobUri);
+               result = createBlobWithUri(resourceMap, ui, xmlPayload, blobUri); // uses the blob resource and doc handler to create the blob
                String blobCsid = CollectionSpaceClientUtils.extractId(result);
                queryParams.add(BlobClient.BLOB_CSID_PARAM, blobCsid); // Add the new blob's csid as an artificial query param -the media doc handler will look for this
         }
@@ -180,7 +182,7 @@ public class MediaResource extends ResourceBase {
                ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(BlobClient.SERVICE_NAME, input);
                BlobInput blobInput = BlobUtil.getBlobInput(ctx);
                blobInput.createBlobFile(blobUri);
-               response = this.create(input, ctx);
+               response = this.create(input, ctx); // calls the blob resource/doc-handler to create the blob
                //
                // Next, update the Media record to be linked to the blob
                //