\r
import javax.servlet.http.HttpServletRequest;\r
\r
-//import org.collectionspace.services.blob.BlobsCommonList; \r
-//import org.collectionspace.services.jaxb.AbstractCommonList;\r
import org.collectionspace.services.nuxeo.client.java.CommonList;\r
-//import org.collectionspace.services.blob.nuxeo.BlobDocumentModelHandler;\r
-//import org.collectionspace.services.common.FileUtils;\r
import org.collectionspace.services.common.Download;\r
import org.collectionspace.services.common.document.DocumentException;\r
-import org.slf4j.LoggerFactory;\r
+import org.collectionspace.services.common.imaging.nuxeo.NuxeoBlobUtils;\r
+\r
import org.apache.commons.io.FileUtils;\r
\r
public class BlobInput {\r
private File blobFile = null;\r
private String blobUri = null;\r
private String blobMimeType = null;\r
+ private String originalFileName = null;\r
\r
private String derivativeTerm;\r
private boolean derivativeListRequested = false;\r
this.blobUri = blobUri;\r
}\r
\r
+ /*\r
+ * Save the original file name in case we rename it because of illegal Nuxeo file name characters\r
+ */\r
+ private void setBlobFileName(String fileName) throws Exception {\r
+ String sanitizedResult = NuxeoBlobUtils.getSanizitedFilename(fileName);\r
+ if (fileName.equals(sanitizedResult) == true) {\r
+ originalFileName = null; //\r
+ } else {\r
+ originalFileName = fileName;\r
+ }\r
+ }\r
+ \r
+ public String getBlobFilename() throws Exception {\r
+ String result = null;\r
+ \r
+ if (originalFileName != null && originalFileName.trim().isEmpty() == false) {\r
+ result = originalFileName;\r
+ } else {\r
+ File theBlobFile = this.getBlobFile();\r
+ if (theBlobFile != null) {\r
+ result = theBlobFile.getName();\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Add a log warning if the blob file name fails Nuxeo's file name restrictions.\r
+ //\r
+ String sanitizedResult = NuxeoBlobUtils.getSanizitedFilename(result);\r
+ if (result.equals(sanitizedResult) == false) {\r
+ logger.warn(String.format("The file name '%s' contains characters that Nuxeo deems illegal.",\r
+ result));\r
+ } \r
+ \r
+ return result;\r
+ }\r
+ \r
/*\r
* Getters and Setters\r
*/\r
return blobFile;\r
}\r
\r
- public void setBlobFile(File blobFile) {\r
+ public void setBlobFile(File blobFile) throws Exception {\r
this.blobFile = blobFile;\r
+ if (blobFile != null) {\r
+ String fileName = blobFile.getName();\r
+ setBlobFileName(fileName);\r
+ }\r
}\r
\r
public String getBlobUri() {\r
// FIXME: REM - The callers of this method are sending us a multipart form-data post, so why\r
// are we also receiving the blobUri?\r
//\r
- public void createBlobFile(HttpServletRequest req, String blobUri) {\r
+ public void createBlobFile(HttpServletRequest req, String blobUri) throws Exception {\r
File tmpFile = org.collectionspace.services.common.FileUtils.createTmpFile(req);\r
this.setBlobFile(tmpFile);\r
this.setBlobUri(blobUri);\r
\r
if (blobUrl.getProtocol().equalsIgnoreCase("http")) {\r
Download fetchedFile = new Download(blobUrl);\r
- logger.debug("Starting blob download into temp file:" + fetchedFile.getFilePath());\r
+ if (logger.isDebugEnabled() == true) {\r
+ logger.debug("Starting blob download into temp file:" + fetchedFile.getFilePath());\r
+ }\r
while (fetchedFile.getStatus() == Download.DOWNLOADING) {\r
// Do nothing while we wait for the file to download\r
}\r
- logger.debug("Finished blob download into temp file: " + fetchedFile.getFilePath());\r
+ if (logger.isDebugEnabled() == true) {\r
+ logger.debug("Finished blob download into temp file: " + fetchedFile.getFilePath());\r
+ }\r
\r
int status = fetchedFile.getStatus();\r
if (status == Download.COMPLETE) {\r
import org.nuxeo.ecm.core.repository.RepositoryManager;\r
\r
import org.nuxeo.ecm.core.repository.RepositoryService;\r
-//import org.nuxeo.runtime.model.ComponentManager;\r
-//import org.nuxeo.runtime.model.impl.ComponentManagerImpl;\r
-//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
+\r
+/*\r
+ * Keep these commented out import statements as reminders of Nuxeo's blob management\r
+import org.nuxeo.runtime.model.ComponentManager;\r
+import org.nuxeo.runtime.model.impl.ComponentManagerImpl;\r
+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.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
+import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor;\r
+import org.nuxeo.ecm.core.api.DocumentResolver;\r
+*/\r
\r
-//import org.nuxeo.ecm.core.api.DocumentResolver;\r
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.InputStreamBlob;\r
import org.nuxeo.ecm.core.api.impl.blob.StreamingBlob;\r
import org.nuxeo.ecm.core.api.repository.Repository;\r
import org.nuxeo.ecm.core.api.Blob;\r
import org.nuxeo.ecm.core.api.ClientException;\r
-import org.nuxeo.ecm.core.api.CoreSession;\r
import org.nuxeo.ecm.core.api.DocumentModel;\r
import org.nuxeo.ecm.core.api.DocumentRef;\r
import org.nuxeo.ecm.core.event.EventServiceAdmin;\r
-import org.nuxeo.ecm.core.event.impl.EventListenerList;\r
\r
-import org.nuxeo.ecm.core.schema.DocumentType;\r
import org.nuxeo.ecm.core.schema.SchemaManager;\r
import org.nuxeo.ecm.core.schema.types.Schema;\r
\r
\r
import org.collectionspace.services.client.PoxPayloadIn;\r
import org.collectionspace.services.client.PoxPayloadOut;\r
+import org.collectionspace.services.common.FileUtils;\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.document.DocumentException;\r
import org.collectionspace.services.common.document.TransactionException;\r
import org.collectionspace.services.common.repository.RepositoryClient;\r
import org.collectionspace.services.common.api.GregorianCalendarDateTimeUtils;\r
+import org.collectionspace.services.common.blob.BlobOutput;\r
import org.collectionspace.services.blob.BlobsCommon;\r
import org.collectionspace.services.blob.DimensionSubGroup;\r
import org.collectionspace.services.blob.DimensionSubGroupList;\r
import org.collectionspace.services.blob.MeasuredPartGroup;\r
import org.collectionspace.services.blob.MeasuredPartGroupList;\r
-//import org.collectionspace.services.blob.BlobsCommonList;\r
-//import org.collectionspace.services.blob.BlobsCommonList.BlobListItem;\r
import org.collectionspace.services.jaxb.BlobJAXBSchema;\r
import org.collectionspace.services.nuxeo.client.java.CommonList;\r
import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;\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
\r
private static final Logger logger = LoggerFactory\r
.getLogger(NuxeoBlobUtils.class);\r
\r
+ //\r
+ // File name constants\r
+ //\r
+ private static final String NUXEO_FILENAME_BAD_CHARS = "[^a-zA-Z_0-9-.%:/\\ ]";\r
+ private static final String NUXEO_FILENAME_VALID_STRING = "[a-zA-Z_0-9-.%:/\\ ]+";\r
+\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
public static final String SCHEMA_IMAGE_METADATA = "image_metadata";\r
\r
private static final int THUMB_SIZE_HEIGHT = 100;\r
-\r
private static final int THUMB_SIZE_WIDTH = 75;\r
\r
// static DefaultBinaryManager binaryManager = new DefaultBinaryManager();\r
\r
return item;\r
}\r
+ \r
+ static public String getSanizitedFilename(File srcFile) throws Exception {\r
+ return getSanizitedFilename(srcFile.getName());\r
+ }\r
+ \r
+ /*\r
+ * Valid Nuxeo file names are a subset of *nix and Windows filenames, so we need to check.\r
+ */\r
+ static public String getSanizitedFilename(String fileName) throws Exception {\r
+ String result = fileName;\r
+ \r
+ if (fileName != null && fileName.matches(NUXEO_FILENAME_VALID_STRING) == false) {\r
+ String fixedString = fileName.replaceAll(NUXEO_FILENAME_BAD_CHARS, "_"); // Replace "bad" chars with underscore character\r
+ if (fixedString.matches(NUXEO_FILENAME_VALID_STRING) == true) {\r
+ result = fixedString;\r
+ } else {\r
+ String errMsg = String.format("\tSorry, the sanizited string '%s' is still bad.", fixedString);\r
+ throw new Exception(errMsg);\r
+ }\r
+ }\r
+ \r
+ if (result != null && logger.isDebugEnabled() == true) {\r
+ if (result.equals(fileName) == false) {\r
+ logger.debug(String.format("The file name '%s' was sanizitized to '%s'.", fileName, result));\r
+ }\r
+ }\r
+\r
+ return result;\r
+ }\r
\r
static public CommonList getBlobDerivatives(RepositoryInstance repoSession,\r
String repositoryId, List<ListResultField> resultsFields, String uri)\r
return blob;\r
}\r
\r
- private static Blob createNuxeoFileBasedBlob(File file) {\r
- Blob result = null;\r
-\r
- result = new FileBlob(file);\r
- return result;\r
+ private static Blob createNuxeoFileBasedBlob(File file) throws Exception {\r
+ return new FileBlob(file);\r
}\r
\r
/**\r
boolean useNuxeoAdaptors) throws Exception {\r
BlobsCommon result = null;\r
\r
+ File originalFile = blobInput.getBlobFile();\r
+ File targetFile = originalFile;\r
try {\r
- File blobFile = blobInput.getBlobFile();\r
// We'll store the blob inside the workspace directory of the calling service\r
String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();\r
DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);\r
DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);\r
+ //\r
+ // If the original file's name contains "illegal" characters, then we create a copy of the file to give Nuxeo.\r
+ //\r
+ String sanitizedName = NuxeoBlobUtils.getSanizitedFilename(originalFile);\r
+ if (sanitizedName.equals(originalFile.getName()) == false) {\r
+ targetFile = FileUtils.createTmpFile(originalFile, sanitizedName);\r
+ if (logger.isDebugEnabled() == true) {\r
+ 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'",\r
+ originalFile.getName(), targetFile.getAbsolutePath()));\r
+ }\r
+ } \r
\r
result = createBlobInRepository(repoSession,\r
wspaceDoc,\r
purgeOriginal,\r
- blobFile, \r
+ targetFile, \r
null, // MIME type\r
useNuxeoAdaptors);\r
+ //\r
+ // Make sure we're using the original file name in our BlobsCommon instance. If the original file's name\r
+ // contained illegal characters, then we created and handed a copy of the file to Nuxeo. We don't want the\r
+ // copy's file name stored in the BlobsCommon instance, we want the original file name instead.\r
+ //\r
+ if (targetFile.equals(originalFile) == false) {\r
+ result.setName(originalFile.getName());\r
+ }\r
+ \r
} catch (Exception e) {\r
- logger.error("Could not create image blob", e);\r
+ logger.error("Could not create image blob.", e);\r
throw e;\r
+ } finally {\r
+ \r
}\r
\r
return result;\r
BlobsCommon result = null;\r
\r
try {\r
- // Blob fileBlob = createStreamingBlob(blobFile, blobFile.getName(),\r
- // mimeType);\r
Blob fileBlob = createNuxeoFileBasedBlob(file);\r
\r
DocumentModel documentModel = createDocumentFromBlob(\r