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)
80520: Merged WAT1 (5.0/Cloud) to HEAD-BUG-FIX (5.0/Cloud) 74961: ACE-1582: Added index control and custom data support for the facet configs. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@82817 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -18,6 +18,8 @@
|
|||||||
<!-- Solr Facets Namespace -->
|
<!-- Solr Facets Namespace -->
|
||||||
<namespaces>
|
<namespaces>
|
||||||
<namespace uri="http://www.alfresco.org/model/solrfacet/1.0" prefix="srft" />
|
<namespace uri="http://www.alfresco.org/model/solrfacet/1.0" prefix="srft" />
|
||||||
|
<!-- if you want to extend the properties of a facet then use this namespace to mark the custom properties -->
|
||||||
|
<namespace uri="http://www.alfresco.org/model/solrfacetcustomproperty/1.0" prefix="srftcustom"/>
|
||||||
</namespaces>
|
</namespaces>
|
||||||
|
|
||||||
<types>
|
<types>
|
||||||
@@ -155,4 +157,18 @@
|
|||||||
<parent>cm:folder</parent>
|
<parent>cm:folder</parent>
|
||||||
</type>
|
</type>
|
||||||
</types>
|
</types>
|
||||||
|
|
||||||
|
<aspects>
|
||||||
|
<!-- Custom Facet Properties Aspect -->
|
||||||
|
<aspect name="srft:customProperties">
|
||||||
|
<title>Facet Custom Properties</title>
|
||||||
|
<properties>
|
||||||
|
<property name="srftcustom:extraInformation">
|
||||||
|
<title>Additional Facet Information</title>
|
||||||
|
<type>d:text</type>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</aspect>
|
||||||
|
</aspects>
|
||||||
|
|
||||||
</model>
|
</model>
|
@@ -12,7 +12,7 @@ default.cm\:content.mimetype.hitThreshold=1
|
|||||||
default.cm\:content.mimetype.minFilterValueLength=4
|
default.cm\:content.mimetype.minFilterValueLength=4
|
||||||
default.cm\:content.mimetype.sortBy=DESCENDING
|
default.cm\:content.mimetype.sortBy=DESCENDING
|
||||||
default.cm\:content.mimetype.scope=SCOPED_SITES
|
default.cm\:content.mimetype.scope=SCOPED_SITES
|
||||||
default.cm\:content.mimetype.scopedSites=site1,site2,site3
|
default.cm\:content.mimetype.scopedSites=
|
||||||
default.cm\:content.mimetype.index=0
|
default.cm\:content.mimetype.index=0
|
||||||
default.cm\:content.mimetype.isEnabled=true
|
default.cm\:content.mimetype.isEnabled=true
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ default.cm\:description.__.hitThreshold=1
|
|||||||
default.cm\:description.__.minFilterValueLength=4
|
default.cm\:description.__.minFilterValueLength=4
|
||||||
default.cm\:description.__.sortBy=DESCENDING
|
default.cm\:description.__.sortBy=DESCENDING
|
||||||
default.cm\:description.__.scope=SCOPED_SITES
|
default.cm\:description.__.scope=SCOPED_SITES
|
||||||
default.cm\:description.__.scopedSites=site1,site2,site3
|
default.cm\:description.__.scopedSites=
|
||||||
default.cm\:description.__.index=1
|
default.cm\:description.__.index=1
|
||||||
default.cm\:description.__.isEnabled=true
|
default.cm\:description.__.isEnabled=true
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ default.cm\:creator.__.u.hitThreshold=1
|
|||||||
default.cm\:creator.__.u.minFilterValueLength=4
|
default.cm\:creator.__.u.minFilterValueLength=4
|
||||||
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
||||||
default.cm\:creator.__.u.scope=SCOPED_SITES
|
default.cm\:creator.__.u.scope=SCOPED_SITES
|
||||||
default.cm\:creator.__.u.scopedSites=site1,site2,site3
|
default.cm\:creator.__.u.scopedSites=
|
||||||
default.cm\:creator.__.u.index=2
|
default.cm\:creator.__.u.index=2
|
||||||
default.cm\:creator.__.u.isEnabled=true
|
default.cm\:creator.__.u.isEnabled=true
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ default.cm\:modifier.__.u.hitThreshold=1
|
|||||||
default.cm\:modifier.__.u.minFilterValueLength=4
|
default.cm\:modifier.__.u.minFilterValueLength=4
|
||||||
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
|
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
|
||||||
default.cm\:modifier.__.u.scope=SCOPED_SITES
|
default.cm\:modifier.__.u.scope=SCOPED_SITES
|
||||||
default.cm\:modifier.__.u.scopedSites=site1,site2,site3
|
default.cm\:modifier.__.u.scopedSites=
|
||||||
default.cm\:modifier.__.u.index=3
|
default.cm\:modifier.__.u.index=3
|
||||||
default.cm\:modifier.__.u.isEnabled=true
|
default.cm\:modifier.__.u.isEnabled=true
|
||||||
|
|
||||||
@@ -59,40 +59,40 @@ default.cm\:modifier.__.u.isEnabled=true
|
|||||||
default.cm\:created.filterID=filter_created
|
default.cm\:created.filterID=filter_created
|
||||||
default.cm\:created.displayName=faceted-search.facet-menu.facet.created
|
default.cm\:created.displayName=faceted-search.facet-menu.facet.created
|
||||||
default.cm\:created.displayControl=alfresco/search/FacetFilters
|
default.cm\:created.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:created.blockIncludeFacetRequest=true
|
|
||||||
default.cm\:created.maxFilters=5
|
default.cm\:created.maxFilters=5
|
||||||
default.cm\:created.hitThreshold=1
|
default.cm\:created.hitThreshold=1
|
||||||
default.cm\:created.minFilterValueLength=4
|
default.cm\:created.minFilterValueLength=4
|
||||||
default.cm\:created.sortBy=ALPHABETICALLY
|
default.cm\:created.sortBy=ALPHABETICALLY
|
||||||
default.cm\:created.scope=SCOPED_SITES
|
default.cm\:created.scope=SCOPED_SITES
|
||||||
default.cm\:created.scopedSites=site1,site2,site3
|
default.cm\:created.scopedSites=
|
||||||
default.cm\:created.index=4
|
default.cm\:created.index=4
|
||||||
default.cm\:created.isEnabled=true
|
default.cm\:created.isEnabled=true
|
||||||
|
default.cm\:created.EXTRA-PROP.blockIncludeFacetRequest=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:modified
|
# Field-Facet-Qname => cm:modified
|
||||||
default.cm\:modified.filterID=filter_modified
|
default.cm\:modified.filterID=filter_modified
|
||||||
default.cm\:modified.displayName=faceted-search.facet-menu.facet.modified
|
default.cm\:modified.displayName=faceted-search.facet-menu.facet.modified
|
||||||
default.cm\:modified.displayControl=alfresco/search/FacetFilters
|
default.cm\:modified.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:modified.blockIncludeFacetRequest=true
|
|
||||||
default.cm\:modified.maxFilters=5
|
default.cm\:modified.maxFilters=5
|
||||||
default.cm\:modified.hitThreshold=1
|
default.cm\:modified.hitThreshold=1
|
||||||
default.cm\:modified.minFilterValueLength=4
|
default.cm\:modified.minFilterValueLength=4
|
||||||
default.cm\:modified.sortBy=ALPHABETICALLY
|
default.cm\:modified.sortBy=ALPHABETICALLY
|
||||||
default.cm\:modified.scope=SCOPED_SITES
|
default.cm\:modified.scope=SCOPED_SITES
|
||||||
default.cm\:modified.scopedSites=site1,site2,site3
|
default.cm\:modified.scopedSites=
|
||||||
default.cm\:modified.index=5
|
default.cm\:modified.index=5
|
||||||
default.cm\:modified.isEnabled=true
|
default.cm\:modified.isEnabled=true
|
||||||
|
default.cm\:modified.EXTRA-PROP.blockIncludeFacetRequest=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:content.size
|
# Field-Facet-Qname => cm:content.size
|
||||||
default.cm\:content.size.filterID=filter_content_size
|
default.cm\:content.size.filterID=filter_content_size
|
||||||
default.cm\:content.size.displayName=faceted-search.facet-menu.facet.size
|
default.cm\:content.size.displayName=faceted-search.facet-menu.facet.size
|
||||||
default.cm\:content.size.displayControl=alfresco/search/FacetFilters
|
default.cm\:content.size.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:content.size.blockIncludeFacetRequest=true
|
|
||||||
default.cm\:content.size.maxFilters=5
|
default.cm\:content.size.maxFilters=5
|
||||||
default.cm\:content.size.hitThreshold=1
|
default.cm\:content.size.hitThreshold=1
|
||||||
default.cm\:content.size.minFilterValueLength=4
|
default.cm\:content.size.minFilterValueLength=4
|
||||||
default.cm\:content.size.sortBy=ALPHABETICALLY
|
default.cm\:content.size.sortBy=ALPHABETICALLY
|
||||||
default.cm\:content.size.scope=SCOPED_SITES
|
default.cm\:content.size.scope=SCOPED_SITES
|
||||||
default.cm\:content.size.scopedSites=site1,site2,site3
|
default.cm\:content.size.scopedSites=
|
||||||
default.cm\:content.size.index=6
|
default.cm\:content.size.index=6
|
||||||
default.cm\:content.size.isEnabled=true
|
default.cm\:content.size.isEnabled=true
|
||||||
|
default.cm\:content.size.EXTRA-PROP.blockIncludeFacetRequest=true
|
||||||
|
@@ -19,15 +19,19 @@
|
|||||||
|
|
||||||
package org.alfresco.repo.search.impl.solr.facet;
|
package org.alfresco.repo.search.impl.solr.facet;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.repo.search.impl.solr.facet.SolrFacetProperties.CustomProperties;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.util.PropertyCheck;
|
import org.alfresco.util.PropertyCheck;
|
||||||
@@ -47,6 +51,7 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
|||||||
* <ul>
|
* <ul>
|
||||||
* <li>custom.cm\:content.mimetype.filterID=filter_abc</li>
|
* <li>custom.cm\:content.mimetype.filterID=filter_abc</li>
|
||||||
* <li>custom.cm\:content.mimetype.displayName=faceted-search.facet-menu.facet.formats</li>
|
* <li>custom.cm\:content.mimetype.displayName=faceted-search.facet-menu.facet.formats</li>
|
||||||
|
* <li>custom.cm\:content.mimetype.displayControl=alfresco/search/FacetFilters</li>
|
||||||
* <li>custom.cm\:content.mimetype.maxFilters=5</li>
|
* <li>custom.cm\:content.mimetype.maxFilters=5</li>
|
||||||
* <li>custom.cm\:content.mimetype.hitThreshold=1</li>
|
* <li>custom.cm\:content.mimetype.hitThreshold=1</li>
|
||||||
* <li>custom.cm\:content.mimetype.minFilterValueLength=4</li>
|
* <li>custom.cm\:content.mimetype.minFilterValueLength=4</li>
|
||||||
@@ -56,6 +61,12 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
|||||||
* <li>custom.cm\:content.mimetype.index=0</li>
|
* <li>custom.cm\:content.mimetype.index=0</li>
|
||||||
* <li>custom.cm\:content.mimetype.isEnabled=true</li>
|
* <li>custom.cm\:content.mimetype.isEnabled=true</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* Also, if there is a need to add additional properties, the following needs to be
|
||||||
|
* put into a properties file:
|
||||||
|
* <ul>
|
||||||
|
* <li>custom.cm\:content.mimetype<b>.EXTRA-PROP.</b>blockIncludeFacetRequest=true</li>
|
||||||
|
* <li>custom.cm\:content.mimetype<b>.EXTRA-PROP.</b>moreProp=additionalInfo</li>
|
||||||
|
* </ul>
|
||||||
* The inheritance order is strictly defined using property:<br/>
|
* The inheritance order is strictly defined using property:<br/>
|
||||||
* <b>${solr_facets.inheritanceHierarchy}</b><br/>
|
* <b>${solr_facets.inheritanceHierarchy}</b><br/>
|
||||||
* The default inheritance orders are:<br/>
|
* The default inheritance orders are:<br/>
|
||||||
@@ -69,6 +80,9 @@ public class SolrFacetConfig extends AbstractLifecycleBean
|
|||||||
{
|
{
|
||||||
private static final Log logger = LogFactory.getLog(SolrFacetConfig.class);
|
private static final Log logger = LogFactory.getLog(SolrFacetConfig.class);
|
||||||
|
|
||||||
|
private static final String KEY_EXTRA_INFO = ".EXTRA-PROP.";
|
||||||
|
private static final int KEY_EXTRA_INFO_LENGTH = KEY_EXTRA_INFO.length();
|
||||||
|
|
||||||
private final Properties rawProperties;
|
private final Properties rawProperties;
|
||||||
private final Set<String> propInheritanceOrder;
|
private final Set<String> propInheritanceOrder;
|
||||||
|
|
||||||
@@ -163,15 +177,39 @@ public class SolrFacetConfig extends AbstractLifecycleBean
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> facetFields = new HashSet<>();
|
Map<String, Set<String>> facetFields = new HashMap<>();
|
||||||
for(String key : propValues.keySet())
|
for(String key : propValues.keySet())
|
||||||
{
|
{
|
||||||
facetFields.add(key.substring(0, key.lastIndexOf('.')));
|
String facetQName = null;
|
||||||
|
Set<String> extraProp = null;
|
||||||
|
int index = key.indexOf(KEY_EXTRA_INFO);
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
String extraInfo = key.substring(index + KEY_EXTRA_INFO_LENGTH);
|
||||||
|
facetQName = key.substring(0, index);
|
||||||
|
|
||||||
|
extraProp = facetFields.get(facetQName);
|
||||||
|
if (extraProp == null)
|
||||||
|
{
|
||||||
|
extraProp = new HashSet<>();
|
||||||
|
}
|
||||||
|
if (extraInfo.length() > 0)
|
||||||
|
{
|
||||||
|
extraProp.add(extraInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = key.lastIndexOf('.');
|
||||||
|
facetQName = key.substring(0, index);
|
||||||
|
extraProp = facetFields.get(facetQName);
|
||||||
|
}
|
||||||
|
facetFields.put(facetQName, extraProp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the facet config objects
|
// Build the facet config objects
|
||||||
Map<String, SolrFacetProperties> facetProperties = new HashMap<>(100);
|
Map<String, SolrFacetProperties> facetProperties = new HashMap<>(100);
|
||||||
for (String field : facetFields)
|
for (String field : facetFields.keySet())
|
||||||
{
|
{
|
||||||
// FacetProperty attributes
|
// FacetProperty attributes
|
||||||
// Resolve facet field into QName
|
// Resolve facet field into QName
|
||||||
@@ -186,7 +224,12 @@ public class SolrFacetConfig extends AbstractLifecycleBean
|
|||||||
String scope = propValues.get(ValueName.PROP_SCOPE.getPropValueName(field));
|
String scope = propValues.get(ValueName.PROP_SCOPE.getPropValueName(field));
|
||||||
Set<String> scopedSites = getScopedSites(propValues.get(ValueName.PROP_SCOPED_SITES.getPropValueName(field)));
|
Set<String> scopedSites = getScopedSites(propValues.get(ValueName.PROP_SCOPED_SITES.getPropValueName(field)));
|
||||||
int index = getIntegerValue(propValues.get(ValueName.PROP_INDEX.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
|
// Construct the FacetProperty object
|
||||||
SolrFacetProperties fp = new SolrFacetProperties.Builder()
|
SolrFacetProperties fp = new SolrFacetProperties.Builder()
|
||||||
@@ -202,7 +245,8 @@ public class SolrFacetConfig extends AbstractLifecycleBean
|
|||||||
.index(index)
|
.index(index)
|
||||||
.isEnabled(isEnabled)
|
.isEnabled(isEnabled)
|
||||||
.isDefault(true)
|
.isDefault(true)
|
||||||
.scopedSites(scopedSites).build();
|
.scopedSites(scopedSites)
|
||||||
|
.customProperties(customProps).build();
|
||||||
|
|
||||||
facetProperties.put(filterID, fp);
|
facetProperties.put(filterID, fp);
|
||||||
}
|
}
|
||||||
@@ -284,6 +328,35 @@ public class SolrFacetConfig extends AbstractLifecycleBean
|
|||||||
return set;
|
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)
|
||||||
|
{
|
||||||
|
String value = propValues.get(field + KEY_EXTRA_INFO + extraInfo);
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
QName qName = QName.createQName(SolrFacetModel.SOLR_FACET_CUSTOM_PROPERTY_URL, extraInfo);
|
||||||
|
String[] extra = value.split(",");
|
||||||
|
if (extra.length == 1)
|
||||||
|
{
|
||||||
|
customProps.add(new CustomProperties(qName, null, null, extra[0]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<String> list = Arrays.asList(extra);
|
||||||
|
customProps.add(new CustomProperties(qName, null, null, (Serializable) list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return customProps;
|
||||||
|
}
|
||||||
|
|
||||||
private static int getIntegerValue(String propValue)
|
private static int getIntegerValue(String propValue)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@@ -31,8 +31,13 @@ public interface SolrFacetModel
|
|||||||
public static final String SOLR_FACET_MODEL_URL = "http://www.alfresco.org/model/solrfacet/1.0";
|
public static final String SOLR_FACET_MODEL_URL = "http://www.alfresco.org/model/solrfacet/1.0";
|
||||||
public static final String PREFIX = "srft";
|
public static final String PREFIX = "srft";
|
||||||
|
|
||||||
|
public static final String SOLR_FACET_CUSTOM_PROPERTY_URL = "http://www.alfresco.org/model/solrfacetcustomproperty/1.0";
|
||||||
|
public static final String SOLR_FACET_CUSTOM_PROPERTY_PREFIX = "srftcustom";
|
||||||
|
|
||||||
public static final QName TYPE_FACET_FIELD = QName.createQName(SOLR_FACET_MODEL_URL, "facetField");
|
public static final QName TYPE_FACET_FIELD = QName.createQName(SOLR_FACET_MODEL_URL, "facetField");
|
||||||
|
|
||||||
|
public static final QName ASPECT_CUSTOM_PROPERTIES = QName.createQName(SOLR_FACET_MODEL_URL, "customProperties");
|
||||||
|
|
||||||
public static final QName PROP_FIELD_TYPE = QName.createQName(SOLR_FACET_MODEL_URL, "fieldType");
|
public static final QName PROP_FIELD_TYPE = QName.createQName(SOLR_FACET_MODEL_URL, "fieldType");
|
||||||
|
|
||||||
public static final QName PROP_FIELD_LABEL = QName.createQName(SOLR_FACET_MODEL_URL, "fieldLabel");
|
public static final QName PROP_FIELD_LABEL = QName.createQName(SOLR_FACET_MODEL_URL, "fieldLabel");
|
||||||
@@ -56,4 +61,6 @@ public interface SolrFacetModel
|
|||||||
public static final QName PROP_IS_ENABLED = QName.createQName(SOLR_FACET_MODEL_URL, "isEnabled");
|
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_IS_DEFAULT = QName.createQName(SOLR_FACET_MODEL_URL, "isDefault");
|
||||||
|
|
||||||
|
public static final QName PROP_EXTRA_INFORMATION = QName.createQName(SOLR_FACET_CUSTOM_PROPERTY_URL, "extraInformation");
|
||||||
}
|
}
|
||||||
|
@@ -19,20 +19,23 @@
|
|||||||
|
|
||||||
package org.alfresco.repo.search.impl.solr.facet;
|
package org.alfresco.repo.search.impl.solr.facet;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.util.EqualsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Domain-Specific Language (DSL) style builder class for encapsulating the
|
* Domain-Specific Language (DSL) style builder class for encapsulating the facet properties.
|
||||||
* facet properties.
|
|
||||||
*
|
*
|
||||||
* @author Jamal Kaabi-Mofrad
|
* @author Jamal Kaabi-Mofrad
|
||||||
*/
|
*/
|
||||||
public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
public class SolrFacetProperties implements Serializable
|
||||||
{
|
{
|
||||||
|
private static final long serialVersionUID = 2991173095752087202L;
|
||||||
|
|
||||||
private final String filterID;
|
private final String filterID;
|
||||||
private final QName facetQName;
|
private final QName facetQName;
|
||||||
private final String displayName;
|
private final String displayName;
|
||||||
@@ -46,6 +49,7 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
private final int index;
|
private final int index;
|
||||||
private final boolean isEnabled;
|
private final boolean isEnabled;
|
||||||
private final boolean isDefault; // is loaded from properties files?
|
private final boolean isDefault; // is loaded from properties files?
|
||||||
|
private final Set<CustomProperties> customProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises a newly created <code>SolrFacetProperty</code> object
|
* Initialises a newly created <code>SolrFacetProperty</code> object
|
||||||
@@ -66,7 +70,8 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
this.index = builder.index;
|
this.index = builder.index;
|
||||||
this.isEnabled = builder.isEnabled;
|
this.isEnabled = builder.isEnabled;
|
||||||
this.isDefault = builder.isDefault;
|
this.isDefault = builder.isDefault;
|
||||||
this.scopedSites = (builder.scopedSites == null) ? null :Collections.unmodifiableSet(new HashSet<String>(builder.scopedSites));
|
this.scopedSites = Collections.unmodifiableSet(new HashSet<String>(builder.scopedSites));
|
||||||
|
this.customProperties = Collections.unmodifiableSet(new HashSet<CustomProperties>(builder.customProperties));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,16 +147,12 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an unmodifiable view of the Scoped Sites set or null
|
* Returns an unmodifiable view of the Scoped Sites set. Never null.
|
||||||
*
|
*
|
||||||
* @return the scopedSites
|
* @return the scopedSites
|
||||||
*/
|
*/
|
||||||
public Set<String> getScopedSites()
|
public Set<String> getScopedSites()
|
||||||
{
|
{
|
||||||
if (this.scopedSites == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(new HashSet<String>(this.scopedSites));
|
return Collections.unmodifiableSet(new HashSet<String>(this.scopedSites));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +182,17 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
return this.isDefault;
|
return this.isDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable view of the custom properties set. Never null.
|
||||||
|
*
|
||||||
|
* @return the customProperties
|
||||||
|
*/
|
||||||
|
public Set<CustomProperties> getCustomProperties()
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableSet(new HashSet<CustomProperties>(this.customProperties));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see java.lang.Object#hashCode()
|
* @see java.lang.Object#hashCode()
|
||||||
*/
|
*/
|
||||||
@@ -226,22 +238,13 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @see java.lang.Comparable#compareTo(T)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int compareTo(SolrFacetProperties that)
|
|
||||||
{
|
|
||||||
return Integer.compare(this.index, that.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder(320);
|
StringBuilder sb = new StringBuilder(400);
|
||||||
sb.append("FacetProperty [filterID=").append(this.filterID).append(", facetQName=")
|
sb.append("FacetProperty [filterID=").append(this.filterID).append(", facetQName=")
|
||||||
.append(this.facetQName).append(", displayName=").append(this.displayName)
|
.append(this.facetQName).append(", displayName=").append(this.displayName)
|
||||||
.append(", displayControl=").append(this.displayControl).append(", maxFilters=")
|
.append(", displayControl=").append(this.displayControl).append(", maxFilters=")
|
||||||
@@ -249,7 +252,8 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
.append(", minFilterValueLength=").append(this.minFilterValueLength).append(", sortBy=")
|
.append(", minFilterValueLength=").append(this.minFilterValueLength).append(", sortBy=")
|
||||||
.append(this.sortBy).append(", scope=").append(this.scope).append(", scopedSites=")
|
.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(", index=").append(this.index).append(", isEnabled=").append(this.isEnabled)
|
||||||
.append(", isDefault=").append(this.isDefault).append("]");
|
.append(", isDefault=").append(this.isDefault).append(", customProperties=").append(this.customProperties)
|
||||||
|
.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,10 +268,38 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
private int minFilterValueLength;
|
private int minFilterValueLength;
|
||||||
private String sortBy;
|
private String sortBy;
|
||||||
private String scope;
|
private String scope;
|
||||||
private Set<String> scopedSites;
|
private Set<String> scopedSites = Collections.emptySet();
|
||||||
private int index;
|
private int index;
|
||||||
private boolean isEnabled;
|
private boolean isEnabled;
|
||||||
private boolean isDefault;
|
private boolean isDefault;
|
||||||
|
private Set<CustomProperties> customProperties = Collections.emptySet();
|
||||||
|
|
||||||
|
public Builder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy builder
|
||||||
|
*
|
||||||
|
* @param that existing {@code SolrFacetProperties} object
|
||||||
|
*/
|
||||||
|
public Builder(SolrFacetProperties that)
|
||||||
|
{
|
||||||
|
this.filterID = that.filterID;
|
||||||
|
this.facetQName = that.facetQName;
|
||||||
|
this.displayName = that.displayName;
|
||||||
|
this.displayControl = that.displayControl;
|
||||||
|
this.maxFilters = that.maxFilters;
|
||||||
|
this.hitThreshold = that.hitThreshold;
|
||||||
|
this.minFilterValueLength = that.minFilterValueLength;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder filterID(String filterID)
|
public Builder filterID(String filterID)
|
||||||
{
|
{
|
||||||
@@ -325,7 +357,10 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
|
|
||||||
public Builder scopedSites(Set<String> scopedSites)
|
public Builder scopedSites(Set<String> scopedSites)
|
||||||
{
|
{
|
||||||
this.scopedSites = scopedSites;
|
if (scopedSites != null)
|
||||||
|
{
|
||||||
|
this.scopedSites = scopedSites;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +382,106 @@ public class SolrFacetProperties implements Comparable<SolrFacetProperties>
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder customProperties(Set<CustomProperties> customProperties)
|
||||||
|
{
|
||||||
|
if (customProperties != null)
|
||||||
|
{
|
||||||
|
this.customProperties = customProperties;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public SolrFacetProperties build()
|
public SolrFacetProperties build()
|
||||||
{
|
{
|
||||||
return new SolrFacetProperties(this);
|
return new SolrFacetProperties(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CustomProperties implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 2250062300454166258L;
|
||||||
|
|
||||||
|
private final QName name;
|
||||||
|
private final String title;
|
||||||
|
private final String type;
|
||||||
|
private final Serializable value;
|
||||||
|
|
||||||
|
public CustomProperties(QName name, String title, String type, Serializable value)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.title = title;
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QName getName()
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the title
|
||||||
|
*/
|
||||||
|
public String getTitle()
|
||||||
|
{
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type
|
||||||
|
*/
|
||||||
|
public String getType()
|
||||||
|
{
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Serializable getValue()
|
||||||
|
{
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || !(obj instanceof CustomProperties))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomProperties other = (CustomProperties) obj;
|
||||||
|
return EqualsHelper.nullSafeEquals(this.name, other.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder(100);
|
||||||
|
builder.append("CustomProperties [name=").append(this.name).append(", title=")
|
||||||
|
.append(this.title).append(", type=").append(this.type).append(", value=")
|
||||||
|
.append(this.value).append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
package org.alfresco.repo.search.impl.solr.facet;
|
package org.alfresco.repo.search.impl.solr.facet;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
@@ -34,10 +34,9 @@ public interface SolrFacetService
|
|||||||
/**
|
/**
|
||||||
* Gets all the available facets.
|
* Gets all the available facets.
|
||||||
*
|
*
|
||||||
* @return Map of {@code SolrFacetProperties} with the
|
* @return List of {@code SolrFacetProperties} or an empty list if none exists
|
||||||
* {@code SolrFacetProperties.filterID} as the key or an empty map if none exists
|
|
||||||
*/
|
*/
|
||||||
public Map<String, SolrFacetProperties> getFacets();
|
public List<SolrFacetProperties> getFacets();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the facet by filter Id.
|
* Gets the facet by filter Id.
|
||||||
@@ -86,4 +85,6 @@ public interface SolrFacetService
|
|||||||
* @param filterID the filter Id
|
* @param filterID the filter Id
|
||||||
*/
|
*/
|
||||||
public void deleteFacet(String filterID);
|
public void deleteFacet(String filterID);
|
||||||
|
|
||||||
|
public int getNextIndex();
|
||||||
}
|
}
|
||||||
|
@@ -21,24 +21,30 @@ package org.alfresco.repo.search.impl.solr.facet;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.NavigableMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentSkipListMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.cache.SimpleCache;
|
import org.alfresco.repo.cache.SimpleCache;
|
||||||
import org.alfresco.repo.node.NodeServicePolicies;
|
import org.alfresco.repo.node.NodeServicePolicies;
|
||||||
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
|
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.OnCreateNodePolicy;
|
||||||
import org.alfresco.repo.node.NodeServicePolicies.OnUpdateNodePolicy;
|
import org.alfresco.repo.node.NodeServicePolicies.OnUpdateNodePolicy;
|
||||||
import org.alfresco.repo.policy.BehaviourFilter;
|
import org.alfresco.repo.policy.BehaviourFilter;
|
||||||
import org.alfresco.repo.policy.JavaBehaviour;
|
import org.alfresco.repo.policy.JavaBehaviour;
|
||||||
import org.alfresco.repo.policy.PolicyComponent;
|
import org.alfresco.repo.policy.PolicyComponent;
|
||||||
|
import org.alfresco.repo.search.impl.solr.facet.SolrFacetProperties.CustomProperties;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
@@ -60,14 +66,13 @@ import org.springframework.context.ApplicationEvent;
|
|||||||
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author Jamal Kaabi-Mofrad
|
* @author Jamal Kaabi-Mofrad
|
||||||
*/
|
*/
|
||||||
public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrFacetService,
|
public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrFacetService,
|
||||||
NodeServicePolicies.OnCreateNodePolicy,
|
NodeServicePolicies.OnCreateNodePolicy,
|
||||||
NodeServicePolicies.OnUpdateNodePolicy,
|
NodeServicePolicies.OnUpdateNodePolicy,
|
||||||
NodeServicePolicies.BeforeDeleteNodePolicy
|
NodeServicePolicies.BeforeDeleteNodePolicy,
|
||||||
|
NodeServicePolicies.BeforeUpdateNodePolicy
|
||||||
{
|
{
|
||||||
private static final Log logger = LogFactory.getLog(SolrFacetServiceImpl.class);
|
private static final Log logger = LogFactory.getLog(SolrFacetServiceImpl.class);
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +97,8 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
private SimpleCache<String, Object> singletonCache; // eg. for facetsHomeNodeRef
|
private SimpleCache<String, Object> singletonCache; // eg. for facetsHomeNodeRef
|
||||||
private final String KEY_FACETS_HOME_NODEREF = "key.facetshome.noderef";
|
private final String KEY_FACETS_HOME_NODEREF = "key.facetshome.noderef";
|
||||||
private SimpleCache<String, NodeRef> facetNodeRefCache; // for filterID to nodeRef lookup
|
private SimpleCache<String, NodeRef> facetNodeRefCache; // for filterID to nodeRef lookup
|
||||||
private ConcurrentMap<String, SolrFacetProperties> facetsMap = new ConcurrentHashMap<>();
|
private NavigableMap<Integer, SolrFacetProperties> facetsMap = new ConcurrentSkipListMap<>();
|
||||||
|
private int maxAllowedFilters = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param authorityService the authorityService to set
|
* @param authorityService the authorityService to set
|
||||||
@@ -182,6 +188,14 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
this.facetNodeRefCache = facetNodeRefCache;
|
this.facetNodeRefCache = facetNodeRefCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param maxAllowedFilters the maxAllowedFilters to set
|
||||||
|
*/
|
||||||
|
public void setMaxAllowedFilters(int maxAllowedFilters)
|
||||||
|
{
|
||||||
|
this.maxAllowedFilters = maxAllowedFilters;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSearchAdmin(String userName)
|
public boolean isSearchAdmin(String userName)
|
||||||
{
|
{
|
||||||
@@ -194,16 +208,26 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, SolrFacetProperties> getFacets()
|
public List<SolrFacetProperties> getFacets()
|
||||||
{
|
{
|
||||||
Map<String, SolrFacetProperties> sortedMap = CollectionUtils.sortMapByValue(facetsMap);
|
return new ArrayList<>(facetsMap.values());
|
||||||
return sortedMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SolrFacetProperties getFacet(String filterID)
|
public SolrFacetProperties getFacet(String filterID)
|
||||||
{
|
{
|
||||||
return facetsMap.get(filterID);
|
/*
|
||||||
|
* Note: There is no need to worry about the state of the SolrFacetProperties returned from
|
||||||
|
* facetConfig (getDefaultLoadedFacet), as if the FP has been modified, then we'll get it from
|
||||||
|
* the nodeService.
|
||||||
|
*/
|
||||||
|
NodeRef nodeRef = getFacetNodeRef(filterID);
|
||||||
|
return (nodeRef == null) ? getDefaultLoadedFacet(filterID) : getFacetProperties(nodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SolrFacetProperties getDefaultLoadedFacet(String filterID)
|
||||||
|
{
|
||||||
|
return facetConfig.getDefaultFacets().get(filterID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -268,6 +292,12 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
List<String> scSites = (List<String>) properties.get(SolrFacetModel.PROP_SCOPED_SITES);
|
List<String> scSites = (List<String>) properties.get(SolrFacetModel.PROP_SCOPED_SITES);
|
||||||
Set<String> scopedSites = (scSites == null) ? null : new HashSet<>(scSites);
|
Set<String> scopedSites = (scSites == null) ? null : new HashSet<>(scSites);
|
||||||
|
|
||||||
|
Map<QName, Serializable> customProperties = getFacetCustomProperties(properties);
|
||||||
|
Set<CustomProperties> 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
|
// Construct the FacetProperty object
|
||||||
SolrFacetProperties fp = new SolrFacetProperties.Builder()
|
SolrFacetProperties fp = new SolrFacetProperties.Builder()
|
||||||
.filterID(filterID)
|
.filterID(filterID)
|
||||||
@@ -282,7 +312,8 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
.index(index)
|
.index(index)
|
||||||
.isEnabled(isEnabled)
|
.isEnabled(isEnabled)
|
||||||
.isDefault(isDefault)
|
.isDefault(isDefault)
|
||||||
.scopedSites(scopedSites).build();
|
.scopedSites(scopedSites)
|
||||||
|
.customProperties(extraProps).build();
|
||||||
|
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
@@ -298,9 +329,9 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
|
|
||||||
final String filterID = facetProperties.getFilterID();
|
final String filterID = facetProperties.getFilterID();
|
||||||
NodeRef facetNodeRef = getFacetNodeRef(filterID);
|
NodeRef facetNodeRef = getFacetNodeRef(filterID);
|
||||||
// We need to check the bootstrapped Facet properties as well, in order
|
// We need to check the bootstrapped Facet properties (i.e loaded from properties file(s)) as well,
|
||||||
// to not allow the user to create a new facet with the same filterID as the bootstrapped FP.
|
// in order to not allow the user to create a new facet with the same filterID as the bootstrapped FP.
|
||||||
if (facetNodeRef != null || (checkDefaultFP && getFacet(filterID) != null))
|
if (facetNodeRef != null || (checkDefaultFP && getDefaultLoadedFacet(filterID) != null))
|
||||||
{
|
{
|
||||||
throw new SolrFacetConfigException("Unable to create facet because the filterID [" + filterID + "] is already in use.");
|
throw new SolrFacetConfigException("Unable to create facet because the filterID [" + filterID + "] is already in use.");
|
||||||
}
|
}
|
||||||
@@ -312,7 +343,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
throw new SolrFacetConfigException("Facets root folder does not exist.");
|
throw new SolrFacetConfigException("Facets root folder does not exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return facetNodeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
return facetNodeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public NodeRef doWork() throws Exception
|
public NodeRef doWork() throws Exception
|
||||||
@@ -324,7 +355,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
behaviourFilter.disableBehaviour(facetRoot, ContentModel.ASPECT_AUDITABLE);
|
behaviourFilter.disableBehaviour(facetRoot, ContentModel.ASPECT_AUDITABLE);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Map<QName, Serializable> properties = createNodeProperties(facetProperties, true);
|
Map<QName, Serializable> properties = createNodeProperties(facetProperties);
|
||||||
// We don't want the node to be indexed
|
// We don't want the node to be indexed
|
||||||
properties.put(ContentModel.PROP_IS_INDEXED, false);
|
properties.put(ContentModel.PROP_IS_INDEXED, false);
|
||||||
NodeRef ref = nodeService.createNode(facetRoot, ContentModel.ASSOC_CONTAINS,
|
NodeRef ref = nodeService.createNode(facetRoot, ContentModel.ASSOC_CONTAINS,
|
||||||
@@ -355,7 +386,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
NodeRef facetNodeRef = getFacetNodeRef(filterID);
|
NodeRef facetNodeRef = getFacetNodeRef(filterID);
|
||||||
if (facetNodeRef == null)
|
if (facetNodeRef == null)
|
||||||
{
|
{
|
||||||
SolrFacetProperties fp = getFacet(filterID);
|
SolrFacetProperties fp = getDefaultLoadedFacet(filterID);
|
||||||
if (fp != null)
|
if (fp != null)
|
||||||
{
|
{
|
||||||
// As we don't create nodes for the bootstrapped FP on server
|
// As we don't create nodes for the bootstrapped FP on server
|
||||||
@@ -370,7 +401,12 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Map<QName, Serializable> properties = createNodeProperties(facetProperties, false);
|
String name = (String) nodeService.getProperty(facetNodeRef, ContentModel.PROP_NAME);
|
||||||
|
if (!filterID.equals(name))
|
||||||
|
{
|
||||||
|
throw new SolrFacetConfigException("The filterID cannot be renamed.");
|
||||||
|
}
|
||||||
|
Map<QName, Serializable> properties = createNodeProperties(facetProperties);
|
||||||
// Set the updated properties back onto the facet node reference
|
// Set the updated properties back onto the facet node reference
|
||||||
this.nodeService.setProperties(facetNodeRef, properties);
|
this.nodeService.setProperties(facetNodeRef, properties);
|
||||||
}
|
}
|
||||||
@@ -384,17 +420,16 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
public void deleteFacet(String filterID)
|
public void deleteFacet(String filterID)
|
||||||
{
|
{
|
||||||
NodeRef facetNodeRef = getFacetNodeRef(filterID);
|
NodeRef facetNodeRef = getFacetNodeRef(filterID);
|
||||||
SolrFacetProperties defaultFP = facetConfig.getDefaultFacets().get(filterID);
|
if (facetNodeRef == null)
|
||||||
if(defaultFP != null)
|
|
||||||
{
|
|
||||||
throw new SolrFacetConfigException("The default [" + filterID + "] facet cannot be deleted. It can only be disabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(facetNodeRef == null)
|
|
||||||
{
|
{
|
||||||
throw new SolrFacetConfigException("The [" + filterID + "] facet cannot be found.");
|
throw new SolrFacetConfigException("The [" + filterID + "] facet cannot be found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SolrFacetProperties defaultFP = getDefaultLoadedFacet(filterID);
|
||||||
|
if (defaultFP != null)
|
||||||
|
{
|
||||||
|
throw new SolrFacetConfigException("The default [" + filterID + "] facet cannot be deleted. It can only be disabled.");
|
||||||
|
}
|
||||||
nodeService.deleteNode(facetNodeRef);
|
nodeService.deleteNode(facetNodeRef);
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
@@ -402,19 +437,17 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<QName, Serializable> createNodeProperties(SolrFacetProperties facetProperties, boolean withFilterId)
|
private Map<QName, Serializable> createNodeProperties(SolrFacetProperties facetProperties)
|
||||||
{
|
{
|
||||||
if (facetProperties.getFilterID() == null)
|
if (facetProperties.getFilterID() == null)
|
||||||
{
|
{
|
||||||
throw new SolrFacetConfigException("Filter Id cannot be null.");
|
throw new SolrFacetConfigException("Filter Id cannot be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(14);
|
Set<CustomProperties> customProperties = facetProperties.getCustomProperties();
|
||||||
|
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(14 + customProperties.size());
|
||||||
|
|
||||||
if (withFilterId)
|
properties.put(ContentModel.PROP_NAME, facetProperties.getFilterID());
|
||||||
{
|
|
||||||
properties.put(ContentModel.PROP_NAME, facetProperties.getFilterID());
|
|
||||||
}
|
|
||||||
properties.put(SolrFacetModel.PROP_FIELD_TYPE, facetProperties.getFacetQName());
|
properties.put(SolrFacetModel.PROP_FIELD_TYPE, facetProperties.getFacetQName());
|
||||||
properties.put(SolrFacetModel.PROP_FIELD_LABEL, facetProperties.getDisplayName());
|
properties.put(SolrFacetModel.PROP_FIELD_LABEL, facetProperties.getDisplayName());
|
||||||
properties.put(SolrFacetModel.PROP_DISPLAY_CONTROL, facetProperties.getDisplayControl());
|
properties.put(SolrFacetModel.PROP_DISPLAY_CONTROL, facetProperties.getDisplayControl());
|
||||||
@@ -427,9 +460,14 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
properties.put(SolrFacetModel.PROP_INDEX, facetProperties.getIndex());
|
properties.put(SolrFacetModel.PROP_INDEX, facetProperties.getIndex());
|
||||||
properties.put(SolrFacetModel.PROP_IS_ENABLED, facetProperties.isEnabled());
|
properties.put(SolrFacetModel.PROP_IS_ENABLED, facetProperties.isEnabled());
|
||||||
|
|
||||||
SolrFacetProperties fp = facetConfig.getDefaultFacets().get(facetProperties.getFilterID());
|
SolrFacetProperties fp = getDefaultLoadedFacet(facetProperties.getFilterID());
|
||||||
properties.put(SolrFacetModel.PROP_IS_DEFAULT, (fp == null) ? false : fp.isDefault());
|
properties.put(SolrFacetModel.PROP_IS_DEFAULT, (fp == null) ? false : fp.isDefault());
|
||||||
|
|
||||||
|
for (CustomProperties cp : customProperties)
|
||||||
|
{
|
||||||
|
properties.put(cp.getName(), cp.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +506,6 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
return facetHomeRef;
|
return facetHomeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBootstrap(ApplicationEvent event)
|
protected void onBootstrap(ApplicationEvent event)
|
||||||
{
|
{
|
||||||
@@ -478,46 +515,89 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
SolrFacetModel.TYPE_FACET_FIELD,
|
SolrFacetModel.TYPE_FACET_FIELD,
|
||||||
new JavaBehaviour(this, "onCreateNode"));
|
new JavaBehaviour(this, "onCreateNode"));
|
||||||
|
|
||||||
|
// Filter before update
|
||||||
|
this.policyComponent.bindClassBehaviour(
|
||||||
|
BeforeUpdateNodePolicy.QNAME,
|
||||||
|
SolrFacetModel.TYPE_FACET_FIELD,
|
||||||
|
new JavaBehaviour(this, "beforeUpdateNode"));
|
||||||
|
|
||||||
// Filter update
|
// Filter update
|
||||||
this.policyComponent.bindClassBehaviour(
|
this.policyComponent.bindClassBehaviour(
|
||||||
OnUpdateNodePolicy.QNAME,
|
OnUpdateNodePolicy.QNAME,
|
||||||
SolrFacetModel.TYPE_FACET_FIELD,
|
SolrFacetModel.TYPE_FACET_FIELD,
|
||||||
new JavaBehaviour(this, "onUpdateNode"));
|
new JavaBehaviour(this, "onUpdateNode"));
|
||||||
|
|
||||||
// Filter deletion
|
// Filter before deletion
|
||||||
this.policyComponent.bindClassBehaviour(
|
this.policyComponent.bindClassBehaviour(
|
||||||
BeforeDeleteNodePolicy.QNAME,
|
BeforeDeleteNodePolicy.QNAME,
|
||||||
SolrFacetModel.TYPE_FACET_FIELD,
|
SolrFacetModel.TYPE_FACET_FIELD,
|
||||||
new JavaBehaviour(this, "beforeDeleteNode"));
|
new JavaBehaviour(this, "beforeDeleteNode"));
|
||||||
|
|
||||||
|
Map<String, SolrFacetProperties> mergedMap = new HashMap<>(100);
|
||||||
|
// Loaded facets
|
||||||
Map<String, SolrFacetProperties> defaultFP = facetConfig.getDefaultFacets();
|
Map<String, SolrFacetProperties> defaultFP = facetConfig.getDefaultFacets();
|
||||||
for(Entry<String, SolrFacetProperties> fpEntry : defaultFP.entrySet())
|
mergedMap.putAll(defaultFP);
|
||||||
{
|
|
||||||
facetsMap.put(fpEntry.getKey(), fpEntry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SolrFacetProperties> persistedProperties = getPersistedFacetProperties();
|
// Persisted facets
|
||||||
|
Map<String, SolrFacetProperties> persistedProperties = getPersistedFacetProperties();
|
||||||
// The persisted facets will override the default facets
|
// The persisted facets will override the default facets
|
||||||
for(SolrFacetProperties fp : persistedProperties)
|
mergedMap.putAll(persistedProperties);
|
||||||
|
|
||||||
|
// Sort the merged maps
|
||||||
|
Map<String, SolrFacetProperties> sortedMap = CollectionUtils.sortMapByValue(mergedMap, getIndextComparator());
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
facetsMap.put(fp.getFilterID(), fp);
|
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)
|
if (logger.isDebugEnabled() && persistedProperties.size() > 0)
|
||||||
{
|
{
|
||||||
logger.debug("The facets [" + persistedProperties + "] have overridden their matched default facets.");
|
logger.debug("The facets [" + persistedProperties + "] have overridden their matched default facets.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SolrFacetProperties> getPersistedFacetProperties()
|
private Map<String, SolrFacetProperties> getPersistedFacetProperties()
|
||||||
{
|
{
|
||||||
List<ChildAssociationRef> list = nodeService.getChildAssocs(getFacetsRoot());
|
List<ChildAssociationRef> list = nodeService.getChildAssocs(getFacetsRoot());
|
||||||
|
|
||||||
List<SolrFacetProperties> facets = new ArrayList<>(list.size());
|
Map<String, SolrFacetProperties> facets = new HashMap<>(list.size());
|
||||||
for (ChildAssociationRef associationRef : list)
|
for (ChildAssociationRef associationRef : list)
|
||||||
{
|
{
|
||||||
SolrFacetProperties fp = getFacetProperties(associationRef.getChildRef());
|
SolrFacetProperties fp = getFacetProperties(associationRef.getChildRef());
|
||||||
facets.add(fp);
|
facets.put(fp.getFilterID(), fp);
|
||||||
}
|
}
|
||||||
return facets;
|
return facets;
|
||||||
}
|
}
|
||||||
@@ -528,18 +608,26 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
// nothing to do
|
// 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
|
@Override
|
||||||
public void onUpdateNode(NodeRef nodeRef)
|
public void onUpdateNode(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
SolrFacetProperties fp = getFacetProperties(nodeRef);
|
SolrFacetProperties fp = getFacetProperties(nodeRef);
|
||||||
this.facetsMap.put(fp.getFilterID(), fp);
|
this.facetsMap.put(fp.getIndex(), fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||||
{
|
{
|
||||||
SolrFacetProperties fp = getFacetProperties(childAssocRef.getChildRef());
|
SolrFacetProperties fp = getFacetProperties(childAssocRef.getChildRef());
|
||||||
this.facetsMap.put(fp.getFilterID(), fp);
|
this.facetsMap.put(fp.getIndex(), fp);
|
||||||
this.facetNodeRefCache.put(fp.getFilterID(), childAssocRef.getChildRef());
|
this.facetNodeRefCache.put(fp.getFilterID(), childAssocRef.getChildRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,7 +635,106 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF
|
|||||||
public void beforeDeleteNode(NodeRef nodeRef)
|
public void beforeDeleteNode(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
String filterID = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
|
String filterID = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
|
||||||
this.facetsMap.remove(filterID);
|
int index = (Integer) nodeService.getProperty(nodeRef, SolrFacetModel.PROP_INDEX);
|
||||||
|
|
||||||
|
this.facetsMap.remove(index);
|
||||||
this.facetNodeRefCache.remove(filterID);
|
this.facetNodeRefCache.remove(filterID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: this comparator imposes orderings that are inconsistent with equals
|
||||||
|
* method of the {@link SolrFacetProperties}."
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Comparator<Entry<String, SolrFacetProperties>> getIndextComparator()
|
||||||
|
{
|
||||||
|
return new Comparator<Entry<String, SolrFacetProperties>>()
|
||||||
|
{
|
||||||
|
public int compare(Entry<String, SolrFacetProperties> facet1,
|
||||||
|
Entry<String, SolrFacetProperties> facet2)
|
||||||
|
{
|
||||||
|
return Integer.compare(facet1.getValue().getIndex(), facet2.getValue().getIndex());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
*
|
||||||
|
* @return Map<QName, Serializable> map containing the custom properties of the facet
|
||||||
|
*/
|
||||||
|
private Map<QName, Serializable> getFacetCustomProperties(Map<QName, Serializable> properties)
|
||||||
|
{
|
||||||
|
Map<QName, Serializable> customProperties = new HashMap<QName, Serializable>(5);
|
||||||
|
|
||||||
|
for (Map.Entry<QName, Serializable> entry : properties.entrySet())
|
||||||
|
{
|
||||||
|
if (SolrFacetModel.SOLR_FACET_CUSTOM_PROPERTY_URL.equals(entry.getKey().getNamespaceURI()))
|
||||||
|
{
|
||||||
|
customProperties.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user