Merged V4.1-BUG-FIX to HEAD

43114: ALF-15986: ALF-15986: Upgrade to Bitrock 8.5.1 in order to improve font scaling and adaptive layout with Gtk
   - Helps I18N
   43131: Fix for ALF-16510 (webview link incorrect style in High Constrast theme) and also corrected background color class in Activities title in High Contrast them.
   43147: ALF-14395: AccessDeniedException Thrown When Adding ch:contentHits Aspect from CustomAspect SDK Project
      Now sets a runAs user in the execution thread (using the correct tenant)
      Also fixes a bug where the read list was being used as the write list!
   43154: Merged BRANCHES/DEV/FEATURES/CLOUD1_DISCUSSIONS to BRANCHES/DEV/V4.1-BUG-FIX:
      43145: CLOUD-889: Fix noderefs to use base name for nested replies. Convert integration test to run all tests within a tenant (ALF-16498)
   43172: Merged V3.4-BUG-FIX to V4.1-BUG-FIX
      43166: ALF-14306 Add priorities to transformers
         << incomplete - initial steps >>
         - Addition of a TransformerSelector with the same logic as was there before.
           Makes changing the selection transformers simpler in future.
         - Addition of TransformerLog that logs a single DEBUG line for each top level transformer attempt (includes no transformers available).
           Records: sourceMimetype, targetMimetype, INFO/WARN/ERROR, FileName, FileSize, TransformerName, FailureMessage, TimeTaken
           Makes adding a true transformer log in future simpler.
      43169: Merged V3.4 to V3.4-BUG-FIX
         43167: ALF-16379: Performance degradation detected in benchmark test
            - Contention found in concurrent searches
            - Due to a correction in path generation behaviour in ALF-15171, there were a lot more 'container' (path) documents in the index. This meant that searches by node ID would hit a lot of path documents as well as the node document with ISNODE=T. This meant that whatever caches were in the indexreaders would be exhausted so concurrent searches would contend with each other on cache loading.
            - Using the ALF-15077 solution, LeafScorer now directly locates 'leaf' nodes using LEAFID=<noderef> (when possible) and avoids exhausting the caches and hitting container documents.
      43171: Merged V3.4 to V3.4-BUG-FIX (RECORD ONLY)
         43168: ALF-16379: Merged PATCHES/V4.1.1 to V3.4
            42592: ALF-16332: Alternative version of AbstractWebScriptViewResolver that uses a ConcurrentHashMap and thus allows multiple views to be resolved at the same time!
   43173: Merged V3.4-BUG-FIX to V4.1-BUG-FIX (RECORD ONLY)
      43170: Merged V4.1-BUG-FIX to V3.4-BUG-FIX
         42741: Fix for ALF-16332 - Alternative version of AbstractWebScriptViewResolver that uses a ConcurrentHashMap and thus allows multiple views to be resolved at the same time!


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@43175 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2012-10-28 11:02:01 +00:00
parent 05c5279912
commit 8fd64e42ec
8 changed files with 400 additions and 320 deletions

View File

@@ -35,7 +35,10 @@ import org.apache.commons.logging.LogFactory;
* <p>
* The transformers themselves are used to determine the applicability
* of a particular transformation.
*
* <p>
* The actual selection of a transformer is done by the injected
* {@link TransformerSelector}.
*
* @see org.alfresco.repo.content.transform.ContentTransformer
*
* @author Derek Hulley
@@ -46,11 +49,14 @@ public class ContentTransformerRegistry
private List<ContentTransformer> transformers;
private final TransformerSelector transformerSelector;
/**
* @param mimetypeMap all the mimetypes available to the system
*/
public ContentTransformerRegistry()
public ContentTransformerRegistry(TransformerSelector transformerSelector)
{
this.transformerSelector = transformerSelector;
this.transformers = new ArrayList<ContentTransformer>(10);
}
@@ -108,67 +114,7 @@ public class ContentTransformerRegistry
public List<ContentTransformer> getActiveTransformers(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
// Get the list of transformers
List<ContentTransformer> transformers = findTransformers(sourceMimetype, sourceSize, targetMimetype, options);
final Map<ContentTransformer,Long> activeTransformers = new HashMap<ContentTransformer, Long>();
// identify the performance of all the transformers
for (ContentTransformer transformer : transformers)
{
long transformationTime = transformer.getTransformationTime();
activeTransformers.put(transformer, transformationTime);
}
// sort by performance (quicker is "better")
List<ContentTransformer> sorted = new ArrayList<ContentTransformer>(activeTransformers.keySet());
Collections.sort(sorted, new Comparator<ContentTransformer>() {
@Override
public int compare(ContentTransformer a, ContentTransformer b)
{
return activeTransformers.get(a).compareTo(activeTransformers.get(b));
}
});
// All done
return sorted;
}
/**
* Gets all transformers, of equal reliability, that can perform the requested transformation.
*
* @return Returns best transformer for the translation - null if all
* score 0.0 on reliability
*/
private List<ContentTransformer> findTransformers(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
{
List<ContentTransformer> transformers = new ArrayList<ContentTransformer>(2);
boolean foundExplicit = false;
// loop through transformers
for (ContentTransformer transformer : this.transformers)
{
if (transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == true)
{
if (transformer.isExplicitTransformation(sourceMimetype, targetMimetype, options) == true)
{
if (foundExplicit == false)
{
transformers.clear();
foundExplicit = true;
}
transformers.add(transformer);
}
else
{
if (foundExplicit == false)
{
transformers.add(transformer);
}
}
}
}
// done
List<ContentTransformer> transformers = transformerSelector.selectTransformers(this.transformers, sourceMimetype, sourceSize, targetMimetype, options);
if (logger.isDebugEnabled())
{
logger.debug("Searched for transformer: \n" +

View File

@@ -70,7 +70,7 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
bytes[i] = (byte)i;
}
// create the dummyRegistry
dummyRegistry = new ContentTransformerRegistry();
dummyRegistry = new ContentTransformerRegistry(new TransformerSelectorImpl());
// create some dummy transformers for reliability tests
new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, B, 10L);
new DummyTransformer(mimetypeService, transformerDebug, dummyRegistry, A, B, 10L);

View File

@@ -27,7 +27,6 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@@ -57,6 +56,8 @@ import org.apache.commons.logging.LogFactory;
public class TransformerDebug
{
private static final Log logger = LogFactory.getLog(TransformerDebug.class);
private static final TransformerLog info = new TransformerLog();
private static final String NO_TRANSFORMERS = "No transformers";
private enum Call
{
@@ -119,16 +120,19 @@ public class TransformerDebug
private Call callType;
private int childId;
private Set<UnavailableTransformer> unavailableTransformers;
// See debug(String, Throwable) as to why this is commented out
// private Throwable lastThrowable;
private Frame(Frame parent, String fromUrl, String sourceMimetype, String targetMimetype,
TransformationOptions options, Call pushCall, boolean origDebugOutput)
private String failureReason;
private long sourceSize;
private String transformerName;
private Frame(Frame parent, String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, TransformationOptions options, Call pushCall, boolean origDebugOutput)
{
this.id = parent == null ? -1 : ++parent.childId;
this.fromUrl = fromUrl;
this.transformerName = transformerName;
this.sourceMimetype = sourceMimetype;
this.targetMimetype = targetMimetype;
this.sourceSize = sourceSize;
this.options = options;
this.callType = pushCall;
this.origDebugOutput = origDebugOutput;
@@ -143,18 +147,48 @@ public class TransformerDebug
}
return id;
}
private void setFailureReason(String failureReason)
{
this.failureReason = failureReason;
}
private String getFailureReason()
{
return failureReason;
}
private void setSourceSize(long sourceSize)
{
this.sourceSize = sourceSize;
}
public long getSourceSize()
{
return sourceSize;
}
private void setTransformerName(String transformerName)
{
this.transformerName = transformerName;
}
public String getTransformerName()
{
return transformerName;
}
}
private class UnavailableTransformer
{
private final String name;
private final String reason;
private final long maxSourceSizeKBytes;
private final transient boolean debug;
UnavailableTransformer(String name, String reason, boolean debug)
UnavailableTransformer(String name, long maxSourceSizeKBytes, boolean debug)
{
this.name = name;
this.reason = reason;
this.maxSourceSizeKBytes = maxSourceSizeKBytes;
this.debug = debug;
}
@@ -162,7 +196,7 @@ public class TransformerDebug
public int hashCode()
{
int hashCode = 37 * name.hashCode();
hashCode += 37 * reason.hashCode();
hashCode += 37 * maxSourceSizeKBytes;
return hashCode;
}
@@ -178,7 +212,7 @@ public class TransformerDebug
UnavailableTransformer that = (UnavailableTransformer) obj;
return
EqualsHelper.nullSafeEquals(name, that.name) &&
EqualsHelper.nullSafeEquals(reason, that.reason);
maxSourceSizeKBytes == that.maxSourceSizeKBytes;
}
else
{
@@ -248,7 +282,7 @@ public class TransformerDebug
}
}
private void push(String name, String fromUrl, String sourceMimetype, String targetMimetype,
private void push(String transformerName, String fromUrl, String sourceMimetype, String targetMimetype,
long sourceSize, TransformationOptions options, Call callType)
{
Deque<Frame> ourStack = ThreadInfo.getStack();
@@ -256,18 +290,20 @@ public class TransformerDebug
if (callType == Call.TRANSFORM && frame != null && frame.callType == Call.AVAILABLE)
{
frame.setTransformerName(transformerName);
frame.setSourceSize(sourceSize);
frame.callType = Call.AVAILABLE_AND_TRANSFORM;
}
// Create a new frame. Logging level is set to trace if the file size is 0
boolean origDebugOutput = ThreadInfo.setDebugOutput(ThreadInfo.getDebugOutput() && sourceSize != 0);
frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, options, callType, origDebugOutput);
frame = new Frame(frame, transformerName, fromUrl, sourceMimetype, targetMimetype, sourceSize, options, callType, origDebugOutput);
ourStack.push(frame);
if (callType == Call.TRANSFORM)
{
// Log the basic info about this transformation
logBasicDetails(frame, sourceSize, name, (ourStack.size() == 1));
logBasicDetails(frame, sourceSize, transformerName, (ourStack.size() == 1));
}
}
@@ -288,20 +324,12 @@ public class TransformerDebug
String name = (!isTransformableStack.isEmpty())
? isTransformableStack.getFirst()
: getName(transformer);
String reason = "> "+fileSize(maxSourceSizeKBytes*1024);
boolean debug = (maxSourceSizeKBytes != 0);
if (ourStack.size() == 1)
if (frame.unavailableTransformers == null)
{
if (frame.unavailableTransformers == null)
{
frame.unavailableTransformers = new HashSet<UnavailableTransformer>();
}
frame.unavailableTransformers.add(new UnavailableTransformer(name, reason, debug));
}
else
{
log("-- " + name + ' ' + reason, debug);
frame.unavailableTransformers = new HashSet<UnavailableTransformer>();
}
frame.unavailableTransformers.add(new UnavailableTransformer(name, maxSourceSizeKBytes, debug));
}
}
}
@@ -315,18 +343,25 @@ public class TransformerDebug
{
Deque<Frame> ourStack = ThreadInfo.getStack();
Frame frame = ourStack.peek();
boolean firstLevel = ourStack.size() == 1;
// Override setDebugOutput(false) to allow debug when there are transformers but they are all unavailable
// Note once turned on we don't turn it off again.
if (transformers.size() == 0 &&
frame.unavailableTransformers != null &&
frame.unavailableTransformers.size() != 0) {
ThreadInfo.setDebugOutput(true);
if (transformers.size() == 0)
{
frame.setFailureReason(NO_TRANSFORMERS);
if (frame.unavailableTransformers != null &&
frame.unavailableTransformers.size() != 0)
{
ThreadInfo.setDebugOutput(true);
}
}
frame.setSourceSize(sourceSize);
// Log the basic info about this transformation
logBasicDetails(frame, sourceSize,
calledFrom + ((transformers.size() == 0) ? " NO transformers" : ""),
(ourStack.size() == 1));
firstLevel);
// Report available and unavailable transformers
char c = 'a';
@@ -346,8 +381,8 @@ public class TransformerDebug
for (UnavailableTransformer unavailable: frame.unavailableTransformers)
{
int pad = longestNameLength - unavailable.name.length();
log("--" + (c++) + ") " + unavailable.name + spaces(pad+1) + unavailable.reason,
unavailable.debug);
String reason = "> "+fileSize(unavailable.maxSourceSizeKBytes*1024);
log("--" + (c++) + ") " + unavailable.name + spaces(pad+1) + reason, unavailable.debug);
}
}
}
@@ -476,38 +511,100 @@ public class TransformerDebug
if (!ourStack.isEmpty())
{
Frame frame = ourStack.peek();
if ((frame.callType == callType) ||
(frame.callType == Call.AVAILABLE_AND_TRANSFORM && callType == Call.AVAILABLE))
{
if (!suppressFinish && (ourStack.size() == 1 || logger.isTraceEnabled()))
int size = ourStack.size();
String ms = ms(System.currentTimeMillis() - frame.start);
logInfo(frame, size, ms);
boolean firstLevel = size == 1;
if (!suppressFinish && (firstLevel || logger.isTraceEnabled()))
{
boolean topFrame = ourStack.size() == 1;
log("Finished in " +
ms(System.currentTimeMillis() - frame.start) +
log("Finished in " + ms +
(frame.callType == Call.AVAILABLE ? " Transformer NOT called" : "") +
(topFrame ? "\n" : ""),
topFrame);
(firstLevel ? "\n" : ""),
firstLevel);
}
setDebugOutput(frame.origDebugOutput);
ourStack.pop();
// See debug(String, Throwable) as to why this is commented out
// if (ourStack.size() >= 1)
// {
// ourStack.peek().lastThrowable = frame.lastThrowable;
// }
}
}
}
private void logInfo(Frame frame, int size, String ms)
{
if (info.isDebugEnabled())
{
String failureReason = frame.getFailureReason();
boolean firstLevel = size == 1;
String sourceExt = getMimetypeExt(frame.sourceMimetype);
String targetExt = getMimetypeExt(frame.targetMimetype);
String fileName = getFileName(frame.options, firstLevel, frame.sourceSize);
long sourceSize = frame.getSourceSize();
String transformerName = frame.getTransformerName();
String level = null;
boolean debug = false;
if (NO_TRANSFORMERS.equals(failureReason))
{
debug = firstLevel;
level = "INFO";
failureReason = NO_TRANSFORMERS;
if (frame.unavailableTransformers != null)
{
level = "WARN";
long smallestMaxSourceSizeKBytes = Long.MAX_VALUE;
for (UnavailableTransformer unavailable: frame.unavailableTransformers)
{
if (smallestMaxSourceSizeKBytes > unavailable.maxSourceSizeKBytes)
{
smallestMaxSourceSizeKBytes = unavailable.maxSourceSizeKBytes;
}
}
failureReason = "No transformers as file is > "+fileSize(smallestMaxSourceSizeKBytes*1024);
}
}
else if (frame.callType == Call.TRANSFORM)
{
level = failureReason == null || failureReason.length() == 0 ? "INFO" : "ERROR";
// Use TRACE logging for all but the first TRANSFORM
debug = size == 1 || (size == 2 && ThreadInfo.getStack().peekLast().callType != Call.TRANSFORM);
}
if (level != null)
{
infoLog(getReference(debug), sourceExt, targetExt, level, fileName, sourceSize, transformerName, failureReason, ms, debug);
}
}
}
private void infoLog(String reference, String sourceExt, String targetExt, String level, String fileName,
long sourceSize, String transformerName, String failureReason, String ms, boolean debug)
{
String message =
" "+reference +
sourceExt +
targetExt +
(level == null ? "" : level+' ') +
(fileName == null ? "" : fileName) +
(sourceSize >= 0 ? ' '+fileSize(sourceSize) : "") +
(transformerName == null ? "" : ' '+transformerName) +
(failureReason == null ? "" : ' '+failureReason) +
' '+ms;
info.log(message, debug);
}
/**
* Indicates if any logging is required.
*/
public boolean isEnabled()
{
// Don't check ThreadInfo.getDebugOutput() as availableTransformers() may upgrade from trace to debug.
return logger.isDebugEnabled();
return logger.isDebugEnabled() || info.isDebugEnabled();
}
/**
@@ -545,40 +642,32 @@ public class TransformerDebug
if (isEnabled())
{
log(message + ' ' + t.getMessage());
// // Generally the full stack is not needed as transformer
// // Exceptions get logged as a Error higher up, so including
// // the stack trace has been found not to be needed. Keeping
// // the following code and code that sets lastThrowable just
// // in case we need it after all.
//
// Frame frame = ThreadInfo.getStack().peek();
// boolean newThrowable = isNewThrowable(frame.lastThrowable, t);
// frame.lastThrowable = t;
//
// if (newThrowable)
// {
// log(message, t, true);
// }
// else
// {
// log(message + ' ' + t.getMessage());
// }
Deque<Frame> ourStack = ThreadInfo.getStack();
if (!ourStack.isEmpty())
{
Frame frame = ourStack.peek();
frame.setFailureReason(message +' '+ getRootCauseMessage(t));
}
}
}
// private boolean isNewThrowable(Throwable lastThrowable, Throwable t)
// {
// while (t != null)
// {
// if (lastThrowable == t)
// {
// return false;
// }
// t = t.getCause();
// }
// return true;
// }
private String getRootCauseMessage(Throwable t)
{
Throwable cause = t;
while (cause != null)
{
t = cause;
cause = t.getCause();
}
String message = t.getMessage();
if (message == null || message.length() == 0)
{
message = t.getClass().getSimpleName();
}
return message;
}
private void log(String message)
{
@@ -592,13 +681,13 @@ public class TransformerDebug
private void log(String message, Throwable t, boolean debug)
{
if (debug && ThreadInfo.getDebugOutput())
if (debug && ThreadInfo.getDebugOutput() && logger.isDebugEnabled())
{
logger.debug(getReference()+message, t);
logger.debug(getReference(false)+message, t);
}
else if (logger.isTraceEnabled())
{
logger.trace(getReference()+message, t);
logger.trace(getReference(false)+message, t);
}
}
@@ -609,19 +698,15 @@ public class TransformerDebug
*/
public <T extends Throwable> T setCause(T t)
{
// See debug(String, Throwable) as to why this is commented out
// if (isEnabled())
// {
// Deque<Frame> ourStack = ThreadInfo.getStack();
// if (!ourStack.isEmpty())
// {
// ourStack.peek().lastThrowable = t;
// }
// }
return t;
}
private String getReference()
/**
* Returns a N.N.N style reference to the transformation.
* @param firstLevelOnly indicates if only the top level should be included.
* @return a padded (fixed length) reference.
*/
private String getReference(boolean firstLevelOnly)
{
StringBuilder sb = new StringBuilder("");
Frame frame = null;
@@ -634,6 +719,10 @@ public class TransformerDebug
{
sb.append(frame.getId());
lengthOfFirstId = sb.length();
if (firstLevelOnly)
{
break;
}
}
else
{
@@ -770,3 +859,30 @@ public class TransformerDebug
return sb.toString();
}
}
class TransformerLog
{
private static final Log logger = LogFactory.getLog(TransformerLog.class);
void log(String message, boolean debug)
{
if (debug)
{
logger.debug(message);
}
else
{
logger.trace(message);
}
}
public boolean isDebugEnabled()
{
return logger.isDebugEnabled();
}
public boolean isTraceEnabled()
{
return logger.isTraceEnabled();
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.content.transform;
import java.util.List;
import org.alfresco.service.cmr.repository.TransformationOptions;
/**
* Selects a transformer from a supplied list of transformers that appear
* able to handle a given transformation.
*
* @author Alan Davis
*/
public interface TransformerSelector
{
/**
* Returns a sorted list of transformers that identifies the order in which transformers
* should be tried.
* @param transformers an unordered list of all transformers. This
* list may be modified.
* @param sourceMimetype
* @param sourceSize
* @param targetMimetype
* @param options transformation options
* @return a sorted list of transformers, with the best one first.
*/
List<ContentTransformer> selectTransformers(List<ContentTransformer> transformers,
String sourceMimetype, long sourceSize, String targetMimetype,
TransformationOptions options);
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.content.transform;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.repository.TransformationOptions;
/**
* Implementation of a transformer selector that matches the code that was in place
* before a selector was introduced. It is expected that this code will be replaced.
*
* @author Alan Davis
*/
public class TransformerSelectorImpl implements TransformerSelector
{
@Override
public List<ContentTransformer> selectTransformers(List<ContentTransformer> transformers,
String sourceMimetype, long sourceSize, String targetMimetype,
TransformationOptions options)
{
transformers = findTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
transformers = discardNonExplicitTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
transformers = sortTransformers(transformers, sourceMimetype, sourceSize, targetMimetype, options);
return transformers;
}
/**
* Reduces the list of transformers down to only those capable of doing the transformation.
*/
private List<ContentTransformer> findTransformers(List<ContentTransformer> allTransformers, String sourceMimetype,
long sourceSize, String targetMimetype, TransformationOptions options)
{
List<ContentTransformer> transformers = new ArrayList<ContentTransformer>(2);
for (ContentTransformer transformer : allTransformers)
{
if (transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == true)
{
transformers.add(transformer);
}
}
return transformers;
}
/**
* Discards non explicit transformers if there are any explicit ones.
*/
private List<ContentTransformer> discardNonExplicitTransformers(List<ContentTransformer> allTransformers, String sourceMimetype,
long sourceSize, String targetMimetype, TransformationOptions options)
{
List<ContentTransformer> transformers = new ArrayList<ContentTransformer>(2);
boolean foundExplicit = false;
for (ContentTransformer transformer : allTransformers)
{
if (transformer.isExplicitTransformation(sourceMimetype, targetMimetype, options) == true)
{
if (foundExplicit == false)
{
transformers.clear();
foundExplicit = true;
}
transformers.add(transformer);
}
else
{
if (foundExplicit == false)
{
transformers.add(transformer);
}
}
}
return transformers;
}
// sort by performance (quicker is "better")
private List<ContentTransformer> sortTransformers(List<ContentTransformer> transformers,
String sourceMimetype, long sourceSize, String targetMimetype,
TransformationOptions options)
{
final Map<ContentTransformer,Long> activeTransformers = new HashMap<ContentTransformer, Long>();
for (ContentTransformer transformer : transformers)
{
long transformationTime = transformer.getTransformationTime();
activeTransformers.put(transformer, transformationTime);
}
List<ContentTransformer> sorted = new ArrayList<ContentTransformer>(activeTransformers.keySet());
Collections.sort(sorted, new Comparator<ContentTransformer>() {
@Override
public int compare(ContentTransformer a, ContentTransformer b)
{
return activeTransformers.get(a).compareTo(activeTransformers.get(b));
}
});
return sorted;
}
}