mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (5.0/Cloud)
80669: Merged WAT1 (5.0/Cloud) to HEAD-BUG-FIX (5.0/Cloud) 78166: ACE-1582: Enhancements to the facet service to persist only the modified value(s) rather than the whole facet's properties. Also fixed facets cache and facets reordering NPE. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@82966 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -119,16 +119,6 @@
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="srft:index">
|
||||
<title>Index</title>
|
||||
<type>d:int</type>
|
||||
<mandatory>true</mandatory>
|
||||
<index enabled="false">
|
||||
<atomic>false</atomic>
|
||||
<stored>false</stored>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="srft:isEnabled">
|
||||
<title>Is enabled</title>
|
||||
<type>d:boolean</type>
|
||||
|
@@ -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
|
||||
|
@@ -38,6 +38,11 @@ public class SolrFacetComparator implements Comparator<SolrFacetProperties>
|
||||
|
||||
@Override public int compare(SolrFacetProperties facet1, SolrFacetProperties facet2)
|
||||
{
|
||||
if (sortedIDs.isEmpty())
|
||||
{
|
||||
return facet1.getFilterID().compareTo(facet2.getFilterID());
|
||||
}
|
||||
|
||||
Pair<Integer, Integer> facetIndicesInSortedList = find(facet1, facet2);
|
||||
|
||||
if (bothSorted(facetIndicesInSortedList))
|
||||
@@ -47,19 +52,7 @@ public class SolrFacetComparator implements Comparator<SolrFacetProperties>
|
||||
}
|
||||
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
|
||||
{
|
||||
|
@@ -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;
|
||||
* <li>custom.cm\:content.mimetype.sortBy=DESCENDING</li>
|
||||
* <li>custom.cm\:content.mimetype.scope=SCOPED_SITES</li>
|
||||
* <li>custom.cm\:content.mimetype.scopedSites=site1,site2,site3</li>
|
||||
* <li>custom.cm\:content.mimetype.index=0</li>
|
||||
* <li>custom.cm\:content.mimetype.isEnabled=true</li>
|
||||
* </ul>
|
||||
* 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<String> 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<CustomProperties> 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<String> propNames, Set<String> propOrderControl)
|
||||
{
|
||||
|
||||
|
||||
for (Object propKeyObj : properties.keySet())
|
||||
{
|
||||
String propKey = (String) propKeyObj;
|
||||
@@ -327,14 +321,14 @@ public class SolrFacetConfig extends AbstractLifecycleBean
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
private static Set<CustomProperties> getCustomProps(Set<String> additionalProps, String field, Map<String, String> propValues)
|
||||
{
|
||||
if (additionalProps == null)
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
Set<CustomProperties> 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)
|
||||
{
|
||||
|
@@ -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");
|
||||
}
|
||||
|
@@ -46,8 +46,7 @@ public class SolrFacetProperties implements Serializable
|
||||
private final String sortBy;
|
||||
private final String scope;
|
||||
private final Set<String> 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> 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<String>(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<CustomProperties>(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<String> scopedSites = Collections.emptySet();
|
||||
private int index;
|
||||
private boolean isEnabled;
|
||||
private Boolean isEnabled;
|
||||
private boolean isDefault;
|
||||
private Set<CustomProperties> 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;
|
||||
|
@@ -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<SolrFacetProperties> 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.
|
||||
*
|
||||
|
@@ -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<String, Object> singletonCache; // eg. for facetsHomeNodeRef
|
||||
private final String KEY_FACETS_HOME_NODEREF = "key.facetshome.noderef";
|
||||
private SimpleCache<String, NodeRef> facetNodeRefCache; // for filterID to nodeRef lookup
|
||||
private NavigableMap<Integer, SolrFacetProperties> facetsMap = new ConcurrentSkipListMap<>(); // TODO
|
||||
private int maxAllowedFilters = 100;
|
||||
private ConcurrentMap<String, SolrFacetProperties> defaultFacetsMap = new ConcurrentHashMap<String, SolrFacetProperties>(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<SolrFacetProperties> result = new TreeSet<>(comparator);
|
||||
result.addAll(facetsMap.values());
|
||||
|
||||
List<ChildAssociationRef> 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<String> getFacetOrder()
|
||||
{
|
||||
final NodeRef facetContainer = getFacetsRoot();
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<String> facetOrder = (List<String>) 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<String> scSites = (List<String>) properties.get(SolrFacetModel.PROP_SCOPED_SITES);
|
||||
Set<String> scopedSites = (scSites == null) ? null : new HashSet<>(scSites);
|
||||
Set<String> scopedSites = getDefaultIfNull(defaultFacet.getScopedSites(), (scSites == null) ? null : new HashSet<>(scSites));
|
||||
|
||||
Set<CustomProperties> extraProps = null;
|
||||
Map<QName, Serializable> customProperties = getFacetCustomProperties(properties);
|
||||
Set<CustomProperties> extraProps = new HashSet<>(customProperties.size());
|
||||
for(Entry<QName, Serializable> 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<QName, Serializable> 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> 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<String> scopedSites = getValue(bootstraptedFP.getScopedSites(), newFP.getScopedSites(), null);
|
||||
Set<CustomProperties> 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> 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> customProperties = facetProperties.getCustomProperties();
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(14 + customProperties.size());
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(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<QName, Serializable> 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<String, SolrFacetProperties> mergedMap = new HashMap<>(100);
|
||||
// Loaded facets
|
||||
Map<String, SolrFacetProperties> 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<String> facetOrder = getFacetOrder();
|
||||
// Sort the merged maps
|
||||
Comparator<Entry<String, SolrFacetProperties>> entryComparator = CollectionUtils.toEntryComparator(new SolrFacetComparator(getFacetOrder()));
|
||||
Comparator<Entry<String, SolrFacetProperties>> entryComparator = CollectionUtils.toEntryComparator(new SolrFacetComparator(facetOrder));
|
||||
Map<String, SolrFacetProperties> sortedMap = CollectionUtils.sortMapByValue(mergedMap, entryComparator);
|
||||
LinkedList<SolrFacetProperties> 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<String> newFacetOrder = (facetOrder == null) ? new LinkedHashSet<String>(sortedMap.size()) : new LinkedHashSet<String>(facetOrder);
|
||||
|
||||
for (SolrFacetProperties fp : sortedMap.values())
|
||||
{
|
||||
newFacetOrder.add(fp.getFilterID());
|
||||
}
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Exception
|
||||
{
|
||||
reorderFacets(new ArrayList<String>(newFacetOrder));
|
||||
return null;
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("The facets order [" + newFacetOrder + "] have been persisted.");
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, SolrFacetProperties> 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<String> facetOrder = (ArrayList<String>) nodeService.getProperty(facetsRoot, SolrFacetModel.PROP_FACET_ORDER);
|
||||
// FIXME This could be null.
|
||||
|
||||
if (facetOrder == null)
|
||||
{
|
||||
List<SolrFacetProperties> facets = getFacets();
|
||||
facetOrder = new ArrayList<String>(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<String> facetOrder = (ArrayList<String>) 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<Integer, SolrFacetProperties> 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<String> facetIds)
|
||||
{
|
||||
// We need to validate the provided facet IDs
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -34,15 +34,16 @@ public class SolrFacetComparatorTest
|
||||
{
|
||||
@Test public void simpleSortOfSortedFacets() throws Exception
|
||||
{
|
||||
List<String> expectedIds = Arrays.asList(new String[] { "a", "b", "c"});
|
||||
List<String> expectedIds = Arrays.asList(new String[] { "a", "b", "c", "d"});
|
||||
|
||||
SolrFacetProperties.Builder builder = new SolrFacetProperties.Builder();
|
||||
|
||||
List<SolrFacetProperties> 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));
|
||||
|
||||
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String, SolrFacetProperties> 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());
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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
|
36
source/test-resources/facets/facets-config-sample.properties
Normal file
36
source/test-resources/facets/facets-config-sample.properties
Normal file
@@ -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
|
21
source/test-resources/facets/test-facet-property-context.xml
Normal file
21
source/test-resources/facets/test-facet-property-context.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="solrFacetRawPropertiesTest" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
|
||||
<property name="locations">
|
||||
<list>
|
||||
<value>classpath*:facets/facets-config-sample.properties</value>
|
||||
<value>classpath*:facets/extension/facets-config-custom-sample.properties</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="solrFacetConfigsTest" class="org.alfresco.repo.search.impl.solr.facet.SolrFacetConfig">
|
||||
<constructor-arg index="0" ref="solrFacetRawPropertiesTest" />
|
||||
<constructor-arg index="1">
|
||||
<value>default,custom</value>
|
||||
</constructor-arg>
|
||||
<property name="namespaceService" ref="namespaceService" />
|
||||
</bean>
|
||||
</beans>
|
Reference in New Issue
Block a user