diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml
index 781b59b8e8..f6ea0ba147 100644
--- a/config/alfresco/content-services-context.xml
+++ b/config/alfresco/content-services-context.xml
@@ -115,6 +115,9 @@
+
+
+
@@ -262,6 +265,9 @@
+
+
+
@@ -287,6 +293,9 @@
${content.transformer.default.readLimitKBytes}
${content.transformer.default.pageLimit}
${content.transformer.default.maxPages}
+
+
+
diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml
index 0993bab943..3485eb18ba 100644
--- a/config/alfresco/model/contentModel.xml
+++ b/config/alfresco/model/contentModel.xml
@@ -1332,7 +1332,11 @@
-
+
+
+
+ Marker aspect to prevent the creation of renditions for a node.
+
Failed Thumbnail Source
diff --git a/config/alfresco/rendition-services-context.xml b/config/alfresco/rendition-services-context.xml
index 85735d07ed..79d9b70c13 100644
--- a/config/alfresco/rendition-services-context.xml
+++ b/config/alfresco/rendition-services-context.xml
@@ -45,6 +45,7 @@
+
@@ -77,8 +78,28 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
${cifs.sessionTimeout}
+
+
+
+
+ ${cifs.maximumVirtualCircuitsPerSession}
+
+
diff --git a/config/alfresco/subsystems/fileServers/default/file-servers.properties b/config/alfresco/subsystems/fileServers/default/file-servers.properties
index 536fbcbd3f..8ec5771f04 100644
--- a/config/alfresco/subsystems/fileServers/default/file-servers.properties
+++ b/config/alfresco/subsystems/fileServers/default/file-servers.properties
@@ -39,6 +39,9 @@ cifs.disableNativeCode=false
# Session timeout, in seconds. Defaults to 15 minutes, to match the default Windows client setting.
# If no I/O is received within that time the session is closed by the server
cifs.sessionTimeout=900
+# Maximum virtual circuits per session
+# Should only be changed when using Terminal Server clients
+cifs.maximumVirtualCircuitsPerSession=16
# Can be mapped to non-privileged ports, then use firewall rules to forward requests from the standard ports
cifs.tcpipSMB.port=445
diff --git a/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java b/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java
index a609b553c1..28cbc25906 100644
--- a/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java
+++ b/source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java
@@ -35,6 +35,7 @@ import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.TransformationOptions;
/**
* @author Stas Sokolovsky
@@ -207,9 +208,12 @@ public class CMISRenditionServiceTest extends BaseCMISTest
contentWriter.setMimetype(mimetype);
contentWriter.setLocale(Locale.ENGLISH);
- if (contentService.isTransformable(contentReader, contentWriter))
+ TransformationOptions options = new TransformationOptions();
+ options.setSourceNodeRef(textDocument);
+
+ if (contentService.isTransformable(contentReader, contentWriter, options))
{
- contentService.transform(contentReader, contentWriter);
+ contentService.transform(contentReader, contentWriter, options);
}
fileFolderService.delete(textDocument);
diff --git a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
index 0c2c9f4196..f171737737 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
@@ -979,7 +979,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Failed to allocate a UID
- throw new SMBSrvException(SMBStatus.NTLogonFailure, SMBStatus.DOSAccessDenied, SMBStatus.ErrDos);
+ throw new SMBSrvException(SMBStatus.NTTooManySessions, SMBStatus.SRVTooManyUIDs, SMBStatus.ErrSrv);
}
else if ( logger.isDebugEnabled() && sess.hasDebug( SMBSrvSession.DBG_NEGOTIATE)) {
diff --git a/source/java/org/alfresco/filesys/config/CIFSConfigBean.java b/source/java/org/alfresco/filesys/config/CIFSConfigBean.java
index 4e5da2c7b8..9424a620be 100644
--- a/source/java/org/alfresco/filesys/config/CIFSConfigBean.java
+++ b/source/java/org/alfresco/filesys/config/CIFSConfigBean.java
@@ -19,6 +19,7 @@
package org.alfresco.filesys.config;
import org.alfresco.jlan.server.auth.ICifsAuthenticator;
+import org.alfresco.jlan.smb.server.VirtualCircuitList;
// TODO: Auto-generated Javadoc
/**
@@ -89,6 +90,10 @@ public class CIFSConfigBean
/** The session timeout. */
private Integer sessionTimeout;
+ // Maximum virtual circuits per session
+
+ private int m_maxVC = VirtualCircuitList.DefMaxCircuits;
+
/**
* Checks if is server enabled.
*
@@ -351,6 +356,15 @@ public class CIFSConfigBean
return tcpipSMB;
}
+ /**
+ * Return the maxmimum virtual circuits per session
+ *
+ * @return int
+ */
+ public int getMaximumVirtualCircuits() {
+ return m_maxVC;
+ }
+
/**
* Sets the tcpip smb.
*
@@ -509,4 +523,12 @@ public class CIFSConfigBean
this.sessionTimeout = sessionTimeout;
}
+ /**
+ * Set the maximum virtual circuits per session
+ *
+ * @param maxVC int
+ */
+ public void setMaximumVirtualCircuits( int maxVC) {
+ m_maxVC = maxVC;
+ }
}
diff --git a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java
index 9d00e53aef..0c1e012afe 100644
--- a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java
+++ b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java
@@ -77,6 +77,7 @@ import org.alfresco.jlan.server.filesys.cache.hazelcast.ClusterConfigSection;
import org.alfresco.jlan.server.filesys.cache.hazelcast.HazelCastClusterFileStateCache;
import org.alfresco.jlan.server.thread.ThreadRequestPool;
import org.alfresco.jlan.smb.server.CIFSConfigSection;
+import org.alfresco.jlan.smb.server.VirtualCircuitList;
import org.alfresco.jlan.util.IPAddress;
import org.alfresco.jlan.util.MemorySize;
import org.alfresco.jlan.util.Platform;
@@ -334,12 +335,21 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean imp
}
// Check for a server comment
+
String comment = cifsConfigBean.getServerComment();
if (comment != null && comment.length() > 0)
{
cifsConfig.setComment(comment);
}
+ // Set the maximum virtual circuits per session
+
+ if ( cifsConfigBean.getMaximumVirtualCircuits() < VirtualCircuitList.MinCircuits ||
+ cifsConfigBean.getMaximumVirtualCircuits() > VirtualCircuitList.MaxCircuits)
+ throw new AlfrescoRuntimeException("Invalid virtual circuits value, valid range is " + VirtualCircuitList.MinCircuits + " - " + VirtualCircuitList.MaxCircuits);
+ else
+ cifsConfig.setMaximumVirtualCircuits( cifsConfigBean.getMaximumVirtualCircuits());
+
// Check for a bind address
// Check if the network adapter name has been specified
diff --git a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java
index 015db34dea..9801efe104 100644
--- a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.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
*
@@ -78,6 +78,7 @@ public class ImageTransformActionExecuter extends TransformActionExecuter
// create some options for the transform
ImageTransformationOptions imageOptions = new ImageTransformationOptions();
imageOptions.setCommandOptions(convertCommand);
+ imageOptions.setSourceNodeRef(sourceNodeRef);
// check if the transformer is going to work, i.e. is available
if (!this.imageMagickContentTransformer.isTransformable(contentReader.getMimetype(), contentReader.getSize(), contentWriter
diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
index 5e5cf635ad..af566c308c 100644
--- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.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
*
@@ -172,7 +172,9 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase
throw new RuleServiceException(CONTENT_READER_NOT_FOUND_MESSAGE);
}
- if (null == contentService.getTransformer(contentReader.getContentUrl(), contentReader.getMimetype(), contentReader.getSize(), mimeType, new TransformationOptions()))
+ TransformationOptions options = new TransformationOptions();
+ options.setSourceNodeRef(actionedUponNodeRef);
+ if (null == contentService.getTransformer(contentReader.getContentUrl(), contentReader.getMimetype(), contentReader.getSize(), mimeType, options))
{
throw new RuleServiceException(String.format(TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN, contentReader.getMimetype(), mimeType));
}
diff --git a/source/java/org/alfresco/repo/content/ContentServiceImpl.java b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
index 34e7de94d3..c36dd94300 100644
--- a/source/java/org/alfresco/repo/content/ContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
@@ -33,7 +33,6 @@ import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy;
import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy;
import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner;
import org.alfresco.repo.content.filestore.FileContentStore;
-import org.alfresco.repo.content.transform.AbstractContentTransformerLimits;
import org.alfresco.repo.content.transform.ContentTransformer;
import org.alfresco.repo.content.transform.ContentTransformerRegistry;
import org.alfresco.repo.content.transform.TransformerDebug;
@@ -41,7 +40,6 @@ import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
-import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
@@ -93,6 +91,8 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
private RetryingTransactionHelper transactionHelper;
private ApplicationContext applicationContext;
protected TransformerDebug transformerDebug;
+ private MimetypeService mimetypeService;
+
/** a registry of all available content transformers */
private ContentTransformerRegistry transformerRegistry;
@@ -190,6 +190,15 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
this.transformerDebug = transformerDebug;
}
+ /**
+ * Helper setter of the mimetypeService.
+ * @param mimetypeService
+ */
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
+ }
+
/**
* Service initialise
*/
@@ -539,7 +548,7 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
public void transform(ContentReader reader, ContentWriter writer)
{
// Call transform with no options
- TransformationOptions options = null;
+ TransformationOptions options = new TransformationOptions();
this.transform(reader, writer, options);
}
@@ -577,11 +586,11 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer);
}
+ long sourceSize = reader.getSize();
try
{
// look for a transformer
- transformerDebug.pushAvailable(reader.getContentUrl(), sourceMimetype, targetMimetype);
- long sourceSize = reader.getSize();
+ transformerDebug.pushAvailable(reader.getContentUrl(), sourceMimetype, targetMimetype, options);
List transformers = getActiveTransformers(sourceMimetype, sourceSize, targetMimetype, options);
transformerDebug.availableTransformers(transformers, sourceSize, "ContentService.transform(...)");
@@ -597,7 +606,11 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
}
finally
{
- transformerDebug.popAvailable();
+ if (transformerDebug.isEnabled())
+ {
+ transformerDebug.popAvailable();
+ debugActiveTransformers(sourceMimetype, targetMimetype, sourceSize, options);
+ }
}
}
@@ -623,7 +636,7 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
try
{
// look for a transformer
- transformerDebug.pushAvailable(sourceUrl, sourceMimetype, targetMimetype);
+ transformerDebug.pushAvailable(sourceUrl, sourceMimetype, targetMimetype, options);
List transformers = getActiveTransformers(sourceMimetype, sourceSize, targetMimetype, options);
transformerDebug.availableTransformers(transformers, sourceSize, "ContentService.getTransformer(...)");
return (transformers.isEmpty()) ? null : transformers.get(0);
@@ -633,6 +646,74 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
transformerDebug.popAvailable();
}
}
+
+ /**
+ * Checks if the file just uploaded into Share is a special "debugTransformers.txt" file and
+ * if it is creates TransformerDebug that lists all the supported mimetype transformation for
+ * each transformer.
+ */
+ private void debugActiveTransformers(String sourceMimetype, String targetMimetype,
+ long sourceSize, TransformationOptions transformOptions)
+ {
+ // check the file name, but do faster tests first
+ if (sourceSize == 18 &&
+ MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) &&
+ MimetypeMap.MIMETYPE_IMAGE_PNG.equals(targetMimetype) &&
+ "debugTransformers.txt".equals(transformerDebug.getFileName(transformOptions, true, 0)))
+ {
+ debugActiveTransformers();
+ }
+ }
+
+ /**
+ * Creates TransformerDebug that lists all the supported mimetype transformation for each transformer.
+ */
+ private void debugActiveTransformers()
+ {
+ try
+ {
+ transformerDebug.pushMisc();
+ transformerDebug.debug("Active and inactive transformers (list not reduced by 'explicit' settings)");
+ TransformationOptions options = new TransformationOptions();
+ for (ContentTransformer transformer: transformerRegistry.getTransformers())
+ {
+ try
+ {
+ transformerDebug.pushMisc();
+ int mimetypePairCount = 0;
+ boolean first = true;
+ for (String sourceMimetype : mimetypeService.getMimetypes())
+ {
+ for (String targetMimetype : mimetypeService.getMimetypes())
+ {
+ if (transformer.isTransformable(sourceMimetype, -1, targetMimetype, options))
+ {
+ long maxSourceSizeKBytes = transformer.getMaxSourceSizeKBytes(
+ sourceMimetype, targetMimetype, options);
+ boolean explicit = transformer.isExplicitTransformation(sourceMimetype,
+ targetMimetype, options);
+ transformerDebug.activeTransformer(++mimetypePairCount, transformer,
+ sourceMimetype, targetMimetype, maxSourceSizeKBytes, explicit, first);
+ first = false;
+ }
+ }
+ }
+ if (first)
+ {
+ transformerDebug.inactiveTransformer(transformer);
+ }
+ }
+ finally
+ {
+ transformerDebug.popMisc();
+ }
+ }
+ }
+ finally
+ {
+ transformerDebug.popMisc();
+ }
+ }
/**
* {@inheritDoc}
@@ -642,8 +723,8 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
try
{
long maxSourceSize = 0;
- transformerDebug.pushAvailable(null, sourceMimetype, targetMimetype);
- List transformers = getActiveTransformers(sourceMimetype, 0, targetMimetype, options);
+ transformerDebug.pushAvailable(null, sourceMimetype, targetMimetype, options);
+ List transformers = getActiveTransformers(sourceMimetype, -1, targetMimetype, options);
for (ContentTransformer transformer: transformers)
{
long maxSourceSizeKBytes = transformer.getMaxSourceSizeKBytes(sourceMimetype, targetMimetype, options);
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java
index 2748c44ef5..680cb9e32c 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer2.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2011 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -19,6 +19,7 @@
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;
@@ -28,6 +29,7 @@ import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
/**
* Provides basic services for {@link org.alfresco.repo.content.transform.ContentTransformer}
@@ -44,15 +46,16 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
private static final Log logger = LogFactory.getLog(AbstractContentTransformer2.class);
private ContentTransformerRegistry registry;
- private double averageTime = 0.0;
+ private Properties properties;
+ private double averageTime;
private long count = 0L;
/**
- * All transformers start with an average transformation time of 0.0ms.
+ * All transformers start with an average transformation time of 0.0 ms,
+ * unless there is an Alfresco global property {@code .initialTime}.
*/
protected AbstractContentTransformer2()
{
- averageTime = 0.0;
}
/**
@@ -65,6 +68,64 @@ 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()
{
@@ -78,6 +139,8 @@ 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
*/
public void register()
{
@@ -88,6 +151,8 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
return;
}
+ setAverageTimeFromAlfrescoGlobalProperties();
+
// register this instance for the fallback case
registry.addTransformer(this);
}
@@ -159,7 +224,8 @@ public abstract class AbstractContentTransformer2 extends AbstractContentTransfo
{
if (transformerDebug.isEnabled())
{
- transformerDebug.pushTransform(this, reader.getContentUrl(), reader.getMimetype(), writer.getMimetype(), reader.getSize());
+ transformerDebug.pushTransform(this, reader.getContentUrl(), reader.getMimetype(),
+ writer.getMimetype(), reader.getSize(), options);
}
// Check the transformability
diff --git a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
index 7b38d4af1e..da96bb4cf8 100644
--- a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
@@ -33,6 +33,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.filestore.FileContentWriter;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.TransformationOptionLimits;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
@@ -314,37 +315,55 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
ContentWriter writer,
TransformationOptions options) throws Exception
{
- ContentReader currentReader = reader;
-
- Iterator transformerIterator = transformers.iterator();
- Iterator intermediateMimetypeIterator = intermediateMimetypes.iterator();
- while (transformerIterator.hasNext())
+ NodeRef origSourceNodeRef = options.getSourceNodeRef();
+ try
{
- ContentTransformer transformer = transformerIterator.next();
- // determine the target mimetype. This is the final target if we are on the last transformation
- ContentWriter currentWriter = null;
- if (!transformerIterator.hasNext())
+ ContentReader currentReader = reader;
+
+ Iterator transformerIterator = transformers.iterator();
+ Iterator intermediateMimetypeIterator = intermediateMimetypes.iterator();
+ boolean first = true;
+ while (transformerIterator.hasNext())
{
- currentWriter = writer;
+ ContentTransformer transformer = transformerIterator.next();
+ // determine the target mimetype. This is the final target if we are on the last transformation
+ ContentWriter currentWriter = null;
+ if (!transformerIterator.hasNext())
+ {
+ currentWriter = writer;
+ }
+ else
+ {
+ String nextMimetype = intermediateMimetypeIterator.next();
+ // make a temp file writer with the correct extension
+ String sourceExt = getMimetypeService().getExtension(currentReader.getMimetype());
+ String targetExt = getMimetypeService().getExtension(nextMimetype);
+ File tempFile = TempFileProvider.createTempFile(
+ "ComplextTransformer_intermediate_" + sourceExt + "_",
+ "." + targetExt);
+ currentWriter = new FileContentWriter(tempFile);
+ currentWriter.setMimetype(nextMimetype);
+
+ // Must clear the sourceNodeRef to avoid transformers thinking the temporary file
+ // is the original node. Not done for the first transformer as the name will be
+ // correct.
+ if (!first)
+ {
+ options.setSourceNodeRef(null);
+ }
+ first = false;
+ }
+ // transform
+ transformer.transform(currentReader, currentWriter, options);
+ // move the source on
+ currentReader = currentWriter.getReader();
}
- else
- {
- String nextMimetype = intermediateMimetypeIterator.next();
- // make a temp file writer with the correct extension
- String sourceExt = getMimetypeService().getExtension(currentReader.getMimetype());
- String targetExt = getMimetypeService().getExtension(nextMimetype);
- File tempFile = TempFileProvider.createTempFile(
- "ComplextTransformer_intermediate_" + sourceExt + "_",
- "." + targetExt);
- currentWriter = new FileContentWriter(tempFile);
- currentWriter.setMimetype(nextMimetype);
- }
- // transform
- transformer.transform(currentReader, currentWriter, options);
- // move the source on
- currentReader = currentWriter.getReader();
+ // done
+ }
+ finally
+ {
+ options.setSourceNodeRef(origSourceNodeRef);
}
- // done
}
public List getIntermediateMimetypes()
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
index b3b91eef97..df6c47acb7 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
@@ -70,6 +70,11 @@ public class ContentTransformerRegistry
}
}
+ public List getTransformers()
+ {
+ return Collections.unmodifiableList(transformers);
+ }
+
/**
* @deprecated use overloaded version with sourceSize parameter.
*/
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
index 0861d5ea0f..b56b64a0b0 100644
--- a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
+++ b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
@@ -18,7 +18,6 @@
*/
package org.alfresco.repo.content.transform;
-import java.text.NumberFormat;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
@@ -27,7 +26,12 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.util.EqualsHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -108,6 +112,7 @@ public class TransformerDebug
private final String fromUrl;
private final String sourceMimetype;
private final String targetMimetype;
+ private final TransformationOptions options;
private final boolean origDebugOutput;
private final long start;
@@ -117,12 +122,14 @@ public class TransformerDebug
// See debug(String, Throwable) as to why this is commented out
// private Throwable lastThrowable;
- private Frame(Frame parent, String fromUrl, String sourceMimetype, String targetMimetype, Call pushCall, boolean origDebugOutput)
+ private Frame(Frame parent, String fromUrl, String sourceMimetype, String targetMimetype,
+ TransformationOptions options, Call pushCall, boolean origDebugOutput)
{
this.id = parent == null ? uniqueId.getAndIncrement() : ++parent.childId;
this.fromUrl = fromUrl;
this.sourceMimetype = sourceMimetype;
this.targetMimetype = targetMimetype;
+ this.options = options;
this.callType = pushCall;
this.origDebugOutput = origDebugOutput;
start = System.currentTimeMillis();
@@ -171,35 +178,53 @@ public class TransformerDebug
}
}
+ private final NodeService nodeService;
private final MimetypeService mimetypeService;
/**
* Constructor
*/
- public TransformerDebug(MimetypeService mimetypeService)
+ public TransformerDebug(NodeService nodeService, MimetypeService mimetypeService)
{
+ this.nodeService = nodeService;
this.mimetypeService = mimetypeService;
}
/**
* Called prior to working out what transformers are available.
*/
- public void pushAvailable(String fromUrl, String sourceMimetype, String targetMimetype)
+ public void pushAvailable(String fromUrl, String sourceMimetype, String targetMimetype,
+ TransformationOptions options)
{
if (isEnabled())
{
- push(null, fromUrl, sourceMimetype, targetMimetype, -1, Call.AVAILABLE);
+ push(null, fromUrl, sourceMimetype, targetMimetype, -1, options, Call.AVAILABLE);
}
}
/**
* Called prior to performing a transform.
*/
- public void pushTransform(ContentTransformer transformer, String fromUrl, String sourceMimetype, String targetMimetype, long sourceSize)
+ public void pushTransform(ContentTransformer transformer, String fromUrl, String sourceMimetype,
+ String targetMimetype, long sourceSize, TransformationOptions options)
{
if (isEnabled())
{
- push(getName(transformer), fromUrl, sourceMimetype, targetMimetype, sourceSize, Call.TRANSFORM);
+ push(getName(transformer), fromUrl, sourceMimetype, targetMimetype, sourceSize,
+ options, Call.TRANSFORM);
+ }
+ }
+
+ /**
+ * Adds a new level to the stack to get a new request number or nesting number.
+ * Called prior to working out what transformers are active
+ * and prior to listing the supported mimetypes for an active transformer.
+ */
+ public void pushMisc()
+ {
+ if (isEnabled())
+ {
+ push(null, null, null, null, -1, null, Call.AVAILABLE);
}
}
@@ -214,7 +239,8 @@ public class TransformerDebug
}
}
- private void push(String name, String fromUrl, String sourceMimetype, String targetMimetype, long sourceSize, Call callType)
+ private void push(String name, String fromUrl, String sourceMimetype, String targetMimetype,
+ long sourceSize, TransformationOptions options, Call callType)
{
Deque ourStack = ThreadInfo.getStack();
Frame frame = ourStack.peek();
@@ -227,7 +253,7 @@ public class TransformerDebug
{
// Create a new frame. Logging level is set to trace if the file size is 0
boolean origDebugOutput = ThreadInfo.setDebugOutput(ThreadInfo.getDebugOutput() && sourceSize != 0);
- frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, callType, origDebugOutput);
+ frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, options, callType, origDebugOutput);
ourStack.push(frame);
if (callType == Call.TRANSFORM)
@@ -310,6 +336,24 @@ public class TransformerDebug
}
}
+ public void inactiveTransformer(ContentTransformer transformer)
+ {
+ log(getName(transformer)+' '+ms(transformer.getTransformationTime())+" INACTIVE");
+ }
+
+ public void activeTransformer(int mimetypePairCount, ContentTransformer transformer, String sourceMimetype,
+ String targetMimetype, long maxSourceSizeKBytes, boolean explicit, boolean firstMimetypePair)
+ {
+ if (firstMimetypePair)
+ {
+ log(getName(transformer)+' '+ms(transformer.getTransformationTime()));
+ }
+ String i = Integer.toString(mimetypePairCount);
+ log(spaces(5-i.length())+mimetypePairCount+") "+getMimetypeExt(sourceMimetype)+getMimetypeExt(targetMimetype)+
+ ' '+fileSize((maxSourceSizeKBytes > 0) ? maxSourceSizeKBytes*1024 : maxSourceSizeKBytes)+
+ (explicit ? " EXPLICIT" : ""));
+ }
+
private int getLongestTransformerNameLength(List transformers,
Frame frame)
{
@@ -320,7 +364,7 @@ public class TransformerDebug
if (longestNameLength < length)
longestNameLength = length;
}
- if (frame.unavailableTransformers != null)
+ if (frame != null && frame.unavailableTransformers != null)
{
for (UnavailableTransformer unavailable: frame.unavailableTransformers)
{
@@ -337,13 +381,14 @@ public class TransformerDebug
// Log the source URL, but there is no point if the parent has logged it
if (frame.fromUrl != null && (firstLevel || frame.id != 1))
{
- log(frame.fromUrl, firstLevel);
+ log(frame.fromUrl, false);
}
-
- log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) +
- ((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") + message);
-
log(frame.sourceMimetype+' '+frame.targetMimetype, false);
+
+ String fileName = getFileName(frame.options, firstLevel, sourceSize);
+ log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) +
+ ((fileName != null) ? fileName+' ' : "")+
+ ((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") + message);
}
/**
@@ -354,7 +399,7 @@ public class TransformerDebug
{
if (isEnabled())
{
- pop(Call.AVAILABLE);
+ pop(Call.AVAILABLE, false);
}
}
@@ -365,10 +410,22 @@ public class TransformerDebug
{
if (isEnabled())
{
- pop(Call.TRANSFORM);
+ pop(Call.TRANSFORM, false);
}
}
+ /**
+ * Removes a frame from the stack. Called prior to working out what transformers are active
+ * and prior to listing the supported mimetypes for an active transformer.
+ */
+ public void popMisc()
+ {
+ if (isEnabled())
+ {
+ pop(Call.AVAILABLE, ThreadInfo.getStack().size() > 1);
+ }
+ }
+
/**
* Called after returning from a nested isTransformable.
*/
@@ -380,7 +437,7 @@ public class TransformerDebug
}
}
- private void pop(Call callType)
+ private void pop(Call callType, boolean suppressFinish)
{
Deque ourStack = ThreadInfo.getStack();
if (!ourStack.isEmpty())
@@ -389,7 +446,7 @@ public class TransformerDebug
if ((frame.callType == callType) ||
(frame.callType == Call.AVAILABLE_AND_TRANSFORM && callType == Call.AVAILABLE))
{
- if (ourStack.size() == 1 || logger.isTraceEnabled())
+ if (!suppressFinish && (ourStack.size() == 1 || logger.isTraceEnabled()))
{
boolean topFrame = ourStack.size() == 1;
log("Finished in " +
@@ -576,6 +633,36 @@ public class TransformerDebug
: "<>"
: "");
}
+
+
+ public String getFileName(TransformationOptions options, boolean firstLevel, long sourceSize)
+ {
+ String fileName = null;
+ if (options != null)
+ {
+ try
+ {
+ NodeRef sourceNodeRef = options.getSourceNodeRef();
+ fileName = (String)nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME);
+ }
+ catch (RuntimeException e)
+ {
+ ; // ignore (normally InvalidNodeRefException) but we should ignore other RuntimeExceptions too
+ }
+ }
+ if (fileName == null)
+ {
+ if (!firstLevel)
+ {
+ fileName = "<>";
+ }
+ else if (sourceSize < 0)
+ {
+ // fileName = "<>"; commented out as it does not add to debug readability
+ }
+ }
+ return fileName;
+ }
private String getMimetypeExt(String mimetype)
{
diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java
index 10b468503f..1be6efa773 100644
--- a/source/java/org/alfresco/repo/jscript/ScriptNode.java
+++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java
@@ -76,6 +76,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
+import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.cmr.security.AccessPermission;
@@ -2425,6 +2426,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
{
ParameterCheck.mandatoryString("Mimetype", mimetype);
ParameterCheck.mandatory("Destination Node", destination);
+ final NodeRef sourceNodeRef = nodeRef;
// the delegate definition for transforming a document
Transformer transformer = new Transformer()
@@ -2433,9 +2435,12 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
ContentWriter writer)
{
ScriptNode transformedNode = null;
- if (contentService.isTransformable(reader, writer))
+ TransformationOptions options = new TransformationOptions();
+ options.setSourceNodeRef(sourceNodeRef);
+
+ if (contentService.isTransformable(reader, writer, options))
{
- contentService.transform(reader, writer);
+ contentService.transform(reader, writer, options);
transformedNode = newInstance(nodeRef, services, scope);
}
return transformedNode;
@@ -2550,6 +2555,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
private ScriptNode transformImage(String mimetype, final String options, NodeRef destination)
{
ParameterCheck.mandatoryString("Mimetype", mimetype);
+ final NodeRef sourceNodeRef = nodeRef;
// the delegate definition for transforming an image
Transformer transformer = new Transformer()
@@ -2558,6 +2564,8 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
ContentWriter writer)
{
ImageTransformationOptions imageOptions = new ImageTransformationOptions();
+ imageOptions.setSourceNodeRef(sourceNodeRef);
+
if (options != null)
{
imageOptions.setCommandOptions(options);
@@ -2738,7 +2746,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
logger.info("Unable to create thumbnail '" + details.getName() + "' as there is no content");
return null;
}
- if (!registry.isThumbnailDefinitionAvailable(contentData.getContentUrl(), nodeMimeType, getSize(), details))
+ if (!registry.isThumbnailDefinitionAvailable(contentData.getContentUrl(), nodeMimeType, getSize(), nodeRef, details))
{
logger.info("Unable to create thumbnail '" + details.getName() + "' for " +
nodeMimeType + " as no transformer is currently available");
diff --git a/source/java/org/alfresco/repo/node/NodeServiceTest.java b/source/java/org/alfresco/repo/node/NodeServiceTest.java
index 6828ffd175..2cb30b3a41 100644
--- a/source/java/org/alfresco/repo/node/NodeServiceTest.java
+++ b/source/java/org/alfresco/repo/node/NodeServiceTest.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
*
@@ -1181,12 +1181,20 @@ public class NodeServiceTest extends TestCase
logger.debug("Found child nodes with deleted parent node (after): " + childNodeIds);
// workaround recovery: force collection of any orphan nodes (ALF-12358 + ALF-13066)
- for (NodeRef nodeRef : nodesAtRisk)
+ for (final NodeRef nodeRef : nodesAtRisk)
{
- if (nodeService.exists(nodeRef))
+ txnService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback()
{
- nodeService.getPath(nodeRef); // ignore return
- }
+ @Override
+ public Void execute() throws Throwable
+ {
+ if (nodeService.exists(nodeRef))
+ {
+ nodeService.getPath(nodeRef); // ignore return
+ }
+ return null;
+ }
+ });
}
// check again ...
@@ -1273,12 +1281,20 @@ public class NodeServiceTest extends TestCase
logger.debug("Found child nodes with deleted parent node (after): " + childNodeIds);
// workaround recovery: force collection of any orphan nodes (ALF-12358 + ALF-13066)
- for (NodeRef nodeRef : childNodeRefs)
+ for (final NodeRef nodeRef : childNodeRefs)
{
- if (nodeService.exists(nodeRef))
+ txnService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback()
{
- nodeService.getPath(nodeRef); // ignore return
- }
+ @Override
+ public Void execute() throws Throwable
+ {
+ if (nodeService.exists(nodeRef))
+ {
+ nodeService.getPath(nodeRef); // ignore return
+ }
+ return null;
+ }
+ });
}
// check again ...
diff --git a/source/java/org/alfresco/repo/rendition/RenditionPreventionRegistry.java b/source/java/org/alfresco/repo/rendition/RenditionPreventionRegistry.java
new file mode 100644
index 0000000000..0ac540a934
--- /dev/null
+++ b/source/java/org/alfresco/repo/rendition/RenditionPreventionRegistry.java
@@ -0,0 +1,103 @@
+/*
+ * 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.rendition;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * This class holds a registry of content class names (types and aspects) which if they are present on a sourceNode will prevent any
+ * renditions from being created for that node.
+ *
+ * @author Neil Mc Erlean
+ * @since 4.0.1
+ */
+public class RenditionPreventionRegistry
+{
+ private final Set registeredContentClasses = new HashSet();
+ private NamespaceService namespaceService;
+
+ public void setNamespaceService(NamespaceService service)
+ {
+ this.namespaceService = service;
+ }
+
+ public void register(String contentClass)
+ {
+ QName qname = QName.createQName(contentClass, namespaceService);
+ registeredContentClasses.add(qname);
+ }
+
+ /**
+ * @return a Set of QNames of types/aspects which will prevent renditions from occurring.
+ */
+ public Set getRegisteredQNames()
+ {
+ return Collections.unmodifiableSet(registeredContentClasses);
+ }
+
+ /**
+ * Checks if the specified type/aspect is registered as a marker for rendition prevention.
+ * @param contentClassName aspect name.
+ * @return true
if this class will prevent renditions, else false
+ */
+ public boolean isContentClassRegistered(String contentClassName)
+ {
+ QName qname = QName.createQName(contentClassName, namespaceService);
+ return isContentClassRegistered(qname);
+ }
+
+ /**
+ * Checks if the specified type/aspect is registered as a marker for rendition prevention.
+ * @param contentClassName aspect name.
+ * @return true
if this aspect will prevent renditions, else false
+ */
+ public boolean isContentClassRegistered(QName aspectQName)
+ {
+ return registeredContentClasses.contains(aspectQName);
+ }
+
+ /**
+ * A utility class which ensures that the specified aspect/type name is registered.
+ */
+ public static class SelfRegisteringClassName
+ {
+ private final String contentClassName;
+ private RenditionPreventionRegistry registry;
+
+ public SelfRegisteringClassName(String className)
+ {
+ this.contentClassName = className;
+ }
+
+ public void setRegistry(RenditionPreventionRegistry registry)
+ {
+ this.registry = registry;
+ }
+
+ public void register()
+ {
+ registry.register(contentClassName);
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/rendition/RenditionServiceImpl.java b/source/java/org/alfresco/repo/rendition/RenditionServiceImpl.java
index d54059b8ad..b0e21a544c 100644
--- a/source/java/org/alfresco/repo/rendition/RenditionServiceImpl.java
+++ b/source/java/org/alfresco/repo/rendition/RenditionServiceImpl.java
@@ -37,6 +37,7 @@ import org.alfresco.service.cmr.rendition.CompositeRenditionDefinition;
import org.alfresco.service.cmr.rendition.RenderCallback;
import org.alfresco.service.cmr.rendition.RenderingEngineDefinition;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
+import org.alfresco.service.cmr.rendition.RenditionPreventedException;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.rendition.RenditionServiceException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -67,6 +68,11 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
private RenditionDefinitionPersisterImpl renditionDefinitionPersister;
+ /**
+ * @since 4.0.1
+ */
+ private RenditionPreventionRegistry renditionPreventionRegistry;
+
/**
* Injects the RenditionDefinitionPersister bean.
* @param renditionDefinitionPersister
@@ -76,6 +82,14 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
this.renditionDefinitionPersister = renditionDefinitionPersister;
}
+ /**
+ * @since 4.0.1
+ */
+ public void setRenditionPreventionRegistry(RenditionPreventionRegistry registry)
+ {
+ this.renditionPreventionRegistry = registry;
+ }
+
/**
* Injects the ServiceRegistry bean.
* @param serviceRegistry
@@ -180,6 +194,8 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
*/
public ChildAssociationRef render(NodeRef sourceNode, RenditionDefinition definition)
{
+ checkSourceNodeForPreventionClass(sourceNode);
+
ChildAssociationRef result = executeRenditionAction(sourceNode, definition, false);
if (log.isDebugEnabled())
@@ -193,6 +209,8 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
public void render(NodeRef sourceNode, RenditionDefinition definition,
RenderCallback callback)
{
+ checkSourceNodeForPreventionClass(sourceNode);
+
// The asynchronous render can't return a ChildAssociationRef as it is created
// asynchronously after this method returns.
definition.setCallback(callback);
@@ -208,6 +226,8 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
*/
public ChildAssociationRef render(NodeRef sourceNode, final QName renditionDefinitionQName)
{
+ checkSourceNodeForPreventionClass(sourceNode);
+
RenditionDefinition rendDefn = AuthenticationUtil.runAs(
new AuthenticationUtil.RunAsWork()
{
@@ -231,6 +251,8 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
*/
public void render(NodeRef sourceNode, final QName renditionDefinitionQName, RenderCallback callback)
{
+ checkSourceNodeForPreventionClass(sourceNode);
+
RenditionDefinition rendDefn = AuthenticationUtil.runAs(
new AuthenticationUtil.RunAsWork()
{
@@ -247,8 +269,41 @@ public class RenditionServiceImpl implements RenditionService, RenditionDefiniti
this.render(sourceNode, rendDefn, callback);
}
-
-
+
+ /**
+ * This method checks whether the specified source node is of a content class which has been registered for rendition prevention.
+ *
+ * @param sourceNode the node to check.
+ * @throws RenditionPreventedException if the source node is configured for rendition prevention.
+ * @since 4.0.1
+ * @see RenditionPreventionRegistry
+ */
+ private void checkSourceNodeForPreventionClass(NodeRef sourceNode)
+ {
+ // A node's content class is its type and all its aspects.
+ // We'll not check the source node for null and leave that to the rendering action.
+ if (sourceNode != null && nodeService.exists(sourceNode))
+ {
+ Set nodeContentClasses = nodeService.getAspects(sourceNode);
+ nodeContentClasses.add(nodeService.getType(sourceNode));
+
+ for (QName contentClass : nodeContentClasses)
+ {
+ if (renditionPreventionRegistry.isContentClassRegistered(contentClass))
+ {
+ StringBuilder msg = new StringBuilder();
+ msg.append("Node ").append(sourceNode)
+ .append(" cannot be renditioned as it is of class ").append(contentClass);
+ if (log.isDebugEnabled())
+ {
+ log.debug(msg.toString());
+ }
+ throw new RenditionPreventedException(msg.toString());
+ }
+ }
+ }
+ }
+
/**
* This method delegates the execution of the specified RenditionDefinition
* to the {@link ActionService action service}.
diff --git a/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java b/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java
index 2715b170e7..bd7f63e34f 100644
--- a/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java
+++ b/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java
@@ -923,6 +923,48 @@ public class RenditionServiceIntegrationTest extends BaseAlfrescoSpringTest
});
}
+ /**
+ * Tests that source nodes with a suitable marker aspect on them are not renditioned.
+ *
+ * @since 4.0.1
+ */
+ public void testSuitablyMarkedNodesDoNotGetRenditioned() throws Exception
+ {
+ setComplete();
+ endTransaction();
+
+ this.renditionNode = transactionHelper
+ .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Throwable
+ {
+ // Initially the node that provides the content
+ // should not have the rn:renditioned aspect on it.
+ assertFalse("Source node has unexpected renditioned aspect.", nodeService.hasAspect(
+ nodeWithImageContent, RenditionModel.ASPECT_RENDITIONED));
+
+ //Add the marker aspect to prevent rendition
+ nodeService.addAspect(nodeWithImageContent, RenditionModel.ASPECT_PREVENT_RENDITIONS, null);
+
+ RenditionDefinition action = makeReformatAction(null, MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ action.setParameterValue(AbstractRenderingEngine.PARAM_MIME_TYPE, MimetypeMap.MIMETYPE_IMAGE_JPEG);
+
+ ChildAssociationRef renditionAssoc = null;
+ boolean expectedExceptionThrown = false;
+ try
+ {
+ renditionAssoc = renditionService.render(nodeWithImageContent, action);
+ } catch (RenditionServiceException expected)
+ {
+ expectedExceptionThrown = true;
+ }
+ assertTrue("Expected exception was not thrown.", expectedExceptionThrown);
+
+ return renditionAssoc == null ? null : renditionAssoc.getChildRef();
+ }
+ });
+ }
+
public void testSuccessfulAsynchronousRendition() throws Exception
{
// There are two relevant threads here: the JUnit test thread and the background
diff --git a/source/java/org/alfresco/repo/rendition/executer/ImageRenderingEngine.java b/source/java/org/alfresco/repo/rendition/executer/ImageRenderingEngine.java
index c0407cdf98..ed2625453b 100644
--- a/source/java/org/alfresco/repo/rendition/executer/ImageRenderingEngine.java
+++ b/source/java/org/alfresco/repo/rendition/executer/ImageRenderingEngine.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2011 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -256,6 +256,8 @@ public class ImageRenderingEngine extends AbstractTransformationRenderingEngine
@Override
protected TransformationOptions getTransformOptionsImpl(TransformationOptions options, RenderingContext context)
{
+ options.setSourceNodeRef(context.getSourceNode());
+ options.setTargetNodeRef(context.getDestinationNode());
ImageTransformationOptions imageTransformationOptions = (ImageTransformationOptions)options;
String commandOptions = context.getCheckedParam(PARAM_COMMAND_OPTIONS, String.class);
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 9c48ebc522..ebb01f8298 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java
@@ -1279,9 +1279,11 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp
try
{
// get the transformer
- transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ TransformationOptions options = new TransformationOptions();
+ options.setSourceNodeRef(nodeRef);
+ transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
long sourceSize = reader.getSize();
- List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions());
+ List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
transformerDebug.availableTransformers(transformers, sourceSize, "ADMLuceneIndexer");
if (transformers.isEmpty())
@@ -1322,7 +1324,7 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp
writer.setEncoding("UTF-8");
try
{
- transformer.transform(reader, writer);
+ transformer.transform(reader, writer, options);
// point the reader to the new-written content
reader = writer.getReader();
// Check that the reader is a view onto something concrete
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java
index e8511695b8..0cfdbfcb3c 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java
@@ -1140,9 +1140,11 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl
try
{
// get the transformer
- transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ TransformationOptions options = new TransformationOptions();
+ options.setSourceNodeRef(banana); // TODO check it is OK to use this noderef
+ transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
long sourceSize = reader.getSize();
- List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, new TransformationOptions());
+ List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, options);
transformerDebug.availableTransformers(transformers, sourceSize, "AVMLuceneIndexer");
if (transformers.isEmpty())
@@ -1177,7 +1179,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl
writer.setEncoding("UTF-8");
try
{
- transformer.transform(reader, writer);
+ transformer.transform(reader, writer, options);
// point the reader to the new-written content
reader = writer.getReader();
// Check that the reader is a view onto something concrete
diff --git a/source/java/org/alfresco/repo/site/SiteAspect.java b/source/java/org/alfresco/repo/site/SiteAspect.java
index 2fec100ae9..187c697f4a 100644
--- a/source/java/org/alfresco/repo/site/SiteAspect.java
+++ b/source/java/org/alfresco/repo/site/SiteAspect.java
@@ -18,8 +18,13 @@
*/
package org.alfresco.repo.site;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies.OnMoveNodePolicy;
+import org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy;
import org.alfresco.repo.policy.Behaviour;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -28,6 +33,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.EqualsHelper;
/**
* Site aspect behaviour bean.
@@ -37,7 +43,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Nick Burch
*/
-public class SiteAspect implements NodeServicePolicies.OnMoveNodePolicy
+public class SiteAspect implements NodeServicePolicies.OnMoveNodePolicy, NodeServicePolicies.OnUpdatePropertiesPolicy
{
/** Services */
private DictionaryService dictionaryService;
@@ -79,14 +85,43 @@ public class SiteAspect implements NodeServicePolicies.OnMoveNodePolicy
*/
public void init()
{
- this.policyComponent.bindClassBehaviour(
- OnMoveNodePolicy.QNAME,
+ this.policyComponent.bindClassBehaviour(OnMoveNodePolicy.QNAME,
SiteModel.TYPE_SITE,
new JavaBehaviour(this, "onMoveNode", Behaviour.NotificationFrequency.EVERY_EVENT));
this.policyComponent.bindClassBehaviour(OnMoveNodePolicy.QNAME,
SiteModel.ASPECT_SITE_CONTAINER,
new JavaBehaviour(this, "onMoveNode", Behaviour.NotificationFrequency.EVERY_EVENT));
+
+ this.policyComponent.bindClassBehaviour(OnUpdatePropertiesPolicy.QNAME,
+ SiteModel.TYPE_SITE,
+ new JavaBehaviour(this, "onUpdateProperties", Behaviour.NotificationFrequency.EVERY_EVENT));
+
+ this.policyComponent.bindClassBehaviour(OnUpdatePropertiesPolicy.QNAME,
+ SiteModel.ASPECT_SITE_CONTAINER,
+ new JavaBehaviour(this, "onUpdateProperties", Behaviour.NotificationFrequency.EVERY_EVENT));
+ }
+
+ public void onUpdateProperties(NodeRef nodeRef,
+ Map before,
+ Map after)
+ {
+ String beforeName = (String)before.get(ContentModel.PROP_NAME);
+ String afterName = (String)after.get(ContentModel.PROP_NAME);
+
+ if(beforeName != null && !beforeName.equals(afterName))
+ {
+ // Deny renames
+ QName type = nodeService.getType(nodeRef);
+ if (dictionaryService.isSubClass(type, SiteModel.TYPE_SITE))
+ {
+ throw new SiteServiceException("Sites can not be renamed.");
+ }
+ else
+ {
+ throw new SiteServiceException("Site containers can not be renamed.");
+ }
+ }
}
/**
diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java
index d67b97e982..e276bb12c5 100644
--- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java
+++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java
@@ -772,7 +772,7 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
// get the sites that match the specified names
StringBuilder query = new StringBuilder(128);
query.append("+PARENT:\"").append(siteRoot.toString()).append('"');
-
+
final boolean filterIsPresent = filter != null && filter.length() > 0;
// The filter string is only used in the Lucene query if it restricts results.
// A search for name/title/description = "*" does not need to be put into the Lucene query.
@@ -919,7 +919,8 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
// Only search for "st:site" nodes.
final Set searchTypeQNames = new HashSet(1);
searchTypeQNames.add(SiteModel.TYPE_SITE);
-
+// searchTypeQNames.addAll(dictionaryService.getSubTypes(SiteModel.TYPE_SITE, true));
+
// get canned query
final String cQBeanName = "siteGetChildrenCannedQueryFactory";
GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(cQBeanName);
diff --git a/source/java/org/alfresco/repo/site/SiteServiceImplTest.java b/source/java/org/alfresco/repo/site/SiteServiceImplTest.java
index 4342790818..cec0837e80 100644
--- a/source/java/org/alfresco/repo/site/SiteServiceImplTest.java
+++ b/source/java/org/alfresco/repo/site/SiteServiceImplTest.java
@@ -106,6 +106,7 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest
private NodeArchiveService nodeArchiveService;
private PermissionService permissionService;
private SiteService siteService;
+
/**
* There are some tests which need access to the unproxied SiteServiceImpl
*/
@@ -142,7 +143,6 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest
this.siteServiceImpl = (SiteServiceImpl) applicationContext.getBean("siteService"); // Small 's'
this.sysAdminParams = (SysAdminParams)this.applicationContext.getBean("sysAdminParams");
-
// Create the test users
createUser(USER_ONE, "UserOne");
createUser(USER_TWO, "UserTwo");
@@ -2070,7 +2070,43 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest
assertNotNull("sites list was null.", sites);
assertEquals(preexistingSitesCount+1, sites.size());
}
+
+ private SiteInfo createSite(String siteShortName, String componentId, SiteVisibility visibility)
+ {
+ // Create a public site
+ SiteInfo siteInfo = this.siteService.createSite(TEST_SITE_PRESET,
+ siteShortName,
+ TEST_TITLE,
+ TEST_DESCRIPTION,
+ visibility);
+ NodeRef siteContainer = this.siteService.createContainer(siteShortName, componentId, ContentModel.TYPE_FOLDER, null);
+ return siteInfo;
+ }
+ public void testRenameSite()
+ {
+ // test that changing the name of a site generates an appropriate exception
+
+ try
+ {
+ String siteName = GUID.generate();
+
+ SiteInfo siteInfo = createSite(siteName, "doclib", SiteVisibility.PUBLIC);
+ NodeRef childRef = siteInfo.getNodeRef();
+
+ Map props = new HashMap();
+ props.put(ContentModel.PROP_NAME, siteName + "Renamed");
+
+ nodeService.addProperties(childRef, props);
+
+ fail("Should have caught rename");
+ }
+ catch(SiteServiceException e)
+ {
+ assertTrue(e.getMessage().contains("can not be renamed"));
+ }
+ }
+
private void validatePermissionsOnRelocatedNode(SiteInfo fromSite,
SiteInfo toSite, NodeRef relocatedNode, Map expectedPermissions)
{
diff --git a/source/java/org/alfresco/repo/template/BaseContentNode.java b/source/java/org/alfresco/repo/template/BaseContentNode.java
index 21cd898b27..7d714b1228 100644
--- a/source/java/org/alfresco/repo/template/BaseContentNode.java
+++ b/source/java/org/alfresco/repo/template/BaseContentNode.java
@@ -37,8 +37,10 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
+import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.webdav.WebDavService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -592,7 +594,8 @@ public abstract class BaseContentNode implements TemplateContent
{
// get the content reader
ContentService contentService = services.getContentService();
- ContentReader reader = contentService.getReader(getNodeRef(), property);
+ NodeRef nodeRef = getNodeRef();
+ ContentReader reader = contentService.getReader(nodeRef, property);
if (reader == null)
{
return ""; // Caller of this method returns "" if there is an IOException
@@ -603,10 +606,13 @@ public abstract class BaseContentNode implements TemplateContent
writer.setMimetype("text/plain");
writer.setEncoding(reader.getEncoding());
+ TransformationOptions options = new TransformationOptions();
+ options.setSourceNodeRef(nodeRef);
+
// try and transform the content
- if (contentService.isTransformable(reader, writer))
+ if (contentService.isTransformable(reader, writer, options))
{
- contentService.transform(reader, writer);
+ contentService.transform(reader, writer, options);
ContentReader resultReader = writer.getReader();
if (resultReader != null && reader.exists())
diff --git a/source/java/org/alfresco/repo/thumbnail/CreateThumbnailActionExecuter.java b/source/java/org/alfresco/repo/thumbnail/CreateThumbnailActionExecuter.java
index f0c7496f89..db2eadef3e 100644
--- a/source/java/org/alfresco/repo/thumbnail/CreateThumbnailActionExecuter.java
+++ b/source/java/org/alfresco/repo/thumbnail/CreateThumbnailActionExecuter.java
@@ -155,7 +155,7 @@ public class CreateThumbnailActionExecuter extends ActionExecuterAbstractBase
{
ContentData content = (ContentData)contentProp;
String mimetype = content.getMimetype();
- if (!registry.isThumbnailDefinitionAvailable(content.getContentUrl(), mimetype, content.getSize(), details))
+ if (!registry.isThumbnailDefinitionAvailable(content.getContentUrl(), mimetype, content.getSize(), actionedUponNodeRef, details))
{
logger.debug("Unable to create thumbnail '" + details.getName() + "' for " +
mimetype + " as no transformer is currently available");
diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java
index 2b43de6e3c..0be52ab5d8 100644
--- a/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java
+++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java
@@ -33,6 +33,8 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.thumbnail.ThumbnailException;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
@@ -254,10 +256,16 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
* @param sourceUrl The URL of the source (optional)
* @param sourceMimetype The source mimetype
* @param sourceSize the size (in bytes) of the source. Use -1 if unknown.
+ * @param sourceNodeRef which is set in a copy of the thumbnailDefinition transformation options,
+ * so that it may be used by transformers and debug.
* @param thumbnailDefinition The {@link ThumbnailDefinition} to check for
*/
- public boolean isThumbnailDefinitionAvailable(String sourceUrl, String sourceMimetype, long sourceSize, ThumbnailDefinition thumbnailDefinition)
+ public boolean isThumbnailDefinitionAvailable(String sourceUrl, String sourceMimetype, long sourceSize, NodeRef sourceNodeRef, ThumbnailDefinition thumbnailDefinition)
{
+ // Copy the thumbnail's TransformationOptions and set the sourceNodeRef, for use by transformers and debug.
+ TransformationOptions options = new TransformationOptions(thumbnailDefinition.getTransformationOptions());
+ options.setSourceNodeRef(sourceNodeRef);
+
// Log the following getTransform() as trace so we can see the wood for the trees
boolean orig = TransformerDebug.setDebugOutput(false);
try
@@ -266,7 +274,7 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
sourceUrl,
sourceMimetype,
sourceSize,
- thumbnailDefinition.getMimetype(), thumbnailDefinition.getTransformationOptions()
+ thumbnailDefinition.getMimetype(), options
) != null;
}
finally
diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplParameterTest.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplParameterTest.java
index ecd8f15362..87320ba925 100644
--- a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplParameterTest.java
+++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplParameterTest.java
@@ -34,6 +34,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
+import org.alfresco.repo.rendition.MockedTestServiceRegistry;
import org.alfresco.repo.rendition.RenditionServiceImpl;
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
@@ -84,6 +85,7 @@ public class ThumbnailServiceImplParameterTest
};
renditionService.setActionService(mockActionService);
+ renditionService.setServiceRegistry(new MockedTestServiceRegistry());
ThumbnailServiceImpl thumbs = new ThumbnailServiceImpl()
{
diff --git a/source/java/org/alfresco/service/cmr/rendition/RenditionPreventedException.java b/source/java/org/alfresco/service/cmr/rendition/RenditionPreventedException.java
new file mode 100644
index 0000000000..83eb9ca454
--- /dev/null
+++ b/source/java/org/alfresco/service/cmr/rendition/RenditionPreventedException.java
@@ -0,0 +1,78 @@
+/*
+ * 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.service.cmr.rendition;
+
+import org.alfresco.repo.rendition.RenditionPreventionRegistry;
+
+/**
+ * This exception is thrown if an attempt is made to render a node which has a {@link RenditionPreventionRegistry content class}
+ * registered to prevent rendition.
+ *
+ * @author Neil Mc Erlean
+ * @since 4.0.1
+ */
+public class RenditionPreventedException extends RenditionServiceException
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a Rendition Service Exception with the specified message.
+ *
+ * @param message the message string
+ */
+ public RenditionPreventedException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Constructs a Rendition Service Exception with the specified message and source exception.
+ *
+ * @param message the message string
+ * @param source the source exception
+ */
+ public RenditionPreventedException(String message, Throwable source)
+ {
+ super(message, source);
+ }
+
+ /**
+ * Constructs a Rendition Service Exception with the specified message and {@link RenditionDefinition}.
+ *
+ * @param message the message string.
+ * @param renditionDefinition the rendition definition.
+ */
+ public RenditionPreventedException(String message, RenditionDefinition renditionDefinition)
+ {
+ super(message);
+ }
+
+ /**
+ * Constructs a Rendition Service Exception with the specified message, {@link RenditionDefinition} and
+ * source exception
+ * .
+ * @param message the message string.
+ * @param renditionDefinition the rendition definition.
+ * @param source the source exception.
+ */
+ public RenditionPreventedException(String message, RenditionDefinition renditionDefinition, Throwable source)
+ {
+ super(message, source);
+ }
+}
diff --git a/source/java/org/alfresco/service/cmr/rendition/RenditionService.java b/source/java/org/alfresco/service/cmr/rendition/RenditionService.java
index ad6b42538b..932ce968d5 100644
--- a/source/java/org/alfresco/service/cmr/rendition/RenditionService.java
+++ b/source/java/org/alfresco/service/cmr/rendition/RenditionService.java
@@ -22,12 +22,10 @@ package org.alfresco.service.cmr.rendition;
import java.util.List;
import org.alfresco.repo.rendition.RenditionDefinitionPersister;
-import org.alfresco.service.PublicService;
+import org.alfresco.service.NotAuditable;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
-import org.alfresco.service.Auditable;
-import org.alfresco.service.NotAuditable;
/**
* The Rendition service.
diff --git a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java
index 845417ad50..5d06f96f13 100644
--- a/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java
+++ b/source/java/org/alfresco/service/cmr/repository/TransformationOptions.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2011 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -63,12 +63,20 @@ public class TransformationOptions
private TransformationOptionLimits limits = new TransformationOptionLimits();
/**
- * Default construtor
+ * Default constructor
*/
public TransformationOptions()
{
}
+ /**
+ * Deep clone constructor
+ */
+ public TransformationOptions(TransformationOptions options)
+ {
+ this(options.toMap());
+ }
+
/**
* Constructor
*