getActiveTransformers(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
return getActiveTransformers(sourceMimetype, -1, targetMimetype, options);
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java
index fbd6e4a0b8..96f65effae 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.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
*
@@ -208,7 +208,9 @@ public abstract class AbstractContentTransformer implements ContentTransformer
@Override
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
- return isTransformable(sourceMimetype, targetMimetype, options);
+ return
+ isTransformableMimetype(sourceMimetype, targetMimetype, options) &&
+ isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
}
/**
@@ -228,6 +230,36 @@ public abstract class AbstractContentTransformer implements ContentTransformer
return result;
}
+ /**
+ * Checks the supplied mimetypes are supported by calling the deprecated
+ * {@link #isTransformable(String, String, TransformationOptions)} method.
+ */
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype,
+ TransformationOptions options)
+ {
+ return isTransformable(sourceMimetype, targetMimetype, options);
+ }
+
+ /**
+ * Always returns {@code true} to indicate size is not an issue.
+ */
+ @Override
+ public boolean isTransformableSize(String sourceMimetype, long sourceSize,
+ String targetMimetype, TransformationOptions options)
+ {
+ return true;
+ }
+
+ /**
+ * Always returns {@code -1} to indicate an unlimited size.
+ */
+ @Override
+ public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ {
+ return -1;
+ }
+
/**
* @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
*/
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimits.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimits.java
index 78af71c77e..2334a6657e 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-2011 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -84,6 +84,11 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
this.transformerDebug = transformerDebug;
}
+ public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ {
+ throw new IllegalStateException("Method should no longer be called. Override isTransformableMimetype in subclass.");
+ }
+
/**
* {@inheritDoc}
*
@@ -91,14 +96,24 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
* and then {@link #isTransformableSize(String, long, String, TransformationOptions)}.
*/
@Override
- @SuppressWarnings("deprecation")
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
return
- isTransformable(sourceMimetype, targetMimetype, options) &&
+ isTransformableMimetype(sourceMimetype, targetMimetype, options) &&
isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
}
+ /**
+ * Indicates if this transformer is able to transform the given source mimetype
+ * to the target mimetype.
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ {
+ return isTransformable(sourceMimetype, targetMimetype, options);
+ }
+
/**
* Indicates if this transformer is able to transform the given {@code sourceSize}.
* The {@code maxSourceSizeKBytes} property may indicate that only small source files
@@ -106,31 +121,45 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
* @param sourceSize size in bytes of the source. If negative, the source size is unknown.
* @return {@code true} if the source is transformable.
*/
- protected boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
boolean sizeOkay = true;
if (sourceSize >= 0)
{
- TransformationOptionLimits limits = getLimits(sourceMimetype, targetMimetype, options);
-
- // The maxSourceSizeKbytes value is ignored if this transformer is able to use
- // page limits and the limits include a pageLimit. Normally used in the creation
- // of icons. Note the readLimitKBytes value is not checked as the combined limits
- // only have the max or limit kbytes value set (the smaller value is returned).
- if (!isPageLimitSupported() || limits.getPageLimit() <= 0)
+ // if maxSourceSizeKBytes == 0 this implies the transformation is disabled
+ long maxSourceSizeKBytes = getMaxSourceSizeKBytes(sourceMimetype, targetMimetype, options);
+ sizeOkay = maxSourceSizeKBytes < 0 || (maxSourceSizeKBytes > 0 && sourceSize <= maxSourceSizeKBytes*1024);
+ if (!sizeOkay && transformerDebug.isEnabled())
{
- // if maxSourceSizeKBytes == 0 this implies the transformation is disabled
- long maxSourceSizeKBytes = limits.getMaxSourceSizeKBytes();
- sizeOkay = maxSourceSizeKBytes < 0 || (maxSourceSizeKBytes > 0 && sourceSize <= maxSourceSizeKBytes*1024);
- if (!sizeOkay && transformerDebug.isEnabled())
- {
- transformerDebug.unavailableTransformer(this, maxSourceSizeKBytes);
- }
+ transformerDebug.unavailableTransformer(this, maxSourceSizeKBytes);
}
}
return sizeOkay;
}
+ /**
+ * Returns the maximum source size (in KBytes) allowed given the supplied values.
+ * @return 0 if the the transformation is disabled, -1 if there is no limit, otherwise the size in KBytes.
+ */
+ @Override
+ public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ {
+ long maxSourceSizeKBytes = -1;
+
+ // The maxSourceSizeKbytes value is ignored if this transformer is able to use
+ // page limits and the limits include a pageLimit. Normally used in the creation
+ // of icons. Note the readLimitKBytes value is not checked as the combined limits
+ // only have the max or limit KBytes value set (the smaller value is returned).
+ TransformationOptionLimits limits = getLimits(sourceMimetype, targetMimetype, options);
+ if (!isPageLimitSupported() || limits.getPageLimit() <= 0)
+ {
+ maxSourceSizeKBytes = limits.getMaxSourceSizeKBytes();
+ }
+
+ return maxSourceSizeKBytes;
+ }
+
/**
* Gets the timeout (ms) on the InputStream after which an IOExecption is thrown
* to terminate very slow transformations or a subprocess is terminated (killed).
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java
index 0879af6dc0..1d5ce5d665 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerLimitsTest.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,7 +63,7 @@ public class AbstractContentTransformerLimitsTest
transformer = new AbstractContentTransformer2()
{
@Override
- public boolean isTransformable(String sourceMimetype, String targetMimetype,
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype,
TransformationOptions options)
{
return false;
@@ -214,6 +214,70 @@ public class AbstractContentTransformerLimitsTest
assertEquals("Getter did not return set value", value, actual);
}
+ @Test
+ public void testGetMaxSourceSizeKBytes() 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));
+
+ // Set limit for A to B mimetypes and test
+ limits.setMaxSourceSizeKBytes(kValue);
+ addMimetypeLimits(A, B, limits);
+ transformer.setMimetypeLimits(mimetypeLimits);
+
+ assertEquals("Expected to have set value returned", kValue,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+
+ // With a mimetype that does not have any specific limits
+ assertEquals("Expected to have -1 (unlimited) returned", -1,
+ transformer.getMaxSourceSizeKBytes(C, B, options));
+
+
+ // Clear the mimetype limits and double check
+ limits.setMaxSourceSizeKBytes(-1);
+
+ assertEquals("Expected to have -1 (unlimited) returned", -1,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+
+ // Check for combinations with transformer limits
+
+ // a) Using just transformer limit to start with
+ transformer.setMaxSourceSizeKBytes(kValue);
+ assertEquals("Expected to have transformer set value returned", kValue,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+
+ // b) combination where transformer limit is used
+ transformer.setMaxSourceSizeKBytes(kValue);
+ limits.setMaxSourceSizeKBytes(kValue+1);
+ assertEquals("Expected to have transformer set value returned", kValue,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+
+ // c) combination where mimetype limit is used
+ transformer.setMaxSourceSizeKBytes(kValue+1);
+ limits.setMaxSourceSizeKBytes(kValue);
+ assertEquals("Expected to have transformer set value returned", kValue,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+
+ // Check no limit when page limit set on a transformer that does not support page limit
+ transformer.setMaxSourceSizeKBytes(kValue);
+ limits.setMaxSourceSizeKBytes(kValue+1);
+ limits.setPageLimit(1);
+ assertEquals("Expected to ignore the page limit as the transformer does not support it", kValue,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+
+ // Check no limit when page limit set on a transformer that does support page limit
+ transformer.setMaxSourceSizeKBytes(kValue);
+ limits.setMaxSourceSizeKBytes(kValue+1);
+ transformer.setPageLimitsSuported(true);
+ limits.setPageLimit(1);
+ assertEquals("Expected to have -1 (unlimited) returned when there are page limits", -1,
+ transformer.getMaxSourceSizeKBytes(A, B, options));
+ }
+
@Test
public void testIsTransformableSize() throws Exception
{
@@ -260,16 +324,16 @@ public class AbstractContentTransformerLimitsTest
transformer.isTransformableSize(A, byteValue+1, B, options));
// b) combination where transformer limit is used
- transformer.setMaxSourceSizeKBytes(kValue+1);
- limits.setMaxSourceSizeKBytes(kValue);
+ transformer.setMaxSourceSizeKBytes(kValue);
+ limits.setMaxSourceSizeKBytes(kValue+1);
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",
transformer.isTransformableSize(A, byteValue+1, B, options));
// c) combination where mimetype limit is used
- transformer.setMaxSourceSizeKBytes(kValue);
- limits.setMaxSourceSizeKBytes(kValue+1);
+ transformer.setMaxSourceSizeKBytes(kValue+1);
+ limits.setMaxSourceSizeKBytes(kValue);
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",
diff --git a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java
index af5cae065c..31bfba5a93 100644
--- a/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/BinaryPassThroughContentTransformer.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
*
@@ -50,7 +50,8 @@ public class BinaryPassThroughContentTransformer extends AbstractContentTransfor
}
- public boolean isTransformable(String sourceMimetype,
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype,
String targetMimetype, TransformationOptions options)
{
if (sourceMimetype.startsWith(StringExtractingContentTransformer.PREFIX_TEXT))
diff --git a/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ComplexContentTransformer.java
index 7063739cd6..7b38d4af1e 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-2010 Alfresco Software Limited.
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -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.TransformationOptionLimits;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.util.TempFileProvider;
@@ -126,15 +127,32 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
}
/**
- * Check we can transform all the way along the chain of mimetypes
- *
- * @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
+ * Overrides this method to avoid calling
+ * {@link #isTransformableMimetype(String, String, TransformationOptions)}
+ * twice on each transformer in the list, as
+ * {@link #isTransformableSize(String, long, String, TransformationOptions)}
+ * in this class must check the mimetype too.
*/
- public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype,
+ TransformationOptions options)
{
- boolean result = true;
- String currentSourceMimetype = sourceMimetype;
+ overrideTransformationOptions(options);
+ // To make TransformerDebug output clearer, check the mimetypes and then the sizes.
+ // If not done, 'unavailable' transformers due to size might be reported even
+ // though they cannot transform the source to the target mimetype.
+
+ return
+ isTransformableMimetype(sourceMimetype, targetMimetype, options) &&
+ isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
+ }
+
+ /**
+ * Sets any transformation option overrides it can.
+ */
+ private void overrideTransformationOptions(TransformationOptions options)
+ {
// Set any transformation options overrides if we can
if(options != null && transformationOptionOverrides != null)
{
@@ -177,8 +195,28 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
}
}
}
+ }
+
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ {
+ return isTransformableMimetypeAndSize(sourceMimetype, -1, targetMimetype, options);
+ }
+
+ @Override
+ public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ {
+ return (sourceSize < 0) ||
+ super.isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options) &&
+ isTransformableMimetypeAndSize(sourceMimetype, sourceSize, targetMimetype, options);
+ }
+
+ private boolean isTransformableMimetypeAndSize(String sourceMimetype, long sourceSize,
+ String targetMimetype, TransformationOptions options)
+ {
+ boolean result = true;
+ String currentSourceMimetype = sourceMimetype;
- boolean first = true;
Iterator transformerIterator = transformers.iterator();
Iterator intermediateMimetypeIterator = intermediateMimetypes.iterator();
while (transformerIterator.hasNext())
@@ -195,28 +233,78 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
// use an intermediate transformation mimetype
currentTargetMimetype = intermediateMimetypeIterator.next();
}
-
- // check we can tranform the current stage (using -1 if not the first stage as we can't know the size)
- long size = first ? sourceSize : -1;
- if (transformer.isTransformable(currentSourceMimetype, size, currentTargetMimetype, options) == false)
+
+ if (sourceSize < 0)
{
- result = false;
- break;
+ // check we can transform the current stage's mimetypes
+ if (transformer.isTransformableMimetype(currentSourceMimetype, currentTargetMimetype, options) == false)
+ {
+ result = false;
+ break;
+ }
+ }
+ else
+ {
+ // check we can transform the current stage's sizes
+ try
+ {
+ transformerDebug.pushIsTransformableSize(this);
+ // (using -1 if not the first stage as we can't know the size)
+ if (transformer.isTransformableSize(currentSourceMimetype, sourceSize, currentTargetMimetype, options) == false)
+ {
+ result = false;
+ break;
+ }
+
+ // As the size is unknown for the next stages stop.
+ // In future we might guess sizes such as excl to pdf
+ // is about 110% of the original size, in which case
+ // we would continue.
+ break;
+ // sourceSize += sourceSize * 10 / 100;
+ }
+ finally
+ {
+ transformerDebug.popIsTransformableSize();
+ }
}
// move on
currentSourceMimetype = currentTargetMimetype;
- first = false;
- }
-
- if (result && !isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options))
- {
- result = false;
}
return result;
}
+ /**
+ * Indicates if 'page' limits are supported by the first transformer in the chain.
+ * @return true if the first transformer supports them.
+ */
+ protected boolean isPageLimitSupported()
+ {
+ ContentTransformer firstTransformer = transformers.iterator().next();
+ return (firstTransformer instanceof AbstractContentTransformerLimits)
+ ? ((AbstractContentTransformerLimits)firstTransformer).isPageLimitSupported()
+ : false;
+ }
+
+ /**
+ * Returns the limits from this transformer combined with those of the first transformer in the chain.
+ */
+ protected TransformationOptionLimits getLimits(String sourceMimetype, String targetMimetype,
+ TransformationOptions options)
+ {
+ TransformationOptionLimits limits = super.getLimits(sourceMimetype, targetMimetype, options);
+ ContentTransformer firstTransformer = transformers.get(0);
+ if (firstTransformer instanceof AbstractContentTransformerLimits)
+ {
+ String firstTargetMimetype = intermediateMimetypes.get(0);
+ limits = limits.combine(((AbstractContentTransformerLimits) firstTransformer).
+ getLimits(sourceMimetype, firstTargetMimetype, options));
+ }
+ return limits;
+ }
+
/**
* @see org.alfresco.repo.content.transform.AbstractContentTransformer2#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions)
*/
@@ -263,15 +351,4 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
{
return Collections.unmodifiableList(intermediateMimetypes);
}
-
- /**
- * @deprecated This method should no longer be called as the overloaded method
- * that calls it has the overridden.
- */
- @Override
- public boolean isTransformable(String sourceMimetype, String targetMimetype,
- TransformationOptions options)
- {
- return false;
- }
}
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ContentTransformer.java
index f644ba6aef..e683b88dbf 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformer.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
*
@@ -44,12 +44,39 @@ public interface ContentTransformer extends ContentWorker
*
* @param sourceMimetype the source mimetype
* @param sourceSize the size (bytes) of the source. If negative it is unknown.
- * @param targetMimetype the target mimetype
+ * @param targetMimetype the target mimetype
* @param options the transformation options
* @return boolean true if this content transformer can satify the mimetypes and options specified, false otherwise
*/
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options);
+ /**
+ * Sub component of {@link #isTransformable(String, long, String, TransformationOptions)
+ * that checks just the mimetypes.
+ * @param sourceMimetype the source mimetype
+ * @param targetMimetype the target mimetype
+ * @param options the transformation options
+ * @return boolean true if this content transformer can satify the mimetypes, false otherwise
+ */
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options);
+
+ /**
+ * Sub component of {@link #isTransformable(String, long, String, TransformationOptions)
+ * that checks just the size limits.
+ * @param sourceMimetype the source mimetype
+ * @param sourceSize the size (bytes) of the source. If negative it is unknown.
+ * @param targetMimetype the target mimetype
+ * @param options the transformation options
+ * @return boolean true if this content transformer can satify the mimetypes, false otherwise
+ */
+ public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options);
+
+ /**
+ * Returns the maximum source size (in KBytes) allowed given the supplied values.
+ * @return 0 if the the transformation is disabled, -1 if there is no limit, otherwise the size in KBytes.
+ */
+ public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options);
+
/**
* Indicates whether given the provided transformation parmaters this transformer can prvide an explict
* transformation.
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
index c1206755db..b3b91eef97 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.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
*
@@ -111,6 +111,7 @@ public class ContentTransformerRegistry
for (ContentTransformer transformer : transformers)
{
// Transformability can be dynamic, i.e. it may have become unusable
+ // Don't know why we do this test as it has already been done by findTransformers(...)
if (transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == false)
{
// It is unreliable now.
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java
index ea4fb31bf1..05a4de2942 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.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
*
@@ -236,7 +236,7 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
disable = true;
}
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if (disable) {
return false;
diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerWorker.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerWorker.java
index ff1e445684..ef3e43f7b7 100644
--- a/source/java/org/alfresco/repo/content/transform/ContentTransformerWorker.java
+++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerWorker.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
*
@@ -28,6 +28,7 @@ import org.alfresco.service.cmr.repository.TransformationOptions;
*
* @author dward
*/
+// TODO Modify ContentTransformerWorker to understand transformer limits. At the moment no workers use them
public interface ContentTransformerWorker
{
/**
diff --git a/source/java/org/alfresco/repo/content/transform/EMLTransformer.java b/source/java/org/alfresco/repo/content/transform/EMLTransformer.java
index 0edee16c5e..d10ae47912 100644
--- a/source/java/org/alfresco/repo/content/transform/EMLTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/EMLTransformer.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
*
@@ -46,7 +46,8 @@ import org.alfresco.service.cmr.repository.TransformationOptions;
*/
public class EMLTransformer extends AbstractContentTransformer2
{
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if (!MimetypeMap.MIMETYPE_RFC822.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
{
diff --git a/source/java/org/alfresco/repo/content/transform/FailoverContentTransformer.java b/source/java/org/alfresco/repo/content/transform/FailoverContentTransformer.java
index ac6ada5789..290aed391f 100644
--- a/source/java/org/alfresco/repo/content/transform/FailoverContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/FailoverContentTransformer.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
*
@@ -79,37 +79,65 @@ public class FailoverContentTransformer extends AbstractContentTransformer2 impl
}
/**
- *
- * @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, long sourceSize, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
- */
- public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
- {
- // For this transformer to be considered operational, there must be at least one transformer
- // in the chain that can perform for us.
- boolean result = false;
-
- for (ContentTransformer ct : this.transformers)
- {
- if (ct.isTransformable(sourceMimetype, sourceSize, targetMimetype, options))
- {
- // There may be size limits on this transformer as well as those it contains.
- result = isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
- break;
- }
- }
-
- return result;
- }
-
- /**
- * @deprecated This method should no longer be called as the overloaded method
- * that calls it has the overridden.
+ * Overrides super class method to avoid calling
+ * {@link #isTransformableMimetype(String, String, TransformationOptions)}
+ * twice on each transformer in the list, as
+ * {@link #isTransformableSize(String, long, String, TransformationOptions)}
+ * in this class must check the mimetype too.
*/
@Override
- public boolean isTransformable(String sourceMimetype, String targetMimetype,
- TransformationOptions options)
+ public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
- return false;
+ return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
+ }
+
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ {
+ return isTransformableMimetypeAndSize(sourceMimetype, -1, targetMimetype, options);
+ }
+
+ @Override
+ public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ {
+ return (sourceSize < 0) || isTransformableMimetypeAndSize(sourceMimetype, sourceSize, targetMimetype, options);
+ }
+
+ private boolean isTransformableMimetypeAndSize(String sourceMimetype, long sourceSize,
+ String targetMimetype, TransformationOptions options)
+ {
+ boolean result = false;
+ if (super.isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options))
+ {
+ for (ContentTransformer ct : this.transformers)
+ {
+ transformerDebug.pushIsTransformableSize(this);
+ if (ct.isTransformableMimetype(sourceMimetype, targetMimetype, options))
+ {
+ if (sourceSize == -1)
+ {
+ result = true;
+ break;
+ }
+ else
+ {
+ try
+ {
+ if (ct.isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options))
+ {
+ result = true;
+ break;
+ }
+ }
+ finally
+ {
+ transformerDebug.popIsTransformableSize();
+ }
+ }
+ }
+ }
+ }
+ return result;
}
public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options)
diff --git a/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java
index f0faf92015..f55e64aaea 100644
--- a/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/FailoverContentTransformerTest.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
*
@@ -118,7 +118,8 @@ class DummyTestContentTransformer extends AbstractContentTransformer2 implements
}
}
- public boolean isTransformable(String sourceMimetype,
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype,
String targetMimetype, TransformationOptions options)
{
// We'll arbitrarily claim to be able to transform PDF to PNG
diff --git a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java
index deeda64c1e..6685b2ba96 100644
--- a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformer.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
*
@@ -50,7 +50,8 @@ public class HtmlParserContentTransformer extends AbstractContentTransformer2
/**
* Only support HTML to TEXT.
*/
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if (!MimetypeMap.MIMETYPE_HTML.equals(sourceMimetype) ||
!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
diff --git a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java
index 07d632cb11..183ae521ad 100644
--- a/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/MediaWikiContentTransformer.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
*
@@ -76,7 +76,9 @@ public class MediaWikiContentTransformer extends AbstractContentTransformer2
* Only transform from mediawiki to html
*
* @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
- */public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ */
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if (!MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI.equals(sourceMimetype) ||
!MimetypeMap.MIMETYPE_HTML.equals(targetMimetype))
diff --git a/source/java/org/alfresco/repo/content/transform/PdfBoxPdfToImageContentTransformer.java b/source/java/org/alfresco/repo/content/transform/PdfBoxPdfToImageContentTransformer.java
index d904a66a65..39736b8826 100644
--- a/source/java/org/alfresco/repo/content/transform/PdfBoxPdfToImageContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/PdfBoxPdfToImageContentTransformer.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
*
@@ -53,7 +53,8 @@ public class PdfBoxPdfToImageContentTransformer extends AbstractContentTransform
private static final String PDF_DEFAULT_PASSWORD = "";
private static Log logger = LogFactory.getLog(PdfBoxPdfToImageContentTransformer.class);
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
// only support PDF -> PNG OR Adobe Illustrator -> PNG.
// Recent .ai file format is a .pdf file.
diff --git a/source/java/org/alfresco/repo/content/transform/PdfToImageContentTransformer.java b/source/java/org/alfresco/repo/content/transform/PdfToImageContentTransformer.java
index 4cf9a442ac..6acb28be1e 100644
--- a/source/java/org/alfresco/repo/content/transform/PdfToImageContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/PdfToImageContentTransformer.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
*
@@ -53,7 +53,8 @@ public class PdfToImageContentTransformer extends AbstractContentTransformer2
/**
* Currently the only transformation performed is that of text extraction from PDF documents.
*/
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
// only support PDF -> PNG OR Adobe Illustrator -> PNG.
// .ai is really just a .pdf file anyway
diff --git a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java
index 8963fd5343..b8783cf999 100644
--- a/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/PoiHssfContentTransformer.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
*
@@ -72,28 +72,17 @@ public class PoiHssfContentTransformer extends TikaPoweredContentTransformer
* We support transforming to HTML, XML, Text or CSV
*/
@Override
- public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if(sourceMimeTypes.contains(sourceMimetype) &&
MimetypeMap.MIMETYPE_TEXT_CSV.equals(targetMimetype))
{
- // Special case for CSV
- return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
+ // Special case for CSV
+ return true;
}
// Otherwise fall back on the default Tika rules
- return super.isTransformable(sourceMimetype, sourceSize, targetMimetype, options);
- }
-
- /**
- * @deprecated This method should no longer be called as the overloaded method
- * that calls it has been overridden.
- */
- @Override
- public boolean isTransformable(String sourceMimetype, String targetMimetype,
- TransformationOptions options)
- {
- return isTransformable(sourceMimetype, -1, targetMimetype, options);
+ return super.isTransformableMimetype(sourceMimetype, targetMimetype, options);
}
/**
@@ -112,7 +101,7 @@ public class PoiHssfContentTransformer extends TikaPoweredContentTransformer
}
// Otherwise fall back on the default Tika rules
- return super.isTransformable(sourceMimetype, targetMimetype, options);
+ return super.isTransformableMimetype(sourceMimetype, targetMimetype, options);
}
@Override
diff --git a/source/java/org/alfresco/repo/content/transform/ProxyContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ProxyContentTransformer.java
index 071a8a6dc6..4d937cc98c 100644
--- a/source/java/org/alfresco/repo/content/transform/ProxyContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/ProxyContentTransformer.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
*
@@ -58,7 +58,8 @@ public class ProxyContentTransformer extends AbstractContentTransformer2
/**
* @see DocumentFormatRegistry
*/
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
return this.worker.isTransformable(sourceMimetype, targetMimetype, options);
}
diff --git a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java
index 742c36d21e..facab76cab 100644
--- a/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/StringExtractingContentTransformer.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
*
@@ -50,7 +50,8 @@ public class StringExtractingContentTransformer extends AbstractContentTransform
*
* Extraction of text from binary data is wholly unreliable.
*/
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if (!targetMimetype.equals(MimetypeMap.MIMETYPE_TEXT_PLAIN))
{
diff --git a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java
index 8c3269bdbc..32676ace1a 100644
--- a/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/TextToPdfContentTransformer.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
*
@@ -100,7 +100,8 @@ public class TextToPdfContentTransformer extends AbstractContentTransformer2
/**
* Only supports Text to PDF
*/
- public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if ( (!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) &&
!MimetypeMap.MIMETYPE_TEXT_CSV.equals(sourceMimetype) &&
@@ -112,21 +113,10 @@ public class TextToPdfContentTransformer extends AbstractContentTransformer2
}
else
{
- return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
+ return true;
}
}
- /**
- * @deprecated This method should no longer be called as the overloaded method
- * that calls it has the overridden.
- */
- @Override
- public boolean isTransformable(String sourceMimetype, String targetMimetype,
- TransformationOptions options)
- {
- return false;
- }
-
@Override
protected void transformInternal(
ContentReader reader,
diff --git a/source/java/org/alfresco/repo/content/transform/TikaPoweredContentTransformer.java b/source/java/org/alfresco/repo/content/transform/TikaPoweredContentTransformer.java
index d9d135975f..34c2c9d25d 100644
--- a/source/java/org/alfresco/repo/content/transform/TikaPoweredContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/TikaPoweredContentTransformer.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
*
@@ -87,7 +87,8 @@ public abstract class TikaPoweredContentTransformer extends AbstractContentTrans
* Can we do the requested transformation via Tika?
* We support transforming to HTML, XML or Text
*/
- public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
+ @Override
+ public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
if(! sourceMimeTypes.contains(sourceMimetype))
{
@@ -101,8 +102,7 @@ public abstract class TikaPoweredContentTransformer extends AbstractContentTrans
MimetypeMap.MIMETYPE_XML.equals(targetMimetype))
{
// We can output to this
- // But there may be size limits on this transformer.
- return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
+ return true;
}
else
{
@@ -110,17 +110,6 @@ public abstract class TikaPoweredContentTransformer extends AbstractContentTrans
return false;
}
}
-
- /**
- * @deprecated This method should no longer be called as the overloaded method
- * that calls it has been overridden.
- */
- @Override
- public boolean isTransformable(String sourceMimetype, String targetMimetype,
- TransformationOptions options)
- {
- return isTransformable(sourceMimetype, -1, targetMimetype, options);
- }
/**
* Returns an appropriate Tika ContentHandler for the
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
index 80b2761014..183c023e17 100644
--- a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
+++ b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
@@ -18,10 +18,9 @@
*/
package org.alfresco.repo.content.transform;
-import java.text.DecimalFormat;
+import java.text.NumberFormat;
import java.util.ArrayDeque;
import java.util.Deque;
-import java.util.Formatter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -74,6 +73,7 @@ public class TransformerDebug
};
private final Deque stack = new ArrayDeque();
+ private final Deque isTransformableStack = new ArrayDeque();
private boolean debugOutput = true;
public static Deque getStack()
@@ -85,6 +85,11 @@ public class TransformerDebug
{
return threadInfo.get().debugOutput;
}
+
+ public static Deque getIsTransformableStack()
+ {
+ return threadInfo.get().isTransformableStack;
+ }
public static boolean setDebugOutput(boolean debugOutput)
{
@@ -103,6 +108,7 @@ public class TransformerDebug
private final String fromUrl;
private final String sourceMimetype;
private final String targetMimetype;
+ private final boolean origDebugOutput;
private final long start;
private Call callType;
@@ -111,13 +117,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)
+ private Frame(Frame parent, String fromUrl, String sourceMimetype, String targetMimetype, Call pushCall, boolean origDebugOutput)
{
this.id = parent == null ? uniqueId.getAndIncrement() : ++parent.childId;
this.fromUrl = fromUrl;
this.sourceMimetype = sourceMimetype;
this.targetMimetype = targetMimetype;
this.callType = pushCall;
+ this.origDebugOutput = origDebugOutput;
start = System.currentTimeMillis();
}
}
@@ -196,6 +203,17 @@ public class TransformerDebug
}
}
+ /**
+ * Called prior to calling a nested isTransformable.
+ */
+ public void pushIsTransformableSize(ContentTransformer transformer)
+ {
+ if (isEnabled())
+ {
+ ThreadInfo.getIsTransformableStack().push(getName(transformer));
+ }
+ }
+
private void push(String name, String fromUrl, String sourceMimetype, String targetMimetype, long sourceSize, Call callType)
{
Deque ourStack = ThreadInfo.getStack();
@@ -207,7 +225,9 @@ public class TransformerDebug
}
else
{
- frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, callType);
+ // Create a new frame. Logging level is set to trace if the file size is 0
+ boolean origDebugOutput = ThreadInfo.setDebugOutput(ThreadInfo.getDebug() && sourceSize != 0);
+ frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, callType, origDebugOutput);
ourStack.push(frame);
if (callType == Call.TRANSFORM)
@@ -231,8 +251,11 @@ public class TransformerDebug
if (frame != null)
{
- String name = getName(transformer);
- String reason = String.format("> %,dK", maxSourceSizeKBytes);
+ Deque isTransformableStack = ThreadInfo.getIsTransformableStack();
+ String name = (!isTransformableStack.isEmpty())
+ ? isTransformableStack.getFirst()
+ : getName(transformer);
+ String reason = "> "+fileSize(maxSourceSizeKBytes*1024);
boolean debug = (maxSourceSizeKBytes != 0);
if (ourStack.size() == 1)
{
@@ -273,7 +296,7 @@ public class TransformerDebug
String name = getName(trans);
int pad = longestNameLength - name.length();
log((c == 'a' ? "**" : " ") + (c++) + ") " +
- name + spaces(pad+1) + trans.getTransformationTime() + " ms");
+ name + spaces(pad+1) + ms(trans.getTransformationTime()));
}
if (frame.unavailableTransformers != null)
{
@@ -317,7 +340,8 @@ public class TransformerDebug
log(frame.fromUrl, firstLevel);
}
- log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) + String.format("%,dK ", (sourceSize/1024)) + message);
+ log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) +
+ ((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") + message);
log(frame.sourceMimetype+' '+frame.targetMimetype, false);
}
@@ -345,6 +369,17 @@ public class TransformerDebug
}
}
+ /**
+ * Called after returning from a nested isTransformable.
+ */
+ public void popIsTransformableSize()
+ {
+ if (isEnabled())
+ {
+ ThreadInfo.getIsTransformableStack().pop();
+ }
+ }
+
private void pop(Call callType)
{
Deque ourStack = ThreadInfo.getStack();
@@ -358,12 +393,13 @@ public class TransformerDebug
{
boolean topFrame = ourStack.size() == 1;
log("Finished in " +
- (System.currentTimeMillis() - frame.start) + " ms" +
+ ms(System.currentTimeMillis() - frame.start) +
(frame.callType == Call.AVAILABLE ? " Transformer NOT called" : "") +
(topFrame ? "\n" : ""),
topFrame);
}
+ setDebugOutput(frame.origDebugOutput);
ourStack.pop();
// See debug(String, Throwable) as to why this is commented out
@@ -523,7 +559,7 @@ public class TransformerDebug
return sb.toString();
}
- private String getName(ContentTransformer transformer)
+ public String getName(ContentTransformer transformer)
{
return
(transformer instanceof AbstractContentTransformer2
@@ -567,4 +603,51 @@ public class TransformerDebug
}
return sb.toString();
}
+
+ public String ms(long time)
+ {
+ return String.format("%,d ms", time);
+ }
+
+ public String fileSize(long size)
+ {
+ if (size < 0)
+ {
+ return "unlimited";
+ }
+ if (size == 1)
+ {
+ return "1 byte";
+ }
+ final String[] units = new String[] { "bytes", "KB", "MB", "GB", "TB" };
+ long divider = 1;
+ for(int i = 0; i < units.length-1; i++)
+ {
+ long nextDivider = divider * 1024;
+ if(size < nextDivider)
+ {
+ return fileSizeFormat(size, divider, units[i]);
+ }
+ divider = nextDivider;
+ }
+ return fileSizeFormat(size, divider, units[units.length-1]);
+ }
+
+ private String fileSizeFormat(long size, long divider, String unit)
+ {
+ size = size * 10 / divider;
+ int decimalPoint = (int) size % 10;
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(size/10);
+ if (decimalPoint != 0)
+ {
+ sb.append(".");
+ sb.append(decimalPoint);
+ }
+ sb.append(' ');
+ sb.append(unit);
+
+ return sb.toString();
+ }
}
diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
index dce9a1588e..b93e4405bf 100644
--- a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
+++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
@@ -1437,6 +1437,32 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
return updateNodeImpl(oldNode, nodeUpdate, null);
}
+
+ @Override
+ public int touchNodes(Long txnId, List nodeIds)
+ {
+ // limit in clause to 1000 node ids
+ int batchSize = 1000;
+
+ int touched = 0;
+ ArrayList batch = new ArrayList(batchSize);
+ for(Long nodeId : nodeIds)
+ {
+ invalidateNodeCaches(nodeId);
+ batch.add(nodeId);
+ if(batch.size() % batchSize == 0)
+ {
+ touched += updateNodes(txnId, batch);
+ batch.clear();
+ }
+ }
+ if(batch.size() > 0)
+ {
+ touched += updateNodes(txnId, batch);
+ }
+ return touched;
+ }
+
/**
* Updates the node's transaction and cm:auditable properties while
* providing a convenient method to control cache entry invalidation.
diff --git a/source/java/org/alfresco/repo/domain/node/NodeDAO.java b/source/java/org/alfresco/repo/domain/node/NodeDAO.java
index d7f1003580..003f674401 100644
--- a/source/java/org/alfresco/repo/domain/node/NodeDAO.java
+++ b/source/java/org/alfresco/repo/domain/node/NodeDAO.java
@@ -202,6 +202,14 @@ public interface NodeDAO extends NodeBulkLoader
QName assocTypeQName,
QName assocQName);
+ /**
+ * Update the transaction associated with a lust of nodes
+ * @param txnId - the tx id to set
+ * @param nodeIds - the nodes to update
+ * @return the number of nodes touched
+ */
+ public int touchNodes(Long txnId, List nodeIds);
+
/**
* @param nodeTypeQName the new type QName for the node or null to keep the existing one
* @param nodeLocale the new locale for the node or null to keep the existing one
diff --git a/source/java/org/alfresco/repo/domain/patch/PatchDAO.java b/source/java/org/alfresco/repo/domain/patch/PatchDAO.java
index 392d66f8df..13e0dd062f 100644
--- a/source/java/org/alfresco/repo/domain/patch/PatchDAO.java
+++ b/source/java/org/alfresco/repo/domain/patch/PatchDAO.java
@@ -244,4 +244,41 @@ public interface PatchDAO
* @return Returns a count of the number of nodes that have either of the aspects
*/
public long getCountNodesWithAspects(Set qnames);
+
+ /**
+ * Find all the nodes ids with the given type
+ * @param typeQNameId - the id of the type qname
+ * @param minNodeId - min node id in the result set - inclusive
+ * @param maxNodeId - max node id in the result set - exclusive
+ * @return
+ */
+ public List getNodesByTypeQNameId(Long typeQNameId, Long minNodeId, Long maxNodeId);
+
+ /**
+ * Find all the nodes ids with the given type uri
+ * @param uriId - the id of the type qname uri
+ * @param minNodeId - min node id in the result set - inclusive
+ * @param maxNodeId - max node id in the result set - exclusive
+ * @return
+ */
+ public List getNodesByTypeUriId(Long uriId, Long minNodeId, Long maxNodeId);
+
+ /**
+ * Find all the nodes ids with the given aspect
+ * @param aspectQNameId - the id of the aspect qname
+ * @param minNodeId - min node id in the result set - inclusive
+ * @param maxNodeId - max node id in the result set - exclusive
+ * @return
+ */
+ public List getNodesByAspectQNameId(Long aspectQNameId, Long minNodeId, Long maxNodeId);
+
+ /**
+ * Find all the nodes ids with the given content property set with the given mimetype
+ * @param mimetypeId - the id of the content data mimetype
+ * @param minNodeId - min node id in the result set - inclusive
+ * @param maxNodeId - max node id in the result set - exclusive
+ * @return
+ */
+ public List getNodesByContentPropertyMimetypeId(Long mimetypeId, Long minNodeId, Long maxNodeId);
+
}
diff --git a/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java b/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java
index 4f95f18723..e314abe414 100644
--- a/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java
+++ b/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java
@@ -103,6 +103,11 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl
private static final String SELECT_SHARED_ACLS_THAT_DO_NOT_INHERIT_CORRECTLY_FROM_THEIR_DEFINING_ACL = "alfresco.patch.select_sharedAclsThatDoNotInheritCorrectlyFromTheirDefiningAcl";
private static final String SELECT_COUNT_NODES_WITH_ASPECTS = "alfresco.patch.select_CountNodesWithAspectIds";
+
+ private static final String SELECT_NODES_BY_TYPE_QNAME = "alfresco.patch.select_NodesByTypeQName";
+ private static final String SELECT_NODES_BY_TYPE_URI = "alfresco.patch.select_NodesByTypeUriId";
+ private static final String SELECT_NODES_BY_ASPECT_QNAME = "alfresco.patch.select_NodesByAspectQName";
+ private static final String SELECT_NODES_BY_CONTENT_MIMETYPE = "alfresco.patch.select_NodesByContentMimetype";
private LocaleDAO localeDAO;
@@ -653,4 +658,49 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl
return count;
}
}
+
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List getNodesByTypeQNameId(Long typeQNameId, Long minNodeId, Long maxNodeId)
+ {
+ Map params = new HashMap();
+ params.put("qnameId", typeQNameId);
+ params.put("minNodeId", minNodeId);
+ params.put("maxNodeId", maxNodeId);
+ return (List) template.selectList(SELECT_NODES_BY_TYPE_QNAME, params);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List getNodesByTypeUriId(Long nsId, Long minNodeId, Long maxNodeId)
+ {
+ Map params = new HashMap();
+ params.put("nsId", nsId);
+ params.put("minNodeId", minNodeId);
+ params.put("maxNodeId", maxNodeId);
+ return (List) template.selectList(SELECT_NODES_BY_TYPE_URI, params);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List getNodesByAspectQNameId(Long aspectQNameId, Long minNodeId, Long maxNodeId)
+ {
+ Map params = new HashMap();
+ params.put("qnameId", aspectQNameId);
+ params.put("minNodeId", minNodeId);
+ params.put("maxNodeId", maxNodeId);
+ return (List) template.selectList(SELECT_NODES_BY_ASPECT_QNAME, params);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List getNodesByContentPropertyMimetypeId(Long mimetypeId, Long minNodeId, Long maxNodeId)
+ {
+ Map params = new HashMap();
+ params.put("mimetypeId", mimetypeId);
+ params.put("minNodeId", minNodeId);
+ params.put("maxNodeId", maxNodeId);
+ return (List) template.selectList(SELECT_NODES_BY_CONTENT_MIMETYPE, params);
+ }
}
diff --git a/source/java/org/alfresco/repo/jscript/ApplicationScriptUtils.java b/source/java/org/alfresco/repo/jscript/ApplicationScriptUtils.java
index c1bdac1606..c9c3ce8d5d 100644
--- a/source/java/org/alfresco/repo/jscript/ApplicationScriptUtils.java
+++ b/source/java/org/alfresco/repo/jscript/ApplicationScriptUtils.java
@@ -1,298 +1,96 @@
-/*
- * Copyright (C) 2005-2011 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.jscript;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.repo.jscript.app.PropertyDecorator;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.security.AccessStatus;
-import org.alfresco.service.namespace.NamespaceException;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.util.ISO8601DateFormat;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.springframework.extensions.surf.util.URLEncoder;
-
-import java.io.Serializable;
-import java.text.MessageFormat;
-import java.util.*;
-
-/**
- * Utility functions specifically for external application use.
- *
- * @author Mike Hatfield
- */
-
-public final class ApplicationScriptUtils extends BaseScopableProcessorExtension
-{
- private static Log logger = LogFactory.getLog(ApplicationScriptUtils.class);
-
- /** Repository Service Registry */
- private ServiceRegistry services;
- private NodeService nodeService = null;
- private Map decoratedProperties;
- private String[] userPermissions;
-
- private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
-
- /**
- * Set the service registry
- *
- * @param serviceRegistry the service registry
- */
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
- {
- this.services = serviceRegistry;
- this.nodeService = services.getNodeService();
- }
-
- /**
- * Set the properties that require decorator beans
- *
- * @param decoratedProperties
- */
- public void setDecoratedProperties(Map decoratedProperties)
- {
- this.decoratedProperties = decoratedProperties;
- }
-
- /**
- * Define the list of user permissions to return in the JSON body
- *
- * @param userPermissions
- */
- public void setUserPermissions(String[] userPermissions)
- {
- this.userPermissions = userPermissions;
- }
-
- /**
- * Returns the JSON representation of a node. Long-form QNames are used in the
- * result.
- *
- * @param node the node to convert to JSON representation.
- * @return The JSON representation of this node
- */
- public String toJSON(ScriptNode node)
- {
- return this.toJSON(node, false);
- }
-
- /**
- * Returns the JSON representation of this node.
- *
- * @param node the node to convert to JSON representation.
- * @param useShortQNames if true short-form qnames will be returned, else long-form.
- * @return The JSON representation of this node
- */
- public String toJSON(ScriptNode node, boolean useShortQNames)
- {
- return this.toJSONObj(node, useShortQNames).toString();
- }
-
- /**
- * Returns a JSON object representing the node.
- *
- * @param node the node to convert to JSON representation.
- * @param useShortQNames if true short-form qnames will be returned, else long-form.
- * @return The JSON representation of this node
- */
- protected Object toJSONObj(ScriptNode node, boolean useShortQNames)
- {
- NodeRef nodeRef = node.getNodeRef();
- JSONObject json = new JSONObject();
-
- if (this.nodeService.exists(nodeRef))
- {
- if (this.services.getPublicServiceAccessService().hasAccess(ServiceRegistry.NODE_SERVICE.getLocalName(), "getProperties", nodeRef) == AccessStatus.ALLOWED)
- {
- try
- {
- String typeString = useShortQNames ? this.getShortQName(node.getQNameType()) : node.getType();
- boolean isLink = node.getIsLinkToContainer() || node.getIsLinkToDocument();
-
- json.put("nodeRef", nodeRef.toString());
- json.put("type", typeString);
- json.put("isContainer", node.getIsContainer() || node.getIsLinkToContainer());
- json.put("isLink", isLink);
- json.put("isLocked", node.getIsLocked());
-
- if (node.getIsDocument())
- {
- json.put("contentURL", this.getDownloadAPIUrl(node));
- json.put("mimetype", node.getMimetype());
- json.put("size", node.getSize());
- }
-
- // permissions
- Map permissionsJSON = new LinkedHashMap(3);
- if (node.hasPermission("ReadPermissions"))
- {
- permissionsJSON.put("roles", node.retrieveAllSetPermissions(false, true));
- }
- permissionsJSON.put("inherited", node.inheritsPermissions());
- Map userPermissionJSON = new LinkedHashMap(this.userPermissions.length);
- for (String userPermission : this.userPermissions)
- {
- userPermissionJSON.put(userPermission, node.hasPermission(userPermission));
- }
- permissionsJSON.put("user", (Serializable) userPermissionJSON);
- json.put("permissions", permissionsJSON);
-
- // add properties
- Map nodeProperties = this.nodeService.getProperties(nodeRef);
- json.put("properties", this.parseToJSON(nodeRef, nodeProperties, useShortQNames));
-
- // add aspects as an array
- Set nodeAspects = this.nodeService.getAspects(nodeRef);
- if (useShortQNames)
- {
- Set nodeAspectsShortQNames = new LinkedHashSet(nodeAspects.size());
- for (QName nextLongQName : nodeAspects)
- {
- String nextShortQName = this.getShortQName(nextLongQName);
- nodeAspectsShortQNames.add(nextShortQName);
- }
- json.put("aspects", nodeAspectsShortQNames);
- }
- else
- {
- json.put("aspects", nodeAspects);
- }
-
- // link to document or folder?
- if (isLink)
- {
- NodeRef targetNodeRef = (NodeRef) nodeProperties.get(ContentModel.PROP_LINK_DESTINATION);
- if (targetNodeRef != null)
- {
- json.put("linkedNode", this.toJSONObj(new ScriptNode(targetNodeRef, this.services, node.scope), useShortQNames));
- }
- }
- }
- catch (JSONException error)
- {
- error.printStackTrace();
- }
- }
- }
-
- return json;
- }
-
- /**
- * Given a long-form QName, this method uses the namespace service to create a
- * short-form QName string.
- *
- * @param longQName
- * @return the short form of the QName string, e.g. "cm:content"
- */
- protected String getShortQName(QName longQName)
- {
- return longQName.toPrefixString(this.services.getNamespaceService());
- }
-
- /**
- * Converts a map of node properties to a format suitable for JSON output
- *
- * @param nodeRef
- * @param properties
- * @param useShortQNames
- * @return a decorated map of properties suitable for JSON output
- */
- protected Map parseToJSON(NodeRef nodeRef, Map properties, boolean useShortQNames)
- {
- Map json = new LinkedHashMap(properties.size());
-
- for (QName nextLongQName : properties.keySet())
- {
- try
- {
- String shortQName = this.getShortQName(nextLongQName);
- String key = useShortQNames ? shortQName : nextLongQName.toString();
- Serializable value = properties.get(nextLongQName);
-
- if (value != null)
- {
- // Has a decorator has been registered for this property?
- if (this.decoratedProperties.containsKey(shortQName))
- {
- json.put(key, ((PropertyDecorator) this.decoratedProperties.get(shortQName)).decorate(nodeRef, shortQName, value));
- }
- else
- {
- // Built-in data type processing
- if (value instanceof Date)
- {
- Map dateObj = new LinkedHashMap(1);
- dateObj.put("value", value);
- dateObj.put("iso8601", ISO8601DateFormat.format((Date)value));
- json.put(key, (Serializable)dateObj);
- }
- else
- {
- json.put(key, value);
- }
- }
- }
- else
- {
- json.put(key, null);
- }
- }
- catch (NamespaceException ne)
- {
- // ignore properties that do not have a registered namespace
- if (logger.isDebugEnabled())
- logger.debug("Ignoring property '" + nextLongQName + "' as its namespace is not registered");
- }
- }
-
- return json;
- }
-
- /**
- * @param node the node to construct the download URL for
- * @return For a content document, this method returns the URL to the /api/node/content
- * API for the default content property
- *
- * For a container node, this method returns an empty string
- *
- */
- public String getDownloadAPIUrl(ScriptNode node)
- {
- if (node.getIsDocument())
- {
- return MessageFormat.format(CONTENT_DOWNLOAD_API_URL, new Object[]{
- node.nodeRef.getStoreRef().getProtocol(),
- node.nodeRef.getStoreRef().getIdentifier(),
- node.nodeRef.getId(),
- URLEncoder.encode(node.getName())});
- }
- else
- {
- return "";
- }
- }
-
-}
+/*
+ * Copyright (C) 2005-2011 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.jscript;
+
+import java.text.MessageFormat;
+
+import org.alfresco.repo.jscript.app.JSONConversionComponent;
+import org.springframework.extensions.surf.util.URLEncoder;
+
+/**
+ * Utility functions specifically for external application use.
+ *
+ * @author Mike Hatfield
+ */
+
+public final class ApplicationScriptUtils extends BaseScopableProcessorExtension
+{
+ /** Content download API URL */
+ private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
+
+ /** JSON conversion component */
+ private JSONConversionComponent jsonConversionComponent;
+
+ /**
+ * @param jsonConversionComponent JSON conversion component
+ */
+ public void setJsonConversionComponent(JSONConversionComponent jsonConversionComponent)
+ {
+ this.jsonConversionComponent = jsonConversionComponent;
+ }
+
+ /**
+ * Returns the JSON representation of a node. Long-form QNames are used in the
+ * result.
+ *
+ * @param node the node to convert to JSON representation.
+ * @return The JSON representation of this node
+ */
+ public String toJSON(ScriptNode node)
+ {
+ return this.toJSON(node, false);
+ }
+
+ /**
+ * Returns the JSON representation of this node.
+ *
+ * @param node the node to convert to JSON representation.
+ * @param useShortQNames if true short-form qnames will be returned, else long-form.
+ * @return The JSON representation of this node
+ */
+ public String toJSON(ScriptNode node, boolean useShortQNames)
+ {
+ return jsonConversionComponent.toJSON(node.getNodeRef(), useShortQNames);
+ }
+
+ /**
+ * @param node the node to construct the download URL for
+ * @return For a content document, this method returns the URL to the /api/node/content
+ * API for the default content property
+ *
+ * For a container node, this method returns an empty string
+ *
+ */
+ public String getDownloadAPIUrl(ScriptNode node)
+ {
+ if (node.getIsDocument())
+ {
+ return MessageFormat.format(CONTENT_DOWNLOAD_API_URL, new Object[]{
+ node.nodeRef.getStoreRef().getProtocol(),
+ node.nodeRef.getStoreRef().getIdentifier(),
+ node.nodeRef.getId(),
+ URLEncoder.encode(node.getName())});
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java
index 33e5894091..6fb9ce0e05 100644
--- a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java
+++ b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.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
*
@@ -65,6 +65,7 @@ import org.springframework.util.FileCopyUtils;
public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcessor, ScriptResourceLoader, InitializingBean
{
private static final Log logger = LogFactory.getLog(RhinoScriptProcessor.class);
+ private static final Log callLogger = LogFactory.getLog(RhinoScriptProcessor.class.getName()+".calls");
private static final String PATH_CLASSPATH = "classpath:";
@@ -188,7 +189,13 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
}
- return executeScriptImpl(script, model, location.isSecure());
+ String debugScriptName = null;
+ if (callLogger.isDebugEnabled())
+ {
+ int i = path.lastIndexOf('/');
+ debugScriptName = (i != -1) ? path.substring(i+1) : path;
+ }
+ return executeScriptImpl(script, model, location.isSecure(), debugScriptName);
}
catch (Throwable err)
{
@@ -238,7 +245,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
Context.exit();
}
- return executeScriptImpl(script, model, false);
+ return executeScriptImpl(script, model, false, nodeRef.toString());
}
catch (Throwable err)
{
@@ -264,7 +271,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
{
Context.exit();
}
- return executeScriptImpl(script, model, true);
+ return executeScriptImpl(script, model, true, "string script");
}
catch (Throwable err)
{
@@ -413,17 +420,19 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
* @param script The script to execute.
* @param model Data model containing objects to be added to the root scope.
* @param secure True if the script is considered secure and may access java.* libs directly
+ * @param debugScriptName To identify the script in debug messages.
*
* @return result of the script execution, can be null.
*
* @throws AlfrescoRuntimeException
*/
- private Object executeScriptImpl(Script script, Map model, boolean secure)
+ private Object executeScriptImpl(Script script, Map model, boolean secure, String debugScriptName)
throws AlfrescoRuntimeException
{
long startTime = 0;
- if (logger.isDebugEnabled())
+ if (callLogger.isDebugEnabled())
{
+ callLogger.debug(debugScriptName+" Start");
startTime = System.nanoTime();
}
@@ -487,6 +496,10 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
catch (WrappedException w)
{
+ if (callLogger.isDebugEnabled())
+ {
+ callLogger.debug(debugScriptName+" Exception", w);
+ }
Throwable err = w.getWrappedException();
if (err instanceof RuntimeException)
{
@@ -496,16 +509,20 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
catch (Throwable err)
{
+ if (callLogger.isDebugEnabled())
+ {
+ callLogger.debug(debugScriptName+" Exception", err);
+ }
throw new AlfrescoRuntimeException(err.getMessage(), err);
}
finally
{
Context.exit();
- if (logger.isDebugEnabled())
+ if (callLogger.isDebugEnabled())
{
long endTime = System.nanoTime();
- logger.debug("Time to execute script: " + (endTime - startTime)/1000000f + "ms");
+ callLogger.debug(debugScriptName+" End " + (endTime - startTime)/1000000 + " ms");
}
}
}
diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java
index f455265e40..c5d3a9c830 100644
--- a/source/java/org/alfresco/repo/jscript/ScriptNode.java
+++ b/source/java/org/alfresco/repo/jscript/ScriptNode.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
*
@@ -2828,7 +2828,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
if (contentReader != null)
{
String mimetype = contentReader.getMimetype();
- List thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentReader.getContentUrl(), mimetype, contentReader.getSize());
+ List thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(mimetype, contentReader.getSize());
for (ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions)
{
result.add(thumbnailDefinition.getName());
diff --git a/source/java/org/alfresco/repo/jscript/app/BasePropertyDecorator.java b/source/java/org/alfresco/repo/jscript/app/BasePropertyDecorator.java
new file mode 100644
index 0000000000..9ce41b2530
--- /dev/null
+++ b/source/java/org/alfresco/repo/jscript/app/BasePropertyDecorator.java
@@ -0,0 +1,75 @@
+/**
+ *
+ */
+package org.alfresco.repo.jscript.app;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * @author Roy Wetherall
+ */
+public abstract class BasePropertyDecorator implements PropertyDecorator
+{
+ protected Set propertyNames;
+
+ protected NodeService nodeService;
+
+ protected NamespaceService namespaceService;
+
+ protected PermissionService permissionService;
+
+ protected JSONConversionComponent jsonConversionComponent;
+
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ public void setJsonConversionComponent(JSONConversionComponent jsonConversionComponent)
+ {
+ this.jsonConversionComponent = jsonConversionComponent;
+ }
+
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
+
+ public void init()
+ {
+ jsonConversionComponent.registerPropertyDecorator(this);
+ }
+
+ @Override
+ public Set getPropertyNames()
+ {
+ return propertyNames;
+ }
+
+ public void setPropertyName(String propertyName)
+ {
+ propertyNames = new HashSet(1);
+ propertyNames.add(QName.createQName(propertyName, namespaceService));
+ }
+
+ public void setPropertyNames(Set propertyNames)
+ {
+ this.propertyNames = new HashSet(propertyNames.size());
+ for (String propertyName : propertyNames)
+ {
+ this.propertyNames.add(QName.createQName(propertyName, namespaceService));
+ }
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/jscript/app/CategoryPropertyDecorator.java b/source/java/org/alfresco/repo/jscript/app/CategoryPropertyDecorator.java
index 5abce11f0b..dd6b852556 100644
--- a/source/java/org/alfresco/repo/jscript/app/CategoryPropertyDecorator.java
+++ b/source/java/org/alfresco/repo/jscript/app/CategoryPropertyDecorator.java
@@ -18,55 +18,46 @@
*/
package org.alfresco.repo.jscript.app;
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.InvalidNodeRefException;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
import java.io.Serializable;
import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
/**
* Category property decorator class.
*
* @author Mike Hatfield
*/
-public class CategoryPropertyDecorator implements PropertyDecorator
+public class CategoryPropertyDecorator extends BasePropertyDecorator
{
private static Log logger = LogFactory.getLog(CategoryPropertyDecorator.class);
-
- private ServiceRegistry services;
- private NodeService nodeService = null;
- private PermissionService permissionService = null;
-
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
- {
- this.services = serviceRegistry;
- this.nodeService = serviceRegistry.getNodeService();
- this.permissionService = serviceRegistry.getPermissionService();
- }
-
- public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
+
+ /**
+ * @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
+ */
+ @SuppressWarnings("unchecked")
+ public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
{
Collection collection = (Collection)value;
- Object[] array = new Object[collection.size()];
- int index = 0;
+ JSONArray array = new JSONArray();
for (NodeRef obj : collection)
{
try
{
- Map jsonObj = new LinkedHashMap(4);
+ JSONObject jsonObj = new JSONObject();
jsonObj.put("name", this.nodeService.getProperty(obj, ContentModel.PROP_NAME));
jsonObj.put("path", this.getPath(obj));
jsonObj.put("nodeRef", obj.toString());
- array[index++] = jsonObj;
+ array.add(jsonObj);
}
catch (InvalidNodeRefException e)
{
diff --git a/source/java/org/alfresco/repo/jscript/app/IgnorePropertyDecorator.java b/source/java/org/alfresco/repo/jscript/app/IgnorePropertyDecorator.java
new file mode 100644
index 0000000000..f51175fe16
--- /dev/null
+++ b/source/java/org/alfresco/repo/jscript/app/IgnorePropertyDecorator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005-2011 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.jscript.app;
+
+import java.io.Serializable;
+
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.json.simple.JSONAware;
+
+/**
+ * Ignores a given property and doesn't output anything in the decoration. This means the property will not appear in the
+ * resulting JSON.
+ *
+ * @author Roy Wetherall
+ */
+public class IgnorePropertyDecorator extends BasePropertyDecorator
+{
+ /**
+ * @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
+ */
+ public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
+ {
+ return null;
+ }
+}
diff --git a/source/java/org/alfresco/repo/jscript/app/JSONConversionComponent.java b/source/java/org/alfresco/repo/jscript/app/JSONConversionComponent.java
new file mode 100644
index 0000000000..32ec674257
--- /dev/null
+++ b/source/java/org/alfresco/repo/jscript/app/JSONConversionComponent.java
@@ -0,0 +1,413 @@
+/**
+ *
+ */
+package org.alfresco.repo.jscript.app;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.lock.LockService;
+import org.alfresco.service.cmr.lock.LockStatus;
+import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.AccessPermission;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.cmr.security.PublicServiceAccessService;
+import org.alfresco.service.namespace.NamespaceException;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ISO8601DateFormat;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+import org.springframework.extensions.surf.util.URLEncoder;
+
+/**
+ * JSON Conversion Component
+ *
+ * @author Roy Wetherall
+ */
+public class JSONConversionComponent
+{
+ /** Content download API URL template */
+ private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
+
+ /** Logger */
+ private static Log logger = LogFactory.getLog(JSONConversionComponent.class);
+
+ /** Registered decorators */
+ protected Map propertyDecorators = new HashMap(3);
+
+ /** User permissions */
+ protected String[] userPermissions;
+
+ /** Services */
+ protected NodeService nodeService;
+ protected PublicServiceAccessService publicServiceAccessService;
+ protected NamespaceService namespaceService;
+ protected FileFolderService fileFolderService;
+ protected LockService lockService;
+ protected ContentService contentService;
+ protected PermissionService permissionService;
+
+ /**
+ * @param nodeService node service
+ */
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ /**
+ * @param publicServiceAccessService public service access service
+ */
+ public void setPublicServiceAccessService(PublicServiceAccessService publicServiceAccessService)
+ {
+ this.publicServiceAccessService = publicServiceAccessService;
+ }
+
+ /**
+ * @param namespaceService namespace service
+ */
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * @param fileFolderService file folder service
+ */
+ public void setFileFolderService(FileFolderService fileFolderService)
+ {
+ this.fileFolderService = fileFolderService;
+ }
+
+ /**
+ * @param lockService lock service
+ */
+ public void setLockService(LockService lockService)
+ {
+ this.lockService = lockService;
+ }
+
+ /**
+ * @param permissionService permission service
+ */
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
+
+ /**
+ * @param userPermissions user permissions
+ */
+ public void setUserPermissions(String[] userPermissions)
+ {
+ this.userPermissions = userPermissions;
+ }
+
+ /**
+ * @param contentService content service
+ */
+ public void setContentService(ContentService contentService)
+ {
+ this.contentService = contentService;
+ }
+
+ /**
+ * Register a property decorator;
+ *
+ * @param propertyDecorator
+ */
+ public void registerPropertyDecorator(PropertyDecorator propertyDecorator)
+ {
+ for (QName propertyName : propertyDecorator.getPropertyNames())
+ {
+ propertyDecorators.put(propertyName, propertyDecorator);
+ }
+ }
+
+ /**
+ * Convert a node reference to a JSON string. Selects the correct converter based on selection
+ * implementation.
+ */
+ @SuppressWarnings("unchecked")
+ public String toJSON(NodeRef nodeRef, boolean useShortQNames)
+ {
+ JSONObject json = new JSONObject();
+
+ if (this.nodeService.exists(nodeRef) == true)
+ {
+ if (publicServiceAccessService.hasAccess(ServiceRegistry.NODE_SERVICE.getLocalName(), "getProperties", nodeRef) == AccessStatus.ALLOWED)
+ {
+ // Get node info
+ FileInfo nodeInfo = fileFolderService.getFileInfo(nodeRef);
+
+ // Set root values
+ setRootValues(nodeInfo, json, useShortQNames);
+
+ // add permissions
+ json.put("permissions", permissionsToJSON(nodeRef));
+
+ // add properties
+ json.put("properties", propertiesToJSON(nodeRef, useShortQNames));
+
+ // add aspects
+ json.put("aspects", apsectsToJSON(nodeRef, useShortQNames));
+ }
+ }
+
+ return json.toJSONString();
+ }
+
+ /**
+ *
+ * @param nodeInfo
+ * @param rootJSONObject
+ * @param useShortQNames
+ * @throws JSONException
+ */
+ @SuppressWarnings("unchecked")
+ protected void setRootValues(FileInfo nodeInfo, JSONObject rootJSONObject, boolean useShortQNames)
+ {
+ NodeRef nodeRef = nodeInfo.getNodeRef();
+
+ rootJSONObject.put("nodeRef", nodeInfo.getNodeRef().toString());
+ rootJSONObject.put("type", nameToString(nodeInfo.getType(), useShortQNames));
+ rootJSONObject.put("isContainer", nodeInfo.isFolder()); //node.getIsContainer() || node.getIsLinkToContainer());
+ rootJSONObject.put("isLocked", isLocked(nodeInfo.getNodeRef()));
+
+ rootJSONObject.put("isLink", nodeInfo.isLink());
+ if (nodeInfo.isLink() == true)
+ {
+ NodeRef targetNodeRef = nodeInfo.getLinkNodeRef();
+ if (targetNodeRef != null)
+ {
+ rootJSONObject.put("linkedNode", toJSON(targetNodeRef, useShortQNames));
+ }
+ }
+
+ // TODO should this be moved to the property output since we may have more than one content property
+ // or a non-standard content property
+
+ if (nodeInfo.isFolder() == false)
+ {
+ ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
+
+ if (reader != null)
+ {
+ String contentURL = MessageFormat.format(
+ CONTENT_DOWNLOAD_API_URL, new Object[]{
+ nodeRef.getStoreRef().getProtocol(),
+ nodeRef.getStoreRef().getIdentifier(),
+ nodeRef.getId(),
+ URLEncoder.encode(nodeInfo.getName())});
+
+ rootJSONObject.put("contentURL", contentURL);
+ rootJSONObject.put("mimetype", reader.getMimetype());
+ rootJSONObject.put("encoding", reader.getEncoding());
+ rootJSONObject.put("size", reader.getSize());
+ }
+ }
+ }
+
+ /**
+ *
+ * @param nodeRef
+ * @return
+ * @throws JSONException
+ */
+ @SuppressWarnings("unchecked")
+ protected JSONObject permissionsToJSON(NodeRef nodeRef)
+ {
+ JSONObject permissionsJSON = new JSONObject();
+ if (AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, PermissionService.READ_PERMISSIONS)) == true)
+ {
+ permissionsJSON.put("inherited", permissionService.getInheritParentPermissions(nodeRef));
+ permissionsJSON.put("roles", allSetPermissionsToJSON(nodeRef));
+ permissionsJSON.put("user", userPermissionsToJSON(nodeRef));
+ }
+ return permissionsJSON;
+ }
+
+ /**
+ *
+ * @param nodeRef
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ protected JSONObject userPermissionsToJSON(NodeRef nodeRef)
+ {
+ JSONObject userPermissionJSON = new JSONObject();
+ for (String userPermission : this.userPermissions)
+ {
+ boolean hasPermission = AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, userPermission));
+ userPermissionJSON.put(userPermission, hasPermission);
+ }
+ return userPermissionJSON;
+ }
+
+ /**
+ *
+ * @param nodeRef
+ * @param useShortQNames
+ * @return
+ * @throws JSONException
+ */
+ @SuppressWarnings("unchecked")
+ protected JSONObject propertiesToJSON(NodeRef nodeRef, boolean useShortQNames)
+ {
+ JSONObject propertiesJSON = new JSONObject();
+
+ Map properties = nodeService.getProperties(nodeRef);
+ for (QName propertyName : properties.keySet())
+ {
+ try
+ {
+ String key = nameToString(propertyName, useShortQNames);
+ Serializable value = properties.get(propertyName);
+
+ if (value != null)
+ {
+ // Has a decorator has been registered for this property?
+ if (propertyDecorators.containsKey(propertyName) == true)
+ {
+ JSONAware jsonAware = propertyDecorators.get(propertyName).decorate(propertyName, nodeRef, value);
+ if (jsonAware != null)
+ {
+ propertiesJSON.put(key, jsonAware);
+ }
+ }
+ else
+ {
+ // Built-in data type processing
+ if (value instanceof Date)
+ {
+ JSONObject dateObj = new JSONObject();
+ dateObj.put("value", JSONObject.escape(value.toString()));
+ dateObj.put("iso8601", JSONObject.escape(ISO8601DateFormat.format((Date)value)));
+ propertiesJSON.put(key, dateObj);
+ }
+ else
+ {
+ propertiesJSON.put(key, value.toString());
+ }
+ }
+ }
+ else
+ {
+ propertiesJSON.put(key, null);
+ }
+ }
+ catch (NamespaceException ne)
+ {
+ // ignore properties that do not have a registered namespace
+ if (logger.isDebugEnabled() == true)
+ {
+ logger.debug("Ignoring property '" + propertyName + "' as its namespace is not registered");
+ }
+ }
+ }
+
+ return propertiesJSON;
+ }
+
+ /**
+ *
+ * @param nodeRef
+ * @param useShortQNames
+ * @return
+ * @throws JSONException
+ */
+ @SuppressWarnings("unchecked")
+ protected JSONArray apsectsToJSON(NodeRef nodeRef, boolean useShortQNames)
+ {
+ JSONArray aspectsJSON = new JSONArray();
+
+ Set aspects = this.nodeService.getAspects(nodeRef);
+ for (QName aspect : aspects)
+ {
+ aspectsJSON.add(nameToString(aspect, useShortQNames));
+ }
+
+ return aspectsJSON;
+ }
+
+ /**
+ *
+ * @param nodeRef
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ protected JSONArray allSetPermissionsToJSON(NodeRef nodeRef)
+ {
+ Set acls = permissionService.getAllSetPermissions(nodeRef);
+ JSONArray permissions = new JSONArray();
+ for (AccessPermission permission : acls)
+ {
+ StringBuilder buf = new StringBuilder(64);
+ buf.append(permission.getAccessStatus())
+ .append(';')
+ .append(permission.getAuthority())
+ .append(';')
+ .append(permission.getPermission())
+ .append(';').append(permission.isSetDirectly() ? "DIRECT" : "INHERITED");
+ permissions.add(buf.toString());
+ }
+ return permissions;
+ }
+
+ /**
+ *
+ * @param qname
+ * @param isShortName
+ * @return
+ */
+ private String nameToString(QName qname, boolean isShortName)
+ {
+ String result = null;
+ if (isShortName == true)
+ {
+ result = qname.toPrefixString(namespaceService);
+ }
+ else
+ {
+ result = qname.toString();
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @param nodeRef
+ * @return
+ */
+ private boolean isLocked(NodeRef nodeRef)
+ {
+ boolean locked = false;
+
+ if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == true)
+ {
+ LockStatus lockStatus = lockService.getLockStatus(nodeRef);
+ if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
+ {
+ locked = true;
+ }
+ }
+
+ return locked;
+ }
+}
diff --git a/source/java/org/alfresco/repo/jscript/app/PropertyDecorator.java b/source/java/org/alfresco/repo/jscript/app/PropertyDecorator.java
index 60a33542c5..b492536624 100644
--- a/source/java/org/alfresco/repo/jscript/app/PropertyDecorator.java
+++ b/source/java/org/alfresco/repo/jscript/app/PropertyDecorator.java
@@ -18,8 +18,12 @@
*/
package org.alfresco.repo.jscript.app;
-import org.alfresco.service.cmr.repository.NodeRef;
import java.io.Serializable;
+import java.util.Set;
+
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.json.simple.JSONAware;
/**
* Interface for property decorators used by ApplicationScriptUtils.toJSON()
@@ -28,5 +32,7 @@ import java.io.Serializable;
*/
public interface PropertyDecorator
{
- Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value);
+ Set getPropertyNames();
+
+ JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value);
}
diff --git a/source/java/org/alfresco/repo/jscript/app/TagPropertyDecorator.java b/source/java/org/alfresco/repo/jscript/app/TagPropertyDecorator.java
index c2b12b69fb..28497df579 100644
--- a/source/java/org/alfresco/repo/jscript/app/TagPropertyDecorator.java
+++ b/source/java/org/alfresco/repo/jscript/app/TagPropertyDecorator.java
@@ -18,51 +18,45 @@
*/
package org.alfresco.repo.jscript.app;
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.InvalidNodeRefException;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
import java.io.Serializable;
import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
/**
* Tag property decorator class.
*
* @author Mike Hatfield
*/
-public class TagPropertyDecorator implements PropertyDecorator
+public class TagPropertyDecorator extends BasePropertyDecorator
{
private static Log logger = LogFactory.getLog(TagPropertyDecorator.class);
- private ServiceRegistry services;
- private NodeService nodeService = null;
-
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
- {
- this.services = serviceRegistry;
- this.nodeService = serviceRegistry.getNodeService();
- }
-
- public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
+ /**
+ * @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
+ */
+ @SuppressWarnings("unchecked")
+ public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
{
Collection collection = (Collection)value;
- Object[] array = new Object[collection.size()];
- int index = 0;
+ JSONArray array = new JSONArray();
for (NodeRef obj : collection)
{
try
{
- Map jsonObj = new LinkedHashMap(2);
+ JSONObject jsonObj = new JSONObject();
jsonObj.put("name", this.nodeService.getProperty(obj, ContentModel.PROP_NAME));
jsonObj.put("nodeRef", obj.toString());
- array[index++] = jsonObj;
+ array.add(jsonObj);
}
catch (InvalidNodeRefException e)
{
diff --git a/source/java/org/alfresco/repo/jscript/app/UsernamePropertyDecorator.java b/source/java/org/alfresco/repo/jscript/app/UsernamePropertyDecorator.java
index 6cddb58b53..680c94281c 100644
--- a/source/java/org/alfresco/repo/jscript/app/UsernamePropertyDecorator.java
+++ b/source/java/org/alfresco/repo/jscript/app/UsernamePropertyDecorator.java
@@ -19,40 +19,43 @@
package org.alfresco.repo.jscript.app;
import java.io.Serializable;
-import java.util.LinkedHashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
-import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
/**
* Username property decorator class.
*
* @author Mike Hatfield
*/
-public class UsernamePropertyDecorator implements PropertyDecorator
+public class UsernamePropertyDecorator extends BasePropertyDecorator
{
- private ServiceRegistry services;
- private NodeService nodeService = null;
+ /** Person service */
private PersonService personService = null;
-
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
+
+ /**
+ * @param personService person service
+ */
+ public void setPersonService(PersonService personService)
{
- this.services = serviceRegistry;
- this.nodeService = serviceRegistry.getNodeService();
- this.personService = serviceRegistry.getPersonService();
+ this.personService = personService;
}
- public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
+ /**
+ * @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
+ */
+ @SuppressWarnings("unchecked")
+ public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
{
String username = value.toString();
String firstName = null;
String lastName = null;
- Map map = new LinkedHashMap(4);
+ JSONObject map = new JSONObject();
map.put("userName", username);
if (this.personService.personExists(username))
@@ -70,12 +73,12 @@ public class UsernamePropertyDecorator implements PropertyDecorator
else
{
map.put("isDeleted", true);
- return (Serializable)map;
+ return map;
}
map.put("firstName", firstName);
map.put("lastName", lastName);
map.put("displayName", (firstName != null ? firstName + " " : "" + lastName != null ? lastName : "").replaceAll("^\\s+|\\s+$", ""));
- return (Serializable)map;
+ return map;
}
}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
index c0378416e5..4b35b0aaac 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
@@ -3945,7 +3945,7 @@ public class IndexInfo implements IndexMonitor
Searcher searcher = new IndexSearcher(reader);
try
{
- for (String stringRef : deletions)
+ for (String stringRef : containerDeletions)
{
TermQuery query = new TermQuery(new Term("ANCESTOR", stringRef));
Hits hits = searcher.search(query);
diff --git a/source/java/org/alfresco/repo/thumbnail/SimpleThumbnailer.java b/source/java/org/alfresco/repo/thumbnail/SimpleThumbnailer.java
index af39196908..a8ac7b6967 100644
--- a/source/java/org/alfresco/repo/thumbnail/SimpleThumbnailer.java
+++ b/source/java/org/alfresco/repo/thumbnail/SimpleThumbnailer.java
@@ -157,7 +157,7 @@ public class SimpleThumbnailer extends TransactionListenerAdapter implements
Serializable value = this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, value);
List thumbnailDefinitions = this.thumbnailService.getThumbnailRegistry()
- .getThumbnailDefinitions(contentData.getContentUrl(), contentData.getMimetype(), contentData.getSize());
+ .getThumbnailDefinitions(contentData.getMimetype(), contentData.getSize());
for (final ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions)
{
final NodeRef existingThumbnail = this.thumbnailService.getThumbnailByName(nodeRef,
diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java
index 71018cb1bb..a144a11e76 100644
--- a/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.java
+++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailRegistry.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
*
@@ -66,8 +66,8 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
/** Map of thumbnail definition */
private Map thumbnailDefinitions = new HashMap();
- /** Cache to store mimetype to thumbnailDefinition mapping */
- private Map> mimetypeMap = new HashMap>(17);
+ /** Cache to store mimetype to thumbnailDefinition mapping with max size limit */
+ private Map> mimetypeMap = new HashMap>(17);
private ThumbnailRenditionConvertor thumbnailRenditionConvertor;
@@ -196,23 +196,24 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
*/
public List getThumbnailDefinitions(String mimetype)
{
- return getThumbnailDefinitions(null, mimetype, -1);
+ return getThumbnailDefinitions(mimetype, -1);
}
- public List getThumbnailDefinitions(String sourceUrl, String mimetype, long sourceSize)
+ public List getThumbnailDefinitions(String mimetype, long sourceSize)
{
- List result = this.mimetypeMap.get(mimetype);
+ List thumbnailDefinitionsLimitsForMimetype = this.mimetypeMap.get(mimetype);
- if (result == null)
+ if (thumbnailDefinitionsLimitsForMimetype == null)
{
boolean foundAtLeastOneTransformer = false;
- result = new ArrayList(7);
+ thumbnailDefinitionsLimitsForMimetype = new ArrayList(7);
for (ThumbnailDefinition thumbnailDefinition : this.thumbnailDefinitions.values())
{
- if (isThumbnailDefinitionAvailable(sourceUrl, mimetype, sourceSize, thumbnailDefinition))
+ long maxSourceSizeBytes = getMaxSourceSizeBytes(mimetype, thumbnailDefinition);
+ if (maxSourceSizeBytes != 0)
{
- result.add(thumbnailDefinition);
+ thumbnailDefinitionsLimitsForMimetype.add(new ThumbnailDefinitionLimits(thumbnailDefinition, maxSourceSizeBytes));
foundAtLeastOneTransformer = true;
}
}
@@ -229,7 +230,18 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
// been launched and that new transformers are available.
if (foundAtLeastOneTransformer)
{
- this.mimetypeMap.put(mimetype, result);
+ this.mimetypeMap.put(mimetype, thumbnailDefinitionsLimitsForMimetype);
+ }
+ }
+
+ // Only return ThumbnailDefinition for this specific source - may be limited on size.
+ List result = new ArrayList(thumbnailDefinitionsLimitsForMimetype.size());
+ for (ThumbnailDefinitionLimits thumbnailDefinitionLimits: thumbnailDefinitionsLimitsForMimetype)
+ {
+ long maxSourceSizeBytes = thumbnailDefinitionLimits.getMaxSourceSizeBytes();
+ if (sourceSize <= 0 || maxSourceSizeBytes < 0 || maxSourceSizeBytes >= sourceSize)
+ {
+ result.add(thumbnailDefinitionLimits.getThumbnailDefinition());
}
}
@@ -253,11 +265,11 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
* is able to thumbnail the source mimetype. Typically used with Thumbnail Definitions
* retrieved by name, and/or when dealing with transient {@link ContentTransformer}s.
* @param sourceUrl The URL of the source (optional)
- * @param sourceMimeType The source mimetype
+ * @param sourceMimetype The source mimetype
* @param sourceSize the size (in bytes) of the source. Use -1 if unknown.
* @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, ThumbnailDefinition thumbnailDefinition)
{
// Log the following getTransform() as trace so we can see the wood for the trees
boolean orig = TransformerDebug.setDebugOutput(false);
@@ -265,7 +277,7 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
{
return this.contentService.getTransformer(
sourceUrl,
- sourceMimeType,
+ sourceMimetype,
sourceSize,
thumbnailDefinition.getMimetype(), thumbnailDefinition.getTransformationOptions()
) != null;
@@ -276,6 +288,28 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
}
}
+ /**
+ * Returns the maximum source size of any content that may transformed between the supplied
+ * sourceMimetype and thumbnailDefinition's targetMimetype using its transformation options.
+ * @param sourceMimetype
+ * @param thumbnailDefinition
+ * @return 0 if there are no transformers, -1 if there is no limit or if positive the size in bytes.
+ */
+ public long getMaxSourceSizeBytes(String sourceMimetype, ThumbnailDefinition thumbnailDefinition)
+ {
+ // Log the following getTransform() as trace so we can see the wood for the trees
+ boolean orig = TransformerDebug.setDebugOutput(false);
+ try
+ {
+ return contentService.getMaxSourceSizeBytes(sourceMimetype,
+ thumbnailDefinition.getMimetype(), thumbnailDefinition.getTransformationOptions());
+ }
+ finally
+ {
+ TransformerDebug.setDebugOutput(orig);
+ }
+ }
+
/**
* Add a thumbnail details
*
@@ -344,4 +378,30 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
// Intentionally empty
}
}
+
+ /**
+ * Links transformer limits (such as maximum size) to a ThumbnailDefinition.
+ *
+ */
+ private class ThumbnailDefinitionLimits
+ {
+ private ThumbnailDefinition thumbnailDefinition;
+ private long maxSourceSizeBytes;
+
+ public ThumbnailDefinitionLimits(ThumbnailDefinition thumbnailDefinition, long maxSourceSizeBytes)
+ {
+ this.thumbnailDefinition = thumbnailDefinition;
+ this.maxSourceSizeBytes = maxSourceSizeBytes;
+ }
+
+ public ThumbnailDefinition getThumbnailDefinition()
+ {
+ return thumbnailDefinition;
+ }
+
+ public long getMaxSourceSizeBytes()
+ {
+ return maxSourceSizeBytes;
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java
index be2ff0c000..ec95256c2b 100644
--- a/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.java
+++ b/source/java/org/alfresco/repo/thumbnail/ThumbnailServiceImplTest.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
*
@@ -724,7 +724,7 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
public void testRegistry()
{
ThumbnailRegistry thumbnailRegistry = this.thumbnailService.getThumbnailRegistry();
- List defs = thumbnailRegistry.getThumbnailDefinitions(null, MimetypeMap.MIMETYPE_HTML, -1);
+ List defs = thumbnailRegistry.getThumbnailDefinitions(MimetypeMap.MIMETYPE_HTML, -1);
System.out.println("Definitions ...");
for (ThumbnailDefinition def : defs)
{
diff --git a/source/java/org/alfresco/repo/version/ContentServiceImplTest.java b/source/java/org/alfresco/repo/version/ContentServiceImplTest.java
index d6a1ca9687..241f0824f9 100644
--- a/source/java/org/alfresco/repo/version/ContentServiceImplTest.java
+++ b/source/java/org/alfresco/repo/version/ContentServiceImplTest.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
*
@@ -19,10 +19,12 @@
package org.alfresco.repo.version;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.content.transform.ContentTransformer;
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.NodeRef;
+import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.version.Version;
/**
@@ -109,4 +111,39 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
// An exception should be raised
}
}
+
+ public void testGetTransformer0()
+ {
+ ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 0,
+ "application/x-shockwave-flash", new TransformationOptions());
+ assertTrue("Found have found a transformer for 0 bytes", transformer != null);
+ }
+
+ public void testGetTransformer10K()
+ {
+ ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 1024*10,
+ "application/x-shockwave-flash", new TransformationOptions());
+ assertTrue("Found have found a transformer for 10 K", transformer != null);
+ }
+
+ public void testGetTransformer1M()
+ {
+ ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 1024*1024,
+ "application/x-shockwave-flash", new TransformationOptions());
+ assertTrue("Found have found a transformer for 1M", transformer != null);
+ }
+
+ public void testGetTransformer10M()
+ {
+ ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 1024*1024*10,
+ "application/x-shockwave-flash", new TransformationOptions());
+ assertTrue("Found NOT have found a transformer for 10M as the is a 1M limit on xsl mimetype", transformer == null);
+ }
+
+ public void testGetMaxSourceSizeByes()
+ {
+ long maxSourceSizeBytes = contentService.getMaxSourceSizeBytes("application/vnd.ms-excel",
+ "application/x-shockwave-flash", new TransformationOptions());
+ assertEquals("Found have found a transformer that can handle 1M", 1024*1024, maxSourceSizeBytes);
+ }
}
diff --git a/source/java/org/alfresco/service/cmr/repository/ContentService.java b/source/java/org/alfresco/service/cmr/repository/ContentService.java
index dc1388a9d3..50f517e2ff 100644
--- a/source/java/org/alfresco/service/cmr/repository/ContentService.java
+++ b/source/java/org/alfresco/service/cmr/repository/ContentService.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
*
@@ -249,6 +249,17 @@ public interface ContentService
*/
public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options);
+ /**
+ * Returns the maximum source size of any content that may transformed between the supplied
+ * mimetypes using the supplied options.
+ * @param sourceMimetype
+ * @param targetMimetype
+ * @param options
+ * @return 0 if there are no transformers, -1 if there is no limit or if positive number the size in bytes.
+ */
+ @Auditable(parameters = {"sourceMimetype", "targetMimetype", "options"})
+ public long getMaxSourceSizeBytes(String sourceMimetype, String targetMimetype, TransformationOptions options);
+
/**
* Fetch all the transformers that are capable of transforming the content in the
* given source mimetype to the given target mimetype with the provided transformation