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:
@@ -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
|
||||
|
Reference in New Issue
Block a user