From a8764cd8ad610e55f9bce57540e8bed0ad206d56 Mon Sep 17 00:00:00 2001 From: Neil McErlean Date: Mon, 26 Apr 2010 19:21:12 +0000 Subject: [PATCH] Fix for ALF-1937. title property text gets cut off after fullstop character found and filename extension is appended during document TransformAction Also tidied up the handling of names and titles during transform to avoid other potential bugs. Added a Unit Test class to cover the obvious cases. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19996 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../executer/TransformActionExecuter.java | 66 +++++++++-- .../executer/TransformActionExecuterTest.java | 109 ++++++++++++++++++ 2 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java index 0fe57798e6..b7573d4ed4 100644 --- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java @@ -246,10 +246,10 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase // Adjust the name of the copy nodeService.setProperty(copyNodeRef, ContentModel.PROP_NAME, newName); String originalTitle = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_TITLE); - if (originalTitle != null && originalTitle.length() > 0) + + if (originalTitle != null) { - String newTitle = transformName(this.mimetypeService, originalTitle, mimeType, false); - nodeService.setProperty(copyNodeRef, ContentModel.PROP_TITLE, newTitle); + nodeService.setProperty(copyNodeRef, ContentModel.PROP_TITLE, originalTitle); } } @@ -306,10 +306,18 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase } /** - * Transform name from original extension to new extension + * Transform a name from original extension to new extension, if appropriate. + * If the original name seems to end with a reasonable file extension, then the name + * will be transformed such that the old extension is replaced with the new. + * Otherwise the name will be returned unaltered. + *

+ * The original name will be deemed to have a reasonable extension if there are one + * or more characters after the (required) final dot, none of which are spaces. * - * @param original - * @param newMimetype + * @param mimetypeService the mimetype service + * @param original the original name + * @param newMimetype the new mime type + * @param alwaysAdd if the name has no extension, then add the new one * * @return name with new extension as appropriate for the mimetype */ @@ -321,20 +329,40 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase if (dotIndex > -1) { // we found it - sb.append(original.substring(0, dotIndex)); + String nameBeforeDot = original.substring(0, dotIndex); + String originalExtension = original.substring(dotIndex + 1, original.length()); - // add the new extension + // See ALF-1937, which actually relates to cm:title not cm:name. + // It is possible that the text after the '.' is not actually an extension + // in which case it should not be replaced. + boolean originalExtensionIsReasonable = isExtensionReasonable(originalExtension); String newExtension = mimetypeService.getExtension(newMimetype); - sb.append('.').append(newExtension); + if (originalExtensionIsReasonable) + { + sb.append(nameBeforeDot); + sb.append('.').append(newExtension); + } + else + { + sb.append(original); + if (alwaysAdd == true) + { + if (sb.charAt(sb.length() - 1) != '.') + { + sb.append('.'); + } + sb.append(newExtension); + } + } } else { - // no extension so dont add a new one + // no extension so don't add a new one sb.append(original); if (alwaysAdd == true) { - // add the new extension + // add the new extension - defaults to .bin String newExtension = mimetypeService.getExtension(newMimetype); sb.append('.').append(newExtension); } @@ -342,5 +370,21 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase // done return sb.toString(); } + + /** + * Given a String, this method tries to determine whether it is a reasonable filename extension. + * There are a number of checks that could be performed here, including checking whether the characters + * in the string are all 'letters'. However these are complicated by unicode and other + * considerations. Therefore this method adopts a simple approach and returns true if the + * string is of non-zero length and contains no spaces. + * + * @param potentialExtensionString the string which may be a file extension. + * @return true if it is deemed reasonable, else false + * @since 3.3 + */ + private static boolean isExtensionReasonable(String potentialExtensionString) + { + return potentialExtensionString.length() > 0 && potentialExtensionString.indexOf(' ') == -1; + } } diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java new file mode 100644 index 0000000000..11cc4d0c97 --- /dev/null +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.executer; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.content.encoding.ContentCharsetFinder; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.junit.Test; + +/** + * This class contains unit tests for {@link TransformActionExecuter}. + * + * @author Neil McErlean + */ +public class TransformActionExecuterTest +{ + @Test + public void transformName() throws Exception + { + MimetypeService dummyMimetypeService = new DummyMimetypeService("txt"); + + // Case 1. A simple name with a reasonable extension. + String original = "Letter to Bank Manager.doc"; + final String newMimetype = MimetypeMap.MIMETYPE_TEXT_PLAIN; + String newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, true); + assertEquals("Letter to Bank Manager.txt", newName); + + // Case 2. String after '.' is clearly not an extension + original = "No.1 - First Document Title"; + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, true); + assertEquals(original + ".txt", newName); + + // Case 2b. String after '.' is clearly not an extension. Don't always add + original = "No.1 - First Document Title"; + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, false); + assertEquals(original, newName); + + // Case 3. A name with no extension + original = "Letter to Bank Manager"; + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, true); + assertEquals(original + ".txt", newName); + + // Case 3b. A name with no extension. Don't always add + original = "Letter to Bank Manager"; + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, false); + assertEquals(original, newName); + + // Case 4. A name ending in a dot + original = "Letter to Bank Manager."; + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, true); + assertEquals(original + "txt", newName); + + // Case 4b. A name ending in a dot. Don't always add + original = "Letter to Bank Manager."; + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, newMimetype, false); + assertEquals(original, newName); + + // Case 5. Unknown mime type + original = "Letter to Bank Manager.txt"; + final String unknownMimetype = "Marcel/Marceau"; + // The real MimetypeService returns a 'bin' extension for unknown mime types. + dummyMimetypeService = new DummyMimetypeService("bin"); + + newName = TransformActionExecuter.transformName(dummyMimetypeService, original, unknownMimetype, true); + assertEquals("Letter to Bank Manager.bin", newName); + } +} + +/** + * This is a very simple stub for the MimetypeService. + * For this test, we're only interested in the values that come back from + * the getExtension call. + */ +class DummyMimetypeService implements MimetypeService +{ + private final String result; + public DummyMimetypeService(String result) { this.result = result; } + public ContentCharsetFinder getContentCharsetFinder() { return null; } + public Map getDisplaysByExtension() { return null; } + public Map getDisplaysByMimetype() { return null; } + public String getExtension(String mimetype) { return result; } + public Map getExtensionsByMimetype() { return null; } + public String getMimetype(String extension) { return null; } + public List getMimetypes() { return null; } + public Map getMimetypesByExtension() { return null; } + public String guessMimetype(String filename) { return null; } + public boolean isText(String mimetype) { return false;} +} \ No newline at end of file