diff --git a/config/alfresco/model/solrFacetModel.xml b/config/alfresco/model/solrFacetModel.xml
index 17d8bea4b9..35da06a990 100644
--- a/config/alfresco/model/solrFacetModel.xml
+++ b/config/alfresco/model/solrFacetModel.xml
@@ -119,16 +119,6 @@
false
-
- Index
- d:int
- true
-
- false
- false
- false
-
-
Is enabled
d:boolean
diff --git a/config/alfresco/subsystems/Search/solr/facet/solr-facets-config.properties b/config/alfresco/subsystems/Search/solr/facet/solr-facets-config.properties
index 050a1dcd5e..fabed8fbb6 100644
--- a/config/alfresco/subsystems/Search/solr/facet/solr-facets-config.properties
+++ b/config/alfresco/subsystems/Search/solr/facet/solr-facets-config.properties
@@ -1,6 +1,6 @@
#
# Alfresco default facets
-# Note: If you have changed the filter’s default value(s) via Share, then any subsequent changes of the default values won’t be applied to the filter on server startup.
+# Note: If you have changed the filter's™ default value(s) via Share, then any subsequent changes of those default values won't be applied to the filter on server startup.
#
# Field-Facet-Qname => cm:content.mimetype
@@ -11,9 +11,8 @@ default.cm\:content.mimetype.maxFilters=5
default.cm\:content.mimetype.hitThreshold=1
default.cm\:content.mimetype.minFilterValueLength=4
default.cm\:content.mimetype.sortBy=DESCENDING
-default.cm\:content.mimetype.scope=SCOPED_SITES
+default.cm\:content.mimetype.scope=ALL
default.cm\:content.mimetype.scopedSites=
-default.cm\:content.mimetype.index=0
default.cm\:content.mimetype.isEnabled=true
# Field-Facet-Qname => cm:description.__
@@ -24,10 +23,9 @@ default.cm\:description.__.maxFilters=5
default.cm\:description.__.hitThreshold=1
default.cm\:description.__.minFilterValueLength=4
default.cm\:description.__.sortBy=DESCENDING
-default.cm\:description.__.scope=SCOPED_SITES
+default.cm\:description.__.scope=ALL
default.cm\:description.__.scopedSites=
-default.cm\:description.__.index=1
-default.cm\:description.__.isEnabled=true
+default.cm\:description.__.isEnabled=false
# Field-Facet-Qname => cm:creator.__.u
default.cm\:creator.__.u.filterID=filter_creator
@@ -37,9 +35,8 @@ default.cm\:creator.__.u.maxFilters=5
default.cm\:creator.__.u.hitThreshold=1
default.cm\:creator.__.u.minFilterValueLength=4
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
-default.cm\:creator.__.u.scope=SCOPED_SITES
+default.cm\:creator.__.u.scope=ALL
default.cm\:creator.__.u.scopedSites=
-default.cm\:creator.__.u.index=2
default.cm\:creator.__.u.isEnabled=true
# Field-Facet-Qname => cm:modifier.__.u
@@ -50,9 +47,8 @@ default.cm\:modifier.__.u.maxFilters=5
default.cm\:modifier.__.u.hitThreshold=1
default.cm\:modifier.__.u.minFilterValueLength=4
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
-default.cm\:modifier.__.u.scope=SCOPED_SITES
+default.cm\:modifier.__.u.scope=ALL
default.cm\:modifier.__.u.scopedSites=
-default.cm\:modifier.__.u.index=3
default.cm\:modifier.__.u.isEnabled=true
# Field-Facet-Qname => cm:created
@@ -63,9 +59,8 @@ default.cm\:created.maxFilters=5
default.cm\:created.hitThreshold=1
default.cm\:created.minFilterValueLength=4
default.cm\:created.sortBy=ALPHABETICALLY
-default.cm\:created.scope=SCOPED_SITES
+default.cm\:created.scope=ALL
default.cm\:created.scopedSites=
-default.cm\:created.index=4
default.cm\:created.isEnabled=true
default.cm\:created.EXTRA-PROP.blockIncludeFacetRequest=true
@@ -77,9 +72,8 @@ default.cm\:modified.maxFilters=5
default.cm\:modified.hitThreshold=1
default.cm\:modified.minFilterValueLength=4
default.cm\:modified.sortBy=ALPHABETICALLY
-default.cm\:modified.scope=SCOPED_SITES
+default.cm\:modified.scope=ALL
default.cm\:modified.scopedSites=
-default.cm\:modified.index=5
default.cm\:modified.isEnabled=true
default.cm\:modified.EXTRA-PROP.blockIncludeFacetRequest=true
@@ -91,8 +85,7 @@ default.cm\:content.size.maxFilters=5
default.cm\:content.size.hitThreshold=1
default.cm\:content.size.minFilterValueLength=4
default.cm\:content.size.sortBy=ALPHABETICALLY
-default.cm\:content.size.scope=SCOPED_SITES
+default.cm\:content.size.scope=ALL
default.cm\:content.size.scopedSites=
-default.cm\:content.size.index=6
default.cm\:content.size.isEnabled=true
default.cm\:content.size.EXTRA-PROP.blockIncludeFacetRequest=true
diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparator.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparator.java
index 55f12337cd..5592bfb256 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparator.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparator.java
@@ -38,6 +38,11 @@ public class SolrFacetComparator implements Comparator
@Override public int compare(SolrFacetProperties facet1, SolrFacetProperties facet2)
{
+ if (sortedIDs.isEmpty())
+ {
+ return facet1.getFilterID().compareTo(facet2.getFilterID());
+ }
+
Pair facetIndicesInSortedList = find(facet1, facet2);
if (bothSorted(facetIndicesInSortedList))
@@ -47,19 +52,7 @@ public class SolrFacetComparator implements Comparator
}
else if (neitherSorted(facetIndicesInSortedList))
{
- // Sorting is by the index value defined in the facet itself.
- final int indexDifference = facet1.getIndex() - facet2.getIndex();
-
- if (indexDifference == 0)
- {
- // This could happen if an end user defines/overrides indexes to be equal.
- // We'll sort based on facet ID if it does happen.
- return facet1.getFilterID().compareTo(facet2.getFilterID());
- }
- else
- {
- return indexDifference;
- }
+ return facet1.getFilterID().compareTo(facet2.getFilterID());
}
else
{
diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfig.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfig.java
index 73ad83c73c..1e196c2911 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfig.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfig.java
@@ -39,6 +39,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
+import org.springframework.extensions.surf.util.ParameterCheck;
/**
* This class picks up all the loaded properties passed to it and uses a naming
@@ -58,7 +59,6 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
* custom.cm\:content.mimetype.sortBy=DESCENDING
* custom.cm\:content.mimetype.scope=SCOPED_SITES
* custom.cm\:content.mimetype.scopedSites=site1,site2,site3
- * custom.cm\:content.mimetype.index=0
* custom.cm\:content.mimetype.isEnabled=true
*
* Also, if there is a need to add additional properties, the following needs to be
@@ -91,8 +91,8 @@ public class SolrFacetConfig extends AbstractLifecycleBean
public SolrFacetConfig(Properties rawProperties, String inheritanceOrder)
{
- PropertyCheck.mandatory(this, "rawProperties", rawProperties);
- PropertyCheck.mandatory(this, "inheritanceOrder", inheritanceOrder);
+ ParameterCheck.mandatory("rawProperties", rawProperties);
+ ParameterCheck.mandatory("inheritanceOrder", inheritanceOrder);
this.rawProperties = rawProperties;
@@ -223,12 +223,7 @@ public class SolrFacetConfig extends AbstractLifecycleBean
String sortBy = propValues.get(ValueName.PROP_SORTBY.getPropValueName(field));
String scope = propValues.get(ValueName.PROP_SCOPE.getPropValueName(field));
Set scopedSites = getScopedSites(propValues.get(ValueName.PROP_SCOPED_SITES.getPropValueName(field)));
- int index = getIntegerValue(propValues.get(ValueName.PROP_INDEX.getPropValueName(field)));
- if(index < 0)
- {
- throw new SolrFacetConfigException("Index must be greater than or equal to 0");
- }
- boolean isEnabled = Boolean.valueOf(propValues.get(ValueName.PROP_IS_ENABLED.getPropValueName(field)));
+ Boolean isEnabled = Boolean.valueOf(propValues.get(ValueName.PROP_IS_ENABLED.getPropValueName(field)));
Set customProps = getCustomProps(facetFields.get(field), field, propValues);
// Construct the FacetProperty object
@@ -242,14 +237,13 @@ public class SolrFacetConfig extends AbstractLifecycleBean
.minFilterValueLength(minFilterValueLength)
.sortBy(sortBy)
.scope(scope)
- .index(index)
.isEnabled(isEnabled)
.isDefault(true)
.scopedSites(scopedSites)
.customProperties(customProps).build();
facetProperties.put(filterID, fp);
- }
+ }
// Done
return facetProperties;
@@ -273,7 +267,7 @@ public class SolrFacetConfig extends AbstractLifecycleBean
private static void getPropertyAndPropOderControl(Properties properties, Set propNames, Set propOrderControl)
{
-
+
for (Object propKeyObj : properties.keySet())
{
String propKey = (String) propKeyObj;
@@ -327,14 +321,14 @@ public class SolrFacetConfig extends AbstractLifecycleBean
}
return set;
}
-
+
private static Set getCustomProps(Set additionalProps, String field, Map propValues)
{
if (additionalProps == null)
{
return Collections.emptySet();
}
-
+
Set customProps = new HashSet<>();
for (String extraInfo : additionalProps)
{
@@ -385,7 +379,7 @@ public class SolrFacetConfig extends AbstractLifecycleBean
{
PROP_FILTER_ID("filterID"), PROP_DISPLAY_NAME("displayName"), PROP_MAX_FILTERS("maxFilters"), PROP_HIT_THRESHOLD("hitThreshold"),
PROP_MIN_FILTER_VALUE_LENGTH("minFilterValueLength"), PROP_SORTBY("sortBy"), PROP_SCOPE("scope"), PROP_SCOPED_SITES("scopedSites"),
- PROP_INDEX("index"), PROP_IS_ENABLED("isEnabled"), PROP_DISPLAY_CONTROL("displayControl");
+ PROP_IS_ENABLED("isEnabled"), PROP_DISPLAY_CONTROL("displayControl");
private ValueName(String propValueName)
{
diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetModel.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetModel.java
index 68645ecf31..8248ad1694 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetModel.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetModel.java
@@ -56,16 +56,14 @@ public interface SolrFacetModel
public static final QName PROP_SCOPED_SITES = QName.createQName(SOLR_FACET_MODEL_URL, "scopedSites");
- public static final QName PROP_INDEX = QName.createQName(SOLR_FACET_MODEL_URL, "index");
-
public static final QName PROP_IS_ENABLED = QName.createQName(SOLR_FACET_MODEL_URL, "isEnabled");
public static final QName PROP_IS_DEFAULT = QName.createQName(SOLR_FACET_MODEL_URL, "isDefault");
public static final QName PROP_EXTRA_INFORMATION = QName.createQName(SOLR_FACET_CUSTOM_PROPERTY_URL, "extraInformation");
-
+
/** The type of the facet container folder. */
public static final QName TYPE_FACETS = QName.createQName(SOLR_FACET_MODEL_URL, "facets");
-
+
public static final QName PROP_FACET_ORDER = QName.createQName(SOLR_FACET_MODEL_URL, "facetOrder");
}
diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetProperties.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetProperties.java
index 49938973c6..ffadae08b7 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetProperties.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetProperties.java
@@ -46,8 +46,7 @@ public class SolrFacetProperties implements Serializable
private final String sortBy;
private final String scope;
private final Set scopedSites;
- private final int index;
- private final boolean isEnabled;
+ private final Boolean isEnabled;
private final boolean isDefault; // is loaded from properties files?
private final Set customProperties;
@@ -67,7 +66,6 @@ public class SolrFacetProperties implements Serializable
this.minFilterValueLength = builder.minFilterValueLength;
this.sortBy = builder.sortBy;
this.scope = builder.scope;
- this.index = builder.index;
this.isEnabled = builder.isEnabled;
this.isDefault = builder.isDefault;
this.scopedSites = Collections.unmodifiableSet(new HashSet(builder.scopedSites));
@@ -157,17 +155,9 @@ public class SolrFacetProperties implements Serializable
}
/**
- * @return the index
+ * @return null if the value is not set
*/
- public int getIndex()
- {
- return this.index;
- }
-
- /**
- * @return the isEnabled
- */
- public boolean isEnabled()
+ public Boolean isEnabled()
{
return this.isEnabled;
}
@@ -191,7 +181,6 @@ public class SolrFacetProperties implements Serializable
{
return Collections.unmodifiableSet(new HashSet(this.customProperties));
}
-
/*
* @see java.lang.Object#hashCode()
@@ -251,7 +240,7 @@ public class SolrFacetProperties implements Serializable
.append(this.maxFilters).append(", hitThreshold=").append(this.hitThreshold)
.append(", minFilterValueLength=").append(this.minFilterValueLength).append(", sortBy=")
.append(this.sortBy).append(", scope=").append(this.scope).append(", scopedSites=")
- .append(this.scopedSites).append(", index=").append(this.index).append(", isEnabled=").append(this.isEnabled)
+ .append(this.scopedSites).append(", isEnabled=").append(this.isEnabled)
.append(", isDefault=").append(this.isDefault).append(", customProperties=").append(this.customProperties)
.append("]");
return sb.toString();
@@ -263,14 +252,13 @@ public class SolrFacetProperties implements Serializable
private QName facetQName;
private String displayName;
private String displayControl;
- private int maxFilters;
- private int hitThreshold;
- private int minFilterValueLength;
+ private int maxFilters = -1;
+ private int hitThreshold = -1;;
+ private int minFilterValueLength = -1;
private String sortBy;
private String scope;
private Set scopedSites = Collections.emptySet();
- private int index;
- private boolean isEnabled;
+ private Boolean isEnabled;
private boolean isDefault;
private Set customProperties = Collections.emptySet();
@@ -295,7 +283,6 @@ public class SolrFacetProperties implements Serializable
this.sortBy = that.sortBy;
this.scope = that.scope;
this.scopedSites = that.scopedSites;
- this.index = that.index;
this.isEnabled = that.isEnabled;
this.isDefault = that.isDefault;
this.customProperties = that.customProperties;
@@ -364,13 +351,7 @@ public class SolrFacetProperties implements Serializable
return this;
}
- public Builder index(int index)
- {
- this.index = index;
- return this;
- }
-
- public Builder isEnabled(boolean isEnabled)
+ public Builder isEnabled(Boolean isEnabled)
{
this.isEnabled = isEnabled;
return this;
@@ -396,7 +377,7 @@ public class SolrFacetProperties implements Serializable
return new SolrFacetProperties(this);
}
}
-
+
public static class CustomProperties implements Serializable
{
private static final long serialVersionUID = 2250062300454166258L;
diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java
index f4a90f179e..2d61b5980e 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java
@@ -20,17 +20,13 @@
package org.alfresco.repo.search.impl.solr.facet;
import java.util.List;
-
-import org.alfresco.repo.search.impl.solr.facet.Exceptions.DuplicateFacetId;
-import org.alfresco.repo.search.impl.solr.facet.Exceptions.IllegalArgument;
-import org.alfresco.repo.search.impl.solr.facet.Exceptions.MissingFacetId;
-import org.alfresco.repo.search.impl.solr.facet.Exceptions.UnrecognisedFacetId;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Solr Facet service configuration API.
*
* @author Jamal Kaabi-Mofrad
+ * @since 5.0
*/
public interface SolrFacetService
{
@@ -41,7 +37,7 @@ public interface SolrFacetService
* @return List of {@code SolrFacetProperties} or an empty list if none exists
*/
public List getFacets();
-
+
/**
* Gets the facet by filter Id.
*
@@ -90,8 +86,6 @@ public interface SolrFacetService
*/
public void deleteFacet(String filterID);
- public int getNextIndex();
-
/**
* Reorders existing facets to the provided order.
*
diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java
index fc15732eac..0d0ae756c4 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java
@@ -21,27 +21,26 @@ package org.alfresco.repo.search.impl.solr.facet;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.NavigableMap;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
-import org.alfresco.repo.node.NodeServicePolicies.BeforeUpdateNodePolicy;
import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy;
-import org.alfresco.repo.node.NodeServicePolicies.OnUpdateNodePolicy;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -71,13 +70,14 @@ import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
/**
+ * Solr Facet Service Implementation.
+ *
* @author Jamal Kaabi-Mofrad
+ * @since 5.0
*/
public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrFacetService,
NodeServicePolicies.OnCreateNodePolicy,
- NodeServicePolicies.OnUpdateNodePolicy,
- NodeServicePolicies.BeforeDeleteNodePolicy,
- NodeServicePolicies.BeforeUpdateNodePolicy
+ NodeServicePolicies.BeforeDeleteNodePolicy
{
private static final Log logger = LogFactory.getLog(SolrFacetServiceImpl.class);
/**
@@ -102,8 +102,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
private SimpleCache singletonCache; // eg. for facetsHomeNodeRef
private final String KEY_FACETS_HOME_NODEREF = "key.facetshome.noderef";
private SimpleCache facetNodeRefCache; // for filterID to nodeRef lookup
- private NavigableMap facetsMap = new ConcurrentSkipListMap<>(); // TODO
- private int maxAllowedFilters = 100;
+ private ConcurrentMap defaultFacetsMap = new ConcurrentHashMap(10);
/**
* @param authorityService the authorityService to set
@@ -193,14 +192,6 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
this.facetNodeRefCache = facetNodeRefCache;
}
- /**
- * @param maxAllowedFilters the maxAllowedFilters to set
- */
- public void setMaxAllowedFilters(int maxAllowedFilters)
- {
- this.maxAllowedFilters = maxAllowedFilters;
- }
-
@Override
public boolean isSearchAdmin(String userName)
{
@@ -217,17 +208,24 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
{
// Sort the facets into display order
final SolrFacetComparator comparator = new SolrFacetComparator(getFacetOrder());
-
+
SortedSet result = new TreeSet<>(comparator);
- result.addAll(facetsMap.values());
-
+ List children = nodeService.getChildAssocs(getFacetsRoot());
+
+ for (ChildAssociationRef ref : children)
+ {
+ result.add(getFacetProperties(ref.getChildRef()));
+ }
+ // add the default filters
+ result.addAll(defaultFacetsMap.values());
+
return new ArrayList<>(result);
}
-
+
public List getFacetOrder()
{
final NodeRef facetContainer = getFacetsRoot();
-
+
@SuppressWarnings("unchecked")
final List facetOrder = (List) nodeService.getProperty(facetContainer, SolrFacetModel.PROP_FACET_ORDER);
return facetOrder;
@@ -242,12 +240,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
* the nodeService.
*/
NodeRef nodeRef = getFacetNodeRef(filterID);
- return (nodeRef == null) ? getDefaultLoadedFacet(filterID) : getFacetProperties(nodeRef);
- }
-
- private SolrFacetProperties getDefaultLoadedFacet(String filterID)
- {
- return facetConfig.getDefaultFacets().get(filterID);
+ return (nodeRef == null) ? defaultFacetsMap.get(filterID) : getFacetProperties(nodeRef);
}
@Override
@@ -297,26 +290,40 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
}
String filterID = (String) properties.get(ContentModel.PROP_NAME);
- QName fieldQName = (QName) properties.get(SolrFacetModel.PROP_FIELD_TYPE);
- String displayName = (String) properties.get(SolrFacetModel.PROP_FIELD_LABEL);
- String displayControl = (String) properties.get(SolrFacetModel.PROP_DISPLAY_CONTROL);
- int maxFilters = (Integer) properties.get(SolrFacetModel.PROP_MAX_FILTERS);
- int hitThreshold = (Integer) properties.get(SolrFacetModel.PROP_HIT_THRESHOLD);
- int minFilterValueLength = (Integer) properties.get(SolrFacetModel.PROP_MIN_FILTER_VALUE_LENGTH);
- String sortBy = (String) properties.get(SolrFacetModel.PROP_SORT_BY);
- String scope = (String) properties.get(SolrFacetModel.PROP_SCOPE);
- int index = (Integer) properties.get(SolrFacetModel.PROP_INDEX);
- boolean isEnabled = (Boolean) properties.get(SolrFacetModel.PROP_IS_ENABLED);
boolean isDefault = (Boolean) properties.get(SolrFacetModel.PROP_IS_DEFAULT);
+
+ SolrFacetProperties defaultFacet = defaultFacetsMap.get(filterID);
+ if(defaultFacet == null)
+ {
+ defaultFacet = new SolrFacetProperties.Builder().build();
+ }
+
+ QName fieldQName = getDefaultIfNull(defaultFacet.getFacetQName(), (QName) properties.get(SolrFacetModel.PROP_FIELD_TYPE));
+ String displayName = getDefaultIfNull(defaultFacet.getDisplayName(), (String) properties.get(SolrFacetModel.PROP_FIELD_LABEL));
+ String displayControl = getDefaultIfNull(defaultFacet.getDisplayControl(), (String) properties.get(SolrFacetModel.PROP_DISPLAY_CONTROL));
+ int maxFilters = getDefaultIfNull(defaultFacet.getMaxFilters(), (Integer) properties.get(SolrFacetModel.PROP_MAX_FILTERS));
+ int hitThreshold = getDefaultIfNull(defaultFacet.getHitThreshold(), (Integer) properties.get(SolrFacetModel.PROP_HIT_THRESHOLD));
+ int minFilterValueLength = getDefaultIfNull(defaultFacet.getMinFilterValueLength(), (Integer) properties.get(SolrFacetModel.PROP_MIN_FILTER_VALUE_LENGTH));
+ String sortBy = getDefaultIfNull(defaultFacet.getSortBy(), (String) properties.get(SolrFacetModel.PROP_SORT_BY));
+ String scope = getDefaultIfNull(defaultFacet.getScope(), (String) properties.get(SolrFacetModel.PROP_SCOPE));
+ Boolean isEnabled = getDefaultIfNull(defaultFacet.isEnabled(), (Boolean) properties.get(SolrFacetModel.PROP_IS_ENABLED));
@SuppressWarnings("unchecked")
List scSites = (List) properties.get(SolrFacetModel.PROP_SCOPED_SITES);
- Set scopedSites = (scSites == null) ? null : new HashSet<>(scSites);
+ Set scopedSites = getDefaultIfNull(defaultFacet.getScopedSites(), (scSites == null) ? null : new HashSet<>(scSites));
+ Set extraProps = null;
Map customProperties = getFacetCustomProperties(properties);
- Set extraProps = new HashSet<>(customProperties.size());
- for(Entry cp : customProperties.entrySet())
+ if (customProperties.isEmpty())
{
- extraProps.add(new CustomProperties(cp.getKey(), (String) properties.get(ContentModel.PROP_TITLE), null, cp.getValue()));
+ extraProps = defaultFacet.getCustomProperties();
+ }
+ else
+ {
+ extraProps = new HashSet<>(customProperties.size());
+ for (Entry cp : customProperties.entrySet())
+ {
+ extraProps.add(new CustomProperties(cp.getKey(), (String) properties.get(ContentModel.PROP_TITLE), null, cp.getValue()));
+ }
}
// Construct the FacetProperty object
SolrFacetProperties fp = new SolrFacetProperties.Builder()
@@ -329,7 +336,6 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
.minFilterValueLength(minFilterValueLength)
.sortBy(sortBy)
.scope(scope)
- .index(index)
.isEnabled(isEnabled)
.isDefault(isDefault)
.scopedSites(scopedSites)
@@ -338,6 +344,11 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
return fp;
}
+ private T getDefaultIfNull(T defaultValue, T newValue)
+ {
+ return (newValue == null) ? defaultValue : newValue;
+ }
+
@Override
public NodeRef createFacetNode(SolrFacetProperties facetProperties)
{
@@ -346,12 +357,11 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
private NodeRef createFacetNodeImpl(final SolrFacetProperties facetProperties, boolean checkDefaultFP)
{
-
final String filterID = facetProperties.getFilterID();
NodeRef facetNodeRef = getFacetNodeRef(filterID);
// We need to check the bootstrapped Facet properties (i.e loaded from properties file(s)) as well,
// in order to not allow the user to create a new facet with the same filterID as the bootstrapped FP.
- if (facetNodeRef != null || (checkDefaultFP && getDefaultLoadedFacet(filterID) != null))
+ if (facetNodeRef != null || (checkDefaultFP && defaultFacetsMap.get(filterID) != null))
{
throw new SolrFacetConfigException("Unable to create facet because the filterID [" + filterID + "] is already in use.");
}
@@ -406,7 +416,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
NodeRef facetNodeRef = getFacetNodeRef(filterID);
if (facetNodeRef == null)
{
- SolrFacetProperties fp = getDefaultLoadedFacet(filterID);
+ SolrFacetProperties fp = defaultFacetsMap.get(filterID);
if (fp != null)
{
// As we don't create nodes for the bootstrapped FP on server
@@ -436,6 +446,51 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
}
}
+ private SolrFacetProperties makeValidFacetPropObj(SolrFacetProperties newFP)
+ {
+
+ SolrFacetProperties bootstraptedFP = defaultFacetsMap.get(newFP.getFilterID());
+ // null means there is no default facet
+ if(bootstraptedFP == null)
+ {
+ return new SolrFacetProperties.Builder(newFP).isDefault(false).build();
+ }
+
+ QName fieldQName = getValue(bootstraptedFP.getFacetQName(), newFP.getFacetQName(), null);
+ String displayName = getValue(bootstraptedFP.getDisplayName(), newFP.getDisplayName(), null);
+ String displayControl = getValue(bootstraptedFP.getDisplayControl(), newFP.getDisplayControl(), null);
+ int maxFilters = getValue(bootstraptedFP.getMaxFilters(), newFP.getMaxFilters(), -1);
+ int hitThreshold = getValue(bootstraptedFP.getHitThreshold(), newFP.getHitThreshold(), -1);
+ int minFilterValueLength = getValue(bootstraptedFP.getMinFilterValueLength(), newFP.getMinFilterValueLength(), -1);
+ String sortBy = getValue(bootstraptedFP.getSortBy(), newFP.getSortBy(), null);
+ String scope = getValue(bootstraptedFP.getScope(), newFP.getScope(), null);
+ Boolean isEnabled = getValue(bootstraptedFP.isEnabled(), newFP.isEnabled(), null);
+ Set scopedSites = getValue(bootstraptedFP.getScopedSites(), newFP.getScopedSites(), null);
+ Set extraProps = getValue(bootstraptedFP.getCustomProperties(), newFP.getCustomProperties(), null);
+ // Construct the FacetProperty object
+ SolrFacetProperties fp = new SolrFacetProperties.Builder()
+ .filterID(newFP.getFilterID())
+ .facetQName(fieldQName)
+ .displayName(displayName)
+ .displayControl(displayControl)
+ .maxFilters(maxFilters)
+ .hitThreshold(hitThreshold)
+ .minFilterValueLength(minFilterValueLength)
+ .sortBy(sortBy)
+ .scope(scope)
+ .isEnabled(isEnabled)
+ .isDefault(true)
+ .scopedSites(scopedSites)
+ .customProperties(extraProps).build();
+
+ return fp;
+ }
+
+ private T getValue(T originalValue, T newValue, T defaultValueIfEquals)
+ {
+ return (originalValue.equals(newValue) ? defaultValueIfEquals : newValue);
+ }
+
@Override
public void deleteFacet(String filterID)
{
@@ -445,7 +500,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
throw new SolrFacetConfigException("The [" + filterID + "] facet cannot be found.");
}
- SolrFacetProperties defaultFP = getDefaultLoadedFacet(filterID);
+ SolrFacetProperties defaultFP = defaultFacetsMap.get(filterID);
if (defaultFP != null)
{
throw new SolrFacetConfigException("The default [" + filterID + "] facet cannot be deleted. It can only be disabled.");
@@ -464,33 +519,51 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
throw new SolrFacetConfigException("Filter Id cannot be null.");
}
+ // construct a valid facet property object
+ facetProperties = makeValidFacetPropObj(facetProperties);
Set customProperties = facetProperties.getCustomProperties();
- Map properties = new HashMap(14 + customProperties.size());
+ Map properties = new HashMap(13 + customProperties.size());
properties.put(ContentModel.PROP_NAME, facetProperties.getFilterID());
- properties.put(SolrFacetModel.PROP_FIELD_TYPE, facetProperties.getFacetQName());
- properties.put(SolrFacetModel.PROP_FIELD_LABEL, facetProperties.getDisplayName());
- properties.put(SolrFacetModel.PROP_DISPLAY_CONTROL, facetProperties.getDisplayControl());
- properties.put(SolrFacetModel.PROP_MAX_FILTERS, facetProperties.getMaxFilters());
- properties.put(SolrFacetModel.PROP_HIT_THRESHOLD, facetProperties.getHitThreshold());
- properties.put(SolrFacetModel.PROP_MIN_FILTER_VALUE_LENGTH, facetProperties.getMinFilterValueLength());
- properties.put(SolrFacetModel.PROP_SCOPE, facetProperties.getScope());
- properties.put(SolrFacetModel.PROP_SORT_BY, facetProperties.getSortBy());
- properties.put(SolrFacetModel.PROP_SCOPED_SITES, (Serializable) facetProperties.getScopedSites());
- properties.put(SolrFacetModel.PROP_INDEX, facetProperties.getIndex());
- properties.put(SolrFacetModel.PROP_IS_ENABLED, facetProperties.isEnabled());
+ properties.put(SolrFacetModel.PROP_IS_DEFAULT, facetProperties.isDefault());
- SolrFacetProperties fp = getDefaultLoadedFacet(facetProperties.getFilterID());
- properties.put(SolrFacetModel.PROP_IS_DEFAULT, (fp == null) ? false : fp.isDefault());
+ addNodeProperty(properties, SolrFacetModel.PROP_FIELD_TYPE, facetProperties.getFacetQName());
+ addNodeProperty(properties, SolrFacetModel.PROP_FIELD_LABEL, facetProperties.getDisplayName());
+ addNodeProperty(properties, SolrFacetModel.PROP_DISPLAY_CONTROL, facetProperties.getDisplayControl());
+ addNodeProperty(properties, SolrFacetModel.PROP_MAX_FILTERS, facetProperties.getMaxFilters());
+ addNodeProperty(properties, SolrFacetModel.PROP_HIT_THRESHOLD, facetProperties.getHitThreshold());
+ addNodeProperty(properties, SolrFacetModel.PROP_MIN_FILTER_VALUE_LENGTH, facetProperties.getMinFilterValueLength());
+ addNodeProperty(properties, SolrFacetModel.PROP_SCOPE, facetProperties.getScope());
+ addNodeProperty(properties, SolrFacetModel.PROP_SORT_BY, facetProperties.getSortBy());
+ addNodeProperty(properties, SolrFacetModel.PROP_SCOPED_SITES, (Serializable) facetProperties.getScopedSites());
+ addNodeProperty(properties, SolrFacetModel.PROP_IS_ENABLED, facetProperties.isEnabled());
for (CustomProperties cp : customProperties)
{
- properties.put(cp.getName(), cp.getValue());
+ addNodeProperty(properties, cp.getName(), cp.getValue());
}
return properties;
}
+ private void addNodeProperty(Map properties, QName qname, Serializable propValue)
+ {
+ if (propValue == null)
+ {
+ return;
+ }
+ if (propValue instanceof Integer && ((Integer) propValue) < 0)
+ {
+ return;
+ }
+ if (propValue instanceof Collection> && ((Collection>) propValue).isEmpty())
+ {
+ return;
+ }
+
+ properties.put(qname, propValue);
+ }
+
public NodeRef getFacetsRoot()
{
NodeRef facetHomeRef = (NodeRef) singletonCache.get(KEY_FACETS_HOME_NODEREF);
@@ -535,18 +608,6 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
SolrFacetModel.TYPE_FACET_FIELD,
new JavaBehaviour(this, "onCreateNode"));
- // Filter before update
- this.policyComponent.bindClassBehaviour(
- BeforeUpdateNodePolicy.QNAME,
- SolrFacetModel.TYPE_FACET_FIELD,
- new JavaBehaviour(this, "beforeUpdateNode"));
-
- // Filter update
- this.policyComponent.bindClassBehaviour(
- OnUpdateNodePolicy.QNAME,
- SolrFacetModel.TYPE_FACET_FIELD,
- new JavaBehaviour(this, "onUpdateNode"));
-
// Filter before deletion
this.policyComponent.bindClassBehaviour(
BeforeDeleteNodePolicy.QNAME,
@@ -556,6 +617,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
Map mergedMap = new HashMap<>(100);
// Loaded facets
Map defaultFP = facetConfig.getDefaultFacets();
+ defaultFacetsMap.putAll(defaultFP); // add the default facets to a ConcurrentHashMap for performance reasons
mergedMap.putAll(defaultFP);
// Persisted facets
@@ -563,51 +625,43 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
// The persisted facets will override the default facets
mergedMap.putAll(persistedProperties);
+ List facetOrder = getFacetOrder();
// Sort the merged maps
- Comparator> entryComparator = CollectionUtils.toEntryComparator(new SolrFacetComparator(getFacetOrder()));
+ Comparator> entryComparator = CollectionUtils.toEntryComparator(new SolrFacetComparator(facetOrder));
Map sortedMap = CollectionUtils.sortMapByValue(mergedMap, entryComparator);
- LinkedList orderedFacets = new LinkedList<>(sortedMap.values());
- // Get the last index, as the map is sorted by the FP's index value
- int maxIndex = orderedFacets.getLast().getIndex();
- int previousIndex = -1;
- SolrFacetProperties previousFP = null;
- for (SolrFacetProperties facet : orderedFacets)
- {
- String filterID = facet.getFilterID();
- int index = facet.getIndex();
- if (index == previousIndex)
- {
- // we can be sure that previousFP is never null, as we don't
- // allow the index to be -1;
- if (defaultFP.get(previousFP.getFilterID()) != null && persistedProperties.get(filterID) != null)
- {
- SolrFacetProperties updatedPreviousFacet = new SolrFacetProperties.Builder(previousFP).index(++maxIndex).build();
- mergedMap.put(previousFP.getFilterID(), updatedPreviousFacet);
- mergedMap.put(filterID, facet);
- }
- else
- {
- SolrFacetProperties updatedCurrentFacet = new SolrFacetProperties.Builder(facet).index(++maxIndex).build();
- mergedMap.put(updatedCurrentFacet.getFilterID(), updatedCurrentFacet);
- }
- }
- else
- {
- mergedMap.put(filterID, facet);
- }
- previousIndex = index;
- previousFP = facet;
- }
-
- for (SolrFacetProperties fp : mergedMap.values())
- {
- facetsMap.put(fp.getIndex(), fp);
- }
if (logger.isDebugEnabled() && persistedProperties.size() > 0)
{
logger.debug("The facets [" + persistedProperties + "] have overridden their matched default facets.");
}
+
+ final Set newFacetOrder = (facetOrder == null) ? new LinkedHashSet(sortedMap.size()) : new LinkedHashSet(facetOrder);
+
+ for (SolrFacetProperties fp : sortedMap.values())
+ {
+ newFacetOrder.add(fp.getFilterID());
+ }
+
+ AuthenticationUtil.runAs(new RunAsWork()
+ {
+ @Override
+ public Void doWork() throws Exception
+ {
+ return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Exception
+ {
+ reorderFacets(new ArrayList(newFacetOrder));
+ return null;
+ }
+ }, false);
+ }
+ }, AuthenticationUtil.getSystemUserName());
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("The facets order [" + newFacetOrder + "] have been persisted.");
+ }
}
private Map getPersistedFacetProperties()
@@ -629,38 +683,29 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
// nothing to do
}
- @Override
- public void beforeUpdateNode(NodeRef nodeRef)
- {
- // Remove the facet, in order to not end up with duplicate facets but different index
- SolrFacetProperties fp = getFacetProperties(nodeRef);
- this.facetsMap.remove(fp.getIndex());
- }
-
- @Override
- public void onUpdateNode(NodeRef nodeRef)
- {
- SolrFacetProperties fp = getFacetProperties(nodeRef);
- this.facetsMap.put(fp.getIndex(), fp);
- }
-
@Override
public void onCreateNode(ChildAssociationRef childAssocRef)
{
SolrFacetProperties fp = getFacetProperties(childAssocRef.getChildRef());
- this.facetsMap.put(fp.getIndex(), fp);
this.facetNodeRefCache.put(fp.getFilterID(), childAssocRef.getChildRef());
-
+
// We must also add the new filterID to the facetOrder property.
final NodeRef facetsRoot = getFacetsRoot();
-
+
@SuppressWarnings("unchecked")
ArrayList facetOrder = (ArrayList) nodeService.getProperty(facetsRoot, SolrFacetModel.PROP_FACET_ORDER);
- // FIXME This could be null.
-
+ if (facetOrder == null)
+ {
+ List facets = getFacets();
+ facetOrder = new ArrayList(facets.size());
+ for (SolrFacetProperties facet : facets)
+ {
+ facetOrder.add(facet.getFilterID());
+ }
+ }
// We'll put it at the end (arbitrarily).
facetOrder.add(fp.getFilterID());
-
+
nodeService.setProperty(facetsRoot, SolrFacetModel.PROP_FACET_ORDER, facetOrder);
}
@@ -668,43 +713,20 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
public void beforeDeleteNode(NodeRef nodeRef)
{
String filterID = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
- int index = (Integer) nodeService.getProperty(nodeRef, SolrFacetModel.PROP_INDEX);
-
- this.facetsMap.remove(index);
this.facetNodeRefCache.remove(filterID);
-
+
// We must also remove the filterID from the facetOrder property.
final NodeRef facetsRoot = getFacetsRoot();
-
+
@SuppressWarnings("unchecked")
ArrayList facetOrder = (ArrayList) nodeService.getProperty(facetsRoot, SolrFacetModel.PROP_FACET_ORDER);
-
+
if (facetOrder.remove(filterID))
{
nodeService.setProperty(facetsRoot, SolrFacetModel.PROP_FACET_ORDER, facetOrder);
}
}
- @Override
- public int getNextIndex()
- {
- synchronized (facetsMap)
- {
- if (facetsMap.size() >= maxAllowedFilters)
- {
- throw new SolrFacetConfigException("You have reached the maximum number of allowed filters. Please delete an existing filter in order to make a new one!");
- }
- int max = facetsMap.lastKey();
- if (max >= Integer.MAX_VALUE)
- {
- reorder();
- max = facetsMap.lastKey();
- }
-
- return max + 1;
- }
- }
-
/**
* Gets a map containing the facet's custom properties
*
@@ -724,46 +746,6 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
return customProperties;
}
- /**
- * This will reorder the facetsMap, hence, the invoker needs to use an
- * appropriate locking mechanism
- */
- private void reorder()
- {
- boolean order = false;
- int previous = 0;
- for (int i : facetsMap.keySet())
- {
- if (i != previous)
- {
- order = true;
- break;
- }
- previous++;
- }
-
- if (order)
- {
- Map tempMap = new LinkedHashMap<>();
- int index = 0;
- for (SolrFacetProperties fp : facetsMap.values())
- {
- if (fp.getIndex() != index)
- {
- fp = new SolrFacetProperties.Builder(fp).index(index).build();
- }
- tempMap.put(index, fp);
- index++;
- }
- facetsMap.clear();
-
- for (SolrFacetProperties fp : tempMap.values())
- {
- updateFacet(fp);
- }
- }
- }
-
@Override public void reorderFacets(List facetIds)
{
// We need to validate the provided facet IDs
diff --git a/source/test-java/org/alfresco/Repository01TestSuite.java b/source/test-java/org/alfresco/Repository01TestSuite.java
index 192f6a32c8..3c25017872 100644
--- a/source/test-java/org/alfresco/Repository01TestSuite.java
+++ b/source/test-java/org/alfresco/Repository01TestSuite.java
@@ -416,4 +416,9 @@ public class Repository01TestSuite extends TestSuite
suite.addTestSuite(org.alfresco.repo.dictionary.DictionaryModelTypeTest.class);
suite.addTestSuite(org.alfresco.repo.tagging.UpdateTagScopesActionExecuterTest.class);
}
+
+ static void tests66(TestSuite suite)
+ {
+ suite.addTest(org.alfresco.repo.search.impl.solr.facet.SolrFacetTestSuite.suite());
+ }
}
diff --git a/source/test-java/org/alfresco/repo/search/SearchTestSuite.java b/source/test-java/org/alfresco/repo/search/SearchTestSuite.java
index 7afa85f541..ada267d42d 100644
--- a/source/test-java/org/alfresco/repo/search/SearchTestSuite.java
+++ b/source/test-java/org/alfresco/repo/search/SearchTestSuite.java
@@ -18,7 +18,6 @@
*/
package org.alfresco.repo.search;
-import junit.framework.JUnit4TestAdapter;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -31,7 +30,6 @@ import org.alfresco.repo.search.impl.lucene.index.IndexInfoTest;
import org.alfresco.repo.search.impl.parsers.CMISTest;
import org.alfresco.repo.search.impl.parsers.CMIS_FTSTest;
import org.alfresco.repo.search.impl.parsers.FTSTest;
-import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelperTest;
import org.alfresco.util.NumericEncodingTest;
/**
@@ -63,11 +61,7 @@ public class SearchTestSuite extends TestSuite
suite.addTestSuite(CMIS_FTSTest.class);
suite.addTestSuite(CMISTest.class);
suite.addTestSuite(FTSTest.class);
- suite.addTest(new JUnit4TestAdapter(SolrFacetHelperTest.class));
-
-
-
-
+
return suite;
}
}
diff --git a/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparatorTest.java b/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparatorTest.java
index eaf0cdeeeb..77659a2d03 100644
--- a/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparatorTest.java
+++ b/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetComparatorTest.java
@@ -34,15 +34,16 @@ public class SolrFacetComparatorTest
{
@Test public void simpleSortOfSortedFacets() throws Exception
{
- List expectedIds = Arrays.asList(new String[] { "a", "b", "c"});
+ List expectedIds = Arrays.asList(new String[] { "a", "b", "c", "d"});
SolrFacetProperties.Builder builder = new SolrFacetProperties.Builder();
List facets = Arrays.asList(new SolrFacetProperties[]
{
- builder.filterID("c").index(1).build(),
- builder.filterID("b").index(2).build(),
- builder.filterID("a").index(3).build(),
+ builder.filterID("a").build(),
+ builder.filterID("d").build(),
+ builder.filterID("b").build(),
+ builder.filterID("c").build(),
});
Collections.sort(facets, new SolrFacetComparator(expectedIds));
diff --git a/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfigTest.java b/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfigTest.java
new file mode 100644
index 0000000000..f2586a58e0
--- /dev/null
+++ b/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetConfigTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2005-2014 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.search.impl.solr.facet;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.junit.*;
+
+import static org.junit.Assert.*;
+
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * This class contains tests for the class {@link SolrFacetConfig}
+ *
+ * @author Jamal Kaabi-Mofrad
+ * @since 5.0
+ */
+public class SolrFacetConfigTest
+{
+ private static ClassPathXmlApplicationContext context;
+ private static Properties rawProperties;
+ private static SolrFacetConfig facetConfig;
+
+ @BeforeClass
+ public static void setUp() throws Exception
+ {
+ context = new ClassPathXmlApplicationContext(new String[] { "classpath:facets/test-facet-property-context.xml" },
+ ApplicationContextHelper.getApplicationContext());
+
+ rawProperties = context.getBean("solrFacetRawPropertiesTest", Properties.class);
+ facetConfig = context.getBean("solrFacetConfigsTest", SolrFacetConfig.class);
+
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception
+ {
+ context.close();
+ }
+
+ @Test
+ public void testBasic() throws Exception
+ {
+ SolrFacetConfig config = null;
+ try
+ {
+ config = new SolrFacetConfig(null, "");
+ fail("Null properties should have been detected");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // Expected
+ }
+ try
+ {
+ config = new SolrFacetConfig(rawProperties, null);
+ fail("Null properties should have been detected");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // Expected
+ }
+ config = new SolrFacetConfig(rawProperties, "default,custom");
+ config.setNamespaceService(context.getBean("namespaceService", NamespaceService.class));
+ try
+ {
+ config.getDefaultFacets();
+ fail("Initialization should be done.");
+ }
+ catch (IllegalStateException e)
+ {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testDefault() throws Exception
+ {
+ Map defaultProps = facetConfig.getDefaultFacets();
+ assertNotNull(defaultProps);
+ assertEquals("Incorrect number of properties", 4, defaultProps.size());
+
+ // loaded from /facets/facets-config-sample.properties
+ SolrFacetProperties contentSizeFP = defaultProps.get("test_filter_content_size");
+ assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}content.size", contentSizeFP.getFacetQName().toString());
+ assertEquals("faceted-search.facet-menu.facet.size", contentSizeFP.getDisplayName());
+ assertEquals("alfresco/search/FacetFilters", contentSizeFP.getDisplayControl());
+ assertEquals(5, contentSizeFP.getMaxFilters());
+ assertEquals(1, contentSizeFP.getHitThreshold());
+ assertEquals(4, contentSizeFP.getMinFilterValueLength());
+ assertEquals("ALPHABETICALLY", contentSizeFP.getSortBy());
+ assertEquals("ALL", contentSizeFP.getScope());
+ assertEquals(0, contentSizeFP.getScopedSites().size());
+ assertEquals(true, contentSizeFP.isEnabled());
+ assertEquals(1, contentSizeFP.getCustomProperties().size());
+ String customValue = (String) contentSizeFP.getCustomProperties().iterator().next().getValue();
+ assertTrue(Boolean.valueOf(customValue));
+
+ // loaded from /facets/extension/facets-config-custom-sample.properties
+ SolrFacetProperties descFP = defaultProps.get("test_filter_description");
+ assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}description", descFP.getFacetQName().toString());
+ assertEquals("faceted-search.facet-menu.facet.description", descFP.getDisplayName());
+ assertEquals("alfresco/search/FacetFilters", descFP.getDisplayControl());
+ assertEquals(3, descFP.getMaxFilters());
+ assertEquals(1, descFP.getHitThreshold());
+ assertEquals(2, descFP.getMinFilterValueLength());
+ assertEquals("DESCENDING", descFP.getSortBy());
+ assertEquals("SCOPED_SITES", descFP.getScope());
+ assertEquals(0, descFP.getScopedSites().size());
+ assertEquals(true, descFP.isEnabled());
+
+ // See if the overrides worked
+ SolrFacetProperties creatorFP = defaultProps.get("test_filter_creator");
+ assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString());
+
+ String msg = "The value has not been overridden with the value from the custom properties";
+ assertEquals(msg, 10, creatorFP.getMaxFilters());
+ assertEquals(msg, 5, creatorFP.getHitThreshold());
+ assertEquals(msg, 14, creatorFP.getMinFilterValueLength());
+ assertEquals(msg, 1, creatorFP.getScopedSites().size());
+ assertEquals("site1", creatorFP.getScopedSites().iterator().next());
+
+ }
+
+ @Test
+ public void testOverrideOrder() throws Exception
+ {
+ ApplicationEvent applicationEvent = new ApplicationEvent(this)
+ {
+ private static final long serialVersionUID = 1L;
+ };
+
+ /*
+ * Override order: default,custom
+ */
+ SolrFacetConfig config = new SolrFacetConfig(rawProperties, "default,custom");
+ config.setNamespaceService(context.getBean("namespaceService", NamespaceService.class));
+ config.onBootstrap(applicationEvent);
+
+ SolrFacetProperties creatorFP = config.getDefaultFacets().get("test_filter_creator");
+ assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString());
+ assertEquals(10, creatorFP.getMaxFilters());
+ assertEquals(5, creatorFP.getHitThreshold());
+ assertEquals(14, creatorFP.getMinFilterValueLength());
+ assertEquals(1, creatorFP.getScopedSites().size());
+ assertEquals("site1", creatorFP.getScopedSites().iterator().next());
+
+ /*
+ * Override order: custom,default
+ */
+ config = new SolrFacetConfig(rawProperties, "custom,default");
+ config.setNamespaceService(context.getBean("namespaceService", NamespaceService.class));
+ config.onBootstrap(applicationEvent);
+
+ creatorFP = config.getDefaultFacets().get("test_filter_creator");
+ assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString());
+ assertEquals(5, creatorFP.getMaxFilters());
+ assertEquals(1, creatorFP.getHitThreshold());
+ assertEquals(4, creatorFP.getMinFilterValueLength());
+ assertEquals(0, creatorFP.getScopedSites().size());
+ }
+}
\ No newline at end of file
diff --git a/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetTestSuite.java b/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetTestSuite.java
new file mode 100644
index 0000000000..0613a2a63f
--- /dev/null
+++ b/source/test-java/org/alfresco/repo/search/impl/solr/facet/SolrFacetTestSuite.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005-2014 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.search.impl.solr.facet;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * @author Jamal Kaabi-Mofrad
+ */
+public class SolrFacetTestSuite extends TestSuite
+{
+
+ /**
+ * Creates the test suite
+ *
+ * @return the test suite
+ */
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite();
+ suite.addTest(new JUnit4TestAdapter(SolrFacetHelperTest.class));
+ suite.addTest(new JUnit4TestAdapter(SolrFacetServiceImplTest.class));
+ suite.addTest(new JUnit4TestAdapter(SolrFacetConfigTest.class));
+
+ return suite;
+ }
+}
diff --git a/source/test-resources/facets/extension/facets-config-custom-sample.properties b/source/test-resources/facets/extension/facets-config-custom-sample.properties
new file mode 100644
index 0000000000..805e69cdbc
--- /dev/null
+++ b/source/test-resources/facets/extension/facets-config-custom-sample.properties
@@ -0,0 +1,26 @@
+# Overrides test_filter_creator in the /facets/facets-config-sample.properties
+custom.cm\:creator.__.u.filterID=test_filter_creator
+custom.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
+custom.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
+custom.cm\:creator.__.u.maxFilters=10
+custom.cm\:creator.__.u.hitThreshold=5
+custom.cm\:creator.__.u.minFilterValueLength=14
+custom.cm\:creator.__.u.sortBy=ALPHABETICALLY
+custom.cm\:creator.__.u.scope=ALL
+custom.cm\:creator.__.u.scopedSites=site1
+custom.cm\:creator.__.u.index=0
+custom.cm\:creator.__.u.isEnabled=true
+
+# Add a new Filter
+# Field-Facet-Qname => cm:description.__
+custom.cm\:description.filterID=test_filter_description
+custom.cm\:description.displayName=faceted-search.facet-menu.facet.description
+custom.cm\:description.displayControl=alfresco/search/FacetFilters
+custom.cm\:description.maxFilters=3
+custom.cm\:description.hitThreshold=1
+custom.cm\:description.minFilterValueLength=2
+custom.cm\:description.sortBy=DESCENDING
+custom.cm\:description.scope=SCOPED_SITES
+custom.cm\:description.scopedSites=
+custom.cm\:description.index=4
+custom.cm\:description.isEnabled=true
\ No newline at end of file
diff --git a/source/test-resources/facets/facets-config-sample.properties b/source/test-resources/facets/facets-config-sample.properties
new file mode 100644
index 0000000000..4a160172dd
--- /dev/null
+++ b/source/test-resources/facets/facets-config-sample.properties
@@ -0,0 +1,36 @@
+# Field-Facet-Qname => cm:creator.__.u
+default.cm\:creator.__.u.filterID=test_filter_creator
+default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
+default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
+default.cm\:creator.__.u.maxFilters=5
+default.cm\:creator.__.u.hitThreshold=1
+default.cm\:creator.__.u.minFilterValueLength=4
+default.cm\:creator.__.u.sortBy=ALPHABETICALLY
+default.cm\:creator.__.u.scope=ALL
+default.cm\:creator.__.u.scopedSites=
+default.cm\:creator.__.u.isEnabled=true
+
+# Field-Facet-Qname => cm:modifier.__.u
+default.cm\:modifier.__.u.filterID=test_filter_modifier
+default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier
+default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters
+default.cm\:modifier.__.u.maxFilters=5
+default.cm\:modifier.__.u.hitThreshold=1
+default.cm\:modifier.__.u.minFilterValueLength=4
+default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
+default.cm\:modifier.__.u.scope=SCOPED_SITES
+default.cm\:modifier.__.u.scopedSites=
+default.cm\:modifier.__.u.isEnabled=true
+
+# Field-Facet-Qname => cm:content.size
+default.cm\:content.size.filterID=test_filter_content_size
+default.cm\:content.size.displayName=faceted-search.facet-menu.facet.size
+default.cm\:content.size.displayControl=alfresco/search/FacetFilters
+default.cm\:content.size.maxFilters=5
+default.cm\:content.size.hitThreshold=1
+default.cm\:content.size.minFilterValueLength=4
+default.cm\:content.size.sortBy=ALPHABETICALLY
+default.cm\:content.size.scope=ALL
+default.cm\:content.size.scopedSites=
+default.cm\:content.size.isEnabled=true
+default.cm\:content.size.EXTRA-PROP.blockIncludeFacetRequest=true
\ No newline at end of file
diff --git a/source/test-resources/facets/test-facet-property-context.xml b/source/test-resources/facets/test-facet-property-context.xml
new file mode 100644
index 0000000000..8f1406b6b8
--- /dev/null
+++ b/source/test-resources/facets/test-facet-property-context.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ classpath*:facets/facets-config-sample.properties
+ classpath*:facets/extension/facets-config-custom-sample.properties
+
+
+
+
+
+
+ default,custom
+
+
+
+
\ No newline at end of file