> explicitTransforms = debugExplicitTransforms();
debugActiveTransformersByTransformer(explicitTransforms);
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java
index 96f65effae..7b57ab97be 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java
@@ -30,6 +30,7 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.TransformationOptions;
+import org.springframework.beans.factory.BeanNameAware;
import org.springframework.extensions.surf.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -47,7 +48,7 @@ import org.apache.commons.logging.LogFactory;
* @author Derek Hulley
*/
@Deprecated
-public abstract class AbstractContentTransformer implements ContentTransformer
+public abstract class AbstractContentTransformer implements ContentTransformer, BeanNameAware
{
private static final Log logger = LogFactory.getLog(AbstractContentTransformer.class);
@@ -58,6 +59,9 @@ public abstract class AbstractContentTransformer implements ContentTransformer
private double averageTime = 0.0;
private long count = 0L;
+ /** The bean name. */
+ private String beanName;
+
/**
* All transformers start with an average transformation time of 0.0ms.
*/
@@ -408,6 +412,11 @@ public abstract class AbstractContentTransformer implements ContentTransformer
return (long) averageTime;
}
+ public long getTransformationTime(String sourceMimetype, String targetMimetype)
+ {
+ return (long) averageTime;
+ }
+
/**
* Records and updates the average transformation time for this transformer.
*
@@ -433,4 +442,29 @@ public abstract class AbstractContentTransformer implements ContentTransformer
double diffTime = ((double) transformationTime) - averageTime;
averageTime += diffTime / (double) count;
}
+
+ /**
+ * Sets the Spring bean name.
+ */
+ @Override
+ public void setBeanName(String beanName)
+ {
+ this.beanName = beanName;
+ }
+
+ /**
+ * Returns the Spring bean name.
+ */
+ public String getBeanName()
+ {
+ return beanName;
+ }
+
+ /**
+ * Returns transformer name. Uses the Spring bean name, but if null uses the class name.
+ */
+ public String getName()
+ {
+ return (beanName == null) ? getClass().getSimpleName() : beanName;
+ }
}
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java
index 9b8d69d387..de8ec07585 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java
@@ -19,7 +19,6 @@
package org.alfresco.repo.content.transform;
import java.util.Map;
-import java.util.Properties;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ContentIOException;
@@ -46,13 +45,20 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
private static final Log logger = LogFactory.getLog(AbstractContentTransformer2.class);
private ContentTransformerRegistry registry;
- private Properties properties;
- private double averageTime;
- private long count = 0L;
-
+
+ private ThreadLocal depth = new ThreadLocal()
+ {
+ @Override
+ protected Integer initialValue()
+ {
+ return 0;
+ }
+ };
+
/**
* All transformers start with an average transformation time of 0.0 ms,
- * unless there is an Alfresco global property {@code .initialTime}.
+ * unless there is an Alfresco global property {@code .time}.
+ * May also be set for given combinations of source and target mimetypes.
*/
protected AbstractContentTransformer2()
{
@@ -68,70 +74,12 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
this.registry = registry;
}
- /**
- * The Alfresco global properties.
- */
- public void setProperties(Properties properties)
- {
- this.properties = properties;
- }
-
- /**
- * Sets the averageTime and count (if global properties were used to set the averageTime).
- * Both default to 0. The property names use the transformer bean name with a ".time"
- * or ".count" suffix. Spring bean configuration is not being used as we don't wish to
- * break existing transformers that know nothing about these properties.
- */
- private void setAverageTimeFromAlfrescoGlobalProperties()
- {
- String beanName = getBeanName();
- averageTime = Long.valueOf(getPositiveLongProperty(beanName+".time", 0L));
- if (averageTime > 0.0)
- {
- // This normally is a large number so that it does not change much if used.
- count = Long.valueOf(getPositiveLongProperty(beanName+".count", 10000));
- }
- }
-
- /**
- * Returns a positive long value from an optional Alfresco global property.
- * Invalid values are ignored but a log message is issued.
- * @param name of the property
- * @param defaultValue if the property does not exist or is negative
- * @return the value
- */
- private long getPositiveLongProperty(String name, long defaultValue)
- {
- long value = defaultValue;
- if (properties != null)
- {
- String property = properties.getProperty(name);
- if (property != null)
- {
- try
- {
- value = Long.valueOf(property);
- if (value < 0)
- {
- value = defaultValue;
- throw new NumberFormatException();
- }
- }
- catch (NumberFormatException e)
- {
- logger.warn("Alfresco global property "+name+" is must be a positive Java long value. Using "+defaultValue);
- }
- }
- }
- return value;
- }
-
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName())
- .append("[ average=").append((long)averageTime).append("ms")
+ .append("[ average=").append(transformerConfig.getStatistics(this, null, null).getAverageTime()).append("ms")
.append("]");
return sb.toString();
}
@@ -140,10 +88,12 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
* Registers this instance with the {@link #setRegistry(ContentTransformerRegistry) registry}
* if it is present.
*
- * THIS IS A CUSTOME SPRING INIT METHOD
+ * THIS IS A CUSTOM SPRING INIT METHOD
*/
public void register()
{
+ super.register();
+
if (registry == null)
{
logger.warn("Property 'registry' has not been set. Ignoring auto-registration: \n" +
@@ -151,8 +101,6 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
return;
}
- setAverageTimeFromAlfrescoGlobalProperties();
-
// register this instance for the fallback case
registry.addTransformer(this);
}
@@ -211,115 +159,127 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
public final void transform(ContentReader reader, ContentWriter writer, TransformationOptions options)
throws ContentIOException
{
- // begin timing
- long before = System.currentTimeMillis();
-
- // check options map
- if (options == null)
- {
- options = new TransformationOptions();
- }
-
try
{
- if (transformerDebug.isEnabled())
+ depth.set(depth.get()+1);
+
+ // begin timing
+ long before = System.currentTimeMillis();
+
+ String sourceMimetype = reader.getMimetype();
+ String targetMimetype = writer.getMimetype();
+
+ // check options map
+ if (options == null)
{
- transformerDebug.pushTransform(this, reader.getContentUrl(), reader.getMimetype(),
- writer.getMimetype(), reader.getSize(), options);
+ options = new TransformationOptions();
}
- // Check the transformability
- checkTransformable(reader, writer, options);
-
- // Pass on any limits to the reader
- setReaderLimits(reader, writer, options);
+ try
+ {
+ if (transformerDebug.isEnabled())
+ {
+ transformerDebug.pushTransform(this, reader.getContentUrl(), sourceMimetype,
+ targetMimetype, reader.getSize(), options);
+ }
+
+ // Check the transformability
+ checkTransformable(reader, writer, options);
+
+ // Pass on any limits to the reader
+ setReaderLimits(reader, writer, options);
- // Transform
- transformInternal(reader, writer, options);
- }
- catch (ContentServiceTransientException cste)
- {
- // A transient failure has occurred within the content transformer.
- // This should not be interpreted as a failure and therefore we should not
- // update the transformer's average time.
+ // Transform
+ transformInternal(reader, writer, options);
+ }
+ catch (ContentServiceTransientException cste)
+ {
+ // A transient failure has occurred within the content transformer.
+ // This should not be interpreted as a failure and therefore we should not
+ // update the transformer's average time.
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Transformation has been transiently declined: \n" +
+ " reader: " + reader + "\n" +
+ " writer: " + writer + "\n" +
+ " options: " + options + "\n" +
+ " transformer: " + this);
+ }
+ // the finally block below will still perform tidyup. Otherwise we're done.
+ // We rethrow the exception
+ throw cste;
+ }
+ catch (Throwable e)
+ {
+ // Make sure that this transformation gets set back i.t.o. time taken.
+ // This will ensure that transformers that compete for the same transformation
+ // will be prejudiced against transformers that tend to fail
+ recordError(sourceMimetype, targetMimetype);
+
+ // Ask Tika to detect the document, and report back on if
+ // the current mime type is plausible
+ String differentType = getMimetypeService().getMimetypeIfNotMatches(reader.getReader());
+
+ // Report the error
+ if(differentType == null)
+ {
+ transformerDebug.debug(" Failed", e);
+ throw new ContentIOException("Content conversion failed: \n" +
+ " reader: " + reader + "\n" +
+ " writer: " + writer + "\n" +
+ " options: " + options.toString(false) + "\n" +
+ " limits: " + getLimits(reader, writer, options),
+ e);
+ }
+ else
+ {
+ transformerDebug.debug(" Failed: Mime type was '"+differentType+"'", e);
+ throw new ContentIOException("Content conversion failed: \n" +
+ " reader: " + reader + "\n" +
+ " writer: " + writer + "\n" +
+ " options: " + options.toString(false) + "\n" +
+ " limits: " + getLimits(reader, writer, options) + "\n" +
+ " claimed mime type: " + reader.getMimetype() + "\n" +
+ " detected mime type: " + differentType,
+ e);
+ }
+ }
+ finally
+ {
+ transformerDebug.popTransform();
+
+ // check that the reader and writer are both closed
+ if (reader.isChannelOpen())
+ {
+ logger.error("Content reader not closed by transformer: \n" +
+ " reader: " + reader + "\n" +
+ " transformer: " + this);
+ }
+ if (writer.isChannelOpen())
+ {
+ logger.error("Content writer not closed by transformer: \n" +
+ " writer: " + writer + "\n" +
+ " transformer: " + this);
+ }
+ }
+
+ // record time
+ long after = System.currentTimeMillis();
+ recordTime(sourceMimetype, targetMimetype, after - before);
+
+ // done
if (logger.isDebugEnabled())
{
- logger.debug("Transformation has been transiently declined: \n" +
+ logger.debug("Completed transformation: \n" +
" reader: " + reader + "\n" +
" writer: " + writer + "\n" +
" options: " + options + "\n" +
" transformer: " + this);
}
- // the finally block below will still perform tidyup. Otherwise we're done.
- // We rethrow the exception
- throw cste;
- }
- catch (Throwable e)
- {
- // Make sure that this transformation gets set back i.t.o. time taken.
- // This will ensure that transformers that compete for the same transformation
- // will be prejudiced against transformers that tend to fail
- recordTime(60 * 1000); // 1 minute, i.e. rubbish
-
- // Ask Tika to detect the document, and report back on if
- // the current mime type is plausible
- String differentType = getMimetypeService().getMimetypeIfNotMatches(reader.getReader());
-
- // Report the error
- if(differentType == null)
- {
- transformerDebug.debug(" Failed", e);
- throw new ContentIOException("Content conversion failed: \n" +
- " reader: " + reader + "\n" +
- " writer: " + writer + "\n" +
- " options: " + options.toString(false) + "\n" +
- " limits: " + getLimits(reader, writer, options),
- e);
- }
- else
- {
- transformerDebug.debug(" Failed: Mime type was '"+differentType+"'", e);
- throw new ContentIOException("Content conversion failed: \n" +
- " reader: " + reader + "\n" +
- " writer: " + writer + "\n" +
- " options: " + options.toString(false) + "\n" +
- " limits: " + getLimits(reader, writer, options) + "\n" +
- " claimed mime type: " + reader.getMimetype() + "\n" +
- " detected mime type: " + differentType,
- e);
- }
}
finally
{
- transformerDebug.popTransform();
-
- // check that the reader and writer are both closed
- if (reader.isChannelOpen())
- {
- logger.error("Content reader not closed by transformer: \n" +
- " reader: " + reader + "\n" +
- " transformer: " + this);
- }
- if (writer.isChannelOpen())
- {
- logger.error("Content writer not closed by transformer: \n" +
- " writer: " + writer + "\n" +
- " transformer: " + this);
- }
- }
-
- // record time
- long after = System.currentTimeMillis();
- recordTime(after - before);
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Completed transformation: \n" +
- " reader: " + reader + "\n" +
- " writer: " + writer + "\n" +
- " options: " + options + "\n" +
- " transformer: " + this);
+ depth.set(depth.get()+1);
}
}
@@ -336,7 +296,23 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
*/
public synchronized long getTransformationTime()
{
- return (long) averageTime;
+ return transformerConfig.getStatistics(this, null, null).getAverageTime();
+ }
+
+ /**
+ * @return Returns the calculated running average of the current transformations
+ */
+ public synchronized long getTransformationTime(String sourceMimetype, String targetMimetype)
+ {
+ return transformerConfig.getStatistics(this, sourceMimetype, targetMimetype).getAverageTime();
+ }
+
+ /**
+ * @deprecated use method with mimetypes.
+ */
+ protected final synchronized void recordTime(long transformationTime)
+ {
+ recordTime(TransformerConfig.ANY, TransformerConfig.ANY, transformationTime);
}
/**
@@ -348,20 +324,33 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
* This method is thread-safe. The time spent in this method is negligible
* so the impact will be minor.
*
+ * @param sourceMimetype
+ * @param targetMimetype
* @param transformationTime the time it took to perform the transformation.
* The value may be 0.
*/
- protected final synchronized void recordTime(long transformationTime)
+ protected final synchronized void recordTime(String sourceMimetype, String targetMimetype,
+ long transformationTime)
{
- if (count == Long.MAX_VALUE)
+ transformerConfig.getStatistics(this, sourceMimetype, targetMimetype).recordTime(transformationTime);
+ if (depth.get() == 1)
{
- // we have reached the max count - reduce it by half
- // the average fluctuation won't be extreme
- count /= 2L;
+ transformerConfig.getStatistics(null, sourceMimetype, targetMimetype).recordTime(transformationTime);
+ }
+ }
+
+ /**
+ * Records an error and updates the average time as if the transformation took a
+ * long time, so that it is less likely to be called again.
+ * @param sourceMimetype
+ * @param targetMimetype
+ */
+ protected final synchronized void recordError(String sourceMimetype, String targetMimetype)
+ {
+ transformerConfig.getStatistics(this, sourceMimetype, targetMimetype).recordError();
+ if (depth.get() == 1)
+ {
+ transformerConfig.getStatistics(null, sourceMimetype, targetMimetype).recordError();
}
- // adjust the average
- count++;
- double diffTime = ((double) transformationTime) - averageTime;
- averageTime += diffTime / (double) count;
}
}
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimits.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimits.java
index e0fb105d35..3fdb505b4e 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimits.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimits.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -18,14 +18,22 @@
*/
package org.alfresco.repo.content.transform;
+import static org.alfresco.service.cmr.repository.TransformationOptionLimits.OPT_MAX_PAGES;
+import static org.alfresco.service.cmr.repository.TransformationOptionLimits.OPT_MAX_SOURCE_SIZE_K_BYTES;
+import static org.alfresco.service.cmr.repository.TransformationOptionLimits.OPT_PAGE_LIMIT;
+import static org.alfresco.service.cmr.repository.TransformationOptionLimits.OPT_READ_LIMIT_K_BYTES;
+import static org.alfresco.service.cmr.repository.TransformationOptionLimits.OPT_READ_LIMIT_TIME_MS;
+import static org.alfresco.service.cmr.repository.TransformationOptionLimits.OPT_TIMEOUT_MS;
+
import java.util.Map;
+import java.util.Map.Entry;
import org.alfresco.repo.content.AbstractContentReader;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.TransformationOptionLimits;
import org.alfresco.service.cmr.repository.TransformationOptions;
-import org.springframework.beans.factory.BeanNameAware;
/**
* Provides transformation limits for {@link org.alfresco.repo.content.transform.ContentTransformer}
@@ -38,26 +46,14 @@ import org.springframework.beans.factory.BeanNameAware;
*
* @author Alan Davis
*/
-public abstract class AbstractContentTransformerLimits extends ContentTransformerHelper implements ContentTransformer, BeanNameAware
+public abstract class AbstractContentTransformerLimits extends ContentTransformerHelper implements ContentTransformer
{
- /** Transformer wide Time, KBytes and page limits */
- private TransformationOptionLimits limits = new TransformationOptionLimits();
-
- /**
- * Time, KBytes and page limits by source and target mimetype combination.
- * The first map's key is the source mimetype. The second map's key is the
- * target mimetype and the value are the limits. */
- private Map> mimetypeLimits;
-
/** Indicates if 'page' limits are supported. */
private boolean pageLimitsSupported;
/** For debug **/
protected TransformerDebug transformerDebug;
- /** The bean name. Used in debug only. */
- private String beanName;
-
/**
* Indicates if 'page' limits are supported.
* @return false by default.
@@ -172,21 +168,17 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected long getTimeoutMs()
{
- return limits.getTimeoutMs();
+ return getLimits().getTimeoutMs();
}
/**
- * Sets a timeout (ms) on the InputStream after which an IOExecption is thrown
- * to terminate very slow transformations or to terminate (kill) a subprocess.
- * @param timeoutMs in milliseconds. If less than or equal to zero (the default)
- * there is no timeout.
- * If greater than zero the {@code readLimitTimeMs} must not be set.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setTimeoutMs(long timeoutMs)
{
- limits.setTimeoutMs(timeoutMs);
+ deprecatedSetter(OPT_TIMEOUT_MS+'='+timeoutMs);
}
-
+
/**
* Gets the limit in terms of the amount of data read (by time) to limit transformations where
* only the start of the content is needed. After this limit is reached the InputStream reports
@@ -195,19 +187,15 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected long getReadLimitTimeMs()
{
- return limits.getReadLimitTimeMs();
+ return getLimits().getReadLimitTimeMs();
}
/**
- * Sets a limit in terms of the amount of data read (by time) to limit transformations where
- * only the start of the content is needed. After this limit is reached the InputStream reports
- * end of file.
- * @param readLimitBytes if less than or equal to zero (the default) there is no limit.
- * If greater than zero the {@code timeoutMs} must not be set.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setReadLimitTimeMs(long readLimitTimeMs)
{
- limits.setReadLimitTimeMs(readLimitTimeMs);
+ deprecatedSetter(OPT_READ_LIMIT_TIME_MS+'='+readLimitTimeMs);
}
/**
@@ -218,19 +206,15 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected long getMaxSourceSizeKBytes()
{
- return limits.getMaxSourceSizeKBytes();
+ return getLimits().getMaxSourceSizeKBytes();
}
/**
- * Sets a maximum source content size, to skip transformations where
- * the source is just too large to expect it to perform. If the source is larger
- * the transformer indicates it is not available.
- * @param maxSourceSizeKBytes if less than or equal to zero (the default) there is no limit.
- * If greater than zero the {@code readLimitKBytes} must not be set.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setMaxSourceSizeKBytes(long maxSourceSizeKBytes)
{
- limits.setMaxSourceSizeKBytes(maxSourceSizeKBytes);
+ deprecatedSetter(OPT_MAX_SOURCE_SIZE_K_BYTES+'='+maxSourceSizeKBytes);
}
/**
@@ -241,19 +225,15 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected long getReadLimitKBytes()
{
- return limits.getReadLimitKBytes();
+ return getLimits().getReadLimitKBytes();
}
/**
- * Sets a limit in terms of the about of data read to limit transformations where
- * only the start of the content is needed. After this limit is reached the InputStream reports
- * end of file.
- * @param readLimitKBytes if less than or equal to zero (the default) there is no limit.
- * If greater than zero the {@code maxSourceSizeKBytes} must not be set.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setReadLimitKBytes(long readLimitKBytes)
{
- limits.setReadLimitKBytes(readLimitKBytes);
+ deprecatedSetter(OPT_READ_LIMIT_K_BYTES+'='+readLimitKBytes);
}
/**
@@ -262,18 +242,15 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected int getMaxPages()
{
- return limits.getMaxPages();
+ return getLimits().getMaxPages();
}
/**
- * Set the number of pages read from the source before an exception is thrown.
- *
- * @param maxPages the number of pages to be read from the source. If less than or equal to zero
- * (the default) no limit is applied.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setMaxPages(int maxPages)
{
- limits.setMaxPages(maxPages);
+ deprecatedSetter(OPT_MAX_PAGES+'='+maxPages);
}
/**
@@ -282,18 +259,15 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected int getPageLimit()
{
- return limits.getPageLimit();
+ return getLimits().getPageLimit();
}
/**
- * Set the number of pages read from the source before returning EOF.
- *
- * @param pageLimit the number of pages to be read from the source. If less
- * than or equal to zero (the default) no limit is applied.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setPageLimit(int pageLimit)
{
- limits.setPageLimit(pageLimit);
+ deprecatedSetter(OPT_PAGE_LIMIT+'='+pageLimit);
}
/**
@@ -301,33 +275,57 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
*/
protected TransformationOptionLimits getLimits()
{
- return limits;
+ return transformerConfig.getLimits(this, null, null);
}
-
+
/**
- * Sets max and limit values for time, size and pages in a single operation.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setLimits(TransformationOptionLimits limits)
{
- this.limits = limits;
+ deprecatedLimitsSetter("", limits);
}
/**
- * Gets the max and limit values for time, size and pages per source and target mimetype
- * combination.
- */
- protected Map> getMimetypeLimits()
- {
- return mimetypeLimits;
- }
-
- /**
- * Sets the max and limit values for time, size and pages per source and target mimetype
- * combination.
+ * @deprecated transformation limits are now set with global properties rather than spring configuration.
*/
public void setMimetypeLimits(Map> mimetypeLimits)
{
- this.mimetypeLimits = mimetypeLimits;
+ for (Entry> source: mimetypeLimits.entrySet())
+ {
+ String sourceExt = getExtensionOrAny(source.getKey());
+ for (Entry target: source.getValue().entrySet())
+ {
+ String targetExt = getExtensionOrAny(target.getKey());
+ TransformationOptionLimits limits = target.getValue();
+ String mimetypeSuffix = TransformerConfig.MIMETYPES_SEPARATOR.substring(1)+sourceExt+'.'+targetExt;
+
+ deprecatedLimitsSetter(mimetypeSuffix, limits);
+ }
+ }
+ }
+
+ private void deprecatedLimitsSetter(String mimetypeSuffix, TransformationOptionLimits limits)
+ {
+ if (limits.supported())
+ {
+ // Ignore limit pairs that are not specified
+ for (String limit: new String[] {
+ limits.getTimePair().toString(OPT_TIMEOUT_MS, OPT_READ_LIMIT_TIME_MS),
+ limits.getKBytesPair().toString(OPT_MAX_SOURCE_SIZE_K_BYTES, OPT_READ_LIMIT_K_BYTES),
+ limits.getPagesPair().toString(OPT_MAX_PAGES, OPT_PAGE_LIMIT)
+ })
+ {
+ if (limit != null)
+ {
+ deprecatedSetter(mimetypeSuffix+'.'+limit);
+ }
+ }
+ }
+ else
+ {
+ deprecatedSetter(mimetypeSuffix+TransformerConfig.SUPPORTED+"=false");
+ }
}
/**
@@ -339,7 +337,7 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
TransformationOptions options)
{
return (reader == null || writer == null)
- ? limits.combine(options.getLimits())
+ ? getLimits().combine(options.getLimits())
: getLimits(reader.getMimetype(), writer.getMimetype(), options);
}
@@ -351,63 +349,8 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
protected TransformationOptionLimits getLimits(String sourceMimetype, String targetMimetype,
TransformationOptions options)
{
- // Get the limits for the source and target mimetypes
- TransformationOptionLimits mimetypeLimits = null;
- if (this.mimetypeLimits != null)
- {
- boolean anySource = false;
- Map targetLimits =
- this.mimetypeLimits.get(sourceMimetype);
- if (targetLimits == null)
- {
- targetLimits = this.mimetypeLimits.get("*");
- anySource = true;
- }
- if (targetLimits != null)
- {
- mimetypeLimits = targetLimits.get(targetMimetype);
- if (mimetypeLimits == null)
- {
- mimetypeLimits = targetLimits.get("*");
-
- // Allow for the case where have specific source and target mimetype limits
- // and general source limits (avoid having to repeat the general values in
- // each specific source definition)
- if (mimetypeLimits == null && !anySource)
- {
- targetLimits = this.mimetypeLimits.get("*");
- if (targetLimits != null)
- {
- mimetypeLimits = targetLimits.get(targetMimetype);
- if (mimetypeLimits == null)
- {
- mimetypeLimits = targetLimits.get("*");
- }
- }
- }
- }
- }
- }
-
- TransformationOptionLimits combined = (mimetypeLimits == null) ? limits : limits.combine(mimetypeLimits);
- return (options == null) ? combined : combined.combine(options.getLimits());
- }
-
- /**
- * Sets the Spring bean name - only for use in debug.
- */
- @Override
- public void setBeanName(String beanName)
- {
- this.beanName = beanName;
- }
-
- /**
- * Returns the Spring bean name - only for use in debug.
- */
- public String getBeanName()
- {
- return beanName;
+ TransformationOptionLimits limits = transformerConfig.getLimits(this, sourceMimetype, targetMimetype);
+ return (options == null) ? limits : limits.combine(options.getLimits());
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java
index 1d5ce5d665..7a779f2e3d 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java
@@ -28,6 +28,7 @@ import java.util.Map;
import org.alfresco.repo.content.AbstractContentReader;
import org.alfresco.repo.content.ContentMinimalContextTestSuite;
import org.alfresco.repo.content.AbstractContentReaderLimitTest.DummyAbstractContentReader;
+import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
@@ -43,9 +44,9 @@ import org.springframework.context.ApplicationContext;
*/
public class AbstractContentTransformerLimitsTest
{
- private static final String A = "a";
- private static final String B = "b";
- private static final String C = "c";
+ private static final String A = MimetypeMap.MIMETYPE_XML;
+ private static final String B = MimetypeMap.MIMETYPE_HTML;
+ private static final String C = MimetypeMap.MIMETYPE_PDF;
private AbstractContentTransformerLimits transformer;
private TransformationOptionLimits limits;
@@ -59,6 +60,7 @@ public class AbstractContentTransformerLimitsTest
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
MimetypeService mimetypeService = serviceRegistry.getMimetypeService();
TransformerDebug transformerDebug = (TransformerDebug) ctx.getBean("transformerDebug");
+ TransformerConfig transformerConfig = (TransformerConfig) ctx.getBean("transformerConfig");
transformer = new AbstractContentTransformer2()
{
@@ -77,6 +79,8 @@ public class AbstractContentTransformerLimitsTest
};
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
+ transformer.setBeanName("transformer.test"+System.currentTimeMillis()%100000);
limits = new TransformationOptionLimits();
options = new TransformationOptions();
@@ -104,6 +108,7 @@ public class AbstractContentTransformerLimitsTest
{
long value = 1234;
transformer.setTimeoutMs(value);
+ transformer.register();
long actual = transformer.getTimeoutMs();
assertEquals("Getter did not return set value", value, actual);
}
@@ -113,6 +118,7 @@ public class AbstractContentTransformerLimitsTest
{
long value = 1234;
transformer.setReadLimitTimeMs(value);
+ transformer.register();
long actual = transformer.getReadLimitTimeMs();
assertEquals("Getter did not return set value", value, actual);
}
@@ -122,6 +128,7 @@ public class AbstractContentTransformerLimitsTest
{
long value = 1234;
transformer.setMaxSourceSizeKBytes(value);
+ transformer.register();
long actual = transformer.getMaxSourceSizeKBytes();
assertEquals("Getter did not return set value", value, actual);
}
@@ -131,6 +138,7 @@ public class AbstractContentTransformerLimitsTest
{
long value = 1234;
transformer.setReadLimitKBytes(value);
+ transformer.register();
long actual = transformer.getReadLimitKBytes();
assertEquals("Getter did not return set value", value, actual);
}
@@ -140,6 +148,7 @@ public class AbstractContentTransformerLimitsTest
{
int value = 1234;
transformer.setMaxPages(value);
+ transformer.register();
int actual = transformer.getMaxPages();
assertEquals("Getter did not return set value", value, actual);
}
@@ -149,6 +158,7 @@ public class AbstractContentTransformerLimitsTest
{
int value = 1234;
transformer.setPageLimit(value);
+ transformer.register();
int actual = transformer.getPageLimit();
assertEquals("Getter did not return set value", value, actual);
}
@@ -161,6 +171,7 @@ public class AbstractContentTransformerLimitsTest
addMimetypeLimits(A, B, limits);
transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
long actual = transformer.getLimits(A, B, options).getMaxSourceSizeKBytes();
assertEquals("Getter did not return set value", value, actual);
@@ -176,6 +187,7 @@ public class AbstractContentTransformerLimitsTest
addMimetypeLimits(A, "*", limits);
transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
long actual = transformer.getLimits(A, B, options).getMaxSourceSizeKBytes();
assertEquals("Getter did not return set value", value, actual);
@@ -191,6 +203,7 @@ public class AbstractContentTransformerLimitsTest
addMimetypeLimits("*", B, limits);
transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
long actual = transformer.getLimits(A, B, options).getMaxSourceSizeKBytes();
assertEquals("Getter did not return set value", value, actual);
@@ -206,6 +219,7 @@ public class AbstractContentTransformerLimitsTest
addMimetypeLimits(A, B, limits);
transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
long actual = transformer.getLimits(A, B, options).getMaxSourceSizeKBytes();
assertEquals("Getter did not return set value", value+1, actual);
@@ -228,6 +242,7 @@ public class AbstractContentTransformerLimitsTest
limits.setMaxSourceSizeKBytes(kValue);
addMimetypeLimits(A, B, limits);
transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertEquals("Expected to have set value returned", kValue,
transformer.getMaxSourceSizeKBytes(A, B, options));
@@ -235,51 +250,115 @@ public class AbstractContentTransformerLimitsTest
// With a mimetype that does not have any specific limits
assertEquals("Expected to have -1 (unlimited) returned", -1,
transformer.getMaxSourceSizeKBytes(C, B, options));
+ }
+
+ @Test
+ // Combination using just transformer limit to start with
+ public void testGetMaxSourceSizeKBytesCombination() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
-
- // Clear the mimetype limits and double check
- limits.setMaxSourceSizeKBytes(-1);
-
- assertEquals("Expected to have -1 (unlimited) returned", -1,
- transformer.getMaxSourceSizeKBytes(A, B, options));
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
// Check for combinations with transformer limits
- // a) Using just transformer limit to start with
transformer.setMaxSourceSizeKBytes(kValue);
+ transformer.register();
assertEquals("Expected to have transformer set value returned", kValue,
transformer.getMaxSourceSizeKBytes(A, B, options));
+ }
- // b) combination where transformer limit is used
+ @Test
+ // Combination where transformer limit is used
+ public void testGetMaxSourceSizeKBytesCombinationTransUsed() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
+
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
+
transformer.setMaxSourceSizeKBytes(kValue);
limits.setMaxSourceSizeKBytes(kValue+1);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertEquals("Expected to have transformer set value returned", kValue,
transformer.getMaxSourceSizeKBytes(A, B, options));
-
- // c) combination where mimetype limit is used
+ }
+
+ @Test
+ // Combination where mimetype limit is used
+ public void testGetMaxSourceSizeKBytesCombinationMimetypeUsed() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
+
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
+
transformer.setMaxSourceSizeKBytes(kValue+1);
limits.setMaxSourceSizeKBytes(kValue);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertEquals("Expected to have transformer set value returned", kValue,
transformer.getMaxSourceSizeKBytes(A, B, options));
+ }
+
+ @Test
+ // Check no limit when page limit set on a transformer that does not support page limit
+ // maxSourceSizeKbytes value should be ignored if a page limit is in use
+ public void testGetMaxSourceSizeKBytesPageSupportsNot() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
- // Check no limit when page limit set on a transformer that does not support page limit
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
+
+ transformer.setPageLimitsSuported(false);
transformer.setMaxSourceSizeKBytes(kValue);
limits.setMaxSourceSizeKBytes(kValue+1);
limits.setPageLimit(1);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertEquals("Expected to ignore the page limit as the transformer does not support it", kValue,
transformer.getMaxSourceSizeKBytes(A, B, options));
+ }
+ @Test
+ // Check no limit when page limit set on a transformer that does support page limit
+ // maxSourceSizeKbytes value should be ignored if a page limit is in use
+ public void testGetMaxSourceSizeKBytesPageSupports() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
- // Check no limit when page limit set on a transformer that does support page limit
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
+
+ transformer.setPageLimitsSuported(true);
transformer.setMaxSourceSizeKBytes(kValue);
limits.setMaxSourceSizeKBytes(kValue+1);
- transformer.setPageLimitsSuported(true);
limits.setPageLimit(1);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertEquals("Expected to have -1 (unlimited) returned when there are page limits", -1,
transformer.getMaxSourceSizeKBytes(A, B, options));
}
@Test
- public void testIsTransformableSize() throws Exception
+ // Using limit on a mimetype
+ public void testIsTransformableSizeMimetype() throws Exception
{
long kValue = 12;
long byteValue = kValue*1024;
@@ -292,12 +371,13 @@ public class AbstractContentTransformerLimitsTest
limits.setMaxSourceSizeKBytes(kValue);
addMimetypeLimits(A, B, limits);
transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertTrue("Size is less than limit so should have been ok",
transformer.isTransformableSize(A, byteValue-1, B, options));
assertTrue("Size is equal to limit so should have been ok",
transformer.isTransformableSize(A, byteValue, B, options));
- assertFalse("Size is greater than limit so should not have failed",
+ assertFalse("Size is greater than limit so should have failed",
transformer.isTransformableSize(A, byteValue+1, B, options));
// With a mimetype that does not have any specific limits
@@ -307,36 +387,68 @@ public class AbstractContentTransformerLimitsTest
transformer.isTransformableSize(A, byteValue+1, C, options));
assertTrue("No limits so should have been ok",
transformer.isTransformableSize(C, byteValue+1, C, options));
-
- // Clear the mimetype limits and double check
- limits.setMaxSourceSizeKBytes(-1);
-
+ }
+
+ @Test
+ // Using limit on transformer as a whole
+ public void testIsTransformableSizeTrans() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
+
+ // Not set mimetype limits yet
assertTrue("No limits so should have been ok",
transformer.isTransformableSize(A, byteValue+1, B, options));
- // Check for combinations with transformer limits
-
- // a) Using just transformer limit to start with
transformer.setMaxSourceSizeKBytes(kValue);
+ transformer.register();
assertTrue("Size is equal to limit so should have been ok",
transformer.isTransformableSize(A, byteValue, B, options));
- assertFalse("Size is greater than limit so should not have failed",
+ assertFalse("Size is greater than limit so should have failed",
transformer.isTransformableSize(A, byteValue+1, B, options));
+ }
- // b) combination where transformer limit is used
+ @Test
+ // Combination where transformer limit is used
+ public void testIsTransformableSizeCombinationTransUsed() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
+
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
+
transformer.setMaxSourceSizeKBytes(kValue);
limits.setMaxSourceSizeKBytes(kValue+1);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertTrue("Size is equal to limit so should have been ok",
transformer.isTransformableSize(A, byteValue, B, options));
- assertFalse("Size is greater than limit so should not have failed",
+ assertFalse("Size is greater than limit so should have failed",
transformer.isTransformableSize(A, byteValue+1, B, options));
+ }
- // c) combination where mimetype limit is used
+ @Test
+ // Combination where mimetype limit is used
+ public void testIsTransformableSizeCombinationMimetypeUsed() throws Exception
+ {
+ long kValue = 12;
+ long byteValue = kValue*1024;
+
+ // Not set mimetype limits yet
+ assertTrue("No limits so should have been ok",
+ transformer.isTransformableSize(A, byteValue+1, B, options));
+
transformer.setMaxSourceSizeKBytes(kValue+1);
limits.setMaxSourceSizeKBytes(kValue);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+ transformer.register();
assertTrue("Size is equal to limit so should have been ok",
transformer.isTransformableSize(A, byteValue, B, options));
- assertFalse("Size is greater than limit so should not have failed",
+ assertFalse("Size is greater than limit so should have failed",
transformer.isTransformableSize(A, byteValue+1, B, options));
}
@@ -348,6 +460,7 @@ public class AbstractContentTransformerLimitsTest
transformer.setMaxSourceSizeKBytes(kValue);
transformer.setPageLimitsSuported(true);
+ transformer.register();
// Test works as normal before setting the pageLimit
assertTrue("Size is less than limit so should have been ok",
@@ -370,6 +483,7 @@ public class AbstractContentTransformerLimitsTest
long value = 1234;
transformer.setTimeoutMs(value);
+ transformer.register();
assertEquals("Limit should not have been set in the reader", null, reader.getLimits());
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java
index c078ac9b1a..e8faadb083 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java
@@ -70,6 +70,7 @@ public abstract class AbstractContentTransformerTest extends TestCase
protected ServiceRegistry serviceRegistry;
protected MimetypeService mimetypeService;
protected TransformerDebug transformerDebug;
+ protected TransformerConfig transformerConfig;
/**
* Fetches a transformer to test for a given transformation. The transformer
@@ -97,6 +98,8 @@ public abstract class AbstractContentTransformerTest extends TestCase
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
mimetypeService = serviceRegistry.getMimetypeService();
transformerDebug = (TransformerDebug) ctx.getBean("transformerDebug");
+ transformerConfig = (TransformerConfig) ctx.getBean("transformerConfig");
+
// perform a little cleaning up
long now = System.currentTimeMillis();
TempFileProvider.TempFileCleanerJob.removeFiles(now);
diff --git a/source/java/org/alfresco/repo/content/transform/AppleIWorksContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/AppleIWorksContentTransformerTest.java
index be25a8ba51..eb8b09822b 100644
--- a/source/java/org/alfresco/repo/content/transform/AppleIWorksContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/AppleIWorksContentTransformerTest.java
@@ -40,6 +40,7 @@ public class AppleIWorksContentTransformerTest extends AbstractContentTransforme
// Ugly cast just to set the MimetypeService
((ContentTransformerHelper)transformer).setMimetypeService(mimetypeService);
+ ((ContentTransformerHelper)transformer).setTransformerConfig(transformerConfig);
}
@Override
diff --git a/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformerTest.java
index 880f7febdf..def6934867 100644
--- a/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformerTest.java
@@ -47,6 +47,7 @@ public class ArchiveContentTransformerTest extends AbstractContentTransformerTes
transformer = new ArchiveContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype)
diff --git a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java
index 565251833e..b0d88bacd8 100644
--- a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformerTest.java
@@ -38,6 +38,7 @@ public class BinaryPassThroughContentTransformerTest extends AbstractContentTran
transformer = new BinaryPassThroughContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
index 55a1364c7e..68055c1728 100644
--- a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -267,7 +267,7 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
transformer = transformerIterator.next();
if (transformer != null)
{
- if (transformer.isTransformableMimetype(sourceMimetype, targetMimetype, options))
+ if (transformer.isTransformable(sourceMimetype, -1, targetMimetype, options))
{
return false;
}
@@ -306,7 +306,7 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
}
else
{
- if (transformer.isTransformableMimetype(currentSourceMimetype, currentTargetMimetype, options) == false)
+ if (transformer.isTransformable(currentSourceMimetype, -1, currentTargetMimetype, options) == false)
{
result = false;
break;
diff --git a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java
index 6316d101cd..b83216f483 100644
--- a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformerTest.java
@@ -63,6 +63,7 @@ public class ComplexContentTransformerTest extends AbstractContentTransformerTes
transformer = new ComplexContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
// set the transformer list
List transformers = new ArrayList(2);
transformers.add(unoTransformer);
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java
index e683b88dbf..200db7ab86 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java
@@ -78,29 +78,39 @@ public interface ContentTransformer extends ContentWorker
public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options);
/**
- * Indicates whether given the provided transformation parmaters this transformer can prvide an explict
+ * @deprecated Use transformer priority and unsupported transformer properties.
+ *
+ * Indicates whether given the provided transformation parameters this transformer can provide an explicit
* transformation.
*
- * An explict transformation indicates that the transformation happens directly and not as a result of
- * another transformation process. Explict transformation always take presidence over normal transformations.
+ * An explicit transformation indicates that the transformation happens directly and not as a result of
+ * another transformation process. Explicit transformation always take presidency over normal transformations.
*
* @param sourceMimetype the source mimetype
* @param targetMimetype the target mimetype
* @param options the transformation options
- * @return boolean true if it is an explicit transformation, flase otherwise
+ * @return boolean true if it is an explicit transformation, false otherwise
*/
public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options);
+ /**
+ * @deprecated use mimetype specific version.
+ */
+ public long getTransformationTime();
+
/**
* Provides an estimate, usually a worst case guess, of how long a transformation
- * will take.
+ * will take. Null mimetype values provide the overall value for the transformer.
*
* This method is used to determine, up front, which of a set of
* equally reliant transformers will be used for a specific transformation.
*
+ * @param sourceMimetype the source mimetype
+ * @param targetMimetype the target mimetype
+ *
* @return Returns the approximate number of milliseconds per transformation
*/
- public long getTransformationTime();
+ public long getTransformationTime(String sourceMimetype, String targetMimetype);
/**
* @see #transform(ContentReader, ContentWriter, TransformationOptions)
@@ -157,4 +167,9 @@ public interface ContentTransformer extends ContentWorker
*/
public void transform(ContentReader reader, ContentWriter contentWriter, TransformationOptions options)
throws ContentIOException;
+
+ /**
+ * Returns transformer's name used in configuration.
+ */
+ public String getName();
}
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java
index c7278c124b..a92cd5e30d 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -18,37 +18,36 @@
*/
package org.alfresco.repo.content.transform;
-import java.util.Collections;
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+
+import java.util.ArrayList;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ContentAccessor;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.TransformationOptions;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.BeanNameAware;
/**
- * A class providing basic functionality shared by both {@link ContentTransformer}s and {@link ContentTransformerWorker}
- * s.
+ * A class providing basic functionality shared by both {@link ContentTransformer}s and {@link ContentTransformerWorker}s.
*
* @author dward
*/
-public class ContentTransformerHelper
+public class ContentTransformerHelper implements BeanNameAware
{
+ private static final Log logger = LogFactory.getLog(ContentTransformerHelper.class);
private MimetypeService mimetypeService;
- private List explicitTransformations;
- private List supportedTransformations;
- private List unsupportedTransformations;
+ protected TransformerConfig transformerConfig;
+
+ private List deprecatedSetterMessages;
+ private static boolean firstDeprecatedSetter = true;
- /**
- *
- */
- public ContentTransformerHelper()
- {
- setExplicitTransformations(Collections. emptyList());
- setSupportedTransformations(null);
- setUnsupportedTransformations(null);
- }
+ /** The bean name. */
+ private String beanName;
/**
* Helper setter of the mimetype service. This is not always required.
@@ -69,37 +68,35 @@ public class ContentTransformerHelper
}
/**
- * Specifies transformations that are considered to be 'exceptional' so
- * should be used in preference to other transformers that can perform
- * the same transformation.
+ * @deprecated supported transformations are now set with global properties rather than spring configuration.
*/
public void setExplicitTransformations(List explicitTransformations)
{
- this.explicitTransformations = explicitTransformations;
+ deprecatedSupportedTransformations(explicitTransformations, null);
+ // TODO Should suggest properties that indicate lower priority transformers should be unsupported.
+ // This is for completeness rather than needed as the priority will avoid the non explicit
+ // transformers from being used. Explicit transformers are given a priority of 5 rather than 10.
}
/**
- * Restricts the transformations that may be performed even though the transformer
- * may perform other transformations. An null value applies no additional restrictions.
- * Even if a list is specified, the
- * {@link ContentTransformer#isTransformableMimetype(String, String, TransformationOptions)}
- * method will still be called.
+ * @deprecated supported transformations are now set with global properties rather than spring configuration.
*/
public void setSupportedTransformations(List supportedTransformations)
{
- this.supportedTransformations = supportedTransformations;
+ deprecatedSupportedTransformations(supportedTransformations, "true");
}
/**
- * Restricts the transformations that may be performed even though the transformer
- * may claim to perform the transformations. An null value applies no additional restrictions.
- * Even if a list is specified, the
- * {@link ContentTransformer#isTransformableMimetype(String, String, TransformationOptions)}
- * method will still be called.
+ * @deprecated supported transformations are now set with global properties rather than spring configuration.
*/
public void setUnsupportedTransformations(List unsupportedTransformations)
{
- this.unsupportedTransformations = unsupportedTransformations;
+ deprecatedSupportedTransformations(unsupportedTransformations, "false");
+ }
+
+ public void setTransformerConfig(TransformerConfig transformerConfig)
+ {
+ this.transformerConfig = transformerConfig;
}
/**
@@ -123,58 +120,138 @@ public class ContentTransformerHelper
}
/**
- * Default implementation, override if need to extend logic
+ * @deprecated Should now use priority and unsupported transformer properties.
*
* @see org.alfresco.repo.content.transform.ContentTransformer#isExplicitTransformation(java.lang.String,
* java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
*/
public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
- boolean result = false;
- for (ExplictTransformationDetails explicitTransformation : this.explicitTransformations)
- {
- if (sourceMimetype.equals(explicitTransformation.getSourceMimetype()) == true
- && targetMimetype.equals(explicitTransformation.getTargetMimetype()) == true)
- {
- result = true;
- break;
- }
- }
- return result;
+ return transformerConfig.getPriority(((ContentTransformer)this), sourceMimetype, targetMimetype) == TransformerConfig.PRIORITY_EXPLICIT;
}
public boolean isSupportedTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
- boolean supported = true;
- if (supportedTransformations != null)
+ return transformerConfig.isSupportedTransformation(((ContentTransformer)this), sourceMimetype, targetMimetype, options);
+ }
+
+ /**
+ * Sets the Spring bean name.
+ */
+ @Override
+ public void setBeanName(String beanName)
+ {
+ this.beanName = beanName;
+ }
+
+ /**
+ * THIS IS A CUSTOM SPRING INIT METHOD
+ */
+ public void register()
+ {
+ logDeprecatedSetter();
+ }
+
+ /**
+ * Returns the Spring bean name.
+ */
+ public String getBeanName()
+ {
+ return beanName;
+ }
+
+ /**
+ * Returns transformer name. Uses the Spring bean name, but if null uses the class name.
+ */
+ public String getName()
+ {
+ return (beanName == null) ? getClass().getSimpleName() : beanName;
+ }
+
+ /**
+ * Called by deprecated property setter methods that should no longer be called
+ * by Spring configuration as the values are now set using global properties.
+ * @param suffixAndValue that should have been used. The first part of the
+ * property name "content.transformer.." should not be included.
+ * The reason is that the setter methods might be called before the bean
+ * name is set.
+ */
+ protected void deprecatedSetter(String suffixAndValue)
+ {
+ if (deprecatedSetterMessages == null)
{
- supported = false;
- for (SupportedTransformation suportedTransformation : supportedTransformations)
+ deprecatedSetterMessages = new ArrayList();
+ }
+ deprecatedSetterMessages.add(suffixAndValue);
+ }
+
+ /**
+ * Called when the bean name is set after all the deprecated setters to log
+ * INFO messages with the Alfresco global properties that should now be set
+ * (if no set) to replace Spring configuration.
+ */
+ private void logDeprecatedSetter()
+ {
+ if (deprecatedSetterMessages != null)
+ {
+ for (String suffixAndValue: deprecatedSetterMessages)
{
- String supportedSourceMimetype = suportedTransformation.getSourceMimetype();
- String supportedTargetMimetype = suportedTransformation.getTargetMimetype();
- if ((supportedSourceMimetype == null || sourceMimetype.equals(supportedSourceMimetype)) &&
- (supportedTargetMimetype == null || targetMimetype.equals(supportedTargetMimetype)))
+ String propertyNameAndValue = TransformerConfig.CONTENT+beanName+'.'+suffixAndValue;
+ String propertyName = propertyNameAndValue.replaceAll("=.*", "");
+ if (transformerConfig.getProperty(propertyName) == null)
{
- supported = true;
- break;
+ if (firstDeprecatedSetter)
+ {
+ firstDeprecatedSetter = false;
+ logger.error("In order to support dynamic setting of transformer options, Spring XML configuration");
+ logger.error("is no longer used to initialise these options.");
+ logger.error(" ");
+ logger.error("Your system appears to contains custom Spring configuration which should be replace by");
+ logger.error("the following Alfresco global properties. In the case of the Enterprise edition these");
+ logger.error("values may then be dynamically changed via JMX.");
+ logger.error(" ");
+ // Note: Cannot set these automatically because, an MBean reset would clear them.
+ }
+ logger.error(propertyNameAndValue);
+
+ // Add them to the subsystem's properties anyway (even though an MBean reset would clear them),
+ // so that existing unit tests work.
+ transformerConfig.setProperty(propertyNameAndValue);
+ }
+ else
+ {
+ logger.warn(propertyNameAndValue+" is set, but spring config still exists");
}
}
+ deprecatedSetterMessages = null;
}
- if (supported && unsupportedTransformations != null)
+ }
+
+ private void deprecatedSupportedTransformations(List extends SupportedTransformation> transformations, String value)
+ {
+ if (transformations != null)
{
- for (SupportedTransformation unsuportedTransformation : unsupportedTransformations)
+ for (SupportedTransformation transformation: transformations)
{
- String unsupportedSourceMimetype = unsuportedTransformation.getSourceMimetype();
- String unsupportedTargetMimetype = unsuportedTransformation.getTargetMimetype();
- if ((unsupportedSourceMimetype == null || sourceMimetype.equals(unsupportedSourceMimetype)) &&
- (unsupportedTargetMimetype == null || targetMimetype.equals(unsupportedTargetMimetype)))
- {
- supported = false;
- break;
- }
+ String sourceMimetype = transformation.getSourceMimetype();
+ String targetMimetype = transformation.getTargetMimetype();
+ String sourceExt = getExtensionOrAny(sourceMimetype);
+ String targetExt = getExtensionOrAny(targetMimetype);
+ deprecatedSetter(TransformerConfig.MIMETYPES_SEPARATOR.substring(1)+sourceExt+'.'+targetExt+
+ (value == null // same as: transformation instanceof ExplictTransformationDetails
+ ? TransformerConfig.PRIORITY+"="+TransformerConfig.PRIORITY_EXPLICIT
+ : TransformerConfig.SUPPORTED+"="+value));
}
}
- return supported;
+ }
+
+ protected String getExtensionOrAny(String mimetype)
+ {
+ return mimetype == null || ANY.equals(mimetype) ? ANY : mimetypeService.getExtension(mimetype);
+ }
+
+ public String toString()
+ {
+ return getName();
}
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
index 66ea3e89cd..f796060704 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
@@ -57,7 +57,7 @@ public class ContentTransformerRegistry
public ContentTransformerRegistry(TransformerSelector transformerSelector)
{
this.transformerSelector = transformerSelector;
- this.transformers = new ArrayList(10);
+ this.transformers = new ArrayList(70);
}
/**
@@ -114,7 +114,7 @@ public class ContentTransformerRegistry
public List getActiveTransformers(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
// Get the list of transformers
- List transformers = transformerSelector.selectTransformers(this.transformers, sourceMimetype, sourceSize, targetMimetype, options);
+ List transformers = transformerSelector.selectTransformers(sourceMimetype, sourceSize, targetMimetype, options);
if (logger.isDebugEnabled())
{
logger.debug("Searched for transformer: \n" +
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java
index c3bd6b9b61..590d1a1b08 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java
@@ -52,6 +52,12 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
private ContentReader reader;
private ContentWriter writer;
+ private DummyTransformer ad20;
+ private DummyTransformer ad30;
+ private DummyTransformer ad10;
+ private DummyTransformer ad25a;
+ private DummyTransformer ad25b;
+
@Override
public void setUp() throws Exception
{
@@ -70,19 +76,23 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
bytes[i] = (byte)i;
}
// create the dummyRegistry
- dummyRegistry = new ContentTransformerRegistry(new TransformerSelectorImpl());
+ TransformerSelectorImpl transformerSelector = new TransformerSelectorImpl();
+ transformerSelector.setTransformerConfig(transformerConfig);
+ transformerSelector.setContentTransformerRegistry(dummyRegistry);
+ dummyRegistry = new ContentTransformerRegistry(transformerSelector);
+ transformerSelector.setContentTransformerRegistry(dummyRegistry);
// create some dummy transformers for reliability tests
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, B, 10L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, B, 10L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, C, 10L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, C, 10L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, B, C, 10L);
+ new DummyTransformer(mimetypeService, "transformer.testAB10a", transformerDebug, transformerConfig, dummyRegistry, A, B, 10L);
+ new DummyTransformer(mimetypeService, "transformer.testAB10b", transformerDebug, transformerConfig, dummyRegistry, A, B, 10L);
+ new DummyTransformer(mimetypeService, "transformer.testAC10a", transformerDebug, transformerConfig, dummyRegistry, A, C, 10L);
+ new DummyTransformer(mimetypeService, "transformer.testAC10b", transformerDebug, transformerConfig, dummyRegistry, A, C, 10L);
+ new DummyTransformer(mimetypeService, "transformer.testBC10", transformerDebug, transformerConfig, dummyRegistry, B, C, 10L);
// create some dummy transformers for speed tests
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, D, 20L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, D, 30L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, D, 10L); // the fast one
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, D, 25L);
- new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, D, 25L);
+ ad20 = new DummyTransformer(mimetypeService, "transformer.testAD20", transformerDebug, transformerConfig, dummyRegistry, A, D, 20L);
+ ad30 = new DummyTransformer(mimetypeService, "transformer.testAD30", transformerDebug, transformerConfig, dummyRegistry, A, D, 30L);
+ ad10 = new DummyTransformer(mimetypeService, "transformer.testAD10", transformerDebug, transformerConfig, dummyRegistry, A, D, 10L); // the fast one
+ ad25a = new DummyTransformer(mimetypeService, "transformer.testAD25a", transformerDebug, transformerConfig, dummyRegistry, A, D, 25L);
+ ad25b = new DummyTransformer(mimetypeService, "transformer.testAD25b", transformerDebug, transformerConfig, dummyRegistry, A, D, 25L);
}
/**
@@ -131,20 +141,45 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
*/
public void testPerformanceRetrieval() throws Exception
{
+ // Until the threshold (3) is reached by each transformer with the same priority it will
+ // be tried that many times in the order defined. 20, 30, 10, 25, 25
+ for (int i=1; i<=3; i++)
+ {
+ long expectedTime = i == 1 ? 0L : 20L;
+ ContentTransformer transformer1 = dummyRegistry.getTransformer(A, -1, D, OPTIONS);
+ assertEquals(i+" incorrect transformation time", expectedTime, transformer1.getTransformationTime(A, D));
+ ad20.transformInternal(null, null, null);
+ }
+ for (int i=1; i<=3; i++)
+ {
+ long expectedTime = i == 1 ? 0L : 30L;
+ ContentTransformer transformer1 = dummyRegistry.getTransformer(A, -1, D, OPTIONS);
+ assertEquals(i+" incorrect transformation time", expectedTime, transformer1.getTransformationTime(A, D));
+ ad30.transformInternal(null, null, null);
+ }
+ for (int i=1; i<=3; i++)
+ {
+ ad10.transformInternal(null, null, null);
+ ad25a.transformInternal(null, null, null);
+ ad25b.transformInternal(null, null, null);
+ }
+
+ // Now the average times are set up, it should find the fastest one
+
// A -> D expect 1.0, 10ms
ContentTransformer transformer1 = dummyRegistry.getTransformer(A, -1, D, OPTIONS);
assertTrue("Incorrect reliability", transformer1.isTransformable(A, -1, D, OPTIONS));
assertFalse("Incorrect reliability", transformer1.isTransformable(D, -1, A, OPTIONS));
- assertEquals("Incorrect transformation time", 10L, transformer1.getTransformationTime());
+ assertEquals("Incorrect transformation time", 10L, transformer1.getTransformationTime(A, D));
// A -> D has 10, 20, 25, 25, 30
List activeTransformers = dummyRegistry.getActiveTransformers(A, -1, D, OPTIONS);
assertEquals("Not all found", 5, activeTransformers.size());
- assertEquals("Incorrect order", 10L, activeTransformers.get(0).getTransformationTime());
- assertEquals("Incorrect order", 20L, activeTransformers.get(1).getTransformationTime());
- assertEquals("Incorrect order", 25L, activeTransformers.get(2).getTransformationTime());
- assertEquals("Incorrect order", 25L, activeTransformers.get(3).getTransformationTime());
- assertEquals("Incorrect order", 30L, activeTransformers.get(4).getTransformationTime());
+ assertEquals("Incorrect order", 10L, activeTransformers.get(0).getTransformationTime(A, D));
+ assertEquals("Incorrect order", 20L, activeTransformers.get(1).getTransformationTime(A, D));
+ assertEquals("Incorrect order", 25L, activeTransformers.get(2).getTransformationTime(A, D));
+ assertEquals("Incorrect order", 25L, activeTransformers.get(3).getTransformationTime(A, D));
+ assertEquals("Incorrect order", 30L, activeTransformers.get(4).getTransformationTime(A, D));
// Disable two of them, and re-test
((DummyTransformer)activeTransformers.get(2)).disable();
@@ -152,9 +187,9 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
activeTransformers = dummyRegistry.getActiveTransformers(A, -1, D, OPTIONS);
assertEquals("Not all found", 3, activeTransformers.size());
- assertEquals("Incorrect order", 10L, activeTransformers.get(0).getTransformationTime());
- assertEquals("Incorrect order", 20L, activeTransformers.get(1).getTransformationTime());
- assertEquals("Incorrect order", 25L, activeTransformers.get(2).getTransformationTime());
+ assertEquals("Incorrect order", 10L, activeTransformers.get(0).getTransformationTime(A, D));
+ assertEquals("Incorrect order", 20L, activeTransformers.get(1).getTransformationTime(A, D));
+ assertEquals("Incorrect order", 25L, activeTransformers.get(2).getTransformationTime(A, D));
}
public void testScoredRetrieval() throws Exception
@@ -180,9 +215,9 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
{
AbstractContentTransformer2 dummyTransformer = new DummyTransformer(
mimetypeService,
- transformerDebug,
- dummyRegistry, MimetypeMap.MIMETYPE_FLASH,
- MimetypeMap.MIMETYPE_EXCEL, 12345);
+ "transformer.testExplicit",
+ transformerDebug, transformerConfig,
+ dummyRegistry, MimetypeMap.MIMETYPE_FLASH, MimetypeMap.MIMETYPE_EXCEL, 12345);
// set an explicit transformation
ExplictTransformationDetails key =
new ExplictTransformationDetails(
@@ -212,25 +247,23 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
public DummyTransformer(
MimetypeService mimetypeService,
- TransformerDebug transformerDebug,
- ContentTransformerRegistry registry, String sourceMimetype,
- String targetMimetype, long transformationTime)
+ String name,
+ TransformerDebug transformerDebug, TransformerConfig transformerConfig,
+ ContentTransformerRegistry registry, String sourceMimetype, String targetMimetype, long transformationTime)
{
super.setMimetypeService(mimetypeService);
super.setTransformerDebug(transformerDebug);
+ super.setTransformerConfig(transformerConfig);
super.setRegistry(registry);
this.sourceMimetype = sourceMimetype;
this.targetMimetype = targetMimetype;
this.transformationTime = transformationTime;
+ setBeanName(name+'.'+System.currentTimeMillis()%100000);
+
// register
register();
}
- protected void enable()
- {
- disable = false;
- }
-
protected void disable()
{
disable = true;
@@ -262,16 +295,16 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
TransformationOptions options) throws Exception
{
// just update the transformation time
- super.recordTime(transformationTime);
+ super.recordTime(sourceMimetype, targetMimetype, transformationTime);
}
- /**
- * @return Returns the fixed dummy average transformation time
- */
- public synchronized long getTransformationTime()
- {
- return transformationTime;
- }
+// /**
+// * @return Returns the fixed dummy average transformation time
+// */
+// public synchronized long getTransformationTime(String sourceMimetype, String targetMimetype)
+// {
+// return transformationTime;
+// }
}
@Override
diff --git a/source/java/org/alfresco/repo/content/transform/DoubleMap.java b/source/java/org/alfresco/repo/content/transform/DoubleMap.java
new file mode 100644
index 0000000000..6f8fd306b6
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/DoubleMap.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2005-2012 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.content.transform;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Provides simple get and put access to a Map like object with a double key that allows
+ * either or both keys to be a wild card that matches any value. May not contain null
+ * keys or values.
+ *
+ * Originally created for mapping source and target mimetypes to transformer configuration data.
+ *
+ * For example:
+ *
+ * DoubleMap foodLikes = new DoubleMap("*", "*");
+ *
+ * foodLikes.put("cat", "mouse", "likes");
+ *
+ * foodLikes.get("cat", "mouse"); // returns "likes"
+ * foodLikes.get("cat", "meat"); // returns null
+ *
+ * foodLikes.put("dog", "meat", "likes");
+ * foodLikes.put("dog", "stick", "unsure");
+ * foodLikes.put("child", "olive", "dislikes");
+ * foodLikes.put("bird", "*", "worms only");
+ * foodLikes.put("*", "meat", "unknown");
+ * foodLikes.put("*", "*", "no idea at all");
+ *
+ * foodLikes.get("cat", "mouse"); // returns "likes"
+ * foodLikes.get("cat", "meat"); // returns "unknown"
+ * foodLikes.get("cat", "tea"); // returns "unknown"
+ * foodLikes.get("*", "mouse"); // returns "no idea at all"
+ * foodLikes.get("dog", "*"); // returns "no idea at all"
+ * foodLikes.get("bird","*"); // returns "worms only"
+ * foodLikes.get("bird","tea"); // returns "worms only"
+ *
+ *
+ * @author Alan Davis
+ */
+public class DoubleMap
+{
+ private final Map> mapMap = new ConcurrentHashMap>();
+ private final K1 anyKey1;
+ private final K2 anyKey2;
+
+ public DoubleMap(K1 anyKey1, K2 anyKey2)
+ {
+ this.anyKey1 = anyKey1;
+ this.anyKey2 = anyKey2;
+ }
+
+ /**
+ * Returns a value for the given keys.
+ */
+ public V get(K1 key1, K2 key2)
+ {
+ V value = null;
+
+ Map map = mapMap.get(key1);
+ boolean anySource = false;
+ if (map == null)
+ {
+ map = mapMap.get(anyKey1);
+ anySource = true;
+ }
+ if (map != null)
+ {
+ value = map.get(key2);
+ if (value == null)
+ {
+ value = map.get(anyKey2);
+
+ // Handle the case were there is no match using an non wildcarded key1 and
+ // key2 but is a match if key1 is wildcarded.
+ if (value == null && !anySource)
+ {
+ map = mapMap.get(anyKey1);
+ if (map != null)
+ {
+ value = map.get(key2);
+ if (value == null)
+ {
+ value = map.get(anyKey2);
+ }
+ }
+ }
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Adds a value for the given keys.
+ */
+ public void put(K1 key1, K2 key2, V t)
+ {
+ Map map = mapMap.get(key1);
+ if (map == null)
+ {
+ map = new ConcurrentHashMap();
+ mapMap.put(key1, map);
+ }
+
+ map.put(key2, t);
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/transform/EMLTransformerTest.java b/source/java/org/alfresco/repo/content/transform/EMLTransformerTest.java
index 2eafdb7b67..dbac19f173 100644
--- a/source/java/org/alfresco/repo/content/transform/EMLTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/EMLTransformerTest.java
@@ -50,6 +50,7 @@ public class EMLTransformerTest extends AbstractContentTransformerTest
transformer = new EMLTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
@Override
diff --git a/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java
index f55e64aaea..ec70b37776 100644
--- a/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java
@@ -57,6 +57,7 @@ public class FailoverContentTransformerTest extends AbstractContentTransformerTe
transformer = (FailoverContentTransformer) failoverAppContext.getBean("transformer.failover.Test-FailThenSucceed");
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java
index 1eb6f2cfb0..8c970b472b 100644
--- a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java
@@ -42,6 +42,7 @@ public class HtmlParserContentTransformerTest extends AbstractContentTransformer
transformer = new HtmlParserContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype)
diff --git a/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java
index 3b410590f1..b847812de2 100644
--- a/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/MailContentTransformerTest.java
@@ -45,6 +45,7 @@ public class MailContentTransformerTest extends AbstractContentTransformerTest
transformer = new MailContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java
index eb7ba7215c..7c97c24860 100644
--- a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformerTest.java
@@ -70,6 +70,7 @@ public class MediaWikiContentTransformerTest extends AbstractContentTransformerT
transformer = new MediaWikiContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
protected ContentTransformer getTransformer(String sourceMimetype, String targetMimetype)
diff --git a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java
index d3728cb03c..31f113c331 100644
--- a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java
@@ -50,6 +50,7 @@ public class OpenOfficeContentTransformerTest extends AbstractContentTransformer
transformer = new ProxyContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
transformer.setWorker(this.worker);
}
diff --git a/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java
index d83eae72b3..facbe456d2 100644
--- a/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/PdfBoxContentTransformerTest.java
@@ -38,6 +38,7 @@ public class PdfBoxContentTransformerTest extends AbstractContentTransformerTest
transformer = new PdfBoxContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/PoiContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/PoiContentTransformerTest.java
index 06386995c6..e4b8ad5832 100644
--- a/source/java/org/alfresco/repo/content/transform/PoiContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/PoiContentTransformerTest.java
@@ -38,6 +38,7 @@ public class PoiContentTransformerTest extends AbstractContentTransformerTest
transformer = new PoiContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java
index 1a8e1ccbfc..df7fc6669d 100644
--- a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformerTest.java
@@ -46,6 +46,7 @@ public class PoiHssfContentTransformerTest extends TikaPoweredContentTransformer
transformer = new PoiHssfContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
@Override
diff --git a/source/java/org/alfresco/repo/content/transform/PoiOOXMLContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/PoiOOXMLContentTransformerTest.java
index 6f29a9a974..56478efa48 100644
--- a/source/java/org/alfresco/repo/content/transform/PoiOOXMLContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/PoiOOXMLContentTransformerTest.java
@@ -38,6 +38,7 @@ public class PoiOOXMLContentTransformerTest extends AbstractContentTransformerTe
transformer = new PoiOOXMLContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java
index 40fdbb8a62..9d6cb4efd0 100644
--- a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java
@@ -74,10 +74,12 @@ public class RuntimeExecutableContentTransformerTest extends BaseAlfrescoTestCas
worker.afterPropertiesSet();
TransformerDebug transformerDebug = (TransformerDebug) ctx.getBean("transformerDebug");
+ TransformerConfig transformerConfig = (TransformerConfig) ctx.getBean("transformerConfig");
ProxyContentTransformer transformer = new ProxyContentTransformer();
transformer.setMimetypeService(serviceRegistry.getMimetypeService());
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
transformer.setWorker(worker);
this.transformer = transformer;
}
diff --git a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerWorker.java b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerWorker.java
index 9537fed4b6..4dcbf7de81 100644
--- a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerWorker.java
+++ b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerWorker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -169,19 +169,7 @@ public class RuntimeExecutableContentTransformerWorker extends ContentTransforme
*/
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
- if (!available)
- {
- return false;
- }
-
- if (isExplicitTransformation(sourceMimetype, targetMimetype, options))
- {
- return true;
- }
- else
- {
- return false;
- }
+ return available;
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java
index d00b5f0932..83b9916bb8 100644
--- a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformerTest.java
@@ -68,6 +68,7 @@ public class StringExtractingContentTransformerTest extends AbstractContentTrans
transformer = new StringExtractingContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
targetWriter = new FileContentWriter(getTempFile());
targetWriter.setMimetype("text/plain");
targetWriter.setEncoding("UTF-8");
diff --git a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java
index 3005d57d43..b5a3d0dd7c 100644
--- a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformerTest.java
@@ -46,6 +46,7 @@ public class TextMiningContentTransformerTest extends AbstractContentTransformer
transformer = new TextMiningContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java
index dbc79e45ae..a43cbf6392 100644
--- a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformerTest.java
@@ -50,9 +50,11 @@ public class TextToPdfContentTransformerTest extends AbstractContentTransformerT
transformer = new TextToPdfContentTransformer();
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
transformer.setStandardFont("Times-Roman");
transformer.setFontSize(20);
transformer.setPageLimit(-1);
+ transformer.register();
}
/**
@@ -120,7 +122,9 @@ public class TextToPdfContentTransformerTest extends AbstractContentTransformerT
private void transformTextAndCheckPageLength(int pageLimit) throws IOException
{
+ transformer.setBeanName("transformer.test"+System.currentTimeMillis()%100000);
transformer.setPageLimit(pageLimit);
+ transformer.register();
int pageLength = 32;
int lines = (pageLength+10) * ((pageLimit > 0) ? pageLimit : 1);
diff --git a/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java
index bb31e33e31..60062fffd6 100644
--- a/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java
@@ -43,6 +43,7 @@ public class TikaAutoContentTransformerTest extends TikaPoweredContentTransforme
transformer = new TikaAutoContentTransformer( config );
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
+ transformer.setTransformerConfig(transformerConfig);
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerConfig.java b/source/java/org/alfresco/repo/content/transform/TransformerConfig.java
new file mode 100644
index 0000000000..a0fe08bd12
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerConfig.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2005-2012 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.content.transform;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.alfresco.service.cmr.repository.TransformationOptionLimits;
+import org.alfresco.service.cmr.repository.TransformationOptions;
+
+/**
+ * Provides access to transformer configuration and current performance data.
+ *
+ * @author Alan Davis
+ */
+public interface TransformerConfig
+{
+ /**
+ * Wild card mimetype and mimetype extension.
+ */
+ public static final String ANY = "*";
+
+ /**
+ * Prefix before the transformer name of all property names that contain transformer
+ * information
+ */
+ static final String CONTENT = "content.";
+
+ /**
+ * Prefix for all transformer names
+ */
+ static final String TRANSFORMER = "transformer.";
+
+ /**
+ * The combined content and transformer name prefix of for all property names that contain
+ * transformer information
+ */
+ static final String PREFIX = CONTENT+TRANSFORMER;
+
+ /**
+ * The 'transformer name' for system wide defaults for all transformers
+ */
+ static final String DEFAULT_TRANSFORMER = TRANSFORMER+"default";
+
+ /**
+ * Name given to the 'SUMMARY' dummy (does not exist) transformer that gathers data
+ * from all root level transformations
+ */
+ static final String SUMMARY_TRANSFORMER_NAME = "SUMMARY";
+
+ /**
+ * The separator between the transformer name and two mimetype extensions in a property name.
+ */
+ static final String MIMETYPES_SEPARATOR = ".mimetypes.";
+
+ /**
+ * The suffix to property names for supported and unsupported combinations.
+ */
+ static final String SUPPORTED = ".supported";
+
+ /**
+ * The suffix to property names for the priority.
+ */
+ static final String PRIORITY = ".priority";
+
+ /**
+ * The suffix to property names for the threshold count.
+ */
+ static final String THRESHOLD_COUNT = ".thresholdCount";
+
+ /**
+ * The suffix to property names for the error time.
+ */
+ static final String ERROR_TIME = ".errorTime";
+
+ /**
+ * The suffix to property names for the the average time. Only used in the initial setup of
+ * TransformerData. This is a historical property used by the 'Transformation Server' to set
+ * an effective priority.
+ */
+ static final String INITIAL_TIME = ".time";
+
+ /**
+ * The suffix to property names for the the average count. Only used in the initial setup of
+ * TransformerData. This is a historical property used by the 'Transformation Server' to set
+ * an effective priority.
+ */
+ static final String INITIAL_COUNT = ".count";
+
+ /**
+ * To support the historical concept of EXPLICIT transformers, all such transformers
+ * are given a {@link PRIORITY_EXPLICIT} (5). By default transformers have a default of 10.
+ * A value of 5 allows better transformers to be added later.
+ */
+ public int PRIORITY_EXPLICIT = 5;
+
+ /**
+ * Suffixes to property names used to define transformation limits
+ */
+ static final Collection LIMIT_SUFFIXES = Arrays.asList(new String [] {
+ '.'+TransformationOptionLimits.OPT_MAX_SOURCE_SIZE_K_BYTES,
+ '.'+TransformationOptionLimits.OPT_TIMEOUT_MS,
+ '.'+TransformationOptionLimits.OPT_MAX_PAGES,
+ '.'+TransformationOptionLimits.OPT_READ_LIMIT_K_BYTES,
+ '.'+TransformationOptionLimits.OPT_READ_LIMIT_TIME_MS,
+ '.'+TransformationOptionLimits.OPT_PAGE_LIMIT
+ });
+
+ /**
+ * No suffixes to property names used to define transformer settings.
+ */
+ public static final Collection NO_SUFFIXES = Collections.singletonList("");
+
+ /**
+ * Returns a transformer property value.
+ * @param name of the property.
+ * @return a transformer property or {@code null} if not set.
+ */
+ String getProperty(String name);
+
+ /**
+ * Sets a transformer property value. This will be stored in the database but on an MBean
+ * reset would be cleared.
+ *
+ * @param propertyNameAndValue
+ */
+ void setProperty(String propertyNameAndValue);
+
+ /**
+ * Returns and creates if needed the {@link TransformerStatistics} object for the combination of
+ * transformer, sourceMimetype and targetMimetype. When transformer is null this is the
+ * system wide summary object for a combination of sourceMimetype and targetMimetype.
+ * When both sourceMimetype and targetMimetype are null this is the transformer's summary
+ * object. When all three parameters are null this is the system wide summary for all
+ * transformers.
+ * @param transformer the transformer for which data is being recorded.
+ * @param sourceMimetype the source mimetype.
+ * @param targetMimetype the source mimetype.
+ * @return the requested {@link TransformerStatistics}.
+ */
+ public TransformerStatistics getStatistics(ContentTransformer transformer, String sourceMimetype, String targetMimetype);
+
+ /**
+ * Returns the limits defined for the combination of transformer, sourceMimetype and targetMimetype.
+ * When the transformer is null, this is a default value. When both sourceMimetype and targetMimetype
+ * are null this is a default for the specified transformer.
+ * @param transformer
+ * @param sourceMimetype
+ * @param targetMimetype
+ * @return the combined (takes into account defaults from higher levels) limits for the combination.
+ */
+ public TransformationOptionLimits getLimits(ContentTransformer transformer, String sourceMimetype, String targetMimetype);
+
+ /**
+ * Returns true if the supplied mimetype transformation pair is allowed by the list of supported
+ * and unsupported transformations.
+ * @param transformer
+ * @param sourceMimetype
+ * @param targetMimetype
+ * @param options not currently used
+ */
+ public boolean isSupportedTransformation(ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype, TransformationOptions options);
+
+ /**
+ * Returns the priority of the specified transformer for the the combination of source and target mimetype.
+ * @param transformer
+ * @param sourceMimetype
+ * @param targetMimetype
+ * @return the priority. To support the historical concept of EXPLICIT transformers, all such transformers
+ * are given a {@link PRIORITY_EXPLICIT} (5). By default transformers have a default of 10.
+ */
+ public int getPriority(ContentTransformer contentTransformerHelper,
+ String sourceMimetype, String targetMimetype);
+
+ /**
+ * Returns the threshold of the transformer. It is only after this number of transformation attempts
+ * that the average time is used.
+ * @param transformer
+ * @param sourceMimetype
+ * @param targetMimetype
+ * @return the threshold.
+ */
+
+ public int getThresholdCount(ContentTransformer contentTransformerHelper, String sourceMimetype,
+ String targetMimetype);
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerConfigImpl.java b/source/java/org/alfresco/repo/content/transform/TransformerConfigImpl.java
new file mode 100644
index 0000000000..d65edc34cc
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerConfigImpl.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2005-2012 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.content.transform;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.TransformationOptionLimits;
+import org.alfresco.service.cmr.repository.TransformationOptions;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.extensions.surf.util.AbstractLifecycleBean;
+
+/**
+ * Provides access to transformer configuration and current performance data.
+ *
+ * @author Alan Davis
+ */
+public class TransformerConfigImpl extends AbstractLifecycleBean implements TransformerConfig
+{
+ /** The logger. */
+ private static Log logger = LogFactory.getLog(TransformerConfigImpl.class);
+
+ private MimetypeService mimetypeService;
+
+ // Holds statistics about each transformer, sourceMimeType and targetMimetype combination.
+ // A null transformer is the system wide value. Null sourceMimeType and targetMimetype values are
+ // transformer wide summaries.
+ private TransformerConfigStatistics statistics;
+
+ // Transformer limits.
+ private TransformerConfigLimits limits;
+
+ // Supported and unsupported transformations.
+ private TransformerConfigSupported supported;
+
+ // Priorities
+ private TransformerConfigProperty priorities;
+
+ // Threshold counts - Initially there will only be the system wide value, but
+ // having this structure provides flexibility.
+ private TransformerConfigProperty thresholdCounts;
+
+ // Times to be recorded if there is an error - Initially there will only be the system wide value, but
+ // having this structure provides flexibility.
+ private TransformerConfigProperty errorTimes;
+
+ // For backward compatibility where priority could not be set, with AMPs that need to have their
+ // transformer used rather than an inbuilt one. Achieved by making the inbuilt transformers look
+ // poor. Generally contains no entries, other than the system wide 0 values.
+ private TransformerConfigProperty initialAverageTimes;
+ private TransformerConfigProperty initialCounts;
+
+ // Needed to read properties.
+ private ChildApplicationContextFactory subsystemFactory;
+
+ /**
+ * Sets of the mimetype service.
+ *
+ * @param mimetypeService
+ */
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
+ }
+
+ /**
+ * Called by spring after bean is initialised.
+ */
+ public void initialise()
+ {
+ statistics= new TransformerConfigStatistics(this, mimetypeService);
+ limits = new TransformerConfigLimits(getSubsystem(), mimetypeService);
+ supported = new TransformerConfigSupported(getSubsystem(), mimetypeService);
+ priorities = new TransformerConfigProperty(getSubsystem(), mimetypeService, PRIORITY);
+ thresholdCounts = new TransformerConfigProperty(getSubsystem(), mimetypeService, THRESHOLD_COUNT);
+ errorTimes = new TransformerConfigProperty(getSubsystem(), mimetypeService, ERROR_TIME);
+ initialAverageTimes = new TransformerConfigProperty(getSubsystem(), mimetypeService, INITIAL_TIME);
+ initialCounts = new TransformerConfigProperty(getSubsystem(), mimetypeService, INITIAL_COUNT);
+ }
+
+ /**
+ * Returns the 'transformers' subsystem which among other things holds transformer properties.
+ */
+ private synchronized ChildApplicationContextFactory getSubsystem()
+ {
+ if (subsystemFactory == null)
+ {
+ subsystemFactory = getApplicationContext().getBean("Transformers", ChildApplicationContextFactory.class);
+ }
+ return subsystemFactory;
+ }
+
+ @Override
+ protected void onBootstrap(ApplicationEvent event)
+ {
+ }
+
+ @Override
+ protected void onShutdown(ApplicationEvent event)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getProperty(String name)
+ {
+ return getSubsystem().getProperty(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setProperty(String propertyNameAndValue)
+ {
+ int i = propertyNameAndValue.indexOf('=');
+ String name = i != -1 ? propertyNameAndValue.substring(0, i) : propertyNameAndValue;
+ String value = i != -1 ? propertyNameAndValue.substring(i+1) : "";
+ getSubsystem().setProperty(name, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public TransformerStatistics getStatistics(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return statistics.getStatistics(transformer, sourceMimetype, targetMimetype);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public TransformationOptionLimits getLimits(ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype)
+ {
+ return limits.getLimits(transformer, sourceMimetype, targetMimetype);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSupportedTransformation(ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype, TransformationOptions options)
+ {
+ return supported.isSupportedTransformation(transformer, sourceMimetype, targetMimetype, options);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getPriority(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return priorities.getInt(transformer, sourceMimetype, targetMimetype);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getThresholdCount(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return thresholdCounts.getInt(transformer, sourceMimetype, targetMimetype);
+ }
+
+ /**
+ * Gets the time to be recorded if there is an error.
+ */
+ long getErrorTime(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return errorTimes.getLong(transformer, sourceMimetype, targetMimetype);
+ }
+
+ /**
+ * Gets the initial average time to be set for a transformer. Used historically to set the priority of transformers in AMPs.
+ * The initial count value may also obtained via {@link #getInitialCount(ContentTransformer, String, String)}.
+ */
+ long getInitialAverageTime(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return initialAverageTimes.getLong(transformer, sourceMimetype, targetMimetype);
+ }
+
+ /**
+ * Gets the initial transformer count to be set for a transformer. Used historically to set the priority of transformers in AMPs.
+ * Only called if {@link #getInitialAverageTime(ContentTransformer, String, String)} returns a value larger than 0.
+ */
+ int getInitialCount(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return initialCounts.getInt(transformer, sourceMimetype, targetMimetype);
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerConfigLimits.java b/source/java/org/alfresco/repo/content/transform/TransformerConfigLimits.java
new file mode 100644
index 0000000000..917127a4a1
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerConfigLimits.java
@@ -0,0 +1,186 @@
+/*
+ * 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 .
+ */
+package org.alfresco.repo.content.transform;
+
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+import static org.alfresco.repo.content.transform.TransformerConfig.CONTENT;
+import static org.alfresco.repo.content.transform.TransformerConfig.DEFAULT_TRANSFORMER;
+import static org.alfresco.repo.content.transform.TransformerConfig.LIMIT_SUFFIXES;
+import static org.alfresco.repo.content.transform.TransformerConfig.MIMETYPES_SEPARATOR;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.TransformationOptionLimits;
+import org.alfresco.util.Triple;
+
+/**
+ * Provides access to transformer limits defined via properties.
+ *
+ * @author Alan Davis
+ */
+public class TransformerConfigLimits extends TransformerPropertyNameExtractor
+{
+ // Holds configured (entries only exist if configured rather than for all possible combinations)
+ // limits for for transformer, sourceMimeType and targetMimetype combination.
+ // A null transformer is the system wide value. SourceMimeType and targetMimetype may be 'ANY'
+ // values to act as wild cards.
+ private Map> limits;
+
+ public TransformerConfigLimits(ChildApplicationContextFactory subsystem, MimetypeService mimetypeService)
+ {
+ setLimits(subsystem, mimetypeService);
+ }
+
+ /**
+ * Sets the transformer limits created from system properties.
+ */
+ private void setLimits(ChildApplicationContextFactory subsystem, MimetypeService mimetypeService)
+ {
+ limits = new HashMap>();
+
+ // Gets all the transformer, source and target combinations in properties that define limits.
+ Set> transformerNamesAndExt =
+ getTransformerNamesAndExt(MIMETYPES_SEPARATOR, LIMIT_SUFFIXES, true, subsystem, mimetypeService);
+
+ // Add the system wide default just in case it is not included, as we always need this one
+ transformerNamesAndExt.add(new Triple(DEFAULT_TRANSFORMER, ANY, ANY));
+
+ // Populate the transformer limits
+ for (Triple triple: transformerNamesAndExt)
+ {
+ String transformerName = triple.getFirst();
+ String sourceExt = triple.getSecond();
+ String targetExt = triple.getThird();
+ String sourceMimetype = ANY.equals(sourceExt) ? ANY : mimetypeService.getMimetype(sourceExt);
+ String targetMimetype = ANY.equals(targetExt) ? ANY : mimetypeService.getMimetype(targetExt);
+
+ TransformationOptionLimits limits = newTransformationOptionLimits(transformerName, sourceExt, targetExt, subsystem);
+
+ DoubleMap mimetypeLimits =
+ this.limits.get(transformerName);
+ if (mimetypeLimits == null)
+ {
+ mimetypeLimits = new DoubleMap(ANY, ANY);
+ this.limits.put(transformerName, mimetypeLimits);
+ }
+ mimetypeLimits.put(sourceMimetype, targetMimetype, limits);
+ }
+ }
+
+ /**
+ * Returns a TransformationOptionLimits object using property values.
+ * @param transformerName
+ * @param sourceExt is null for overall transformer options rather than for a specific mimetype pair
+ * @param targetExt is null for overall transformer options rather than for a specific mimetype pair
+ * @return a TransformationOptionLimits object or null if not created
+ */
+ private TransformationOptionLimits newTransformationOptionLimits(String transformerName,
+ String sourceExt, String targetExt, ChildApplicationContextFactory subsystem)
+ {
+ TransformationOptionLimits limits = new TransformationOptionLimits();
+
+ // The overall values can be defined in two ways
+ if (ANY.equals(sourceExt) && ANY.equals(targetExt))
+ {
+ setTransformationOptionsFromProperties(limits, transformerName, null, null, subsystem);
+ }
+ setTransformationOptionsFromProperties(limits, transformerName, sourceExt, targetExt, subsystem);
+
+ return limits;
+ }
+
+ private void setTransformationOptionsFromProperties(TransformationOptionLimits limits,
+ String transformerName, String sourceExt, String targetExt, ChildApplicationContextFactory subsystem)
+ {
+ String propertyNameRoot = CONTENT+transformerName+
+ (sourceExt == null ? "" : MIMETYPES_SEPARATOR+sourceExt+'.'+targetExt);
+ int i = 0;
+ for (String suffix: LIMIT_SUFFIXES)
+ {
+ String value = subsystem.getProperty(propertyNameRoot+suffix);
+ if (value != null)
+ {
+ long l = Long.parseLong(value);
+ switch (i)
+ {
+ case 0:
+ limits.setMaxSourceSizeKBytes(l);
+ break;
+ case 1:
+ limits.setTimeoutMs(l);
+ break;
+ case 2:
+ limits.setMaxPages((int)l);
+ break;
+ case 3:
+ limits.setReadLimitKBytes(l);
+ break;
+ case 4:
+ limits.setReadLimitTimeMs(l);
+ break;
+ case 5:
+ limits.setPageLimit((int)l);
+ break;
+ }
+ }
+ i++;
+ }
+ }
+
+ /**
+ * See {@link TransformerConfig#getLimits(ContentTransformer, String, String)}.
+ */
+ public TransformationOptionLimits getLimits(ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype)
+ {
+ if (sourceMimetype == null)
+ {
+ sourceMimetype = ANY;
+ }
+
+ if (targetMimetype == null)
+ {
+ targetMimetype = ANY;
+ }
+
+ String name = (transformer == null) ? DEFAULT_TRANSFORMER : transformer.getName();
+
+ DoubleMap transformerLimits = limits.get(name);
+
+ TransformationOptionLimits limits = (transformerLimits == null) ? null : transformerLimits.get(sourceMimetype, targetMimetype);
+
+ // Individual transformer limits might not exist.
+ TransformationOptionLimits transformerWideLimits = (transformerLimits == null) ? null : transformerLimits.get(ANY, ANY);
+ limits = (limits == null) ? transformerWideLimits : transformerWideLimits == null ? limits : transformerWideLimits.combine(limits);
+
+ // If a non recursive call
+ if (transformer != null)
+ {
+ // System wide 'default' limits should exist.
+ TransformationOptionLimits systemWideLimits = getLimits(null, sourceMimetype, targetMimetype);
+ limits = (limits == null) ? systemWideLimits : systemWideLimits.combine(limits);
+ }
+
+ return limits;
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerConfigProperty.java b/source/java/org/alfresco/repo/content/transform/TransformerConfigProperty.java
new file mode 100644
index 0000000000..cf5c46b079
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerConfigProperty.java
@@ -0,0 +1,155 @@
+/*
+ * 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 .
+ */
+package org.alfresco.repo.content.transform;
+
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+import static org.alfresco.repo.content.transform.TransformerConfig.CONTENT;
+import static org.alfresco.repo.content.transform.TransformerConfig.DEFAULT_TRANSFORMER;
+import static org.alfresco.repo.content.transform.TransformerConfig.MIMETYPES_SEPARATOR;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.util.Triple;
+
+/**
+ * Provides access to single transformer configuration property depending on the
+ * transformer and source and target mimetypes, falling back to defaults.
+ *
+ * @author Alan Davis
+ */
+public class TransformerConfigProperty extends TransformerPropertyNameExtractor
+{
+ private Map> values;
+
+ public TransformerConfigProperty(ChildApplicationContextFactory subsystem,
+ MimetypeService mimetypeService, String propertySuffix)
+ {
+ setValues(subsystem, mimetypeService, propertySuffix);
+ }
+
+ /**
+ * Sets the transformer values created from system properties.
+ */
+ private void setValues(ChildApplicationContextFactory subsystem, MimetypeService mimetypeService, String propertySuffix)
+ {
+ values = new HashMap>();
+
+ // Gets all the transformer, source and target combinations in properties that define
+ // this value.
+ Set> transformerNamesAndMimetypes =
+ getTransformerNamesAndExt(MIMETYPES_SEPARATOR, Collections.singletonList(propertySuffix), true, subsystem, mimetypeService);
+
+ // Add the system wide default just in case it is not included, as we always need this one
+ transformerNamesAndMimetypes.add(new Triple(DEFAULT_TRANSFORMER, ANY, ANY));
+
+ // Populate the transformer values
+ for (Triple triple: transformerNamesAndMimetypes)
+ {
+ String transformerName = triple.getFirst();
+ String sourceExt = triple.getSecond();
+ String targetExt = triple.getThird();
+ String sourceMimetype = ANY.equals(sourceExt) ? ANY : mimetypeService.getMimetype(sourceExt);
+ String targetMimetype = ANY.equals(targetExt) ? ANY : mimetypeService.getMimetype(targetExt);
+
+ String value = newTransformerValue(transformerName, sourceExt, targetExt, subsystem, propertySuffix);
+
+ DoubleMap mimetypeLimits = this.values.get(transformerName);
+ if (mimetypeLimits == null)
+ {
+ mimetypeLimits = new DoubleMap(ANY, ANY);
+ this.values.put(transformerName, mimetypeLimits);
+ }
+ mimetypeLimits.put(sourceMimetype, targetMimetype, value);
+ }
+ }
+
+ /**
+ * Returns a String object using property values.
+ * @param transformerName
+ * @param sourceExt is null for overall transformer options rather than for a specific mimetype pair
+ * @param targetExt is null for overall transformer options rather than for a specific mimetype pair
+ * @return a String object or null if not created
+ */
+ private String newTransformerValue(String transformerName, String sourceExt, String targetExt,
+ ChildApplicationContextFactory subsystem, String propertySuffix)
+ {
+ String value = getValueFromProperties(transformerName, sourceExt, targetExt, subsystem, propertySuffix);
+
+ // The overall values can be defined in another way
+ if (value == null && ANY.equals(sourceExt) && ANY.equals(targetExt))
+ {
+ value = getValueFromProperties(transformerName, null, null, subsystem, propertySuffix);
+ }
+
+ return value;
+ }
+
+ private String getValueFromProperties(String transformerName, String sourceExt, String targetExt,
+ ChildApplicationContextFactory subsystem, String propertySuffix)
+ {
+ String propertyName = CONTENT+transformerName+
+ (sourceExt == null ? "" : MIMETYPES_SEPARATOR+sourceExt+'.'+targetExt)+
+ propertySuffix;
+ String value = subsystem.getProperty(propertyName);
+ return value;
+ }
+
+ private String getString(ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype)
+ {
+ if (sourceMimetype == null)
+ {
+ sourceMimetype = ANY;
+ }
+
+ if (targetMimetype == null)
+ {
+ targetMimetype = ANY;
+ }
+
+ String name = (transformer == null) ? DEFAULT_TRANSFORMER : transformer.getName();
+
+ DoubleMap mimetypeLimits = values.get(name);
+
+ String value = (mimetypeLimits == null) ? null : mimetypeLimits.get(sourceMimetype, targetMimetype);
+
+ if (value == null && transformer != null)
+ {
+ // System wide 'default' limits should exist, but individual transformer values might not.
+ value = getString(null, sourceMimetype, targetMimetype);
+ }
+
+ return value;
+ }
+
+ public long getLong(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return Long.parseLong(getString(transformer, sourceMimetype, targetMimetype));
+ }
+
+ public int getInt(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ return Integer.parseInt(getString(transformer, sourceMimetype, targetMimetype));
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerConfigStatistics.java b/source/java/org/alfresco/repo/content/transform/TransformerConfigStatistics.java
new file mode 100644
index 0000000000..434428f271
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerConfigStatistics.java
@@ -0,0 +1,113 @@
+/*
+ * 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 .
+ */
+package org.alfresco.repo.content.transform;
+
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+import static org.alfresco.repo.content.transform.TransformerConfig.SUMMARY_TRANSFORMER_NAME;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.service.cmr.repository.MimetypeService;
+
+/**
+ * Provides a place to store and access statistics about transformers, source and target mimetypes combinations.
+ * It also provides summaries for transformers as a whole and the system as a whole.
+ *
+ * @author Alan Davis
+ */
+public class TransformerConfigStatistics
+{
+ private TransformerConfigImpl transformerConfigImpl;
+ private MimetypeService mimetypeService;
+
+ // Holds statistics about each transformer, sourceMimeType and targetMimetype combination.
+ // A null transformer is the system wide value. Null sourceMimeType and targetMimetype values are
+ // transformer wide summaries.
+ private Map> statistics =
+ new HashMap>();
+
+ public TransformerConfigStatistics(TransformerConfigImpl transformerConfigImpl,
+ MimetypeService mimetypeService)
+ {
+ this.transformerConfigImpl = transformerConfigImpl;
+ this.mimetypeService = mimetypeService;
+ }
+
+ public TransformerStatistics getStatistics(ContentTransformer transformer, String sourceMimetype, String targetMimetype)
+ {
+ if (sourceMimetype == null)
+ {
+ sourceMimetype = ANY;
+ }
+
+ if (targetMimetype == null)
+ {
+ targetMimetype = ANY;
+ }
+
+ TransformerStatistics transformerStatistics;
+
+ String name = (transformer == null) ? SUMMARY_TRANSFORMER_NAME : transformer.getName();
+ DoubleMap mimetypeStatistics = statistics.get(name);
+
+ if (mimetypeStatistics == null)
+ {
+ // Create the summary for the transformer as a whole
+ mimetypeStatistics = new DoubleMap(ANY, ANY);
+ statistics.put(name, mimetypeStatistics);
+ transformerStatistics = newTransformerStatistics(transformer, ANY, ANY, null);
+ mimetypeStatistics.put(ANY, ANY, transformerStatistics);
+ }
+
+ if (ANY.equals(sourceMimetype) && ANY.equals(targetMimetype))
+ {
+ transformerStatistics = mimetypeStatistics.get(ANY, ANY);
+ }
+ else
+ {
+ // Not looking for the summary, so will have to create if not found or the summary is returned
+ transformerStatistics = mimetypeStatistics.get(sourceMimetype, targetMimetype);
+ if (transformerStatistics == null || transformerStatistics.isSummary())
+ {
+ // Create individual mimetype to mimetype transformation by this transformer
+ transformerStatistics = newTransformerStatistics(transformer, sourceMimetype, targetMimetype, mimetypeStatistics.get(ANY, ANY));
+ mimetypeStatistics.put(sourceMimetype, targetMimetype, transformerStatistics);
+ }
+ }
+
+ return transformerStatistics;
+ }
+
+ private TransformerStatistics newTransformerStatistics(ContentTransformer transformer,
+ String sourceMimetype, String targetMimetype, TransformerStatistics parent)
+ {
+ long initialAverageTime = transformerConfigImpl.getInitialAverageTime(transformer, sourceMimetype, targetMimetype);
+ long initialCount = initialAverageTime <= 0
+ ? 0
+ : transformerConfigImpl.getInitialCount(transformer, sourceMimetype, targetMimetype);
+ long errorTime = transformerConfigImpl.getErrorTime(transformer, sourceMimetype, targetMimetype);
+
+ TransformerStatistics transformerStatistics = new TransformerStatisticsImpl(mimetypeService, sourceMimetype, targetMimetype,
+ transformer, parent, errorTime, initialAverageTime, initialCount);
+
+ return transformerStatistics;
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerConfigSupported.java b/source/java/org/alfresco/repo/content/transform/TransformerConfigSupported.java
new file mode 100644
index 0000000000..7de77fc9e3
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerConfigSupported.java
@@ -0,0 +1,169 @@
+/*
+ * 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 .
+ */
+package org.alfresco.repo.content.transform;
+
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+import static org.alfresco.repo.content.transform.TransformerConfig.CONTENT;
+import static org.alfresco.repo.content.transform.TransformerConfig.MIMETYPES_SEPARATOR;
+import static org.alfresco.repo.content.transform.TransformerConfig.SUPPORTED;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.TransformationOptions;
+import org.alfresco.util.Triple;
+
+/**
+ * Provides access to the lists of supported and unsupported mimetype transformations
+ * defined via properties for all transformers.
+ *
+ * @author Alan Davis
+ */
+public class TransformerConfigSupported extends TransformerPropertyNameExtractor
+{
+ // Holds configured (entries only exist if configured rather than for all possible combinations)
+ // of supported and unsupported mimetypes transformations for a transformer.
+ // SourceMimetype and targetMimetype may be 'ANY' values to act as wild cards.
+ private Map supported;
+
+ public TransformerConfigSupported(ChildApplicationContextFactory subsystem, MimetypeService mimetypeService)
+ {
+ setSupported(subsystem, mimetypeService);
+ }
+
+ /**
+ * Sets the supported/unsupported mimetype transformations created from system properties.
+ */
+ private void setSupported(ChildApplicationContextFactory subsystem, MimetypeService mimetypeService)
+ {
+ supported = new HashMap();
+
+ // Gets all the supported and unsupported transformer, source and target combinations
+ Set> transformerNamesAndMimetypes =
+ getTransformerNamesAndExt(MIMETYPES_SEPARATOR, Collections.singletonList(SUPPORTED), false, subsystem, mimetypeService);
+
+
+
+
+ // Populate the transformer values
+ for (Triple triple: transformerNamesAndMimetypes)
+ {
+ String transformerName = triple.getFirst();
+ String sourceExt = triple.getSecond();
+ String targetExt = triple.getThird();
+ String sourceMimetype = ANY.equals(sourceExt) ? ANY : mimetypeService.getMimetype(sourceExt);
+ String targetMimetype = ANY.equals(targetExt) ? ANY : mimetypeService.getMimetype(targetExt);
+
+ SupportedAndUnsupportedTransformations supportedBytransformer = this.supported.get(transformerName);
+
+ if (supportedBytransformer == null)
+ {
+ supportedBytransformer = new SupportedAndUnsupportedTransformations();
+ this.supported.put(transformerName, supportedBytransformer);
+ }
+ boolean supported = getValueFromProperties(transformerName, sourceExt, targetExt, subsystem, SUPPORTED);
+ supportedBytransformer.put(sourceMimetype, targetMimetype, supported);
+ }
+ }
+
+ private boolean getValueFromProperties(String transformerName, String sourceExt, String targetExt,
+ ChildApplicationContextFactory subsystem, String propertySuffix)
+ {
+ String propertyName = CONTENT+transformerName+
+ (sourceExt == null ? "" : MIMETYPES_SEPARATOR+sourceExt+'.'+targetExt)+
+ propertySuffix;
+ String value = subsystem.getProperty(propertyName);
+ return value == null || value.equalsIgnoreCase("true");
+ }
+
+ /**
+ * See {@link TransformerConfig#isSupportedTransformation(ContentTransformer, String, String, TransformationOptions)}.
+ */
+ public boolean isSupportedTransformation(ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype, TransformationOptions options)
+ {
+ if (sourceMimetype == null)
+ {
+ sourceMimetype = ANY;
+ }
+
+ if (targetMimetype == null)
+ {
+ targetMimetype = ANY;
+ }
+
+ boolean isSupported = true;
+ String name = transformer.getName();
+ SupportedAndUnsupportedTransformations supportedBytransformer = supported.get(name);
+ if (supportedBytransformer != null)
+ {
+ isSupported = supportedBytransformer.isSupported(sourceMimetype, targetMimetype);
+ }
+ return isSupported;
+ }
+
+ // Class contains both supported and unsupported combinations to avoid having to
+ // add in an extra ANY to ANY combination which could be true or false. Having an
+ // extra combination might reduce understandability.
+ private class SupportedAndUnsupportedTransformations
+ {
+ DoubleMap supportedTransformations;
+ DoubleMap unsupportedTransformations;
+
+ boolean isSupported(String sourceMimetype, String targetMimetype)
+ {
+ boolean isSupported = true;
+ if (supportedTransformations != null)
+ {
+ Boolean sup = supportedTransformations.get(sourceMimetype, targetMimetype);
+ isSupported = sup != null;
+ }
+ if (isSupported && unsupportedTransformations != null)
+ {
+ Boolean sup = unsupportedTransformations.get(sourceMimetype, targetMimetype);
+ isSupported = sup == null;
+ }
+ return isSupported;
+ }
+
+ public void put(String sourceMimetype, String targetMimetype, boolean supported)
+ {
+ if (supported)
+ {
+ if (supportedTransformations == null)
+ {
+ supportedTransformations = new DoubleMap(ANY, ANY);
+ }
+ supportedTransformations.put(sourceMimetype, targetMimetype, supported);
+ }
+ else
+ {
+ if (unsupportedTransformations == null)
+ {
+ unsupportedTransformations = new DoubleMap(ANY, ANY);
+ }
+ unsupportedTransformations.put(sourceMimetype, targetMimetype, supported);
+ }
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
index bbad7a87b4..2af69f6aae 100644
--- a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
+++ b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -118,6 +118,7 @@ public class TransformerDebug
private final long start;
private Call callType;
+ private Frame parent;
private int childId;
private Set unavailableTransformers;
private String failureReason;
@@ -127,7 +128,8 @@ public class TransformerDebug
private Frame(Frame parent, String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, TransformationOptions options, Call pushCall, boolean origDebugOutput)
{
- this.id = parent == null ? -1 : ++parent.childId;
+ this.id = -1;
+ this.parent = parent;
this.fromUrl = fromUrl;
this.transformerName = transformerName;
this.sourceMimetype = sourceMimetype;
@@ -143,8 +145,8 @@ public class TransformerDebug
{
if (id == -1)
{
- id = uniqueId.getAndIncrement();
- }
+ id = parent == null ? uniqueId.getAndIncrement() : ++parent.childId;
+ }
return id;
}
@@ -223,14 +225,16 @@ public class TransformerDebug
private final NodeService nodeService;
private final MimetypeService mimetypeService;
+ private final TransformerConfig transformerConfig;
/**
* Constructor
*/
- public TransformerDebug(NodeService nodeService, MimetypeService mimetypeService)
+ public TransformerDebug(NodeService nodeService, MimetypeService mimetypeService, TransformerConfig transformerConfig)
{
this.nodeService = nodeService;
this.mimetypeService = mimetypeService;
+ this.transformerConfig = transformerConfig;
}
/**
@@ -373,8 +377,10 @@ public class TransformerDebug
long maxSourceSizeKBytes = trans.getMaxSourceSizeKBytes(frame.sourceMimetype, frame.targetMimetype, frame.options);
String size = maxSourceSizeKBytes > 0 ? "< "+fileSize(maxSourceSizeKBytes*1024) : "";
int padSize = 10 - size.length();
- log((c == 'a' ? "**" : " ") + (c++) + ") " + name + spaces(padName) +
- size + spaces(padSize) + ms(trans.getTransformationTime()));
+ String priority = Integer.toString(transformerConfig.getPriority(trans, frame.sourceMimetype, frame.targetMimetype));
+ priority = spaces(2-priority.length())+priority;
+ log((c == 'a' ? "**" : " ") + (c++) + ") " + priority + ' ' + name + spaces(padName) +
+ size + spaces(padSize) + ms(trans.getTransformationTime(frame.sourceMimetype, frame.targetMimetype)));
}
if (frame.unavailableTransformers != null)
{
@@ -382,7 +388,7 @@ public class TransformerDebug
{
int pad = longestNameLength - unavailable.name.length();
String reason = "> "+fileSize(unavailable.maxSourceSizeKBytes*1024);
- log("--" + (c++) + ") " + unavailable.name + spaces(pad+1) + reason, unavailable.debug);
+ log("--" + (c++) + ") " + unavailable.name + spaces(pad+1) + reason, unavailable.debug);
}
}
}
@@ -390,7 +396,7 @@ public class TransformerDebug
public void inactiveTransformer(ContentTransformer transformer)
{
- log(getName(transformer)+' '+ms(transformer.getTransformationTime())+" INACTIVE");
+ log(getName(transformer)+' '+ms(transformer.getTransformationTime(null, null))+" INACTIVE");
}
public void activeTransformer(int mimetypePairCount, ContentTransformer transformer, String sourceMimetype,
@@ -398,7 +404,7 @@ public class TransformerDebug
{
if (firstMimetypePair)
{
- log(getName(transformer)+' '+ms(transformer.getTransformationTime()));
+ log(getName(transformer)+' '+ms(transformer.getTransformationTime(sourceMimetype, targetMimetype)));
}
String i = Integer.toString(mimetypePairCount);
log(spaces(5-i.length())+mimetypePairCount+") "+getMimetypeExt(sourceMimetype)+getMimetypeExt(targetMimetype)+
@@ -416,7 +422,7 @@ public class TransformerDebug
: spaces(10);
char c = (char)('a'+transformerCount);
log(mimetypes+
- " "+c+") "+getName(transformer)+' '+ms(transformer.getTransformationTime())+
+ " "+c+") "+getName(transformer)+' '+ms(transformer.getTransformationTime(sourceMimetype, targetMimetype))+
' '+fileSize((maxSourceSizeKBytes > 0) ? maxSourceSizeKBytes*1024 : maxSourceSizeKBytes)+
(maxSourceSizeKBytes == 0 || (explicit != null && !explicit) ? " disabled" : "")+
(explicit == null ? "" : explicit ? " EXPLICIT" : " not explicit"));
@@ -593,8 +599,8 @@ public class TransformerDebug
(fileName == null ? "" : fileName) +
(sourceSize >= 0 ? ' '+fileSize(sourceSize) : "") +
(transformerName == null ? "" : ' '+transformerName) +
- (failureReason == null ? "" : ' '+failureReason) +
- ' '+ms;
+ ' '+ms +
+ (failureReason == null ? "" : '\n'+failureReason.trim());
info.log(message, debug);
}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerPropertyNameExtractor.java b/source/java/org/alfresco/repo/content/transform/TransformerPropertyNameExtractor.java
new file mode 100644
index 0000000000..b937b1ab91
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerPropertyNameExtractor.java
@@ -0,0 +1,91 @@
+/*
+ * 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 .
+ */
+package org.alfresco.repo.content.transform;
+
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+import static org.alfresco.repo.content.transform.TransformerConfig.CONTENT;
+import static org.alfresco.repo.content.transform.TransformerConfig.PREFIX;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.util.Triple;
+
+/**
+ * Provides access to transformer property names and values.
+ *
+ * @author Alan Davis
+ */
+public abstract class TransformerPropertyNameExtractor
+{
+ /**
+ * Returns a set of transformer names, source extensions and target mimetype extensions
+ * from property names that defined transformation limits.
+ * @param separator after the transformer name and the source mimetype extension.
+ * Must start and end in a '.'.
+ * @param suffixes possible endings to the property names after the target mimetype extension.
+ * Must start with a '.' if there is a suffix.
+ * @param includeSummary if true will also look for property names without the separator,
+ * source mimetype and target mimetype.
+ * @param subsystem that provides the properties
+ * @param mimetypeService
+ */
+ protected Set> getTransformerNamesAndExt(String separator, Collection suffixes, boolean includeSummary,
+ ChildApplicationContextFactory subsystem, MimetypeService mimetypeService)
+ {
+ Set> transformerNamesAndExtensions =
+ new HashSet>();
+
+ for (String propertyName: subsystem.getPropertyNames())
+ {
+ if (propertyName.startsWith(PREFIX))
+ {
+ for (String suffix: suffixes)
+ {
+ if (propertyName.endsWith(suffix))
+ {
+ String name = propertyName.substring(CONTENT.length(), propertyName.length()-suffix.length());
+ int i = name.lastIndexOf(separator);
+ if (i != -1)
+ {
+ String[] ext = name.substring(i+separator.length()).split("\\.");
+ if (ext.length == 2)
+ {
+ name = name.substring(0, i);
+ transformerNamesAndExtensions.add(
+ new Triple(name, ext[0], ext[1]));
+ break;
+ }
+ }
+ else if (includeSummary)
+ {
+ transformerNamesAndExtensions.add(new Triple(name, ANY, ANY));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return transformerNamesAndExtensions;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerSelector.java b/source/java/org/alfresco/repo/content/transform/TransformerSelector.java
index a0279ff75e..f5c97882cf 100644
--- a/source/java/org/alfresco/repo/content/transform/TransformerSelector.java
+++ b/source/java/org/alfresco/repo/content/transform/TransformerSelector.java
@@ -33,15 +33,12 @@ public interface TransformerSelector
/**
* Returns a sorted list of transformers that identifies the order in which transformers
* should be tried.
- * @param transformers an unordered list of all transformers. This
- * list may be modified.
* @param sourceMimetype
* @param sourceSize
* @param targetMimetype
* @param options transformation options
* @return a sorted list of transformers, with the best one first.
*/
- List selectTransformers(List transformers,
- String sourceMimetype, long sourceSize, String targetMimetype,
- TransformationOptions options);
+ List selectTransformers(String sourceMimetype, long sourceSize,
+ String targetMimetype, TransformationOptions options);
}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerSelectorImpl.java b/source/java/org/alfresco/repo/content/transform/TransformerSelectorImpl.java
index 3a9d8a36b8..86f714b8be 100644
--- a/source/java/org/alfresco/repo/content/transform/TransformerSelectorImpl.java
+++ b/source/java/org/alfresco/repo/content/transform/TransformerSelectorImpl.java
@@ -28,94 +28,127 @@ import java.util.Map;
import org.alfresco.service.cmr.repository.TransformationOptions;
/**
- * Implementation of a transformer selector that matches the code that was in place
- * before a selector was introduced. It is expected that this code will be replaced.
+ * Default transformer selector implementation, which sorts by priority and then
+ * by average transform time. The transform time is only used once a threshold
+ * (number of transforms) has been reached. This average is maintained for each
+ * source target mimetype pair.
+ *
+ * Prior to the introduction of this class the transformation time was only kept
+ * for each transformer. There was no threshold and there was a concept of
+ * 'Explicit' transformers, which would cause all other transformers to be discarded.
+ * It is still possible to disable transformers by giving adding unsupported mappings
+ * as has been done for transformers that would not have been used in the past as
+ * there existed one or more 'explicit' transformers (a concept not used by this
+ * TransformerSelector). By default a transformer has a priority of {@code 10}.
+ * Old 'Explicit' transformers have been given a priority of {@code 5}.
*
* @author Alan Davis
*/
public class TransformerSelectorImpl implements TransformerSelector
{
+ private TransformerConfig transformerConfig;
+ private ContentTransformerRegistry contentTransformerRegistry;
+
+ public void setTransformerConfig(TransformerConfig transformerConfig)
+ {
+ this.transformerConfig = transformerConfig;
+ }
+
+ public void setContentTransformerRegistry(ContentTransformerRegistry contentTransformerRegistry)
+ {
+ this.contentTransformerRegistry = contentTransformerRegistry;
+ }
@Override
- public List selectTransformers(List transformers,
- String sourceMimetype, long sourceSize, String targetMimetype,
- TransformationOptions options)
+ public List selectTransformers(String sourceMimetype, long sourceSize,
+ String targetMimetype, TransformationOptions options)
{
- transformers = findTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
- transformers = discardNonExplicitTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
- transformers = sortTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
- return transformers;
+ // TODO cache results for reuse. This was a heavy operation in the past and still is.
+
+ List transformers = contentTransformerRegistry.getTransformers();
+ List possibleTransformers = findTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
+ return sortTransformers(possibleTransformers);
}
/**
- * Reduces the list of transformers down to only those capable of doing the transformation.
+ * Returns the list of possible transformers for the transformation.
*/
- private List findTransformers(List allTransformers, String sourceMimetype,
+ private List findTransformers(List allTransformers, String sourceMimetype,
long sourceSize, String targetMimetype, TransformationOptions options)
{
- List transformers = new ArrayList(2);
-
+ List transformers = new ArrayList(8);
for (ContentTransformer transformer : allTransformers)
{
- if (transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == true)
+ int priority = transformerConfig.getPriority(transformer, sourceMimetype, targetMimetype);
+ if (priority > 0 &&
+ transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == true)
+
{
- transformers.add(transformer);
+ transformers.add(new TransformerSortData(transformer, sourceMimetype, targetMimetype, priority));
}
}
return transformers;
}
/**
- * Discards non explicit transformers if there are any explicit ones.
+ * Returns a sorted list of transformers by priority and then average time (ignored if the threshold
+ * has not been reached).
*/
- private List discardNonExplicitTransformers(List allTransformers, String sourceMimetype,
- long sourceSize, String targetMimetype, TransformationOptions options)
+ private List sortTransformers(List possibleTransformers)
{
- List transformers = new ArrayList(2);
- boolean foundExplicit = false;
+ Collections.sort(possibleTransformers);
- for (ContentTransformer transformer : allTransformers)
+ List transformers = new ArrayList(possibleTransformers.size());
+ for (TransformerSortData possibleTransformer: possibleTransformers)
{
- if (transformer.isExplicitTransformation(sourceMimetype, targetMimetype, options) == true)
- {
- if (foundExplicit == false)
- {
- transformers.clear();
- foundExplicit = true;
- }
- transformers.add(transformer);
- }
- else
- {
- if (foundExplicit == false)
- {
- transformers.add(transformer);
- }
- }
+ transformers.add(possibleTransformer.transformer);
}
return transformers;
}
-
- // sort by performance (quicker is "better")
- private List sortTransformers(List transformers,
- String sourceMimetype, long sourceSize, String targetMimetype,
- TransformationOptions options)
+
+ private class TransformerSortData implements Comparable
{
- final Map activeTransformers = new HashMap();
- for (ContentTransformer transformer : transformers)
+ private final ContentTransformer transformer;
+ private final int priority;
+ private long averageTime = -1;
+
+ TransformerSortData(ContentTransformer transformer, String sourceMimetype, String targetMimetype, int priority)
{
- long transformationTime = transformer.getTransformationTime();
- activeTransformers.put(transformer, transformationTime);
+ this.transformer = transformer;
+ this.priority = priority;
+
+ TransformerStatistics stats = transformerConfig.getStatistics(transformer, sourceMimetype, targetMimetype);
+ long threashold = transformerConfig.getThresholdCount(transformer, sourceMimetype, targetMimetype);
+ averageTime = (stats.getCount() < threashold) ? 0 : stats.getAverageTime();
}
-
- List sorted = new ArrayList(activeTransformers.keySet());
- Collections.sort(sorted, new Comparator() {
- @Override
- public int compare(ContentTransformer a, ContentTransformer b)
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (int) (averageTime ^ (averageTime >>> 32));
+ result = prime * result + priority;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return transformer == ((TransformerSortData) obj).transformer;
+ }
+
+ @Override
+ public int compareTo(TransformerSortData that)
+ {
+ int relativePriority = priority - that.priority;
+ if (relativePriority != 0)
{
- return activeTransformers.get(a).compareTo(activeTransformers.get(b));
+ return relativePriority;
}
- });
- return sorted;
+
+ long relativeTime = averageTime - that.averageTime;
+ return relativeTime > 0L ? 1 : relativeTime < 0L ? -1 : 0;
+ }
}
}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerSelectorImplOriginal.java b/source/java/org/alfresco/repo/content/transform/TransformerSelectorImplOriginal.java
new file mode 100644
index 0000000000..409f8af5e0
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerSelectorImplOriginal.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2005-2012 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.content.transform;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.service.cmr.repository.TransformationOptions;
+
+/**
+ * Implementation of a transformer selector that matches the code that was in place
+ * before a selector was introduced. Class is not used but exists to allow customers
+ * to maintain the previous approach if they really wish.
+ *
+ * @author Alan Davis
+ */
+public class TransformerSelectorImplOriginal implements TransformerSelector
+{
+ private ContentTransformerRegistry contentTransformerRegistry;
+
+ public void setContentTransformerRegistry(ContentTransformerRegistry contentTransformerRegistry)
+ {
+ this.contentTransformerRegistry = contentTransformerRegistry;
+ }
+
+ @Override
+ public List selectTransformers( String sourceMimetype, long sourceSize,
+ String targetMimetype, TransformationOptions options)
+ {
+ List transformers = contentTransformerRegistry.getTransformers();
+ transformers = findTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
+ transformers = discardNonExplicitTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
+ transformers = sortTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
+ return transformers;
+ }
+
+ /**
+ * Reduces the list of transformers down to only those capable of doing the transformation.
+ */
+ private List findTransformers(List allTransformers, String sourceMimetype,
+ long sourceSize, String targetMimetype, TransformationOptions options)
+ {
+ List transformers = new ArrayList(2);
+
+ for (ContentTransformer transformer : allTransformers)
+ {
+ if (transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == true)
+ {
+ transformers.add(transformer);
+ }
+ }
+ return transformers;
+ }
+
+ /**
+ * Discards non explicit transformers if there are any explicit ones.
+ */
+ private List discardNonExplicitTransformers(List allTransformers, String sourceMimetype,
+ long sourceSize, String targetMimetype, TransformationOptions options)
+ {
+ List transformers = new ArrayList(2);
+ boolean foundExplicit = false;
+
+ for (ContentTransformer transformer : allTransformers)
+ {
+ if (transformer.isExplicitTransformation(sourceMimetype, targetMimetype, options) == true)
+ {
+ if (foundExplicit == false)
+ {
+ transformers.clear();
+ foundExplicit = true;
+ }
+ transformers.add(transformer);
+ }
+ else
+ {
+ if (foundExplicit == false)
+ {
+ transformers.add(transformer);
+ }
+ }
+ }
+ return transformers;
+ }
+
+ // sort by performance (quicker is "better")
+ private List sortTransformers(List transformers,
+ String sourceMimetype, long sourceSize, String targetMimetype,
+ TransformationOptions options)
+ {
+ final Map activeTransformers = new HashMap();
+ for (ContentTransformer transformer : transformers)
+ {
+ long transformationTime = transformer.getTransformationTime(sourceMimetype, targetMimetype);
+ activeTransformers.put(transformer, transformationTime);
+ }
+
+ List sorted = new ArrayList(activeTransformers.keySet());
+ Collections.sort(sorted, new Comparator() {
+ @Override
+ public int compare(ContentTransformer a, ContentTransformer b)
+ {
+ return activeTransformers.get(a).compareTo(activeTransformers.get(b));
+ }
+ });
+ return sorted;
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerStatistics.java b/source/java/org/alfresco/repo/content/transform/TransformerStatistics.java
new file mode 100644
index 0000000000..a5d06f2719
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerStatistics.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2005-2012 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.content.transform;
+
+
+/**
+ * Interface to obtain the configuration and performance data for every
+ * source, target and transformer combination.
+ *
+ * @author Alan Davis
+ */
+public interface TransformerStatistics
+{
+ /**
+ * @return the extension of the source mimetype of the transformer.
+ */
+ public String getSourceExt();
+
+ /**
+ * @return the extension of the target mimetype of the transformer.
+ */
+ public String getTargetExt();
+
+ /**
+ * @return the name of the parent transformer.
+ */
+ public String getTransformerName();
+
+ /**
+ * @return the number of time the transformer has been called.
+ */
+ public long getCount();
+
+ /**
+ * @param count overrides the number of time the transformer has been called.
+ */
+ public void setCount(long count);
+
+ /**
+ * @return the number of time the transformer has failed.
+ */
+ public long getErrorCount();
+
+ /**
+ * @param errorCount overrides the number of time the transformer has failed.
+ */
+ public void setErrorCount(long errorCount);
+
+ /**
+ * @return the average time taken by the the transformer.
+ */
+ public long getAverageTime();
+
+ /**
+ * @param averageTime overrides the average time taken by the the transformer.
+ */
+ public void setAverageTime(long averageTime);
+
+ /**
+ * @return true
if this is the summary of all transformations done
+ * by a transformer rather than just between two specific mimetypes.
+ */
+ public boolean isSummary();
+
+ /**
+ * @param transformationTime to be added to this TransformationData and its parents.
+ */
+ public void recordTime(long transformationTime);
+
+ /**
+ * Adds 1 to the error count of this TransformationData and its parents.
+ */
+ public void recordError();
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerStatisticsImpl.java b/source/java/org/alfresco/repo/content/transform/TransformerStatisticsImpl.java
new file mode 100644
index 0000000000..1ccd185f5b
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/transform/TransformerStatisticsImpl.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2005-2012 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.content.transform;
+
+import static org.alfresco.repo.content.transform.TransformerConfig.ANY;
+
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.TransformationOptionLimits;
+
+
+/**
+ * Implementation of a {@link TransformerStatistics}.
+ *
+ * @author Alan Davis
+ */
+// TODO These values should be made visible via JMX.
+public class TransformerStatisticsImpl implements TransformerStatistics
+{
+ private final MimetypeService mimetypeService;
+ private final String sourceMimetype;
+ private final String targetMimetype;
+ private final ContentTransformer transformer;
+ private final TransformerStatistics parent;
+ private final long errorTime;
+
+ private double averageTime;
+ private long count = 0L;
+ private long errorCount = 0L;
+
+ public TransformerStatisticsImpl(MimetypeService mimetypeService, String sourceMimetype, String targetMimetype,
+ ContentTransformer transformer, TransformerStatistics parent, long errorTime,
+ long initialAverageTime, long initialCount)
+ {
+ this.mimetypeService = mimetypeService;
+ this.sourceMimetype = sourceMimetype;
+ this.targetMimetype = targetMimetype;
+ this.transformer = transformer;
+ this.parent = parent;
+ this.errorTime = errorTime;
+
+ averageTime = initialAverageTime;
+ count = initialCount;
+ }
+
+ @Override
+ public String getSourceExt()
+ {
+ return ANY.equals(sourceMimetype) ? ANY : mimetypeService.getExtension(sourceMimetype);
+ }
+
+ @Override
+ public String getTargetExt()
+ {
+ return ANY.equals(targetMimetype) ? ANY : mimetypeService.getExtension(targetMimetype);
+ }
+
+ @Override
+ public String getTransformerName()
+ {
+ return transformer == null ? TransformerConfig.SUMMARY_TRANSFORMER_NAME : transformer.getName();
+ }
+
+ @Override
+ public synchronized void recordTime(long transformationTime)
+ {
+ if (count == Long.MAX_VALUE)
+ {
+ // we have reached the max count - reduce it by half
+ // the average fluctuation won't be extreme
+ count /= 2L;
+ }
+ // adjust the average
+ count++;
+ double diffTime = ((double) transformationTime) - averageTime;
+ averageTime += diffTime / (double) count;
+
+ if (parent != null)
+ {
+ parent.recordTime(transformationTime);
+ }
+ }
+
+ @Override
+ public synchronized void recordError()
+ {
+ if (errorCount < Long.MAX_VALUE)
+ {
+ errorCount++;
+ }
+ if (errorTime > 0)
+ {
+ recordTime(errorTime);
+ }
+ if (parent != null)
+ {
+ parent.recordError();
+ }
+ }
+
+ @Override
+ public long getCount()
+ {
+ return count;
+ }
+
+ @Override
+ public void setCount(long count)
+ {
+ this.count = count;
+ }
+
+ @Override
+ public long getErrorCount()
+ {
+ return errorCount;
+ }
+
+ @Override
+ public void setErrorCount(long errorCount)
+ {
+ this.errorCount = errorCount;
+ }
+
+ @Override
+ public long getAverageTime()
+ {
+ return (long)averageTime;
+ }
+
+ @Override
+ public void setAverageTime(long averageTime)
+ {
+ this.averageTime = (double)averageTime;
+ }
+
+ public boolean isSummary()
+ {
+ return TransformerConfig.ANY.equals(sourceMimetype) && TransformerConfig.ANY.equals(targetMimetype);
+ }
+
+
+
+
+
+
+ //////////////////////////////////////// TODO Split into summary class ///////////////////////////////////
+
+
+
+
+
+// private enum Property
+// {
+// priority(true)
+// {
+// String getValue(TransformerData bean)
+// {
+// return Integer.toString(bean.getPriority());
+// }
+// void setValue(TransformerData bean, String value)
+// {
+// bean.setPriority(Integer.valueOf(value));
+// }
+// },
+//
+// averageTime(false)
+// {
+// String getValue(TransformerData bean)
+// {
+// return Integer.toString(bean.getPriority());
+// }
+// },
+//
+// count(false)
+// {
+// String getValue(TransformerData bean)
+// {
+// return Integer.toString(bean.getPriority());
+// }
+// },
+//
+// errors(false)
+// {
+// String getValue(TransformerData bean)
+// {
+// return Integer.toString(bean.getPriority());
+// }
+// };
+//
+// private final boolean updatable;
+//
+// Property(boolean updatable)
+// {
+// this.updatable = updatable;
+// }
+//
+// abstract String getValue(TransformerData bean);
+//
+// void setValue(TransformerData bean, String value)
+// {
+// }
+//
+// public boolean isUpdatable()
+// {
+// return updatable;
+// }
+//
+// public static Set getNames()
+// {
+// Set names = new HashSet();
+// for (Property property: Property.class.getEnumConstants())
+// {
+// names.add(property.name());
+// }
+// return names;
+// }
+// };
+//
+// public List getId()
+// {
+// List id = super.getId();
+//
+// id.add(transformerName);
+//
+// if (TransformerConfig.ANY.equals(sourceExt))
+// {
+// id.add(sourceExt);
+// }
+//
+// if (TransformerConfig.ANY.equals(targetExt))
+// {
+// id.add(targetExt);
+// }
+//
+// return id;
+// }
+//
+// public boolean isUpdateable(String name)
+// {
+// return Enum.valueOf(Property.class, name).isUpdatable();
+// }
+//
+// @Override
+// protected PropertyBackedBeanState createInitialState() throws IOException
+// {
+// return new PropertyBackedBeanState()
+// {
+//
+// @Override
+// public Set getPropertyNames()
+// {
+// return Property.getNames();
+// }
+//
+// @Override
+// public String getProperty(String name)
+// {
+// return Enum.valueOf(Property.class, name).getValue(TransformerDataImpl.this);
+// }
+//
+// @Override
+// public void setProperty(String name, String value)
+// {
+// Enum.valueOf(Property.class, name).setValue(TransformerDataImpl.this, value);
+// }
+//
+// @Override
+// public void start()
+// {
+// ;
+// }
+//
+// @Override
+// public void stop()
+// {
+// ;
+// }
+// };
+// }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java b/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java
index 42dcfb3906..5032bd293c 100644
--- a/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java
+++ b/source/java/org/alfresco/repo/management/subsystems/AbstractPropertyBackedBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -20,6 +20,7 @@ package org.alfresco.repo.management.subsystems;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -96,6 +97,41 @@ public abstract class AbstractPropertyBackedBean implements PropertyBackedBean,
/** Lock for concurrent access. */
protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ /**
+ * Used in conjunction with {@link #localSetProperties} to control setting of
+ * properties from either a JMX client or by code in the local Alfresco
+ * node calling {@link AbstractPropertyBackedBean#setProperties(Map)} or
+ * {@link AbstractPropertyBackedBean#setProperty(String, String)}.
+ * Is true
when there is a nested call to either of these
+ * methods. This is the case when there is an MBean AND one of these method was
+ * NOT originally called from that MBean (it is a local code).
+ */
+ private ThreadLocal nestedCall = new ThreadLocal()
+ {
+ @Override
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ };
+
+ /**
+ * Used in conjunction with {@link #nestedCall} to control setting of
+ * properties from either a JMX client or by code in the local Alfresco
+ * node calling {@link AbstractPropertyBackedBean#setProperties(Map)} or
+ * {@link AbstractPropertyBackedBean#setProperty(String, String)}.
+ * Is set to true
when there is a nested call back from
+ * a JMX bean.
+ */
+ private ThreadLocal localSetProperties = new ThreadLocal()
+ {
+ @Override
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ };
+
/** The logger. */
private static Log logger = LogFactory.getLog(AbstractPropertyBackedBean.class);
@@ -554,74 +590,249 @@ public abstract class AbstractPropertyBackedBean implements PropertyBackedBean,
}
}
+ private void setPropertyInternal(String name, String value)
+ {
+ // Bring down the bean. The caller may have already broadcast this across the cluster
+ stop(false);
+ doInit();
+ this.state.setProperty(name, value);
+ }
+
+ private void setPropertiesInternal(Map properties)
+ {
+ // Bring down the bean. The caller may have already broadcast this across the cluster
+ stop(false);
+ doInit();
+
+ Map previousValues = new HashMap(properties.size() * 2);
+ try
+ {
+ // Set each of the properties and back up their previous values just in case
+ for (Map.Entry entry : properties.entrySet())
+ {
+ String property = entry.getKey();
+ String previousValue = this.state.getProperty(property);
+ this.state.setProperty(property, entry.getValue());
+ previousValues.put(property, previousValue);
+ }
+
+ // Attempt to start locally
+ start(false, true);
+
+ // We still haven't broadcast the start - a persist is required first so this will be done by the caller
+ }
+ catch (Exception e)
+ {
+ // Oh dear - something went wrong. So restore previous state before rethrowing
+ for (Map.Entry entry : previousValues.entrySet())
+ {
+ this.state.setProperty(entry.getKey(), entry.getValue());
+ }
+
+ // Bring the bean back up across the cluster
+ start(true, false);
+ if (e instanceof RuntimeException)
+ {
+ throw (RuntimeException) e;
+ }
+ throw new IllegalStateException(e);
+ }
+ }
+
/**
* {@inheritDoc}
+ *
+ * When called from code within the local node the values are saved to the
+ * database in the Enterprise edition and will be visible in a JMX client.
+ *
+ * @param name
+ * @param value
*/
public void setProperty(String name, String value)
{
- this.lock.writeLock().lock();
- try
+ if (logger.isDebugEnabled())
{
- // Bring down the bean. The caller may have already broadcast this across the cluster
- stop(false);
- doInit();
- this.state.setProperty(name, value);
+ logger.debug("setProperty("+name+','+value+")");
}
- finally
+ if (!nestedCall.get())
{
- this.lock.writeLock().unlock();
- }
- }
-
- public void setProperties(Map properties)
- {
- this.lock.writeLock().lock();
- try
- {
- // Bring down the bean. The caller may have already broadcast this across the cluster
- stop(false);
- doInit();
-
- Map previousValues = new HashMap(properties.size() * 2);
+ nestedCall.set(true);
+ this.lock.writeLock().lock();
try
{
- // Set each of the properties and back up their previous values just in case
- for (Map.Entry entry : properties.entrySet())
+ boolean mBeanInfoChange = !getPropertyNames().contains(name);
+
+ // When setting properties locally AND there is an MBean, the following broadcast
+ // results in a call to the MBean's setAttributes method, which in turn results
+ // in a nested call back. The call back sets the values in this bean and
+ // localSetProperties will be set to true. The MBean persists the changes and the
+ // broadcast method returns. If there is no MBean (community edition) OR when
+ // initiated from the MBean (say setting a value via JConsole), nothing happens
+ // as a result of the broadcast.
+ logger.debug("setProperty() broadcastSetProperties");
+ this.registry.broadcastSetProperty(this, name, value);
+
+ if (localSetProperties.get())
{
- String property = entry.getKey();
- String previousValue = this.state.getProperty(property);
- this.state.setProperty(property, entry.getValue());
- previousValues.put(property, previousValue);
+ if (mBeanInfoChange)
+ {
+ // Re register the bean so new properties are visible in JConsole which does
+ // not check MBeanInfo for changes otherwise.
+ logger.debug("setProperty() destroy");
+ destroy(false);
+
+ // Attempt to start locally
+ start(false, true);
+ }
+ }
+ else
+ {
+ logger.debug("setProperty() setPropertyInternal");
+ setPropertyInternal(name, value);
}
-
- // Attempt to start locally
- start(false, true);
-
- // We still haven't broadcast the start - a persist is required first so this will be done by the caller
}
- catch (Exception e)
+ finally
{
- // Oh dear - something went wrong. So restore previous state before rethrowing
- for (Map.Entry entry : previousValues.entrySet())
+ localSetProperties.set(false);
+ nestedCall.set(false);
+ this.lock.writeLock().unlock();
+ }
+ }
+ else
+ {
+ // A nested call indicates there is a MBean and that this method was
+ // NOT originally called from that MBean.
+ localSetProperties.set(true);
+
+ logger.debug("setProperty() callback setPropertyInternal");
+ setPropertyInternal(name, value);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * When called from code within the local node the values are saved to the
+ * database in the Enterprise edition and will be visible in a JMX client.
+ *
+ * @param properties to be saved.
+ */
+ public void setProperties(Map properties)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("setProperties("+properties+")");
+ }
+ if (!nestedCall.get())
+ {
+ nestedCall.set(true);
+
+ boolean hadWriteLock = this.lock.isWriteLockedByCurrentThread();
+ if (!hadWriteLock)
+ {
+ this.lock.writeLock().lock();
+ }
+ try
+ {
+ boolean mBeanInfoChange = !getPropertyNames().containsAll(properties.keySet());
+
+ // When setting properties locally AND there is an MBean, the following broadcast
+ // results in a call to the MBean's setAttributes method, which in turn results
+ // in a nested call back. The call back sets the values in this bean and
+ // localSetProperties will be set to true. The MBean persists the changes and the
+ // broadcast method returns. If there is no MBean (community edition) OR when
+ // initiated from the MBean (say setting a value via JConsole), nothing happens
+ // as a result of the broadcast.
+ logger.debug("setProperties() broadcastSetProperties");
+ this.registry.broadcastSetProperties(this, properties);
+
+ if (localSetProperties.get())
{
- this.state.setProperty(entry.getKey(), entry.getValue());
+ if (mBeanInfoChange)
+ {
+ // Re register the bean so new properties are visible in JConsole which does
+ // not check MBeanInfo for changes otherwise.
+ logger.debug("setProperties() destroy");
+ destroy(false);
+
+ // Attempt to start locally
+ start(true, false);
+ }
}
-
- // Bring the bean back up across the cluster
- start(true, false);
- if (e instanceof RuntimeException)
+ else
{
- throw (RuntimeException) e;
+ logger.debug("setProperties() setPropertiesInternal");
+ setPropertiesInternal(properties);
}
- throw new IllegalStateException(e);
+ }
+ finally
+ {
+ localSetProperties.set(false);
+ nestedCall.set(false);
+ if (!hadWriteLock)
+ {
+ this.lock.writeLock().unlock();
+ }
+ }
+ }
+ else
+ {
+ // A nested call indicates there is a MBean and that this method was
+ // NOT originally called from that MBean.
+ localSetProperties.set(true);
+
+ logger.debug("setProperties() callback setPropertiesInternal");
+ setPropertiesInternal(properties);
+ }
+ }
+
+ /**
+ * Removes a property added by code within the local node.
+ *
+ * @param propertyNames to be removed.
+ */
+ public void removeProperty(String name)
+ {
+ removeProperties(Collections.singleton(name));
+ }
+
+ /**
+ * Removes properties added by code within the local node.
+ *
+ * @param propertyNames to be removed.
+ */
+ public void removeProperties(Collection propertyNames)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("removeProperties("+propertyNames+")");
+ }
+ this.lock.writeLock().lock();
+ try
+ {
+ Set originalPropertyNames = state.getPropertyNames();
+ Map propertiesToKeep = new HashMap(originalPropertyNames.size()*2);
+ for (String name: originalPropertyNames)
+ {
+ if (!propertyNames.contains(name))
+ {
+ propertiesToKeep.put(name, state.getProperty(name));
+ }
+ }
+
+ // Check just in case there is nothing to do.
+ if (propertiesToKeep.size() != originalPropertyNames.size())
+ {
+ destroy(true);
+ setProperties(propertiesToKeep);
}
}
finally
{
this.lock.writeLock().unlock();
}
-
}
+
/**
* {@inheritDoc}
*/
diff --git a/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java b/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java
index 69637cb276..8a7f9916e1 100644
--- a/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java
+++ b/source/java/org/alfresco/repo/management/subsystems/DefaultPropertyBackedBeanRegistry.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -20,6 +20,7 @@ package org.alfresco.repo.management.subsystems;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import org.alfresco.repo.domain.schema.SchemaAvailableEvent;
import org.springframework.context.ApplicationEvent;
@@ -98,6 +99,30 @@ public class DefaultPropertyBackedBeanRegistry implements PropertyBackedBeanRegi
broadcastEvent(new PropertyBackedBeanStoppedEvent(bean));
}
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.management.subsystems.PropertyBackedBeanRegistry#broadcastSetProperty(org.alfresco.repo.management
+ * .subsystems.PropertyBackedBean, String, String)
+ */
+ @Override
+ public void broadcastSetProperty(PropertyBackedBean bean, String name, String value)
+ {
+ broadcastEvent(new PropertyBackedBeanSetPropertyEvent(bean, name, value));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * org.alfresco.repo.management.subsystems.PropertyBackedBeanRegistry#broadcastSetProperties(org.alfresco.repo.management
+ * .subsystems.PropertyBackedBean, Map)
+ */
+ @Override
+ public void broadcastSetProperties(PropertyBackedBean bean, Map properties)
+ {
+ broadcastEvent(new PropertyBackedBeanSetPropertiesEvent(bean, properties));
+ }
+
/**
* Broadcast event.
*
diff --git a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java
index 4814c45a29..45e868bbe0 100644
--- a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanRegistry.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -18,6 +18,8 @@
*/
package org.alfresco.repo.management.subsystems;
+import java.util.Map;
+
import org.springframework.context.ApplicationListener;
/**
@@ -75,4 +77,26 @@ public interface PropertyBackedBeanRegistry
* the bean
*/
public void broadcastStop(PropertyBackedBean bean);
+
+ /**
+ * Signals that a {@link PropertyBackedBean} has been asked to
+ * update a property.
+ *
+ * @param bean
+ * the bean
+ * @param name
+ * the name
+ * @param value
+ * the value
+ */
+ public void broadcastSetProperty(PropertyBackedBean bean, String name, String value);
+
+ /**
+ * Signals that a {@link PropertyBackedBean} has been asked to
+ * update properties.
+ *
+ * @param bean
+ * the bean
+ */
+ public void broadcastSetProperties(PropertyBackedBean bean, Map properties);
}
diff --git a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanSetPropertiesEvent.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanSetPropertiesEvent.java
new file mode 100644
index 0000000000..32bf8ce64e
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanSetPropertiesEvent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2005-2012 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.management.subsystems;
+
+import java.util.Map;
+
+
+/**
+ * An event emitted before a {@link PropertyBackedBean} updates its properties.
+ *
+ * @author Alan Davis
+ */
+public class PropertyBackedBeanSetPropertiesEvent extends PropertyBackedBeanEvent
+{
+ private static final long serialVersionUID = 7530572539759535003L;
+
+ private Map properties;
+
+ /**
+ * The Constructor.
+ *
+ * @param source
+ * the source of the event
+ */
+ public PropertyBackedBeanSetPropertiesEvent(PropertyBackedBean source, Map properties)
+ {
+ super(source);
+ this.properties = properties;
+ }
+
+ public Map getProperties()
+ {
+ return properties;
+ }
+}
diff --git a/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanSetPropertyEvent.java b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanSetPropertyEvent.java
new file mode 100644
index 0000000000..d2bf15f738
--- /dev/null
+++ b/source/java/org/alfresco/repo/management/subsystems/PropertyBackedBeanSetPropertyEvent.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2005-2012 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.management.subsystems;
+
+
+
+/**
+ * An event emitted before a {@link PropertyBackedBean} updates a property.
+ *
+ * @author Alan Davis
+ */
+public class PropertyBackedBeanSetPropertyEvent extends PropertyBackedBeanEvent
+{
+ private static final long serialVersionUID = 7421919310357212865L;
+
+ private String name;
+ private String value;
+
+ /**
+ * The Constructor.
+ *
+ * @param source
+ * the source of the event
+ */
+ public PropertyBackedBeanSetPropertyEvent(PropertyBackedBean source, String name, String value)
+ {
+ super(source);
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java
index d8beb345b5..ef0711afd3 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java
@@ -1430,16 +1430,17 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp
// We have a reader, so use it
boolean readerReady = true;
// transform if necessary (it is not a UTF-8 text document)
- if (!EqualsHelper.nullSafeEquals(reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN) || !EqualsHelper.nullSafeEquals(reader.getEncoding(), "UTF-8"))
+ String sourceMimetype = reader.getMimetype();
+ if (!EqualsHelper.nullSafeEquals(sourceMimetype, MimetypeMap.MIMETYPE_TEXT_PLAIN) || !EqualsHelper.nullSafeEquals(reader.getEncoding(), "UTF-8"))
{
try
{
// get the transformer
TransformationOptions options = new TransformationOptions();
options.setSourceNodeRef(nodeRef);
- transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
+ transformerDebug.pushAvailable(reader.getContentUrl(), sourceMimetype, MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
long sourceSize = reader.getSize();
- List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
+ List transformers = contentService.getActiveTransformers(sourceMimetype, sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
transformerDebug.availableTransformers(transformers, sourceSize, "ADMLuceneIndexer");
if (transformers.isEmpty())
@@ -1458,7 +1459,7 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp
doc.add(new Field(attributeName, NOT_INDEXED_NO_TRANSFORMATION, Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.NO));
}
// is this transformer good enough?
- else if (indexAtomicPropertiesOnly && transformers.get(0).getTransformationTime() > maxAtomicTransformationTime)
+ else if (indexAtomicPropertiesOnly && transformers.get(0).getTransformationTime(sourceMimetype, MimetypeMap.MIMETYPE_TEXT_PLAIN) > maxAtomicTransformationTime)
{
// only indexing atomic properties
// indexing will take too long, so push it to the background
diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimits.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimits.java
index 9ca790e1e5..295e7578ba 100644
--- a/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimits.java
+++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimits.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -150,6 +150,18 @@ public class TransformationOptionLimits
pages.setLimit(pageLimit, PAGES_MESSAGE);
}
+ // --------------- Enabled ---------------
+
+ /**
+ * Indicates if the limits allow a transformation to take place at all.
+ * If any of the limits are 0, it would not be possible.
+ * @return true if a transformation is possible.
+ */
+ public boolean supported()
+ {
+ return time.supported() && kbytes.supported() && pages.supported();
+ }
+
// --------------- Map ---------------
public Map toMap(Map optionsMap)
{
diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimitsMap.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimitsMap.java
index 876537a730..10edd47dc3 100644
--- a/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimitsMap.java
+++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptionLimitsMap.java
@@ -37,7 +37,7 @@ import org.apache.commons.logging.LogFactory;
* <bean id="mimetypeLimits.OpenOffice" class="org.alfresco.service.cmr.repository.TransformationOptionLimitsMap">
* <constructor-arg>
* <value>
- * * txt TransformationOptionLimits ${content.transformer.OpenOffice.mimeTypeLimits.txt.pdf.maxSourceSizeKBytes} ;
+ * * txt maxSourceSizeKBytes ${content.transformer.OpenOffice.mimeTypeLimits.txt.pdf.maxSourceSizeKBytes} ;
* doc pdf maxSourceSizeKBytes ${content.transformer.OpenOffice.mimeTypeLimits.doc.pdf.maxSourceSizeKBytes}
* </value>
* </constructor-arg>
diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptionPair.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptionPair.java
index 31eb29f7c3..ac0b8fc8b8 100644
--- a/source/java/org/alfresco/service/cmr/repository/TransformationOptionPair.java
+++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptionPair.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -104,6 +104,16 @@ public class TransformationOptionPair
return minSet(getMax(), getLimit());
}
+ /**
+ * Indicates if the limit allows a transformation to take place at all.
+ * If 0, it would not be possible.
+ * @return true if a transformation is possible.
+ */
+ public boolean supported()
+ {
+ return getValue() != 0;
+ }
+
public Action getAction()
{
return
@@ -112,6 +122,19 @@ public class TransformationOptionPair
: null;
}
+ public String toString(String max, String limit)
+ {
+ if (getMax() >= 0)
+ {
+ return max+'='+getValue();
+ }
+ if (getLimit() >= 0)
+ {
+ return limit+'='+getValue();
+ }
+ return null;
+ }
+
/**
* Returns the lower of the two value supplied, ignoring values less than
* 0 unless both are less than zero.
diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java
index a42c29d131..ad426fb32a 100644
--- a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java
+++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java
@@ -517,7 +517,7 @@ public class TransformationOptions implements Cloneable
* {@link #OPT_INCLUDE_EMBEDDED}
* {@link TransformationOptionLimits#OPT_TIMEOUT_MS}
* {@link TransformationOptionLimits#OPT_READ_LIMIT_TIME_MS}
- * {@link TransformationOptionLimits#OPT_MAX_SOURCE_SIZE_K_BYTES = "maxSourceSizeKBytes";
+ * {@link TransformationOptionLimits#OPT_MAX_SOURCE_SIZE_K_BYTES
* {@link TransformationOptionLimits#OPT_READ_LIMIT_K_BYTES}
* {@link TransformationOptionLimits#OPT_MAX_PAGES}
* {@link TransformationOptionLimits#OPT_PAGE_LIMIT}