locales = searchParameters.getLocales();
- if (((locales == null) || (locales.size() == 0)))
- {
- locales = Collections.singletonList(I18NUtil.getLocale());
- }
-
- if (locales.size() > 1)
- {
- throw new SearcherException("Order on text/mltext properties with more than one locale is not curently supported");
- }
-
- Locale sortLocale = locales.get(0);
- return sortLocale;
- }
-
- String findSortField(SearchParameters searchParameters, ClosingIndexSearcher searcher, String field, Locale sortLocale)
+ protected String findSortField(SearchParameters searchParameters, ClosingIndexSearcher searcher, String field, Locale sortLocale)
{
// find best field match
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java
index c940b59ea8..8978b6e41a 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java
@@ -25,6 +25,7 @@ import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.text.Collator;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -485,7 +486,8 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
// note: cm:thumbnail - hence auditable aspect will be applied with mandatory properties (cm:created, cm:modified, cm:creator, cm:modifier)
n15 = nodeService.createNode(n13, ASSOC_TYPE_QNAME, QName.createQName("{namespace}fifteen"), ContentModel.TYPE_THUMBNAIL, getOrderProperties()).getChildRef();
-
+ nodeService.setProperty(n15, ContentModel.PROP_CONTENT, new ContentData(null, "text/richtext", 0L, "UTF-8", Locale.FRENCH));
+
ContentWriter writer = contentService.getWriter(n14, ContentModel.PROP_CONTENT, true);
writer.setEncoding("UTF-8");
// InputStream is =
@@ -495,6 +497,13 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
+ " as at be but by for if in into is it no not of on or such that the their then there these they this to was will with: "
+ " and random charcters \u00E0\u00EA\u00EE\u00F0\u00F1\u00F6\u00FB\u00FF");
// System.out.println("Size is " + writer.getSize());
+
+ writer = contentService.getWriter(n15, ContentModel.PROP_CONTENT, true);
+ writer.setEncoding("UTF-8");
+ // InputStream is =
+ // this.getClass().getClassLoader().getResourceAsStream("test.doc");
+ // writer.putContent(is);
+ writer.putContent(" ");
nodeService.addChild(rootNodeRef, n8, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}eight-0"));
nodeService.addChild(n1, n8, ASSOC_TYPE_QNAME, QName.createQName("{namespace}eight-1"));
@@ -1762,7 +1771,9 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
ftsQueryWithCount(searcher, "PATH", "\"//.\"", 16);
ftsQueryWithCount(searcher, "cm:content:brown", 1);
ftsQueryWithCount(searcher, "ANDY:brown", 1);
+ ftsQueryWithCount(searcher, "andy:brown", 1);
ftsQueryWithCount(searcher, "ANDY", "brown", 1);
+ ftsQueryWithCount(searcher, "andy", "brown", 1);
// test date ranges - note: expected 2 results = n14 (cm:content) and n15 (cm:thumbnail)
ftsQueryWithCount(searcher, "modified:*", 2, Arrays.asList(new NodeRef[]{n14,n15}));
@@ -3079,6 +3090,8 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
*/
public void testSort() throws Exception
{
+ Collator collator = Collator.getInstance(I18NUtil.getLocale());
+
luceneFTS.pause();
buildBaseIndex();
runBaseTests();
@@ -3099,7 +3112,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
if (current != null)
{
- if (current.compareTo(id) > 0)
+ if (collator.compare(current, id) > 0)
{
fail();
}
@@ -3121,7 +3134,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
String id = row.getNodeRef().getId();
if (current != null)
{
- if (current.compareTo(id) < 0)
+ if (collator.compare(current, id) < 0)
{
fail();
}
@@ -3476,7 +3489,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
// System.out.println( (currentBun == null ? "null" : NumericEncoder.encode(currentBun))+ " "+currentBun);
if ((text != null) && (currentBun != null))
{
- assertTrue(text.compareTo(currentBun) <= 0);
+ assertTrue(collator.compare(text, currentBun) <= 0);
}
text = currentBun;
}
@@ -3496,7 +3509,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
// System.out.println(currentBun);
if ((text != null) && (currentBun != null))
{
- assertTrue(text.compareTo(currentBun) >= 0);
+ assertTrue(collator.compare(text, currentBun) >= 0);
}
text = currentBun;
}
@@ -3512,7 +3525,8 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
Locale[] testLocales = new Locale[] { I18NUtil.getLocale(), Locale.ENGLISH, Locale.FRENCH };
for (Locale testLocale : testLocales)
{
-
+ Collator localisedCollator = Collator.getInstance(testLocale);
+
SearchParameters sp19 = new SearchParameters();
sp19.addStore(rootNodeRef.getStoreRef());
sp19.setLanguage(SearchService.LANGUAGE_LUCENE);
@@ -3532,7 +3546,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
// "+currentBun);
if ((text != null) && (currentBun != null))
{
- assertTrue(text.compareTo(currentBun) <= 0);
+ assertTrue(localisedCollator.compare(text, currentBun) <= 0);
}
text = currentBun;
}
@@ -3556,7 +3570,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener
String currentBun = mltext.getValue(testLocale);
if ((text != null) && (currentBun != null))
{
- assertTrue(text.compareTo(currentBun) >= 0);
+ assertTrue(localisedCollator.compare(text, currentBun) >= 0);
}
text = currentBun;
}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java
index f9fd74c941..32e1b7bc1e 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java
@@ -201,6 +201,10 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory extends AbstractIn
private boolean contentIndexingEnabled = true;
+ private boolean useInMemorySort = true;
+
+ private int maxRawResultSetSizeForInMemorySort = 1000;
+
/**
* Private constructor for the singleton TODO: FIt in with IOC
*/
@@ -1041,6 +1045,38 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory extends AbstractIn
this.threadPoolExecutor = threadPoolExecutor;
}
+ /**
+ * @return the useInMemorySort
+ */
+ public boolean getUseInMemorySort()
+ {
+ return useInMemorySort;
+ }
+
+ /**
+ * @param useInMemorySort the useInMemorySort to set
+ */
+ public void setUseInMemorySort(boolean useInMemorySort)
+ {
+ this.useInMemorySort = useInMemorySort;
+ }
+
+ /**
+ * @return the maxRawResultSetSizeForInMemorySort
+ */
+ public int getMaxRawResultSetSizeForInMemorySort()
+ {
+ return maxRawResultSetSizeForInMemorySort;
+ }
+
+ /**
+ * @param maxRawResultSetSizeForInMemorySort the maxRawResultSetSizeForInMemorySort to set
+ */
+ public void setMaxRawResultSetSizeForInMemorySort(int maxRawResultSetSizeForInMemorySort)
+ {
+ this.maxRawResultSetSizeForInMemorySort = maxRawResultSetSizeForInMemorySort;
+ }
+
/**
* This component is able to safely perform backups of the Lucene indexes while the server is running.
*
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java
index b8c2888db0..879d79cc5f 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java
@@ -80,6 +80,8 @@ public class LuceneAlfrescoFtsQueryLanguage extends AbstractLuceneQueryLanguage
searchParameters.getNamespace());
QueryOptions options = QueryOptions.create(searchParameters);
+ options.setUseInMemorySort(searchParameters.getUseInMemorySort());
+ options.setMaxRawResultSetSizeForInMemorySort(searchParameters.getMaxRawResultSetSizeForInMemorySort());
FTSParser.Mode mode;
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoLuceneQueryLanguage.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoLuceneQueryLanguage.java
index d0088b7504..2ab15de706 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoLuceneQueryLanguage.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoLuceneQueryLanguage.java
@@ -19,42 +19,18 @@
package org.alfresco.repo.search.impl.lucene;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Locale;
-import java.util.Map;
import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.search.EmptyResultSet;
import org.alfresco.repo.search.SearcherException;
import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
-import org.alfresco.repo.search.impl.parsers.AlfrescoFunctionEvaluationContext;
-import org.alfresco.repo.search.impl.parsers.FTSParser;
-import org.alfresco.repo.search.impl.parsers.FTSQueryParser;
-import org.alfresco.repo.search.impl.querymodel.Argument;
-import org.alfresco.repo.search.impl.querymodel.Column;
-import org.alfresco.repo.search.impl.querymodel.Constraint;
-import org.alfresco.repo.search.impl.querymodel.Function;
-import org.alfresco.repo.search.impl.querymodel.Order;
-import org.alfresco.repo.search.impl.querymodel.Ordering;
-import org.alfresco.repo.search.impl.querymodel.QueryEngine;
-import org.alfresco.repo.search.impl.querymodel.QueryEngineResults;
-import org.alfresco.repo.search.impl.querymodel.QueryModelFactory;
-import org.alfresco.repo.search.impl.querymodel.QueryOptions;
-import org.alfresco.repo.search.impl.querymodel.QueryOptions.Connective;
-import org.alfresco.repo.search.impl.querymodel.impl.functions.PropertyAccessor;
-import org.alfresco.repo.search.impl.querymodel.impl.functions.Score;
-import org.alfresco.repo.search.impl.querymodel.impl.lucene.LuceneOrdering;
import org.alfresco.repo.search.results.SortedResultSet;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
-import org.alfresco.service.cmr.search.LimitBy;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
-import org.alfresco.service.cmr.search.SearchParameters.SortDefinition;
-import org.alfresco.service.cmr.search.SearchParameters.SortDefinition.SortType;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -111,17 +87,18 @@ public class LuceneAlfrescoLuceneQueryLanguage extends AbstractLuceneQueryLangua
Hits hits;
- boolean requiresPostSort = false;
+ boolean requiresDateTimePostSort = false;
+ SortField[] fields = new SortField[searchParameters.getSortDefinitions().size()];
+
if (searchParameters.getSortDefinitions().size() > 0)
{
int index = 0;
- SortField[] fields = new SortField[searchParameters.getSortDefinitions().size()];
for (SearchParameters.SortDefinition sd : searchParameters.getSortDefinitions())
{
switch (sd.getSortType())
{
case FIELD:
- Locale sortLocale = admLuceneSearcher.getLocale(searchParameters);
+ Locale sortLocale = searchParameters.getSortLocale();
String field = sd.getField();
if (field.startsWith("@"))
{
@@ -199,7 +176,7 @@ public class LuceneAlfrescoLuceneQueryLanguage extends AbstractLuceneQueryLangua
switch (propertyDef.getIndexTokenisationMode())
{
case TRUE:
- requiresPostSort = true;
+ requiresDateTimePostSort = true;
break;
case BOTH:
field = field + ".sort";
@@ -211,7 +188,7 @@ public class LuceneAlfrescoLuceneQueryLanguage extends AbstractLuceneQueryLangua
}
else
{
- requiresPostSort = true;
+ requiresDateTimePostSort = true;
}
}
}
@@ -230,30 +207,39 @@ public class LuceneAlfrescoLuceneQueryLanguage extends AbstractLuceneQueryLangua
fields[index++] = new SortField(null, SortField.DOC, !sd.isAscending());
break;
case SCORE:
- fields[index++] = new SortField(null, SortField.SCORE, !sd.isAscending());
+ // Score is naturally high to low -ie desc
+ fields[index++] = new SortField(null, SortField.SCORE, sd.isAscending());
break;
}
}
- hits = searcher.search(query, new Sort(fields));
+ }
+
+ hits = searcher.search(query);
+
+ boolean postSort = false;;
+ if(fields.length > 0)
+ {
+ postSort = searchParameters.usePostSort(hits.length(), admLuceneSearcher.getLuceneConfig().getUseInMemorySort(), admLuceneSearcher.getLuceneConfig().getMaxRawResultSetSizeForInMemorySort());
+ if(postSort == false)
+ {
+ hits = searcher.search(query, new Sort(fields));
+ }
+ }
+ ResultSet answer;
+ ResultSet result = new LuceneResultSet(hits, searcher, admLuceneSearcher.getNodeService(), admLuceneSearcher.getTenantService(), searchParameters, admLuceneSearcher.getLuceneConfig());
+ if(postSort || (admLuceneSearcher.getLuceneConfig().getPostSortDateTime() && requiresDateTimePostSort))
+ {
+ ResultSet sorted = new SortedResultSet(result, admLuceneSearcher.getNodeService(), searchParameters.getSortDefinitions(), admLuceneSearcher.getNamespacePrefixResolver(), admLuceneSearcher.getDictionaryService(), searchParameters.getSortLocale());
+ answer = sorted;
}
else
{
- hits = searcher.search(query);
- }
-
- ResultSet rs = new LuceneResultSet(hits, searcher, admLuceneSearcher.getNodeService(), admLuceneSearcher.getTenantService(), searchParameters, admLuceneSearcher.getLuceneConfig());
- rs = new PagingLuceneResultSet(rs, searchParameters, admLuceneSearcher.getNodeService());
- if (admLuceneSearcher.getLuceneConfig().getPostSortDateTime() && requiresPostSort)
- {
- ResultSet sorted = new SortedResultSet(rs, admLuceneSearcher.getNodeService(), searchParameters, admLuceneSearcher.getNamespacePrefixResolver());
- return sorted;
- }
- else
- {
- return rs;
+ answer = result;
}
+ ResultSet rs = new PagingLuceneResultSet(answer, searchParameters, admLuceneSearcher.getNodeService());
+ return rs;
}
catch (ParseException e)
{
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java
index 31ef9a3c27..9e835131fe 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java
@@ -278,6 +278,11 @@ public interface LuceneConfig
*/
long getMaxTransformationTime();
+ /**
+ * @return
+ */
+ public boolean getUseInMemorySort();
+
/**
* @param indexerBatchSize
*/
@@ -423,6 +428,11 @@ public interface LuceneConfig
*/
void setWriterMergeFactor(int writerMergeFactor);
+ /**
+ * @return
+ */
+ public int getMaxRawResultSetSizeForInMemorySort();
+
/**
* @param writerMaxBufferedDocs
*/
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java
index 9759c2ce0d..8652e6a099 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java
@@ -315,5 +315,21 @@ public class LuceneResultSet extends AbstractResultSet
{
return bulkFetchSize;
}
+
+ /**
+ * @param index
+ * @return
+ */
+ public int doc(int index)
+ {
+ try
+ {
+ return hits.id(index);
+ }
+ catch (IOException e)
+ {
+ throw new SearcherException(e);
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSetRow.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSetRow.java
index d0730d75d1..35e417b65f 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSetRow.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSetRow.java
@@ -152,4 +152,8 @@ public class LuceneResultSetRow extends AbstractResultSetRow
throw new UnsupportedOperationException();
}
+ public int doc()
+ {
+ return ((LuceneResultSet)getResultSet()).doc(getIndex());
+ }
}
diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java
index f027fc545d..8b0cd3a9a6 100644
--- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java
+++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java
@@ -37,6 +37,7 @@ import org.alfresco.repo.search.impl.querymodel.QueryEngine;
import org.alfresco.repo.search.impl.querymodel.QueryEngineResults;
import org.alfresco.repo.search.impl.querymodel.QueryModelFactory;
import org.alfresco.repo.search.impl.querymodel.QueryOptions;
+import org.alfresco.repo.search.results.SortedResultSet;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeService;
@@ -49,6 +50,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
/**
* @author andyh
@@ -64,6 +66,10 @@ public class LuceneQueryEngine implements QueryEngine
private TenantService tenantService;
private NamespaceService namespaceService;
+
+ private boolean useInMemorySort = true;
+
+ private int maxRawResultSetSizeForInMemorySort = 1000;
/**
* @param dictionaryService
@@ -114,6 +120,38 @@ public class LuceneQueryEngine implements QueryEngine
{
return new LuceneQueryModelFactory();
}
+
+ /**
+ * @return the useInMemorySort
+ */
+ public boolean isUseInMemorySort()
+ {
+ return useInMemorySort;
+ }
+
+ /**
+ * @param useInMemorySort the useInMemorySort to set
+ */
+ public void setUseInMemorySort(boolean useInMemorySort)
+ {
+ this.useInMemorySort = useInMemorySort;
+ }
+
+ /**
+ * @return the maxRawResultSetSizeForInMemorySort
+ */
+ public int getMaxRawResultSetSizeForInMemorySort()
+ {
+ return maxRawResultSetSizeForInMemorySort;
+ }
+
+ /**
+ * @param maxRawResultSetSizeForInMemorySort the maxRawResultSetSizeForInMemorySort to set
+ */
+ public void setMaxRawResultSetSizeForInMemorySort(int maxRawResultSetSizeForInMemorySort)
+ {
+ this.maxRawResultSetSizeForInMemorySort = maxRawResultSetSizeForInMemorySort;
+ }
public QueryEngineResults executeQuery(Query query, QueryOptions options, FunctionEvaluationContext functionContext)
{
@@ -159,6 +197,8 @@ public class LuceneQueryEngine implements QueryEngine
{
searchParameters.setLimitBy(LimitBy.UNLIMITED);
}
+ searchParameters.setUseInMemorySort(options.getUseInMemorySort());
+ searchParameters.setMaxRawResultSetSizeForInMemorySort(options.getMaxRawResultSetSizeForInMemorySort());
try
{
@@ -175,23 +215,43 @@ public class LuceneQueryEngine implements QueryEngine
LuceneQueryBuilder builder = (LuceneQueryBuilder) query;
org.apache.lucene.search.Query luceneQuery = builder.buildQuery(selectorGroup, luceneContext, functionContext);
- // System.out.println(luceneQuery);
Sort sort = builder.buildSort(selectorGroup, luceneContext, functionContext);
- Hits hits;
-
- if (sort == null)
+
+ Hits hits = searcher.search(luceneQuery);
+
+ boolean postSort = false;;
+ if(sort != null)
{
- hits = searcher.search(luceneQuery);
+ postSort = searchParameters.usePostSort(hits.length(), useInMemorySort, maxRawResultSetSizeForInMemorySort);
+ if(postSort == false)
+ {
+ hits = searcher.search(luceneQuery, sort);
+ }
+ }
+
+ ResultSet answer;
+ ResultSet result = new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters, indexAndSearcher);
+ if(postSort)
+ {
+ if(sort != null)
+ {
+ for(SortField sf : sort.getSort())
+ {
+ searchParameters.addSort(sf.getField(), !sf.getReverse());
+ }
+ }
+
+ ResultSet sorted = new SortedResultSet(result, nodeService, builder.buildSortDefinitions(selectorGroup, luceneContext, functionContext), namespaceService, dictionaryService, searchParameters.getSortLocale());
+ answer = sorted;
}
else
{
- hits = searcher.search(luceneQuery, sort);
+ answer = result;
}
-
- LuceneResultSet result = new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters, indexAndSearcher);
- ResultSet rs = new PagingLuceneResultSet(result, searchParameters, nodeService);
+ ResultSet rs = new PagingLuceneResultSet(answer, searchParameters, nodeService);
+
Map, ResultSet> map = new HashMap, ResultSet>(1);
map.put(selectorGroup, rs);
return new QueryEngineResults(map);
diff --git a/source/java/org/alfresco/repo/search/results/SortedResultSet.java b/source/java/org/alfresco/repo/search/results/SortedResultSet.java
index 880e3a819a..d5fa3aa6f5 100644
--- a/source/java/org/alfresco/repo/search/results/SortedResultSet.java
+++ b/source/java/org/alfresco/repo/search/results/SortedResultSet.java
@@ -19,17 +19,27 @@
package org.alfresco.repo.search.results;
import java.io.Serializable;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
+import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.search.SearcherException;
+import org.alfresco.repo.search.impl.lucene.LuceneResultSetRow;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetMetaData;
import org.alfresco.service.cmr.search.ResultSetRow;
@@ -42,39 +52,55 @@ import org.alfresco.util.Pair;
/**
* Sorted results
+ *
* @author andyh
- *
*/
public class SortedResultSet implements ResultSet
{
- ArrayList nodeRefsAndScores;
+ private ArrayList nodeRefsAndScores;
- NodeService nodeService;
+ private NodeService nodeService;
- SearchParameters searchParameters;
+ private ResultSet resultSet;
- ResultSet resultSet;
+ private DictionaryService dictionaryService;
+
+ private Locale locale;
+
+ private Collator collator;
+
+ public SortedResultSet(ResultSet resultSet, NodeService nodeService, SearchParameters searchParametersx, NamespacePrefixResolver namespacePrefixResolver,
+ DictionaryService dictionaryService, Locale locale)
+ {
+ this(resultSet, nodeService, searchParametersx.getSortDefinitions(), namespacePrefixResolver, dictionaryService, locale);
+ }
/**
* Source and resources required to sort
+ *
* @param resultSet
* @param nodeService
* @param searchParameters
* @param namespacePrefixResolver
*/
- public SortedResultSet(ResultSet resultSet, NodeService nodeService, SearchParameters searchParameters, NamespacePrefixResolver namespacePrefixResolver)
+ public SortedResultSet(ResultSet resultSet, NodeService nodeService, List sortDefinitions, NamespacePrefixResolver namespacePrefixResolver,
+ DictionaryService dictionaryService, Locale locale)
{
this.nodeService = nodeService;
- this.searchParameters = searchParameters;
this.resultSet = resultSet;
+ this.dictionaryService = dictionaryService;
+ this.locale = locale;
+
+ collator = Collator.getInstance(this.locale);
nodeRefsAndScores = new ArrayList(resultSet.length());
for (ResultSetRow row : resultSet)
{
- nodeRefsAndScores.add(new NodeRefAndScore(row.getNodeRef(), row.getScore()));
+ LuceneResultSetRow lrow = (LuceneResultSetRow) row;
+ nodeRefsAndScores.add(new NodeRefAndScore(row.getNodeRef(), row.getScore(), lrow.doc()));
}
- ArrayList order = new ArrayList();
- for (SortDefinition sd : searchParameters.getSortDefinitions())
+ ArrayList order = new ArrayList();
+ for (SortDefinition sd : sortDefinitions)
{
switch (sd.getSortType())
{
@@ -82,16 +108,62 @@ public class SortedResultSet implements ResultSet
String field = sd.getField();
if (field.startsWith("@"))
{
+ if (field.endsWith(".size"))
+ {
+ QName qname = expandAttributeFieldName(field.substring(0, field.length() - 5), namespacePrefixResolver);
+ if (qname != null)
+ {
+ PropertyDefinition propDef = dictionaryService.getProperty(qname);
+ if ((propDef != null) && propDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
+ {
+ order.add(new ContentSizeOrder(qname, sd.isAscending(), nodeService));
+ }
+
+ }
+ }
+ if (field.endsWith(".mimetype"))
+ {
+ QName qname = expandAttributeFieldName(field.substring(0, field.length() - 9), namespacePrefixResolver);
+ if (qname != null)
+ {
+ PropertyDefinition propDef = dictionaryService.getProperty(qname);
+ if ((propDef != null) && propDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
+ {
+ order.add(new ContentMimetypeOrder(qname, sd.isAscending(), nodeService, collator));
+ }
+
+ }
+ }
QName qname = expandAttributeFieldName(field, namespacePrefixResolver);
- order.add(new AttributeOrder(qname, sd.isAscending()));
+ if (qname != null)
+ {
+ order.add(new AttributeOrder(qname, sd.isAscending(), nodeService, this.dictionaryService, collator, locale));
+ }
+ }
+ else
+ {
+ if (field.equals("ID"))
+ {
+ order.add(new IdOrder(sd.isAscending(), collator));
+ }
+ else if (field.equals("EXACTTYPE"))
+ {
+ order.add(new TypeOrder(sd.isAscending(), nodeService, collator));
+ }
+ else if (field.equals("PARENT"))
+ {
+ order.add(new ParentIdOrder(sd.isAscending(), nodeService, collator));
+ }
+ else
+ {
+ // SKIP UNKNOWN throw new AlfrescoRuntimeException("Property is not orderable: "+field);
+ }
}
break;
case DOCUMENT:
- // ignore
- break;
+ order.add(new DocumentOrder(sd.isAscending()));
case SCORE:
- // ignore
- break;
+ order.add(new ScoreOrder(sd.isAscending()));
}
}
@@ -166,9 +238,9 @@ public class SortedResultSet implements ResultSet
return new SortedResultSetRowIterator(this);
}
- private void orderNodes(List answer, List order)
+ private void orderNodes(List answer, List order)
{
- Collections.sort(answer, new NodeRefAndScoreComparator(nodeService, order));
+ Collections.sort(answer, new NodeRefAndScoreComparator(order));
}
private QName expandAttributeFieldName(String field, NamespacePrefixResolver namespacePrefixResolver)
@@ -185,8 +257,16 @@ public class SortedResultSet implements ResultSet
}
else
{
+ String prefix = field.substring(1, colonPosition);
+
+ String uri = namespacePrefixResolver.getNamespaceURI(prefix);
+ if (uri == null)
+ {
+ return null;
+ }
+
// find the prefix
- qname = QName.createQName(field.substring(1, colonPosition), field.substring(colonPosition + 1), namespacePrefixResolver);
+ qname = QName.createQName(prefix, field.substring(colonPosition + 1), namespacePrefixResolver);
}
}
else
@@ -198,86 +278,576 @@ public class SortedResultSet implements ResultSet
static class NodeRefAndScoreComparator implements Comparator
{
- List order;
+ private List order;
- NodeService nodeService;
-
- NodeRefAndScoreComparator(NodeService nodeService, List order)
+ NodeRefAndScoreComparator(List order)
{
- this.nodeService = nodeService;
this.order = order;
}
- @SuppressWarnings("unchecked")
public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
{
// Treat missing nodes as null for comparison
- for (AttributeOrder attributeOrder : order)
+ for (OrderDefinition orderDefinition : order)
{
- Serializable o1;
- try
+ int answer = orderDefinition.compare(n1, n2);
+ if (answer != 0)
{
- o1 = nodeService.getProperty(n1.nodeRef, attributeOrder.attribute);
- }
- catch(InvalidNodeRefException inre)
- {
- o1 = null;
- }
- Serializable o2;
- try
- {
- o2 = nodeService.getProperty(n2.nodeRef, attributeOrder.attribute);
- }
- catch(InvalidNodeRefException inre)
- {
- o2 = null;
- }
-
- if (o1 == null)
- {
- if (o2 == null)
- {
- continue;
- }
- else
- {
- return attributeOrder.ascending ? -1 : 1;
- }
+ return answer;
}
else
{
- if (o2 == null)
- {
- return attributeOrder.ascending ? 1 : -1;
- }
- else
- {
- if ((o1 instanceof Comparable) && (o2 instanceof Comparable))
- {
- return (attributeOrder.ascending ? 1 : -1) * ((Comparable) o1).compareTo((Comparable) o2);
- }
- else
- {
- continue;
- }
- }
+ continue;
}
-
}
return 0;
}
}
- private static class AttributeOrder
+ private static interface OrderDefinition
+ {
+ int compare(NodeRefAndScore n1, NodeRefAndScore n2);
+ }
+
+ private static class AttributeOrder implements OrderDefinition
{
QName attribute;
boolean ascending;
- AttributeOrder(QName attribute, boolean ascending)
+ NodeService nodeService;
+
+ DictionaryService dictionaryService;
+
+ Collator collator;
+
+ Locale locale;
+
+ AttributeOrder(QName attribute, boolean ascending, NodeService nodeService, DictionaryService dictionaryService, Collator collator, Locale locale)
{
this.attribute = attribute;
this.ascending = ascending;
+ this.nodeService = nodeService;
+ this.dictionaryService = dictionaryService;
+ this.collator = collator;
+ this.locale = locale;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+
+ Serializable o1;
+ try
+ {
+ o1 = nodeService.getProperty(n1.nodeRef, attribute);
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o1 = null;
+ }
+ Serializable o2;
+ try
+ {
+ o2 = nodeService.getProperty(n2.nodeRef, attribute);
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o2 = null;
+ }
+
+ if (o1 == null)
+ {
+ if (o2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (o2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+ PropertyDefinition propertyDefinition = dictionaryService.getProperty(attribute);
+ if (propertyDefinition != null)
+ {
+ DataTypeDefinition dataType = propertyDefinition.getDataType();
+ if (dataType.getName().equals(DataTypeDefinition.TEXT))
+ {
+ String s1 = DefaultTypeConverter.INSTANCE.convert(String.class, o1);
+ String s2 = DefaultTypeConverter.INSTANCE.convert(String.class, o2);
+ int answer = (ascending ? 1 : -1) * collator.compare(s1, s2);
+ return answer;
+ }
+ else if (dataType.getName().equals(DataTypeDefinition.MLTEXT))
+ {
+ String s1 = DefaultTypeConverter.INSTANCE.convert(MLText.class, o1).getValue(locale);
+ String s2 = DefaultTypeConverter.INSTANCE.convert(MLText.class, o2).getValue(locale);
+
+ if (s1 == null)
+ {
+ if (s2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (s2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+ int answer = (ascending ? 1 : -1) * collator.compare(s1, s2);
+ return answer;
+ }
+ }
+ }
+ else
+ {
+ if ((o1 instanceof Comparable) && (o2 instanceof Comparable))
+ {
+ int answer = (ascending ? 1 : -1) * ((Comparable) o1).compareTo((Comparable) o2);
+ return answer;
+
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ if ((o1 instanceof Comparable) && (o2 instanceof Comparable))
+ {
+ int answer = (ascending ? 1 : -1) * ((Comparable) o1).compareTo((Comparable) o2);
+ return answer;
+
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ private static class ContentSizeOrder implements OrderDefinition
+ {
+ QName attribute;
+
+ boolean ascending;
+
+ NodeService nodeService;
+
+ ContentSizeOrder(QName attribute, boolean ascending, NodeService nodeService)
+ {
+ this.attribute = attribute;
+ this.ascending = ascending;
+ this.nodeService = nodeService;
+
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+
+ Serializable o1;
+ try
+ {
+ o1 = nodeService.getProperty(n1.nodeRef, attribute);
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o1 = null;
+ }
+ Serializable o2;
+ try
+ {
+ o2 = nodeService.getProperty(n2.nodeRef, attribute);
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o2 = null;
+ }
+
+ if (o1 == null)
+ {
+ if (o2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (o2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+
+ ContentData cd1 = DefaultTypeConverter.INSTANCE.convert(ContentData.class, o1);
+ ContentData cd2 = DefaultTypeConverter.INSTANCE.convert(ContentData.class, o2);
+
+ if (cd1 == null)
+ {
+ if (cd2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (cd2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+ return (ascending ? 1 : -1) * (int)(cd1.getSize() - cd2.getSize());
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ private static class ContentMimetypeOrder implements OrderDefinition
+ {
+ QName attribute;
+
+ boolean ascending;
+
+ NodeService nodeService;
+
+ Collator collator;
+
+ ContentMimetypeOrder(QName attribute, boolean ascending, NodeService nodeService, Collator collator)
+ {
+ this.attribute = attribute;
+ this.ascending = ascending;
+ this.nodeService = nodeService;
+ this.collator = collator;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+
+ Serializable o1;
+ try
+ {
+ o1 = nodeService.getProperty(n1.nodeRef, attribute);
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o1 = null;
+ }
+ Serializable o2;
+ try
+ {
+ o2 = nodeService.getProperty(n2.nodeRef, attribute);
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o2 = null;
+ }
+
+ if (o1 == null)
+ {
+ if (o2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (o2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+
+ ContentData cd1 = DefaultTypeConverter.INSTANCE.convert(ContentData.class, o1);
+ ContentData cd2 = DefaultTypeConverter.INSTANCE.convert(ContentData.class, o2);
+
+ if (cd1 == null)
+ {
+ if (cd2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (cd2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+ return (ascending ? 1 : -1) * collator.compare(cd1.getMimetype(), cd2.getMimetype());
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ private static class IdOrder implements OrderDefinition
+ {
+ boolean ascending;
+
+ Collator collator;
+
+ IdOrder(boolean ascending, Collator collator)
+ {
+ this.ascending = ascending;
+ this.collator = collator;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+
+ String o1 = n1.nodeRef.toString();
+ String o2 = n2.nodeRef.toString();
+
+ if (o1 == null)
+ {
+ if (o2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (o2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+
+ int answer = (ascending ? 1 : -1) * collator.compare(o1, o2);
+ return answer;
+ }
+ }
+ }
+ }
+
+ private static class ScoreOrder implements OrderDefinition
+ {
+ boolean ascending;
+
+ ScoreOrder(boolean ascending)
+ {
+ this.ascending = ascending;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+ return (ascending ? 1 : -1) * Float.compare(n1.score, n2.score);
+
+ }
+ }
+
+ private static class DocumentOrder implements OrderDefinition
+ {
+ boolean ascending;
+
+ DocumentOrder(boolean ascending)
+ {
+ this.ascending = ascending;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+ return (ascending ? 1 : -1) * Float.compare(n1.doc, n2.doc);
+
+ }
+ }
+
+ private static class TypeOrder implements OrderDefinition
+ {
+ boolean ascending;
+
+ NodeService nodeService;
+
+ Collator collator;
+
+ TypeOrder(boolean ascending, NodeService nodeService, Collator collator)
+ {
+ this.ascending = ascending;
+ this.nodeService = nodeService;
+ this.collator = collator;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+
+ String o1;
+ try
+ {
+ o1 = nodeService.getType(n1.nodeRef).toString();
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o1 = null;
+ }
+ String o2;
+ try
+ {
+ o2 = nodeService.getType(n2.nodeRef).toString();
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o2 = null;
+ }
+
+ if (o1 == null)
+ {
+ if (o2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (o2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+
+ int answer = (ascending ? 1 : -1) * collator.compare(o1, o2);
+ return answer;
+ }
+ }
+
+ }
+ }
+
+ private static class ParentIdOrder implements OrderDefinition
+ {
+ boolean ascending;
+
+ NodeService nodeService;
+
+ Collator collator;
+
+ ParentIdOrder(boolean ascending, NodeService nodeService, Collator collator)
+ {
+ this.ascending = ascending;
+ this.nodeService = nodeService;
+ this.collator = collator;
+ }
+
+ public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
+ {
+ // Treat missing nodes as null for comparison
+
+ String o1 = null;
+ ;
+ try
+ {
+ ChildAssociationRef ca1 = nodeService.getPrimaryParent(n1.nodeRef);
+ if ((ca1 != null) && (ca1.getParentRef() != null))
+ {
+ o1 = ca1.getParentRef().toString();
+ }
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o1 = null;
+ }
+ String o2 = null;
+ try
+ {
+ ChildAssociationRef ca2 = nodeService.getPrimaryParent(n2.nodeRef);
+ if ((ca2 != null) && (ca2.getParentRef() != null))
+ {
+ o2 = ca2.getParentRef().toString();
+ }
+ }
+ catch (InvalidNodeRefException inre)
+ {
+ o2 = null;
+ }
+
+ if (o1 == null)
+ {
+ if (o2 == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return ascending ? -1 : 1;
+ }
+ }
+ else
+ {
+ if (o2 == null)
+ {
+ return ascending ? 1 : -1;
+ }
+ else
+ {
+
+ int answer = (ascending ? 1 : -1) * collator.compare(o1, o2);
+ return answer;
+ }
+ }
+
}
}
@@ -287,10 +857,13 @@ public class SortedResultSet implements ResultSet
float score;
- NodeRefAndScore(NodeRef nodeRef, float score)
+ int doc;
+
+ NodeRefAndScore(NodeRef nodeRef, float score, int doc)
{
this.nodeRef = nodeRef;
this.score = score;
+ this.doc = doc;
}
}
@@ -304,7 +877,7 @@ public class SortedResultSet implements ResultSet
{
throw new UnsupportedOperationException();
}
-
+
/**
* Bulk fetch results in the cache
*
@@ -312,7 +885,7 @@ public class SortedResultSet implements ResultSet
*/
public boolean setBulkFetch(boolean bulkFetch)
{
- return resultSet.setBulkFetch(bulkFetch);
+ return resultSet.setBulkFetch(bulkFetch);
}
/**
@@ -332,7 +905,7 @@ public class SortedResultSet implements ResultSet
*/
public int setBulkFetchSize(int bulkFetchSize)
{
- return resultSet.setBulkFetchSize(bulkFetchSize);
+ return resultSet.setBulkFetchSize(bulkFetchSize);
}
/**
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
index dff690f4f4..08c246f524 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
@@ -962,8 +962,16 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
}
else
{
- List cars = nodeService.getChildAssocs(nodeRef, RegexQNamePattern.MATCH_ALL,
- RegexQNamePattern.MATCH_ALL, false);
+ List cars = childAuthorityCache.get(nodeRef);
+ if (cars == null)
+ {
+ cars = nodeService.getChildAssocs(nodeRef, RegexQNamePattern.MATCH_ALL,
+ RegexQNamePattern.MATCH_ALL, false);
+ if (!cars.isEmpty() && cars.get(0).getTypeQName().equals(ContentModel.ASSOC_MEMBER))
+ {
+ childAuthorityCache.put(nodeRef, cars);
+ }
+ }
// Take advantage of the fact that the authority name is on the child association
for (ChildAssociationRef car : cars)
diff --git a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
index ba519e4bab..3c72676ce7 100644
--- a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
+++ b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
@@ -658,6 +658,10 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe
// Freeze the details of the aspect
dbNodeService.addAspect(versionNodeRef, aspect, nodeDetails.getProperties(aspect));
}
+
+ // ALF-9638: Freeze the aspect specific associations
+ freezeChildAssociations(versionNodeRef, nodeDetails.getChildAssociations(aspect));
+ freezeAssociations(versionNodeRef, nodeDetails.getAssociations(aspect));
}
}
diff --git a/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java b/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java
index 3a970ae7b0..b1dd512e28 100644
--- a/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java
+++ b/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java
@@ -237,8 +237,7 @@ public class WorkflowInterpreter extends BaseInterpreter
* @return The textual output of the command.
*/
@Override
- protected String executeCommand(String line)
- throws IOException
+ protected String executeCommand(String line) throws IOException
{
String[] command = line.split(" ");
if (command.length == 0)
@@ -956,7 +955,7 @@ public class WorkflowInterpreter extends BaseInterpreter
{
return "Syntax Error.\n";
}
- WorkflowPath path = workflowService.signal(command[1], (command.length == 3) ? command[2] : null);
+ WorkflowPath path = workflowService.signal(command[1], getTransition(command));
out.println("signal sent - path id: " + path.getId());
out.print(interpretCommand("show transitions"));
}
@@ -1260,6 +1259,23 @@ public class WorkflowInterpreter extends BaseInterpreter
out.close();
return retVal;
}
+
+ private String getTransition(String[] command)
+ {
+ int length = command.length;
+ if(length <3)
+ {
+ return null;
+ }
+ // Transition name may contain spaces
+ StringBuilder builder = new StringBuilder(command[2]);
+ int i = 3;
+ while(i cmrPooledTasks = this.services.getWorkflowService().getPooledTasks(
- authority);
- ArrayList pooledTasks = new ArrayList();
- for (WorkflowTask cmrPooledTask : cmrPooledTasks)
- {
- pooledTasks.add(new JscriptWorkflowTask(cmrPooledTask, this.services, this.getScope()));
- }
-
- Scriptable pooledTasksScriptable = (Scriptable)new ValueConverter().convertValueForScript(
- this.services, getScope(), null, pooledTasks);
- return pooledTasksScriptable;
- }
-
- /**
- * Get task by id
- *
- * @param id task id
- * @return the task (null if not found)
- */
- public JscriptWorkflowTask getTask(String id)
- {
- WorkflowTask cmrWorkflowTask = this.services.getWorkflowService().getTaskById(id);
- return new JscriptWorkflowTask(cmrWorkflowTask, this.services, this.getScope());
- }
-
- /**
- * Get task by id. Alternative method signature to getTask(String id)
for
- * those used to the Template API
- *
- * @param id task id
- * @return the task (null if not found)
- */
- public JscriptWorkflowTask getTaskById(String id)
- {
- return getTask(id);
- }
-
- /**
- * Gets the latest versions of the deployed, workflow definitions
- *
- * @return the latest versions of the deployed workflow definitions
- */
- public Scriptable getLatestDefinitions()
- {
- List cmrDefinitions = this.services.getWorkflowService().getDefinitions();
- ArrayList workflowDefs = new ArrayList();
- for (WorkflowDefinition cmrDefinition : cmrDefinitions)
- {
- workflowDefs.add(new JscriptWorkflowDefinition(cmrDefinition, this.services, getScope()));
- }
-
- Scriptable workflowDefsScriptable = (Scriptable)new ValueConverter().convertValueForScript(
- this.services, this.getScope(), null, workflowDefs);
- return workflowDefsScriptable;
- }
+ */
+ public Scriptable getPooledTasks(final String authority)
+ {
+ List cmrPooledTasks = services.getWorkflowService().getPooledTasks(authority);
+ ArrayList pooledTasks = new ArrayList();
+ for (WorkflowTask cmrPooledTask : cmrPooledTasks)
+ {
+ pooledTasks.add(new JscriptWorkflowTask(cmrPooledTask, services, getScope()));
+ }
+ ValueConverter converter = new ValueConverter();
+ return (Scriptable)converter.convertValueForScript(services, getScope(), null, pooledTasks);
+ }
+
+ /**
+ * Get task by id
+ *
+ * @param id task id
+ * @return the task (null if not found)
+ */
+ public JscriptWorkflowTask getTask(String id)
+ {
+ WorkflowTask task = services.getWorkflowService().getTaskById(id);
+ return task == null ? null : new JscriptWorkflowTask(task, services, this.getScope());
+ }
+
+ /**
+ * Get task by id. Alternative method signature to getTask(String id)
for
+ * those used to the Template API
+ *
+ * @param id task id
+ * @return the task (null if not found)
+ */
+ public JscriptWorkflowTask getTaskById(String id)
+ {
+ return getTask(id);
+ }
+
+ /**
+ * Gets the latest versions of the deployed, workflow definitions
+ *
+ * @return the latest versions of the deployed workflow definitions
+ */
+ public Scriptable getLatestDefinitions()
+ {
+ List cmrDefinitions = services.getWorkflowService().getDefinitions();
+ ArrayList workflowDefs = new ArrayList();
+ for (WorkflowDefinition cmrDefinition : cmrDefinitions)
+ {
+ workflowDefs.add(new JscriptWorkflowDefinition(cmrDefinition, services, getScope()));
+ }
+
+ return (Scriptable)new ValueConverter().convertValueForScript(services, getScope(), null, workflowDefs);
+ }
- /**
- * Gets all versions of the deployed workflow definitions
- *
- * @return all versions of the deployed workflow definitions
- */
- public Scriptable getAllDefinitions()
- {
- List cmrDefinitions = this.services.getWorkflowService().getAllDefinitions();
- ArrayList workflowDefs = new ArrayList();
- for (WorkflowDefinition cmrDefinition : cmrDefinitions)
- {
- workflowDefs.add(new JscriptWorkflowDefinition(cmrDefinition, this.services, getScope()));
- }
-
- Scriptable workflowDefsScriptable = (Scriptable)new ValueConverter().convertValueForScript(
- this.services, this.getScope(), null, workflowDefs);
- return workflowDefsScriptable;
- }
-
- /**
- * Create a workflow package (a container of content to route through a workflow)
- *
- * @return the created workflow package
- */
- public ScriptNode createPackage()
- {
- NodeRef node = this.services.getWorkflowService().createPackage(null);
- return new ScriptNode(node, services);
- }
+ /**
+ * Gets all versions of the deployed workflow definitions
+ *
+ * @return all versions of the deployed workflow definitions
+ */
+ public Scriptable getAllDefinitions()
+ {
+ List cmrDefinitions = services.getWorkflowService().getAllDefinitions();
+ ArrayList workflowDefs = new ArrayList();
+ for (WorkflowDefinition cmrDefinition : cmrDefinitions)
+ {
+ workflowDefs.add(new JscriptWorkflowDefinition(cmrDefinition, services, getScope()));
+ }
+ return (Scriptable)new ValueConverter().convertValueForScript(services, getScope(), null, workflowDefs);
+ }
+
+ /**
+ * Create a workflow package (a container of content to route through a workflow)
+ *
+ * @return the created workflow package
+ */
+ public ScriptNode createPackage()
+ {
+ NodeRef node = services.getWorkflowService().createPackage(null);
+ return new ScriptNode(node, services);
+ }
- /**
- * Get tasks assigned to the current user, filtered by workflow task state.
- * Only tasks having the specified state will be returned.
- *
+ /**
+ * Get tasks assigned to the current user, filtered by workflow task state.
+ * Only tasks having the specified state will be returned.
+ *
* @param state workflow task state to filter assigned tasks by
* @return the list of assigned tasks, filtered by state
- */
- private Scriptable getAssignedTasksByState(WorkflowTaskState state)
- {
- List cmrAssignedTasks = this.services.getWorkflowService().getAssignedTasks(
- services.getAuthenticationService().getCurrentUserName(), state);
- ArrayList assignedTasks = new ArrayList();
- for (WorkflowTask cmrTask : cmrAssignedTasks)
- {
- assignedTasks.add(new JscriptWorkflowTask(cmrTask, this.services, this.getScope()));
- }
-
- Scriptable assignedTasksScriptable =
- (Scriptable)new ValueConverter().convertValueForScript(this.services, getScope(), null, assignedTasks);
-
- return assignedTasksScriptable;
- }
+ */
+ private Scriptable getAssignedTasksByState(WorkflowTaskState state)
+ {
+ WorkflowService workflowService = services.getWorkflowService();
+ String currentUser = services.getAuthenticationService().getCurrentUserName();
+ List cmrAssignedTasks = workflowService.getAssignedTasks(currentUser, state);
+ ArrayList assignedTasks = new ArrayList();
+ for (WorkflowTask cmrTask : cmrAssignedTasks)
+ {
+ assignedTasks.add(new JscriptWorkflowTask(cmrTask, services, getScope()));
+ }
+ return (Scriptable)new ValueConverter().convertValueForScript(services, getScope(), null, assignedTasks);
+ }
}