ALF-14306 Add priorities to transformers

- properties with .mimtypes. in their name win over those with .extensions (for Ray)
   - extension and minetype expressions now only support the * wildcard

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@46950 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2013-02-22 00:51:25 +00:00
parent 3207aa4603
commit b031ba0ded
5 changed files with 269 additions and 72 deletions

View File

@@ -56,14 +56,14 @@ public class TransformerConfigLimits extends TransformerPropertyNameExtractor
limits = new HashMap<String, DoubleMap<String, String, TransformationOptionLimits>>(); limits = new HashMap<String, DoubleMap<String, String, TransformationOptionLimits>>();
// Gets all the transformer, source and target combinations in properties that define limits. // Gets all the transformer, source and target combinations in properties that define limits.
Collection<TransformerSourceTargetValue> transformerNamesAndExt = Collection<TransformerSourceTargetSuffixValue> properties =
getTransformerSourceTargetValues(LIMIT_SUFFIXES, true, subsystem, mimetypeService); getTransformerSourceTargetValues(LIMIT_SUFFIXES, true, subsystem, mimetypeService);
// Add the system wide default just in case it is not included, as we always need this one // Add the system wide default just in case it is not included, as we always need this one
TransformationOptionLimits options = getOrCreateTransformerOptionLimits(DEFAULT_TRANSFORMER, ANY, ANY); TransformationOptionLimits options = getOrCreateTransformerOptionLimits(DEFAULT_TRANSFORMER, ANY, ANY);
// Populate the transformer limits // Populate the transformer limits
for (TransformerSourceTargetValue property: transformerNamesAndExt) for (TransformerSourceTargetSuffixValue property: properties)
{ {
options = getOrCreateTransformerOptionLimits(property.transformerName, options = getOrCreateTransformerOptionLimits(property.transformerName,
property.sourceMimetype, property.targetMimetype); property.sourceMimetype, property.targetMimetype);

View File

@@ -55,19 +55,19 @@ public class TransformerConfigProperty extends TransformerPropertyNameExtractor
// Gets all the transformer, source and target combinations in properties that define // Gets all the transformer, source and target combinations in properties that define
// this value. // this value.
Collection<TransformerSourceTargetValue> transformerNamesAndMimetypes = Collection<TransformerSourceTargetSuffixValue> properties =
getTransformerSourceTargetValues(Collections.singletonList(suffix), true, subsystem, mimetypeService); getTransformerSourceTargetValues(Collections.singletonList(suffix), true, subsystem, mimetypeService);
// Add the system wide default if it does not exist, as we always need this one // Add the system wide default if it does not exist, as we always need this one
TransformerSourceTargetValue transformerSourceTargetValue = TransformerSourceTargetSuffixValue transformerSourceTargetValue =
new TransformerSourceTargetValue(DEFAULT_TRANSFORMER, ANY, ANY, defaultValue, suffix, mimetypeService); new TransformerSourceTargetSuffixValue(DEFAULT_TRANSFORMER, ANY, ANY, suffix, defaultValue, mimetypeService);
if (transformerNamesAndMimetypes.contains(transformerSourceTargetValue.key())) if (properties.contains(transformerSourceTargetValue.key()))
{ {
transformerNamesAndMimetypes.add(transformerSourceTargetValue); properties.add(transformerSourceTargetValue);
} }
// Populate the transformer values // Populate the transformer values
for (TransformerSourceTargetValue property: transformerNamesAndMimetypes) for (TransformerSourceTargetSuffixValue property: properties)
{ {
DoubleMap<String, String, String> mimetypeLimits = this.values.get(property.transformerName); DoubleMap<String, String, String> mimetypeLimits = this.values.get(property.transformerName);
if (mimetypeLimits == null) if (mimetypeLimits == null)

View File

@@ -56,12 +56,12 @@ public class TransformerConfigSupported extends TransformerPropertyNameExtractor
supported = new HashMap<String, SupportedAndUnsupportedTransformations>(); supported = new HashMap<String, SupportedAndUnsupportedTransformations>();
// Gets all the supported and unsupported transformer, source and target combinations // Gets all the supported and unsupported transformer, source and target combinations
Collection<TransformerSourceTargetValue> transformerNamesAndMimetypes = Collection<TransformerSourceTargetSuffixValue> properties =
getTransformerSourceTargetValues(Collections.singletonList(SUPPORTED), getTransformerSourceTargetValues(Collections.singletonList(SUPPORTED),
false, subsystem, mimetypeService); false, subsystem, mimetypeService);
// Populate the transformer values // Populate the transformer values
for (TransformerSourceTargetValue property: transformerNamesAndMimetypes) for (TransformerSourceTargetSuffixValue property: properties)
{ {
SupportedAndUnsupportedTransformations supportedBytransformer = this.supported.get(property.transformerName); SupportedAndUnsupportedTransformations supportedBytransformer = this.supported.get(property.transformerName);
if (supportedBytransformer == null) if (supportedBytransformer == null)

View File

@@ -24,6 +24,7 @@ import static org.alfresco.repo.content.transform.TransformerConfig.PREFIX;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -58,11 +59,11 @@ public abstract class TransformerPropertyNameExtractor
* @param subsystem that provides the properties * @param subsystem that provides the properties
* @param mimetypeService * @param mimetypeService
*/ */
protected Collection<TransformerSourceTargetValue> getTransformerSourceTargetValues(Collection<String> suffixes, protected Collection<TransformerSourceTargetSuffixValue> getTransformerSourceTargetValues(Collection<String> suffixes,
boolean includeSummary, ChildApplicationContextFactory subsystem, MimetypeService mimetypeService) boolean includeSummary, ChildApplicationContextFactory subsystem, MimetypeService mimetypeService)
{ {
Map<Triple<String, String, String>, TransformerSourceTargetValue> TransformerSourceTargetValues = Map<TransformerSourceTargetSuffixKey, TransformerSourceTargetSuffixValue> transformerSourceTargetSuffixValues =
new HashMap<Triple<String, String, String>, TransformerSourceTargetValue>(); new HashMap<TransformerSourceTargetSuffixKey, TransformerSourceTargetSuffixValue>();
for (String propertyName: subsystem.getPropertyNames()) for (String propertyName: subsystem.getPropertyNames())
{ {
@@ -87,35 +88,31 @@ public abstract class TransformerPropertyNameExtractor
if (ext.length == 2) if (ext.length == 2)
{ {
name = name.substring(0, i); name = name.substring(0, i);
if (separator == TransformerConfig.EXTENSIONS) List<String> sourceExtensions = (separator == TransformerConfig.EXTENSIONS)
? getMatchingExtensionsFromExtensions(ext[0], mimetypeService)
: getMatchingExtensionsFromMimetypes( ext[0], mimetypeService);
List<String> targetExtensions = (separator == TransformerConfig.EXTENSIONS)
? getMatchingExtensionsFromExtensions(ext[1], mimetypeService)
: getMatchingExtensionsFromMimetypes( ext[1], mimetypeService);
for (String sourceExt : sourceExtensions)
{ {
addTransformerSourceTargetValue(TransformerSourceTargetValues, for (String targetExt : targetExtensions)
false, name, ext[0], ext[1], value, suffix, mimetypeService);
}
else if (separator == TransformerConfig.MIMETYPES)
{
List<String> sourceExtensions = getMatchingExtensions(ext[0], mimetypeService);
List<String> targetExtensions = getMatchingExtensions(ext[1], mimetypeService);
for (String sourceExt : sourceExtensions)
{ {
for (String targetExt : targetExtensions) addTransformerSourceTargetValue(transformerSourceTargetSuffixValues,
{ (separator == TransformerConfig.MIMETYPES),
addTransformerSourceTargetValue(TransformerSourceTargetValues, name, sourceExt, targetExt, suffix,
true, name, sourceExt, targetExt, value, value, mimetypeService);
suffix, mimetypeService);
}
} }
} }
break suffixesLoop; break suffixesLoop;
} }
} }
} }
if (!separatorMatch && includeSummary) if (!separatorMatch && includeSummary)
{ {
addTransformerSourceTargetValue(TransformerSourceTargetValues, false, name, ANY, ANY, addTransformerSourceTargetValue(transformerSourceTargetSuffixValues, false, name, ANY, ANY,
value, suffix, mimetypeService); suffix, value, mimetypeService);
break suffixesLoop; break suffixesLoop;
} }
} }
@@ -123,27 +120,27 @@ public abstract class TransformerPropertyNameExtractor
} }
} }
return TransformerSourceTargetValues.values(); return transformerSourceTargetSuffixValues.values();
} }
/** /**
* Optionally adds a new TransformerSourceTargetValue. If the supplied value is not constructed from * Optionally adds a new TransformerSourceTargetValue. If the supplied value is constructed from
* from a property that uses a regular expression against a mimetype, a new value is always added and * from a mimetypes property a new value is always added and will replace any existing value. If
* will replace any existing value. If not, the value is only added if there is not a current value. * from an extensions property the value is only added if there is not a current value.
* In other words properties that include extensions win out over those that use mimetypes. * In other words properties that include mimetypes win out over those that use extensions.
*/ */
private void addTransformerSourceTargetValue( private void addTransformerSourceTargetValue(
Map<Triple<String, String, String>, TransformerSourceTargetValue> transformerSourceTargetValues, Map<TransformerSourceTargetSuffixKey, TransformerSourceTargetSuffixValue> transformerSourceTargetSuffixValues,
boolean mimetypeProperty, String name, String sourceExt, String targetExt, String value, boolean mimetypeProperty, String name, String sourceExt, String targetExt, String suffix,
String suffix, MimetypeService mimetypeService) String value, MimetypeService mimetypeService)
{ {
TransformerSourceTargetValue transformerSourceTargetValue = TransformerSourceTargetSuffixValue transformerSourceTargetSuffixValue =
new TransformerSourceTargetValue(name, sourceExt, targetExt, value, suffix, mimetypeService); new TransformerSourceTargetSuffixValue(name, sourceExt, targetExt, suffix, value, mimetypeService);
Triple<String, String, String> key = transformerSourceTargetValue.key(); TransformerSourceTargetSuffixKey key = transformerSourceTargetSuffixValue.key();
if (!mimetypeProperty || !transformerSourceTargetValues.containsKey(key)) if (mimetypeProperty || !transformerSourceTargetSuffixValues.containsKey(key))
{ {
transformerSourceTargetValues.put(key, transformerSourceTargetValue); transformerSourceTargetSuffixValues.put(key, transformerSourceTargetSuffixValue);
} }
} }
@@ -152,7 +149,7 @@ public abstract class TransformerPropertyNameExtractor
* that is not escaped (preceded by a back slash '\'). * that is not escaped (preceded by a back slash '\').
* This is to allow regular expressions to be used for mimetypes. * This is to allow regular expressions to be used for mimetypes.
*/ */
private String[] splitExt(String extensions) static String[] splitExt(String extensions)
{ {
String[] ext = NO_EXT_MATCH; String[] ext = NO_EXT_MATCH;
Matcher matcher = EXTENSIONS_SEPARATOR.matcher(extensions); Matcher matcher = EXTENSIONS_SEPARATOR.matcher(extensions);
@@ -167,26 +164,37 @@ public abstract class TransformerPropertyNameExtractor
} }
/** /**
* Gets the extensions of the mimetypes which match the given <code>configMimetype</code> from the given * Returns a regex Pattern for the supplied expression where '*' represents zero
* <code>mimetypeService</code>. * or more characters.
* <p>
* If the given mimetype string contains one or more wildcards (*) in the subtype, the string
* is converted to a regular expression and the extensions of the mimetypes which match are returned.
* <p>
* If the given mimetype string has no wildcards a list with only the given
* mimetype's extension is returned.
*
* @param mimetypeWildcardRegex
* @param mimetypeService
* @return the list of extensions of mimetypes which match
*/ */
private List<String> getMatchingExtensions( static Pattern pattern(String expression)
String mimetypeWildcardRegex, MimetypeService mimetypeService)
{ {
// Turn the pattern into a regular expression where any special regex
// characters have no meaning and then get any * values to represent
// zero or more chars.
String regex = Pattern.quote(expression).replaceAll("\\*", "\\\\E.*\\\\Q");
return Pattern.compile(regex);
}
/**
* Gets the extensions of the mimetypes that match the given expression.
* However if the expression is "*", only the ANY ("*") extension is returned.
* @param expression which may contain '*' to represent zero or more characters.
* @param mimetypeService
* @return the list of extensions of mimetypes that match
*/
private List<String> getMatchingExtensionsFromMimetypes(
String expression, MimetypeService mimetypeService)
{
if (ANY.equals(expression))
{
return Collections.singletonList(ANY);
}
Pattern pattern = pattern(expression);
List<String> matchingMimetypes = new ArrayList<String>(1); List<String> matchingMimetypes = new ArrayList<String>(1);
for (String mimetype : mimetypeService.getMimetypes()) for (String mimetype : mimetypeService.getMimetypes())
{ {
if (mimetype.matches(mimetypeWildcardRegex)) if (pattern.matcher(mimetype).matches())
{ {
String ext = mimetypeService.getExtension(mimetype); String ext = mimetypeService.getExtension(mimetype);
matchingMimetypes.add(ext); matchingMimetypes.add(ext);
@@ -194,40 +202,139 @@ public abstract class TransformerPropertyNameExtractor
} }
return matchingMimetypes; return matchingMimetypes;
} }
/**
* Gets the extensions that match the given expression. Only the main extension
* of each mimetype is checked.
* However if the expression is "*", only the ANY ("*") extension is returned.
* @param expression which may contain '*' to represent zero or more characters.
* @param mimetypeService
* @return the list of extensions that match
*/
private List<String> getMatchingExtensionsFromExtensions(
String expression, MimetypeService mimetypeService)
{
if (ANY.equals(expression))
{
return Collections.singletonList(ANY);
}
Pattern pattern = pattern(expression);
List<String> matchingMimetypes = new ArrayList<String>(1);
for (String mimetype : mimetypeService.getMimetypes())
{
String ext = mimetypeService.getExtension(mimetype);
if (pattern.matcher(ext).matches())
{
matchingMimetypes.add(ext);
}
}
return matchingMimetypes;
}
} }
class TransformerSourceTargetValue class TransformerSourceTargetSuffixKey
{ {
final String transformerName; final String transformerName;
final String sourceExt; final String sourceExt;
final String targetExt; final String targetExt;
final String value;
final String suffix; final String suffix;
final String sourceMimetype;
final String targetMimetype;
public TransformerSourceTargetValue(String transformerName, String sourceExt, public TransformerSourceTargetSuffixKey(String transformerName, String sourceExt, String targetExt, String suffix)
String targetExt, String value, String suffix, MimetypeService mimetypeService)
{ {
this.transformerName = transformerName; this.transformerName = transformerName;
this.sourceExt = sourceExt; this.sourceExt = sourceExt;
this.targetExt = targetExt; this.targetExt = targetExt;
this.value = value;
this.suffix = suffix; this.suffix = suffix;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((sourceExt == null) ? 0 : sourceExt.hashCode());
result = prime * result + ((suffix == null) ? 0 : suffix.hashCode());
result = prime * result + ((targetExt == null) ? 0 : targetExt.hashCode());
result = prime * result + ((transformerName == null) ? 0 : transformerName.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TransformerSourceTargetSuffixKey other = (TransformerSourceTargetSuffixKey) obj;
if (sourceExt == null)
{
if (other.sourceExt != null)
return false;
}
else if (!sourceExt.equals(other.sourceExt))
return false;
if (suffix == null)
{
if (other.suffix != null)
return false;
}
else if (!suffix.equals(other.suffix))
return false;
if (targetExt == null)
{
if (other.targetExt != null)
return false;
}
else if (!targetExt.equals(other.targetExt))
return false;
if (transformerName == null)
{
if (other.transformerName != null)
return false;
}
else if (!transformerName.equals(other.transformerName))
return false;
return true;
}
}
class TransformerSourceTargetSuffixValue
{
final String transformerName;
final String sourceExt;
final String targetExt;
final String suffix;
final String value;
final String sourceMimetype;
final String targetMimetype;
public TransformerSourceTargetSuffixValue(String transformerName, String sourceExt,
String targetExt, String suffix, String value, MimetypeService mimetypeService)
{
this.transformerName = transformerName;
this.sourceExt = sourceExt;
this.targetExt = targetExt;
this.suffix = suffix;
this.value = value;
this.sourceMimetype = ANY.equals(sourceExt) ? ANY : mimetypeService.getMimetype(sourceExt); this.sourceMimetype = ANY.equals(sourceExt) ? ANY : mimetypeService.getMimetype(sourceExt);
this.targetMimetype = ANY.equals(targetExt) ? ANY : mimetypeService.getMimetype(targetExt); this.targetMimetype = ANY.equals(targetExt) ? ANY : mimetypeService.getMimetype(targetExt);
} }
public Triple<String, String, String> key() public TransformerSourceTargetSuffixKey key()
{ {
return new Triple<String, String, String>(transformerName, sourceExt, targetExt); return new TransformerSourceTargetSuffixKey(transformerName, sourceExt, targetExt, suffix);
} }
public String toString() public String toString()
{ {
return transformerName+'.'+(sourceExt.equals(ANY) && targetExt.equals(ANY) return transformerName+(sourceExt.equals(ANY) && targetExt.equals(ANY)
? "" ? ""
: TransformerConfig.EXTENSIONS+'.'+sourceExt+'.'+targetExt+'.')+ : TransformerConfig.EXTENSIONS+sourceExt+'.'+targetExt)+
suffix+'='+value; suffix+'='+value;
} }
@@ -237,6 +344,7 @@ class TransformerSourceTargetValue
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((sourceExt == null) ? 0 : sourceExt.hashCode()); result = prime * result + ((sourceExt == null) ? 0 : sourceExt.hashCode());
result = prime * result + ((suffix == null) ? 0 : suffix.hashCode());
result = prime * result + ((targetExt == null) ? 0 : targetExt.hashCode()); result = prime * result + ((targetExt == null) ? 0 : targetExt.hashCode());
result = prime * result + ((transformerName == null) ? 0 : transformerName.hashCode()); result = prime * result + ((transformerName == null) ? 0 : transformerName.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode()); result = prime * result + ((value == null) ? 0 : value.hashCode());
@@ -252,7 +360,7 @@ class TransformerSourceTargetValue
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
TransformerSourceTargetValue other = (TransformerSourceTargetValue) obj; TransformerSourceTargetSuffixValue other = (TransformerSourceTargetSuffixValue) obj;
if (sourceExt == null) if (sourceExt == null)
{ {
if (other.sourceExt != null) if (other.sourceExt != null)
@@ -260,6 +368,13 @@ class TransformerSourceTargetValue
} }
else if (!sourceExt.equals(other.sourceExt)) else if (!sourceExt.equals(other.sourceExt))
return false; return false;
if (suffix == null)
{
if (other.suffix != null)
return false;
}
else if (!suffix.equals(other.suffix))
return false;
if (targetExt == null) if (targetExt == null)
{ {
if (other.targetExt != null) if (other.targetExt != null)

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2005-2013 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.content.transform;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Test class for some of the regex methods.
*
* @author Alan Davis
*/
public class TransformerPropertyNameExtractorTest
{
@Test
public void textSplitExt()
{
String[][] values = new String[][]
{
{"AAA.BBB", "AAA", "BBB"},
{"AA\\.BB.CC\\.DD\\.EE", "AA.BB", "CC.DD.EE"},
};
for (String[] args: values)
{
String input = args[0];
String expectedSource = args[1];
String expectedTarget = args[2];
String[] sourceTarget = TransformerPropertyNameExtractor.splitExt(input);
assertEquals("length", sourceTarget.length, 2);
assertEquals("source", expectedSource, sourceTarget[0]);
assertEquals("target", expectedTarget, sourceTarget[1]);
}
}
@Test
public void testPattern()
{
assertTrue( TransformerPropertyNameExtractor.pattern("ABC").matcher("ABC").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("ABC").matcher("x").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("ABC").matcher("ABCD").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("ABC").matcher("DABC").matches());
assertTrue( TransformerPropertyNameExtractor.pattern("*B").matcher("B").matches());
assertTrue( TransformerPropertyNameExtractor.pattern("*B").matcher("xxB").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("*B").matcher("xxBx").matches());
assertFalse( TransformerPropertyNameExtractor.pattern("B*").matcher("").matches());
assertTrue( TransformerPropertyNameExtractor.pattern("C*").matcher("C").matches());
assertTrue( TransformerPropertyNameExtractor.pattern("C*").matcher("CxxB").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("C*").matcher("xxBx").matches());
assertTrue(TransformerPropertyNameExtractor.pattern("D*E*F").matcher("DEF").matches());
assertTrue(TransformerPropertyNameExtractor.pattern("D*E*F").matcher("DxxExxF").matches());
assertTrue(TransformerPropertyNameExtractor.pattern("D*E*F").matcher("D*E*F").matches());
assertTrue( TransformerPropertyNameExtractor.pattern("A+").matcher("A+").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("A+").matcher("AA").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("A+").matcher("AAA").matches());
assertFalse(TransformerPropertyNameExtractor.pattern("A+").matcher("A+A").matches());
}
}