- Refactored facet display handlers

- Changed date buckets implementation to use Solr Date math
- Added Site title display handler as well as a test for it
- Reverted back Neil’s work to inject the "special" facet IDs (SITE, TAG etc) from the solr-facets-context.xml as I re-wrote the SolrFacetHelper class.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85946 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2014-09-29 21:14:26 +00:00
parent 1ae074b266
commit fc8c649191
20 changed files with 1184 additions and 907 deletions

View File

@@ -113,6 +113,12 @@
<property name="repositoryHelper"> <property name="repositoryHelper">
<ref bean="repositoryHelper"/> <ref bean="repositoryHelper"/>
</property> </property>
<property name="solrFacetHelper">
<ref bean="facet.solrFacetHelper"/>
</property>
<property name="facetLabelDisplayHandlerRegistry">
<ref bean="facet.facetLabelDisplayHandlerRegistry"/>
</property>
<property name="storeUrl"> <property name="storeUrl">
<value>${spaces.store}</value> <value>${spaces.store}</value>
</property> </property>

View File

@@ -43,4 +43,118 @@
<value>${solr_facets.root}</value> <value>${solr_facets.root}</value>
</property> </property>
</bean> </bean>
<!-- Facet Label Display Handler Registry -->
<bean id="facet.facetLabelDisplayHandlerRegistry" class="org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandlerRegistry" />
<!-- Abstract bean, defining base definition for all facet label display handlers -->
<bean id="baseFacetLabelDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.AbstractFacetLabelDisplayHandler"
abstract="true" init-method="register">
<property name="registry">
<ref bean="facet.facetLabelDisplayHandlerRegistry" />
</property>
<property name="serviceRegistry">
<ref bean="ServiceRegistry" />
</property>
</bean>
<bean id="facet.mimetypeDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.MimetypeDisplayHandler" parent="baseFacetLabelDisplayHandler" >
<constructor-arg>
<set>
<value>@{http://www.alfresco.org/model/content/1.0}content.mimetype</value>
</set>
</constructor-arg>
</bean>
<bean id="facet.userNameDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.UserNameDisplayHandler" parent="baseFacetLabelDisplayHandler" >
<constructor-arg>
<set>
<value>@{http://www.alfresco.org/model/content/1.0}creator</value>
<value>@{http://www.alfresco.org/model/content/1.0}modifier</value>
</set>
</constructor-arg>
</bean>
<bean id="facet.siteTitleDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.SiteTitleDisplayHandler" parent="baseFacetLabelDisplayHandler" >
<constructor-arg>
<set>
<value>SITE</value>
</set>
</constructor-arg>
</bean>
<bean id="facet.contentSizeBucketsDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.ContentSizeBucketsDisplayHandler" parent="baseFacetLabelDisplayHandler" >
<constructor-arg index="0">
<set>
<value>@{http://www.alfresco.org/model/content/1.0}content.size</value>
</set>
</constructor-arg>
<constructor-arg index="1">
<bean class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.LinkedHashMap</value>
</property>
<property name="sourceMap">
<map>
<entry key="[0 TO 10240]" value="faceted-search.size.0-10KB.label" />
<entry key="[10240 TO 102400]" value="faceted-search.size.10-100KB.label" />
<entry key="[102400 TO 1048576]" value="faceted-search.size.100KB-1MB.label" />
<entry key="[1048576 TO 16777216]" value="faceted-search.size.1-16MB.label" />
<entry key="[16777216 TO 134217728]" value="faceted-search.size.16-128MB.label" />
<entry key="[134217728 TO MAX]" value="faceted-search.size.over128.label" />
</map>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="facet.dateBucketsDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.DateBucketsDisplayHandler" parent="baseFacetLabelDisplayHandler" >
<constructor-arg index="0">
<set>
<value>@{http://www.alfresco.org/model/content/1.0}created</value>
<value>@{http://www.alfresco.org/model/content/1.0}modified</value>
</set>
</constructor-arg>
<constructor-arg index="1">
<bean class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.LinkedHashMap</value>
</property>
<property name="sourceMap">
<map>
<!-- Bucket => yesterday TO today -->
<entry key="[NOW/DAY-1DAY TO NOW/DAY+1DAY]" value="faceted-search.date.one-day.label" />
<!-- Bucket => Last week TO today -->
<entry key="[NOW/DAY-7DAYS TO NOW/DAY+1DAY]" value="faceted-search.date.one-week.label" />
<!-- Bucket => Last month TO today -->
<entry key="[NOW/DAY-1MONTH TO NOW/DAY+1DAY]" value="faceted-search.date.one-month.label" />
<!-- Bucket => Last 6 months TO today -->
<entry key="[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]" value="faceted-search.date.six-months.label" />
<!-- Bucket => Last year TO today -->
<entry key="[NOW/DAY-1YEAR TO NOW/DAY+1DAY]" value="faceted-search.date.one-year.label" />
</map>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="facet.solrFacetHelper" class="org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper" >
<constructor-arg>
<list>
<ref bean="facet.contentSizeBucketsDisplayHandler" />
<ref bean="facet.dateBucketsDisplayHandler" />
</list>
</constructor-arg>
<property name="specialFacetIds">
<set>
<value>SITE</value>
<value>TAG</value>
<value>ANCESTOR</value>
<value>PARENT</value>
<value>ASPECT</value>
<value>TYPE</value>
<value>OWNER</value>
</set>
</property>
</bean>
</beans> </beans>

View File

@@ -15,41 +15,41 @@ default.cm\:content.mimetype.scope=ALL
default.cm\:content.mimetype.scopedSites= default.cm\:content.mimetype.scopedSites=
default.cm\:content.mimetype.isEnabled=true default.cm\:content.mimetype.isEnabled=true
# Field-Facet-Qname => cm:description.__ # Field-Facet-Qname => cm:description
default.cm\:description.__.filterID=filter_description default.cm\:description.filterID=filter_description
default.cm\:description.__.displayName=faceted-search.facet-menu.facet.description default.cm\:description.displayName=faceted-search.facet-menu.facet.description
default.cm\:description.__.displayControl=alfresco/search/FacetFilters default.cm\:description.displayControl=alfresco/search/FacetFilters
default.cm\:description.__.maxFilters=5 default.cm\:description.maxFilters=5
default.cm\:description.__.hitThreshold=1 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=ALL default.cm\:description.scope=ALL
default.cm\:description.__.scopedSites= default.cm\:description.scopedSites=
default.cm\:description.__.isEnabled=false default.cm\:description.isEnabled=false
# Field-Facet-Qname => cm:creator.__.u # Field-Facet-Qname => cm:creator
default.cm\:creator.__.u.filterID=filter_creator default.cm\:creator.filterID=filter_creator
default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator default.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters default.cm\:creator.displayControl=alfresco/search/FacetFilters
default.cm\:creator.__.u.maxFilters=5 default.cm\:creator.maxFilters=5
default.cm\:creator.__.u.hitThreshold=1 default.cm\:creator.hitThreshold=1
default.cm\:creator.__.u.minFilterValueLength=4 default.cm\:creator.minFilterValueLength=4
default.cm\:creator.__.u.sortBy=ALPHABETICALLY default.cm\:creator.sortBy=ALPHABETICALLY
default.cm\:creator.__.u.scope=ALL default.cm\:creator.scope=ALL
default.cm\:creator.__.u.scopedSites= default.cm\:creator.scopedSites=
default.cm\:creator.__.u.isEnabled=true default.cm\:creator.isEnabled=true
# Field-Facet-Qname => cm:modifier.__.u # Field-Facet-Qname => cm:modifier
default.cm\:modifier.__.u.filterID=filter_modifier default.cm\:modifier.filterID=filter_modifier
default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier default.cm\:modifier.displayName=faceted-search.facet-menu.facet.modifier
default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters default.cm\:modifier.displayControl=alfresco/search/FacetFilters
default.cm\:modifier.__.u.maxFilters=5 default.cm\:modifier.maxFilters=5
default.cm\:modifier.__.u.hitThreshold=1 default.cm\:modifier.hitThreshold=1
default.cm\:modifier.__.u.minFilterValueLength=4 default.cm\:modifier.minFilterValueLength=4
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY default.cm\:modifier.sortBy=ALPHABETICALLY
default.cm\:modifier.__.u.scope=ALL default.cm\:modifier.scope=ALL
default.cm\:modifier.__.u.scopedSites= default.cm\:modifier.scopedSites=
default.cm\:modifier.__.u.isEnabled=true default.cm\:modifier.isEnabled=true
# Field-Facet-Qname => cm:created # Field-Facet-Qname => cm:created
default.cm\:created.filterID=filter_created default.cm\:created.filterID=filter_created
@@ -62,7 +62,6 @@ default.cm\:created.sortBy=ALPHABETICALLY
default.cm\:created.scope=ALL default.cm\:created.scope=ALL
default.cm\:created.scopedSites= default.cm\:created.scopedSites=
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
@@ -75,7 +74,6 @@ default.cm\:modified.sortBy=ALPHABETICALLY
default.cm\:modified.scope=ALL default.cm\:modified.scope=ALL
default.cm\:modified.scopedSites= default.cm\:modified.scopedSites=
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
@@ -88,4 +86,3 @@ default.cm\:content.size.sortBy=ALPHABETICALLY
default.cm\:content.size.scope=ALL default.cm\:content.size.scope=ALL
default.cm\:content.size.scopedSites= default.cm\:content.size.scopedSites=
default.cm\:content.size.isEnabled=true default.cm\:content.size.isEnabled=true
default.cm\:content.size.EXTRA-PROP.blockIncludeFacetRequest=true

View File

@@ -34,8 +34,9 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory;
import org.alfresco.repo.model.Repository; import org.alfresco.repo.model.Repository;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper; import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper.FacetLabel; import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabel;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper.FacetLabelDisplayHandler; import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandler;
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandlerRegistry;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -96,12 +97,14 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
/** Solr facet helper */ /** Solr facet helper */
private SolrFacetHelper solrFacetHelper; private SolrFacetHelper solrFacetHelper;
private FacetLabelDisplayHandlerRegistry facetLabelDisplayHandlerRegistry;
@Override @Override
public void afterPropertiesSet() throws Exception public void afterPropertiesSet() throws Exception
{ {
PropertyCheck.mandatory(this, "services", services); PropertyCheck.mandatory(this, "services", services);
this.solrFacetHelper = new SolrFacetHelper(services); PropertyCheck.mandatory(this, "solrFacetHelper", solrFacetHelper);
PropertyCheck.mandatory(this, "facetLabelDisplayHandlerRegistry", facetLabelDisplayHandlerRegistry);
} }
/** /**
@@ -146,6 +149,20 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
// JavaScript API // JavaScript API
/**
* @param solrFacetHelper the solrFacetHelper to set
*/
public void setSolrFacetHelper(SolrFacetHelper solrFacetHelper)
{
this.solrFacetHelper = solrFacetHelper;
}
/**
* @param facetLabelDisplayHandlerRegistry the facetLabelDisplayHandlerRegistry to set
*/
public void setFacetLabelDisplayHandlerRegistry(FacetLabelDisplayHandlerRegistry facetLabelDisplayHandlerRegistry)
{
this.facetLabelDisplayHandlerRegistry = facetLabelDisplayHandlerRegistry;
}
public String getSearchSubsystem() public String getSearchSubsystem()
{ {
return (searchSubsystem == null) ? "" : searchSubsystem.getCurrentSourceBeanName(); return (searchSubsystem == null) ? "" : searchSubsystem.getCurrentSourceBeanName();
@@ -717,34 +734,28 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
{ {
for (String field: facets) for (String field: facets)
{ {
final FieldFacet fieldFacet; final String modifiedField = "@" + field;
if (solrFacetHelper.isSpecialFacetId(field)) if (solrFacetHelper.hasFacetQueries(modifiedField))
{ {
fieldFacet = new FieldFacet(field); List<String> facetQueries = solrFacetHelper.getFacetQueries(modifiedField);
addFacetQuery(sp, field, facetQueries, query);
} }
else else
{ {
fieldFacet = new FieldFacet("@" + field); final FieldFacet fieldFacet;
if (solrFacetHelper.isSpecialFacetId(field))
{
fieldFacet = new FieldFacet(field);
}
else
{
fieldFacet = new FieldFacet(modifiedField);
}
sp.addFieldFacet(fieldFacet);
} }
sp.addFieldFacet(fieldFacet);
}
List<String> facetQueries = null;
// Workaround for ACE-1605
if (query.indexOf("created:") < 0 && query.indexOf("modified:") < 0)
{
facetQueries = solrFacetHelper.getDefaultFacetQueries();
}
else
{
facetQueries = solrFacetHelper.createFacetQueriesFromSearchQuery(query);
}
for (String fq : facetQueries)
{
sp.addFacetQuery(fq);
} }
} }
// error handling opions // error handling opions
boolean exceptionOnError = true; boolean exceptionOnError = true;
if (onerror != null) if (onerror != null)
@@ -954,7 +965,7 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
if (f.getSecond() > 0) if (f.getSecond() > 0)
{ {
String facetValue = f.getFirst(); String facetValue = f.getFirst();
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(ff.getField()); FacetLabelDisplayHandler handler = facetLabelDisplayHandlerRegistry.getDisplayHandler(ff.getField());
String label = (handler == null) ? facetValue : handler.getDisplayLabel(facetValue).getLabel(); String label = (handler == null) ? facetValue : handler.getDisplayLabel(facetValue).getLabel();
facets.add(new ScriptFacetResult(facetValue, label, -1, f.getSecond())); facets.add(new ScriptFacetResult(facetValue, label, -1, f.getSecond()));
@@ -979,23 +990,23 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
if (entry.getValue() > 0) if (entry.getValue() > 0)
{ {
String key = entry.getKey(); String key = entry.getKey();
// for example the key could be: {!afts}@{http://www.alfresco.org/model/content/1.0}created:[2013-10-29 TO 2014-04-29] // for example the key could be: {!afts}@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1DAY TO NOW/DAY+1DAY]
// qName => @{http://www.alfresco.org/model/content/1.0}created // qName => @{http://www.alfresco.org/model/content/1.0}created
// 7 => {!afts} // 7 => {!afts}
String qName = key.substring(7, key.lastIndexOf(':')); key = key.substring(7);
String qName = key.substring(0, key.lastIndexOf(':'));
// Retrieve the previous facet queries // Retrieve the previous facet queries
List<ScriptFacetResult> fqs = facetMeta.get(qName); List<ScriptFacetResult> fqs = facetMeta.get(qName);
if (fqs == null) if (fqs == null)
{ {
// Shouldn't be here fqs = new ArrayList<>();
throw new AlfrescoRuntimeException("Field facet [" + qName + "] has" logger.info("Field facet [" + key + "] has not been registered.");
+ " not been registered with SolrFacetHelper.BUCKETED_FIELD_FACETS.");
} }
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(qName); // Get the handler for this qName
FacetLabel facetLabel = (handler == null) ? new FacetLabel(qName, key.substring(qName.length(), FacetLabelDisplayHandler handler = facetLabelDisplayHandlerRegistry.getDisplayHandler(qName);
key.length()), -1) : handler.getDisplayLabel(key); FacetLabel facetLabel = (handler == null) ? new FacetLabel(key, key, -1) : handler.getDisplayLabel(key);
fqs.add(new ScriptFacetResult(facetLabel.getValue(), facetLabel.getLabel(), facetLabel.getLabelIndex(), entry.getValue())); fqs.add(new ScriptFacetResult(facetLabel.getValue(), facetLabel.getLabel(), facetLabel.getLabelIndex(), entry.getValue()));
} }
}// End of bucketing }// End of bucketing
@@ -1037,6 +1048,33 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
return new Pair<Object[], Map<String,Object>>(res, meta); return new Pair<Object[], Map<String,Object>>(res, meta);
} }
/**
* Adds facet queries to the {@code SearchParameters}
*
* @param sp the SearchParameters
* @param field the requested field facet
* @param facetQueries list of generated facet queries
* @param query the requested search query
*/
protected void addFacetQuery(SearchParameters sp, String field, List<String> facetQueries, String query)
{
// Workaround for ACE-1605
if (query.indexOf(field) < 0)
{
for (String fq : facetQueries)
{
sp.addFacetQuery(fq);
}
}
else
{
String fq = solrFacetHelper.createFacetQueriesFromSearchQuery(field, query);
if (fq != null)
{
sp.addFacetQuery(fq);
}
}
}
/** /**
* Search sort column * Search sort column

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet;
import java.util.List;
import java.util.Map;
/**
* A contract for classes which need to create a set of predefined facet queries.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public interface FacetQueryProvider
{
/**
* Gets the created facet queries
*
* @return read-only map of facet queries or an empty map.
*/
public Map<String, List<String>> getFacetQueries();
}

View File

@@ -16,273 +16,104 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.alfresco.repo.search.impl.solr.facet; package org.alfresco.repo.search.impl.solr.facet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.util.PropertyCheck;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
/** /**
* A helper class to overcome the limitation of Solr 1.4 for dealing with facets. * A helper class for facet queries.
* <p>
* Notice: probably this class or most of its functionalities will be removed
* when we upgrade to Solr 4
* *
* @author Jamal Kaabi-Mofrad * @author Jamal Kaabi-Mofrad
* @since 5.0
*/ */
// TODO use Solr4 date math for date buckets...
public class SolrFacetHelper public class SolrFacetHelper
{ {
private static Log logger = LogFactory.getLog(SolrFacetHelper.class); private static Log logger = LogFactory.getLog(SolrFacetHelper.class);
private static final String FQ_NS_PREFIX = "@{http://www.alfresco.org/model/content/1.0}"; private final Map<String, List<String>> facetQueries;
private static final String CREATED_FIELD_FACET_QUERY = FQ_NS_PREFIX + "created";
private static final String MODIFIED_FIELD_FACET_QUERY = FQ_NS_PREFIX + "modified";
private static final String CONTENT_SIZE_FIELD_FACET_QUERY = FQ_NS_PREFIX + "content.size";
// Content size buckets
private static final int KB = 1024;
private static final int MB = KB * 1024;
private static final int TINY = 10 * KB;
private static final int SMALL = 100 * KB;
private static final int MEDIUM = MB;
private static final int LARGE = 16 * MB;
private static final int HUGE = 128 * MB;
private static final String SIZE_BUCKETS_CACHE_KEY = "sizeBucketsCacheKey"; /** These facet IDs are recognised by SOLR and can be used directly within faceted searches. */
private Set<String> specialFacetIds = Collections.emptySet();
// Positive-look-behind RegEx.
// E.g. pattern-input => {http://www.alfresco.org/model/content/1.0}created:("2014-04-07".."2014-05-07")
// the matcher-output => 2014-04-07".."2014-05-07
/** Pattern to search for created date */
private static final Pattern CREATED_DATE_PATTERN = Pattern.compile("(?<=created:\\(\")(\\d{4}-\\d{2}-\\d{2})(\"..\")(\\d{4}-\\d{2}-\\d{2})");
/** Pattern to search for modified date */
private static final Pattern MODIFIED_DATE_PATTERN = Pattern.compile("(?<=modified:\\(\")(\\d{4}-\\d{2}-\\d{2})(\"..\")(\\d{4}-\\d{2}-\\d{2})");
/** Content size buckets */
private static final List<String> CONTENT_SIZE_BUCKETS = new ArrayList<>(6);
static
{
CONTENT_SIZE_BUCKETS.add("0 TO " + TINY);
CONTENT_SIZE_BUCKETS.add(TINY + " TO " + SMALL);
CONTENT_SIZE_BUCKETS.add(SMALL + " TO " + MEDIUM);
CONTENT_SIZE_BUCKETS.add(MEDIUM + " TO " + LARGE);
CONTENT_SIZE_BUCKETS.add(LARGE + " TO " + HUGE);
CONTENT_SIZE_BUCKETS.add(HUGE + " TO MAX");
}
/** Field facet buckets */
private static final Set<String> BUCKETED_FIELD_FACETS = new HashSet<>(3);
static
{
BUCKETED_FIELD_FACETS.add(CREATED_FIELD_FACET_QUERY);
BUCKETED_FIELD_FACETS.add(MODIFIED_FIELD_FACET_QUERY);
BUCKETED_FIELD_FACETS.add(CONTENT_SIZE_FIELD_FACET_QUERY);
}
/** These facet IDs are recognised by SOLR and can be used directly within facetted searches. */
private final List<String> specialFacetIds = Arrays.asList(new String[] {
"SITE", "TAG", "ANCESTOR",
"PARENT", "ASPECT", "TYPE", "OWNER" });
/** Facet value and facet query display label handlers */
private Map<String, FacetLabelDisplayHandler> displayHandlers;
/** Thread safe cache for storing the Date buckets facet query */
private BucketsCache<LocalDate, List<String>> fqDateCache = null;
/** /**
* Constructor * Constructor
* *
* @param serviceRegistry * @param serviceRegistry
*/ */
public SolrFacetHelper(ServiceRegistry serviceRegistry) public SolrFacetHelper(List<FacetQueryProvider> facetQueryProviders)
{ {
this.fqDateCache = new BucketsCache<>(new FacetQueryParamDateBuckets()); PropertyCheck.mandatory(this, "facetQueryProviders", facetQueryProviders);
this.displayHandlers = new HashMap<>(6);
facetQueries = new LinkedHashMap<>();
UserNameDisplayHandler userNameDisplayHandler = new UserNameDisplayHandler(serviceRegistry); for (FacetQueryProvider queryProvider : facetQueryProviders)
MimetypeDisplayHandler mimetypeDisplayHandler = new MimetypeDisplayHandler(serviceRegistry); {
DateBucketsDisplayHandler dateBucketsDisplayHandler = new DateBucketsDisplayHandler(); for (Entry<String, List<String>> entry : queryProvider.getFacetQueries().entrySet())
ContentSizeBucketsDisplayHandler contentSizeBucketsDisplayHandler = new ContentSizeBucketsDisplayHandler(); {
facetQueries.put(entry.getKey(), entry.getValue());
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}creator.__.u", userNameDisplayHandler); }
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}modifier.__.u", userNameDisplayHandler); }
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}content.mimetype", mimetypeDisplayHandler);
this.displayHandlers.put(CREATED_FIELD_FACET_QUERY, dateBucketsDisplayHandler);
this.displayHandlers.put(MODIFIED_FIELD_FACET_QUERY, dateBucketsDisplayHandler);
this.displayHandlers.put(CONTENT_SIZE_FIELD_FACET_QUERY, contentSizeBucketsDisplayHandler);
} }
public void setSpecialFacetIds(Set<String> ids)
{
this.specialFacetIds = ids;
}
/** /**
* Gets the predefined set of facet queries. Currently the facet queries are: * Gets the predefined set of facet queries. Currently the facet queries
* <li>Created date buckets</li> * are: <li>Created date buckets</li> <li>Modified date buckets</li> <li>
* <li>Modified date buckets</li> * Content size buckets</li>
* <li>Content size buckets</li>
* *
* @return list of facet queries * @return list of facet queries
*/ */
public List<String> getDefaultFacetQueries() public List<String> getDefaultFacetQueries()
{ {
List<String> facetQueries = new ArrayList<>(); Collection<List<String>> queries = facetQueries.values();
List<String> dateBuckets = getDateBuckets(); List<String> list = new ArrayList<String>();
for (List<String> q : queries)
// Created and Modified dates facet queries
for (String bucket : dateBuckets)
{ {
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + bucket + ']'); list.addAll(q);
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + bucket + ']');
} }
return list;
// Content size facet query
for (String bucket : CONTENT_SIZE_BUCKETS)
{
facetQueries.add(CONTENT_SIZE_FIELD_FACET_QUERY + ":[" + bucket + ']');
}
return facetQueries;
}
/**
* Creates <i>Created</i> and <i>Modified</i> facet queries by trying to
* extract the date range from the Created and/or Modified filter(s) within
* the search query. If either of the <i>Created</i> or <i>Modified</i>
* filter is missing from the search query, the default set of facet queries
* will be created for the missing date filter. Also, creates the default
* <i>Content.Size</i> facet queries.
*
* @return list of facet queries
*/
// ACE-1605
public List<String> createFacetQueriesFromSearchQuery(String searchQuery)
{
String createdDateRange = extractDateRange(searchQuery, CREATED_DATE_PATTERN);
String modifiedDateRange = extractDateRange(searchQuery, MODIFIED_DATE_PATTERN);
if (createdDateRange == null && modifiedDateRange == null)
{
return getDefaultFacetQueries();
}
List<String> facetQueries = new ArrayList<>();
List<String> dateBuckets = getDateBuckets();
if (createdDateRange != null && modifiedDateRange != null)
{
// Add the Created and Modified dates facet queries
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + createdDateRange + ']');
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + modifiedDateRange + ']');
}
else if (createdDateRange == null)
{
// As Created date is null, add all the the predefined created buckets.
for (String bucket : dateBuckets)
{
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + bucket + ']');
}
// We can be sure, that modifiedDateRange is not null (see the first 'if' statement).
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + modifiedDateRange + ']');
}
else
{
// If we are here, it means, Modified date is null, hence, add
// all the the predefined modified buckets.
for (String bucket : dateBuckets)
{
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + bucket + ']');
}
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + createdDateRange + ']');
}
// Always add the content size facet query
for (String bucket : CONTENT_SIZE_BUCKETS)
{
facetQueries.add(CONTENT_SIZE_FIELD_FACET_QUERY + ":[" + bucket + ']');
}
return facetQueries;
}
/**
* Gets the date range that will match against the pattern from the search query
*
* @param searchQuery the string input
* @param pattern the compiled representation of a RegEx
* @return the date range or null, if there is no match. An example of the
* date range string representation is: 2014-04-28 TO 2014-04-29
*/
private String extractDateRange(String searchQuery, Pattern pattern)
{
String dateRange = null;
Matcher matcher = pattern.matcher(searchQuery);
if (matcher.find())
{
dateRange = matcher.group();
// E.g. dateRange => 2014-04-28".."2014-04-29
}
return (dateRange == null) ? null : dateRange.replace("\"..\"", " TO ");
}
/**
* Gets the predefined date buckets from the cache
*
* @return list of date ranges. An example of the date range string
* representation is: 2014-04-28 TO 2014-04-29
*/
private List<String> getDateBuckets()
{
List<String> dateBuckets = null;
try
{
dateBuckets = fqDateCache.getRangeBuckets(LocalDate.now());
}
catch (Exception e)
{
logger.error(
"Error occured while trying to get the date buckets from the cache. Calculating the dates without the cache.", e);
dateBuckets = makeDateBuckets(LocalDate.now());
}
return dateBuckets;
} }
/** /**
* Gets the appropriate facet display label handler * Whether the specified field is defined as a <i>facet.query</i> or not
* *
* @param qName the field facet QName * @param facetField
* @return the diplayHandler object or null if there is no handler * @return true if the facet is <i>facet.query</i>, false otherwise
* registered for the given @{code qName}
*/ */
public FacetLabelDisplayHandler getDisplayHandler(String qName) public boolean hasFacetQueries(String facetField)
{ {
return displayHandlers.get(qName); return facetQueries.containsKey(facetField);
}
/**
* Gets all the defined facet queries for the specified field
* @param facetField the requested field
* @return an unmodifiable list of facet queries, or null if none found
*/
public List<String> getFacetQueries(String facetField)
{
List<String> queries = facetQueries.get(facetField);
if (queries == null)
{
return null;
}
return Collections.unmodifiableList(queries);
} }
/** /**
@@ -292,9 +123,50 @@ public class SolrFacetHelper
*/ */
public Set<String> getBucketedFieldFacets() public Set<String> getBucketedFieldFacets()
{ {
return Collections.unmodifiableSet(BUCKETED_FIELD_FACETS); return Collections.unmodifiableSet(facetQueries.keySet());
}
/**
* Creates a facet query by trying to extract the date range from the the
* search query.
*
* @return the facet query, or null if the date range cannot be extracted
*/
// workaround for https://issues.alfresco.com/jira/browse/ACE-1605
public String createFacetQueriesFromSearchQuery(String field, String searchQuery)
{
if (field == null)
{
return null;
}
try
{
if (field.startsWith("@"))
{
field = field.substring(1);
}
String escapedField = searchQuery.substring(searchQuery.indexOf(field));
String dateRange = escapedField.substring(field.length() + 2, escapedField.indexOf(")")).trim();
// E.g. dateRange => "NOW/DAY-7DAYS".."NOW/DAY+1DAY"
dateRange = dateRange.replace("\"..\"", " TO ");
// remove the date-range quotations marks
dateRange = dateRange.replace("\"", "");
// the processed dateRange will be, for example, NOW/DAY-7DAY TO NOW/DAY+1DAY
dateRange = (dateRange == null) ? null : field + ":[" + dateRange + "]";
return "@" + dateRange;
}
catch (Exception e)
{
logger.warn("Couldnt extract " + field + " date range from the search query." + e);
return null;
}
} }
/** /**
* Is the specified facet ID part of the list of "specials" which are * Is the specified facet ID part of the list of "specials" which are
* handled by our SOLR service as is? * handled by our SOLR service as is?
@@ -303,440 +175,4 @@ public class SolrFacetHelper
{ {
return specialFacetIds.contains(facetId); return specialFacetIds.contains(facetId);
} }
/**
* Creates Date buckets. The dates are in ISO8601 format (yyyy-MM-dd)
*
* @return list of date ranges. An example of the date range string
* representation is: 2014-04-28 TO 2014-04-29
*/
private static List<String> makeDateBuckets(LocalDate currentDate)
{
List<String> list = new ArrayList<>(5);
String nowStr = " TO " + currentDate.toString();
// Bucket => yesterday TO today
list.add(currentDate.minusDays(1).toString() + nowStr);
// Bucket => Last week TO today
list.add(currentDate.minusWeeks(1).toString() + nowStr);
// Bucket => Last month TO today
list.add(currentDate.minusMonths(1).toString() + nowStr);
// Bucket => Last 6 months TO today
list.add(currentDate.minusMonths(6).toString() + nowStr);
// Bucket => Last year TO today
list.add(currentDate.minusYears(1).toString() + nowStr);
return list;
}
/**
* Creates display name for the Date buckets.
*
* @return Map of {@literal <date range, (display label key, insertion index)>}
*/
private static Map<String, Pair<String, Integer>> makeDateBucketsDisplayLabel(LocalDate date)
{
List<String> dateBuckets = makeDateBuckets(date);
Map<String, Pair<String, Integer>> bucketDisplayName = new HashMap<>(5);
if (dateBuckets.size() != 5)
{
throw new AlfrescoRuntimeException("Date buckets size does not match the bucket display label size!");
}
bucketDisplayName.put(dateBuckets.get(0), new Pair<String, Integer>("faceted-search.date.one-day.label", 0));
bucketDisplayName.put(dateBuckets.get(1), new Pair<String, Integer>("faceted-search.date.one-week.label", 1));
bucketDisplayName.put(dateBuckets.get(2), new Pair<String, Integer>("faceted-search.date.one-month.label", 2));
bucketDisplayName.put(dateBuckets.get(3), new Pair<String, Integer>("faceted-search.date.six-months.label", 3));
bucketDisplayName.put(dateBuckets.get(4), new Pair<String, Integer>("faceted-search.date.one-year.label", 4));
return bucketDisplayName;
}
/**
* Creates display name for the Content size buckets.
*
* @return Map of {@literal <size range, (display label key, insertion index)>}
*/
private static Map<String, Pair<String, Integer>> makeContentSizeBucketsDisplayLabel()
{
Map<String, Pair<String, Integer>> bucketDisplayName = new HashMap<>(6);
if (CONTENT_SIZE_BUCKETS.size() != 6)
{
throw new AlfrescoRuntimeException("Content size buckets size does not match the bucket display label size!");
}
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(0), new Pair<String, Integer>("faceted-search.size.0-10KB.label", 0));
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(1), new Pair<String, Integer>("faceted-search.size.10-100KB.label", 1));
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(2), new Pair<String, Integer>("faceted-search.size.100KB-1MB.label", 2));
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(3), new Pair<String, Integer>("faceted-search.size.1-16MB.label", 3));
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(4), new Pair<String, Integer>("faceted-search.size.16-128MB.label", 4));
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(5), new Pair<String, Integer>("faceted-search.size.over128.label", 5));
return bucketDisplayName;
}
/**
* Single value cache for date and size buckets.
*
* @author Jamal Kaabi-Mofrad
*/
private static class BucketsCache<K, V>
{
private final ConcurrentMap<K, Future<V>> cache = new ConcurrentHashMap<>();
private final Buckets<K, V> buckets;
public BucketsCache(Buckets<K, V> buckets)
{
this.buckets = buckets;
}
public V getRangeBuckets(final K arg) throws Exception
{
while (true)
{
Future<V> future = cache.get(arg);
// first checks to see if the buckets computation has been started
if (future == null)
{
Callable<V> result = new Callable<V>()
{
public V call() throws Exception
{
// remove the previous entry
Set<K> keys = cache.keySet();
for (K key : keys)
{
if (!key.equals(arg))
{
cache.remove(key);
}
}
return buckets.compute(arg);
}
};
// If the calculation has been started, creates a
// FutureTask, registers it in the Map, and starts the computation
FutureTask<V> futureTask = new FutureTask<>(result);
future = cache.putIfAbsent(arg, futureTask);
if (future == null)
{
future = futureTask;
futureTask.run();
}
}
try
{
return future.get();
}
catch (CancellationException ce)
{
// Removes cache pollution. If the calculation is cancelled
// or failed. As caching a Future instead of a value creates
// the possibility of cache pollution
cache.remove(arg, future);
}
catch (ExecutionException e)
{
throw new IllegalStateException(e);
}
}
}
}
/**
* Interface to be implemented by classes that wish to create buckets.
*
* @author Jamal Kaabi-Mofrad
*/
private static interface Buckets<K, V>
{
V compute(K arg) throws Exception;
}
/**
* A simple implementation which creates Date buckets for the facet query.
*
* @author Jamal Kaabi-Mofrad
*/
private static class FacetQueryParamDateBuckets implements Buckets<LocalDate, List<String>>
{
@Override
public List<String> compute(LocalDate localDate) throws Exception
{
return makeDateBuckets(localDate);
}
}
/**
* A simple implementation which creates display label for the Date buckets
* from the facet query result.
*
* @author Jamal Kaabi-Mofrad
*/
private static class FacetQueryResultDateBuckets implements Buckets<LocalDate, Map<String, Pair<String, Integer>>>
{
@Override
public Map<String, Pair<String, Integer>> compute(LocalDate localDate) throws Exception
{
return makeDateBucketsDisplayLabel(localDate);
}
}
/**
* A simple implementation which creates display label for the Content size
* buckets from the facet query result.
*
* @author Jamal Kaabi-Mofrad
*/
private static class FacetQueryResultContentSizeBuckets implements Buckets<String, Map<String, Pair<String, Integer>>>
{
@Override
public Map<String, Pair<String, Integer>> compute(String arg) throws Exception
{
return makeContentSizeBucketsDisplayLabel();
}
}
/**
* Solr facet value and facet query result display label handler
*
* @author Jamal Kaabi-Mofrad
*/
public static interface FacetLabelDisplayHandler
{
FacetLabel getDisplayLabel(String value);
}
/**
* A class to encapsulate the result of the facet label display handler
*
* @author Jamal Kaabi-Mofrad
*/
public static class FacetLabel
{
private final String value;
private final String label;
private final int labelIndex;
/**
* @param value
* @param label
* @param labelIndex
*/
public FacetLabel(String value, String label, int labelIndex)
{
this.value = value;
this.label = label;
this.labelIndex = labelIndex;
}
/**
* Gets the original facet value or a new modified value
*
* @return the original facet value or a new modified value
*/
public String getValue()
{
return this.value;
}
/**
* Gets the facet display label
*
* @return the label
*/
public String getLabel()
{
return this.label;
}
/**
* Gets the label index to be used for sorting. The index only relevant
* to to Date and Size facets.
*
* @return the index or -1, if it isn't relevant to the facet label
*/
public int getLabelIndex()
{
return this.labelIndex;
}
/*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((this.label == null) ? 0 : this.label.hashCode());
result = prime * result + this.labelIndex;
result = prime * result + ((this.value == null) ? 0 : this.value.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)
return false;
if (!(obj instanceof FacetLabel))
return false;
FacetLabel other = (FacetLabel) obj;
if (this.label == null)
{
if (other.label != null)
return false;
}
else if (!this.label.equals(other.label))
return false;
if (this.labelIndex != other.labelIndex)
return false;
if (this.value == null)
{
if (other.value != null)
return false;
}
else if (!this.value.equals(other.value))
return false;
return true;
}
}
/**
* A simple handler to get the full user name from the userID
*
* @author Jamal Kaabi-Mofrad
*/
public static class UserNameDisplayHandler implements FacetLabelDisplayHandler
{
private final PersonService personService;
private final NodeService nodeService;
public UserNameDisplayHandler(ServiceRegistry services)
{
this.personService = services.getPersonService();
this.nodeService = services.getNodeService();
}
@Override
public FacetLabel getDisplayLabel(String value)
{
String name = null;
final NodeRef personRef = personService.getPersonOrNull(value);
if (personRef != null)
{
final String firstName = (String) nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
final String lastName = (String) nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
name = (firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "");
}
return new FacetLabel(value, name == null ? value : name.trim(), -1);
}
}
/**
* A simple handler to get the Mimetype display label.
*
* @author Jamal Kaabi-Mofrad
*/
public static class MimetypeDisplayHandler implements FacetLabelDisplayHandler
{
private final MimetypeService mimetypeService;
public MimetypeDisplayHandler(ServiceRegistry services)
{
this.mimetypeService = services.getMimetypeService();
}
@Override
public FacetLabel getDisplayLabel(String value)
{
Map<String, String> mimetypes = mimetypeService.getDisplaysByMimetype();
String displayName = mimetypes.get(value);
return new FacetLabel(value, displayName == null ? value : displayName.trim(), -1);
}
}
/**
* A simple handler to get the appropriate display label for the date buckets.
*
* @author Jamal Kaabi-Mofrad
*/
public static class DateBucketsDisplayHandler implements FacetLabelDisplayHandler
{
private final BucketsCache<LocalDate, Map<String, Pair<String, Integer>>> cache = new BucketsCache<>(
new FacetQueryResultDateBuckets());
@Override
public FacetLabel getDisplayLabel(String value)
{
Map<String, Pair<String, Integer>> dateBuckets = null;
String dateRange = value.substring(value.indexOf('[') + 1, value.length() - 1);
String[] lowerUpperDates = dateRange.split("\\sTO\\s");
LocalDate date = LocalDate.parse(lowerUpperDates[1]);
try
{
dateBuckets = cache.getRangeBuckets(date);
}
catch (Exception e)
{
logger.error(
"Error occurred while trying to get the date buckets from the cache. Calculating the dates without the cache.", e);
dateBuckets = makeDateBucketsDisplayLabel(date);
}
String newValue = lowerUpperDates[0] + "\"..\"" + lowerUpperDates[1];
Pair<String, Integer> labelIndexPair = dateBuckets.get(dateRange);
return new FacetLabel(newValue, labelIndexPair.getFirst(), labelIndexPair.getSecond());
}
}
/**
* A simple handler to get the appropriate display label for the content size buckets.
*
* @author Jamal Kaabi-Mofrad
*/
public static class ContentSizeBucketsDisplayHandler implements FacetLabelDisplayHandler
{
private final BucketsCache<String, Map<String, Pair<String, Integer>>> cache = new BucketsCache<>(
new FacetQueryResultContentSizeBuckets());
@Override
public FacetLabel getDisplayLabel(String value)
{
String sizeRange = value.substring(value.indexOf('[') + 1, value.length() - 1);
String[] lowerUppperSize = sizeRange.split("\\sTO\\s");
Map<String, Pair<String, Integer>> sizeBuckets;
try
{
sizeBuckets = cache.getRangeBuckets(SIZE_BUCKETS_CACHE_KEY);
}
catch (Exception e)
{
logger.error(
"Error occurred while trying to get the content size buckets from the cache. Calculating the size without the cache.", e);
sizeBuckets = makeContentSizeBucketsDisplayLabel();
}
String newValue = lowerUppperSize[0] + "\"..\"" + lowerUppperSize[1];
Pair<String, Integer> labelIndexPair = sizeBuckets.get(sizeRange);
return new FacetLabel(newValue, labelIndexPair.getFirst(), labelIndexPair.getSecond());
}
}
} }

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.Set;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.util.PropertyCheck;
/**
* A support class for facet label display handlers.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public abstract class AbstractFacetLabelDisplayHandler implements FacetLabelDisplayHandler
{
protected ServiceRegistry serviceRegistry;
protected Set<String> supportedFieldFacets;
private FacetLabelDisplayHandlerRegistry registry;
/**
* Registers this instance of the facet handler with the registry. This will
* call the {@link #init()} method and then register if the registry is available.
*
*/
public final void register()
{
init();
for (String fieldFacet : supportedFieldFacets)
{
registry.addDisplayHandler(fieldFacet, this);
}
}
protected void init()
{
PropertyCheck.mandatory(this, "registry", registry);
PropertyCheck.mandatory(this, "serviceRegistry", serviceRegistry);
PropertyCheck.mandatory(this, "supportedFieldFacets", supportedFieldFacets);
}
/**
* @param supportedFieldFacets the supportedFieldFacets to set
*/
public void setSupportedFieldFacets(Set<String> supportedFieldFacets)
{
this.supportedFieldFacets = supportedFieldFacets;
}
/**
* Set the service registry
*
* @param services the service registry
*/
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.serviceRegistry = serviceRegistry;
}
/**
* Set the registry to register with
*
* @param registry a metadata extracter registry
*/
public void setRegistry(FacetLabelDisplayHandlerRegistry registry)
{
this.registry = registry;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Set;
import org.alfresco.repo.search.impl.solr.facet.FacetQueryProvider;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetConfigException;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* A simple handler to get the appropriate display label for the content size buckets.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class ContentSizeBucketsDisplayHandler extends AbstractFacetLabelDisplayHandler implements FacetQueryProvider
{
private static final Pattern SIZE_RANGE_PATTERN = Pattern.compile("(\\[\\d+\\sTO\\s(\\d+|MAX)\\])");
private final Map<String, FacetLabel> facetLabelMap;
private final Map<String, List<String>> facetQueriesMap;
public ContentSizeBucketsDisplayHandler(Set<String> facetQueryFields, LinkedHashMap<String, String> sizeBucketsMap)
{
ParameterCheck.mandatory("facetQueryFields", facetQueryFields);
ParameterCheck.mandatory("sizeBucketsMap", sizeBucketsMap);
this.supportedFieldFacets = Collections.unmodifiableSet(facetQueryFields);
facetLabelMap = new HashMap<>(sizeBucketsMap.size());
Map<String, List<String>> facetQueries = new LinkedHashMap<>(facetQueryFields.size());
for (String facetQueryField : facetQueryFields)
{
List<String> queries = new ArrayList<>();
int index = 0;
for (Entry<String, String> bucket : sizeBucketsMap.entrySet())
{
String sizeRange = bucket.getKey().trim();
Matcher matcher = SIZE_RANGE_PATTERN.matcher(sizeRange);
if (!matcher.find())
{
throw new SolrFacetConfigException(
"Invalid size range. Example of a valid size range is: [0 TO 1024]");
}
// build the facet query. e.g. {http://www.alfresco.org/model/content/1.0}content.size:[0 TO 1024]
String facetQuery = facetQueryField + ':' + sizeRange;
queries.add(facetQuery);
// indexOf('[') => 1
String sizeRangeQuery = sizeRange.substring(1, sizeRange.length() - 1);
sizeRangeQuery = sizeRangeQuery.replaceFirst("\\sTO\\s", "\"..\"");
facetLabelMap.put(facetQuery, new FacetLabel(sizeRangeQuery, bucket.getValue(), index++));
}
facetQueries.put(facetQueryField, queries);
}
this.facetQueriesMap = Collections.unmodifiableMap(facetQueries);
}
@Override
public FacetLabel getDisplayLabel(String value)
{
FacetLabel facetLabel = facetLabelMap.get(value);
return (facetLabel == null) ? new FacetLabel(value, value, -1) : facetLabel;
}
@Override
public Map<String, List<String>> getFacetQueries()
{
return this.facetQueriesMap;
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.repo.search.impl.solr.facet.FacetQueryProvider;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetConfigException;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* A simple handler to get the appropriate display label for the date buckets.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class DateBucketsDisplayHandler extends AbstractFacetLabelDisplayHandler implements FacetQueryProvider
{
private static final Pattern DATE_RANGE_PATTERN = Pattern.compile("(\\[\\w+\\S+\\sTO\\s(\\w+\\S+)\\])");
private final Map<String, FacetLabel> facetLabelMap;
private final Map<String, List<String>> facetQueriesMap;
public DateBucketsDisplayHandler(Set<String> facetQueryFields, LinkedHashMap<String, String> dateBucketsMap)
{
ParameterCheck.mandatory("facetQueryFields", facetQueryFields);
ParameterCheck.mandatory("dateBucketsMap", dateBucketsMap);
this.supportedFieldFacets = Collections.unmodifiableSet(facetQueryFields);
facetLabelMap = new HashMap<>(dateBucketsMap.size());
Map<String, List<String>> facetQueries = new LinkedHashMap<>(facetQueryFields.size());
for (String facetQueryField : facetQueryFields)
{
List<String> queries = new ArrayList<>();
int index = 0;
for (Entry<String, String> bucket : dateBucketsMap.entrySet())
{
String dateRange = bucket.getKey().trim();
Matcher matcher = DATE_RANGE_PATTERN.matcher(dateRange);
if (!matcher.find())
{
throw new SolrFacetConfigException(
"Invalid date range. Example of a valid date range is: '[NOW/DAY-1DAY TO NOW/DAY+1DAY]'");
}
// build the facet query. e.g. {http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1DAY TO NOW/DAY+1DAY]
String facetQuery = facetQueryField + ':' + dateRange;
queries.add(facetQuery);
// indexOf('[') => 1
String dateRangeQuery = dateRange.substring(1, dateRange.length() - 1);
dateRangeQuery = dateRangeQuery.replaceFirst("\\sTO\\s", "\"..\"");
facetLabelMap.put(facetQuery, new FacetLabel(dateRangeQuery, bucket.getValue(), index++));
}
facetQueries.put(facetQueryField, queries);
}
this.facetQueriesMap = Collections.unmodifiableMap(facetQueries);
}
@Override
public FacetLabel getDisplayLabel(String value)
{
FacetLabel facetLabel = facetLabelMap.get(value);
return (facetLabel == null) ? new FacetLabel(value, value, -1) : facetLabel;
}
@Override
public Map<String, List<String>> getFacetQueries()
{
return this.facetQueriesMap;
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
/**
* A class to encapsulate the result of the facet label display handler.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class FacetLabel
{
private final String value;
private final String label;
private final int labelIndex;
/**
* @param value
* @param label
* @param labelIndex
*/
public FacetLabel(String value, String label, int labelIndex)
{
this.value = value;
this.label = label;
this.labelIndex = labelIndex;
}
/**
* Gets the original facet value or a new modified value
*
* @return the original facet value or a new modified value
*/
public String getValue()
{
return this.value;
}
/**
* Gets the facet display label
*
* @return the label
*/
public String getLabel()
{
return this.label;
}
/**
* Gets the label index to be used for sorting. The index only relevant to
* to Date and Size facets.
*
* @return the index or -1, if it isn't relevant to the facet label
*/
public int getLabelIndex()
{
return this.labelIndex;
}
/*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((this.label == null) ? 0 : this.label.hashCode());
result = prime * result + this.labelIndex;
result = prime * result + ((this.value == null) ? 0 : this.value.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)
return false;
if (!(obj instanceof FacetLabel))
return false;
FacetLabel other = (FacetLabel) obj;
if (this.label == null)
{
if (other.label != null)
return false;
}
else if (!this.label.equals(other.label))
return false;
if (this.labelIndex != other.labelIndex)
return false;
if (this.value == null)
{
if (other.value != null)
return false;
}
else if (!this.value.equals(other.value))
return false;
return true;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
/**
* An interface for Solr facet value and facet query result display label handler.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public interface FacetLabelDisplayHandler
{
/**
* Gets the user friendly display label for the returned facet value
*
* @param value the facet value
* @return user friendly display label or the original value, if there is no result
*/
public FacetLabel getDisplayLabel(String value);
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* A registry which holds and provides the appropriate display handler for a
* particular facet field.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class FacetLabelDisplayHandlerRegistry
{
private final ConcurrentMap<String, FacetLabelDisplayHandler> registry;
public FacetLabelDisplayHandlerRegistry()
{
this.registry = new ConcurrentHashMap<String, FacetLabelDisplayHandler>();
}
/**
* Register an instance of {@code FacetLabelDisplayHandler} with the
* specified field facet.
*
* @param fieldFacet the field facet
* @param displayHandler the display handler
*/
public void addDisplayHandler(String fieldFacet, FacetLabelDisplayHandler displayHandler)
{
registry.putIfAbsent(fieldFacet, displayHandler);
}
/**
* Gets the display handler.
*
* @param fieldFacet the field facet to perform the lookup
* @return the display handler or null if none found
*/
public FacetLabelDisplayHandler getDisplayHandler(String fieldFacet)
{
return registry.get(fieldFacet);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* A simple handler to get the Mimetype display label.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class MimetypeDisplayHandler extends AbstractFacetLabelDisplayHandler
{
public MimetypeDisplayHandler(Set<String> supportedFieldFacets)
{
ParameterCheck.mandatory("supportedFieldFacets", supportedFieldFacets);
this.supportedFieldFacets = Collections.unmodifiableSet(new HashSet<>(supportedFieldFacets));
}
@Override
public FacetLabel getDisplayLabel(String value)
{
Map<String, String> mimetypes = serviceRegistry.getMimetypeService().getDisplaysByMimetype();
String displayName = mimetypes.get(value);
return new FacetLabel(value, displayName == null ? value : displayName.trim(), -1);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* A simple handler to get the site title from the site short name.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class SiteTitleDisplayHandler extends AbstractFacetLabelDisplayHandler
{
public SiteTitleDisplayHandler(Set<String> supportedFieldFacets)
{
ParameterCheck.mandatory("supportedFieldFacets", supportedFieldFacets);
this.supportedFieldFacets = Collections.unmodifiableSet(new HashSet<>(supportedFieldFacets));
}
@Override
public FacetLabel getDisplayLabel(String value)
{
SiteService siteService = serviceRegistry.getSiteService();
SiteInfo siteInfo = siteService.getSite(value);
String title = siteInfo != null ? siteInfo.getTitle() : value;
return new FacetLabel(value, title, -1);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet.handler;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* A simple handler to get the full user name from the userID.
*
* @author Jamal Kaabi-Mofrad
* @since 5.0
*/
public class UserNameDisplayHandler extends AbstractFacetLabelDisplayHandler
{
public UserNameDisplayHandler(Set<String> supportedFieldFacets)
{
ParameterCheck.mandatory("supportedFieldFacets", supportedFieldFacets);
this.supportedFieldFacets = Collections.unmodifiableSet(new HashSet<>(supportedFieldFacets));
}
@Override
public FacetLabel getDisplayLabel(String value)
{
String name = null;
final NodeRef personRef = serviceRegistry.getPersonService().getPersonOrNull(value);
if (personRef != null)
{
NodeService nodeService = serviceRegistry.getNodeService();
final String firstName = (String) nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
final String lastName = (String) nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
name = (firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "");
}
return new FacetLabel(value, name == null ? value : name.trim(), -1);
}
}

View File

@@ -133,7 +133,7 @@ public class SolrFacetConfigTest
// See if the overrides worked // See if the overrides worked
SolrFacetProperties creatorFP = defaultProps.get("test_filter_creator"); SolrFacetProperties creatorFP = defaultProps.get("test_filter_creator");
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString()); assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator", creatorFP.getFacetQName().toString());
String msg = "The value has not been overridden with the value from the custom properties"; String msg = "The value has not been overridden with the value from the custom properties";
assertEquals(msg, 10, creatorFP.getMaxFilters()); assertEquals(msg, 10, creatorFP.getMaxFilters());
@@ -160,7 +160,7 @@ public class SolrFacetConfigTest
config.onBootstrap(applicationEvent); config.onBootstrap(applicationEvent);
SolrFacetProperties creatorFP = config.getDefaultFacets().get("test_filter_creator"); SolrFacetProperties creatorFP = config.getDefaultFacets().get("test_filter_creator");
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString()); assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator", creatorFP.getFacetQName().toString());
assertEquals(10, creatorFP.getMaxFilters()); assertEquals(10, creatorFP.getMaxFilters());
assertEquals(5, creatorFP.getHitThreshold()); assertEquals(5, creatorFP.getHitThreshold());
assertEquals(14, creatorFP.getMinFilterValueLength()); assertEquals(14, creatorFP.getMinFilterValueLength());
@@ -175,7 +175,7 @@ public class SolrFacetConfigTest
config.onBootstrap(applicationEvent); config.onBootstrap(applicationEvent);
creatorFP = config.getDefaultFacets().get("test_filter_creator"); creatorFP = config.getDefaultFacets().get("test_filter_creator");
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString()); assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator", creatorFP.getFacetQName().toString());
assertEquals(5, creatorFP.getMaxFilters()); assertEquals(5, creatorFP.getMaxFilters());
assertEquals(1, creatorFP.getHitThreshold()); assertEquals(1, creatorFP.getHitThreshold());
assertEquals(4, creatorFP.getMinFilterValueLength()); assertEquals(4, creatorFP.getMinFilterValueLength());

View File

@@ -21,34 +21,38 @@ package org.alfresco.repo.search.impl.solr.facet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper.FacetLabel;
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabel;
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandler;
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandlerRegistry;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.joda.time.LocalDate;
import org.junit.*; import org.junit.*;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import static org.junit.Assert.*; import static org.junit.Assert.*;
/** /**
* This class contains tests for the class <code>{@link SolrFacetHelper}</code>. * This class contains tests for the class <code>{@link SolrFacetHelper}</code> and <code>{@link FacetLabelDisplayHandler}</code>.
* *
* @author Jamal Kaabi-Mofrad * @author Jamal Kaabi-Mofrad
* @since 5.0
*/ */
public class SolrFacetHelperTest public class SolrFacetQueriesDisplayHandlersTest
{ {
private static ApplicationContext context; private static ApplicationContext context;
private static SolrFacetHelper helper; private static SolrFacetHelper helper;
private static FacetLabelDisplayHandlerRegistry displayHandlerRegistry;
@BeforeClass @BeforeClass
public static void initStaticData() throws Exception public static void initStaticData() throws Exception
{ {
context = ApplicationContextHelper.getApplicationContext(); context = ApplicationContextHelper.getApplicationContext();
ServiceRegistry serviceRegistry = (ServiceRegistry) context.getBean("ServiceRegistry");
helper = new SolrFacetHelper(serviceRegistry); helper = (SolrFacetHelper) context.getBean("facet.solrFacetHelper");
displayHandlerRegistry = (FacetLabelDisplayHandlerRegistry) context.getBean("facet.facetLabelDisplayHandlerRegistry");
} }
/** /**
* Perform pre-test initialization. * Perform pre-test initialization.
* *
@@ -76,85 +80,44 @@ public class SolrFacetHelperTest
} }
/** /**
* Run the List<String> createFacetQueriesFromSearchQuery(String) method test. * Run the String createFacetQueriesFromSearchQuery(String) method test.
* *
* @throws Exception * @throws Exception
* *
*/ */
@Test @Test
public void testCreateFacetQueriesFromSearchQuery() throws Exception public void testCreateFacetQueryFromSearchQuery() throws Exception
{ {
String searchQueryWithCreatedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"2014-05-30\"..\"2014-06-06\" ))" String searchQueryWithCreatedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"NOW/DAY-7DAYS\"..\"NOW/DAY+1DAY\" ))"
+ " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND"
+ " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
+ " -cm:creator:system, stores=[workspace://SpacesStore]";
List<String> result = helper.createFacetQueriesFromSearchQuery(searchQueryWithCreatedDate);
assertNotNull(result);
LocalDate currentDate = LocalDate.now();
String nowStr = " TO " + currentDate.toString();
String yesterday = currentDate.minusDays(1).toString() + nowStr;
String lastWeek = currentDate.minusWeeks(1).toString() + nowStr;
String lastMonth = currentDate.minusMonths(1).toString() + nowStr;
String last6Months = currentDate.minusMonths(6).toString() + nowStr;
String lastYear = currentDate.minusYears(1).toString() + nowStr;
// As the created date has been specified in the search, we don't create
// the rest of the buckets for the created date facet.
assertEquals(12, result.size());
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[2014-05-30 TO 2014-06-06]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + yesterday + "]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastWeek + "]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastMonth + "]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + last6Months + "]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastYear + "]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[102400 TO 1048576]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[1048576 TO 16777216]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[16777216 TO 134217728]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[134217728 TO MAX]"));
String searchQueryWithCreatedAndModifiedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"2014-05-30\"..\"2014-06-06\" ) AND AND ({http://www.alfresco.org/model/content/1.0}modified:(\"2014-05-30\"..\"2014-05-31\" ))"
+ " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND" + " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND"
+ " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND" + " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND" + " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
+ " -cm:creator:system, stores=[workspace://SpacesStore]"; + " -cm:creator:system, stores=[workspace://SpacesStore]";
result = helper.createFacetQueriesFromSearchQuery(searchQueryWithCreatedAndModifiedDate); String result = helper.createFacetQueriesFromSearchQuery("{http://www.alfresco.org/model/content/1.0}created", searchQueryWithCreatedDate);
assertNotNull(result); assertNotNull(result);
assertEquals("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]", result);
currentDate = LocalDate.now(); String searchQueryWithCreatedAndModifiedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"NOW/DAY-7DAYS\"..\"NOW/DAY+1DAY\" ) AND ({http://www.alfresco.org/model/content/1.0}modified:(\"NOW/DAY-1DAY\"..\"NOW/DAY+1DAY\" ))"
nowStr = " TO " + currentDate.toString(); + " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND"
yesterday = currentDate.minusDays(1).toString() + nowStr; + " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
lastWeek = currentDate.minusWeeks(1).toString() + nowStr; + " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
lastMonth = currentDate.minusMonths(1).toString() + nowStr; + " -cm:creator:system, stores=[workspace://SpacesStore]";
last6Months = currentDate.minusMonths(6).toString() + nowStr;
lastYear = currentDate.minusYears(1).toString() + nowStr;
// As the created and modified dates have been specified in the search, String[] fields = { "{http://www.alfresco.org/model/content/1.0}created", "{http://www.alfresco.org/model/content/1.0}modified" };
// we don't create the rest of the buckets for the created and modified date facets.
assertEquals(8, result.size());
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[2014-05-30 TO 2014-06-06]")); result = helper.createFacetQueriesFromSearchQuery(fields[0], searchQueryWithCreatedAndModifiedDate);
assertNotNull(result);
assertEquals("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]", result);
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[2014-05-30 TO 2014-05-31]")); result = helper.createFacetQueriesFromSearchQuery(fields[1], searchQueryWithCreatedAndModifiedDate);
assertNotNull(result);
assertEquals("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1DAY TO NOW/DAY+1DAY]", result);
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[102400 TO 1048576]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[1048576 TO 16777216]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[16777216 TO 134217728]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[134217728 TO MAX]"));
} }
/** /**
* Run the Set<String> getBucketedFieldFacets() method test. * Run the List<String> getBucketedFieldFacets() method test.
* *
* @throws Exception * @throws Exception
* *
@@ -180,29 +143,21 @@ public class SolrFacetHelperTest
public void testGetDefaultFacetQueries() throws Exception public void testGetDefaultFacetQueries() throws Exception
{ {
List<String> result = helper.getDefaultFacetQueries(); List<String> result = helper.getDefaultFacetQueries();
LocalDate currentDate = LocalDate.now();
String nowStr = " TO " + currentDate.toString();
String yesterday = currentDate.minusDays(1).toString() + nowStr;
String lastWeek = currentDate.minusWeeks(1).toString() + nowStr;
String lastMonth = currentDate.minusMonths(1).toString() + nowStr;
String last6Months =currentDate.minusMonths(6).toString() + nowStr;
String lastYear = currentDate.minusYears(1).toString() + nowStr;
assertNotNull(result); assertNotNull(result);
assertEquals(16, result.size()); assertEquals(16, result.size());
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + yesterday + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1DAY TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + lastWeek + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + lastMonth + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1MONTH TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + last6Months + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + lastYear + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1YEAR TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + yesterday + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1DAY TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastWeek + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastMonth + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1MONTH TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + last6Months + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastYear + "]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1YEAR TO NOW/DAY+1DAY]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[102400 TO 1048576]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[102400 TO 1048576]"));
@@ -210,18 +165,16 @@ public class SolrFacetHelperTest
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[16777216 TO 134217728]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[16777216 TO 134217728]"));
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[134217728 TO MAX]")); assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[134217728 TO MAX]"));
} }
/** /**
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test. * User name display handler test.
* *
* @throws Exception * @throws Exception
*
*/ */
@Test @Test
public void testGetUserNameDisplayHandler() throws Exception public void testGetUserNameDisplayHandler() throws Exception
{ {
// Username handler FacetLabelDisplayHandler userNameHandler = displayHandlerRegistry.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}creator");
SolrFacetHelper.FacetLabelDisplayHandler userNameHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}creator.__.u");
assertNotNull(userNameHandler); assertNotNull(userNameHandler);
String randomUserName = "randomUserName" + System.currentTimeMillis(); String randomUserName = "randomUserName" + System.currentTimeMillis();
FacetLabel name = userNameHandler.getDisplayLabel(randomUserName); FacetLabel name = userNameHandler.getDisplayLabel(randomUserName);
@@ -231,9 +184,9 @@ public class SolrFacetHelperTest
assertNotNull(name); assertNotNull(name);
assertEquals("Expected admin's full name.", "Administrator", name.getLabel()); assertEquals("Expected admin's full name.", "Administrator", name.getLabel());
} }
/** /**
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test. * MimeType display handler test.
* *
* @throws Exception * @throws Exception
* *
@@ -241,8 +194,8 @@ public class SolrFacetHelperTest
@Test @Test
public void testGetMimetypeDisplayHandler() throws Exception public void testGetMimetypeDisplayHandler() throws Exception
{ {
// Mimetype handler // Mimetype handler
SolrFacetHelper.FacetLabelDisplayHandler mimeTypeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.mimetype"); FacetLabelDisplayHandler mimeTypeHandler = displayHandlerRegistry.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.mimetype");
assertNotNull(mimeTypeHandler); assertNotNull(mimeTypeHandler);
FacetLabel mimetype = mimeTypeHandler.getDisplayLabel("someMimetype123"); FacetLabel mimetype = mimeTypeHandler.getDisplayLabel("someMimetype123");
assertNotNull(mimetype); assertNotNull(mimetype);
@@ -251,56 +204,48 @@ public class SolrFacetHelperTest
assertNotNull(mimetype); assertNotNull(mimetype);
assertEquals("Expected [text/plain] display name.", "Plain Text", mimetype.getLabel()); assertEquals("Expected [text/plain] display name.", "Plain Text", mimetype.getLabel());
} }
/** /**
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test. * Created date buckets display handler test.
* *
* @throws Exception * @throws Exception
* *
*/ */
@Test @Test
public void testGetDateBucketsDisplayHandler() throws Exception public void testGetCreatedDateBucketsDisplayHandler() throws Exception
{ {
// Date buckets handler final String createdDateField = "@{http://www.alfresco.org/model/content/1.0}created";
SolrFacetHelper.FacetLabelDisplayHandler dateBucketeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}created"); FacetLabelDisplayHandler dateBucketeHandler = displayHandlerRegistry.getDisplayHandler(createdDateField);
assertNotNull(dateBucketeHandler); assertNotNull(dateBucketeHandler);
LocalDate currentDate = LocalDate.now(); FacetLabel dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1DAY TO NOW/DAY+1DAY]");
String nowStr = " TO " + currentDate.toString();
String yesterday = '[' + currentDate.minusDays(1).toString() + nowStr + ']';
String lastWeek = '[' + currentDate.minusWeeks(1).toString() + nowStr + ']';
String lastMonth = '[' + currentDate.minusMonths(1).toString() + nowStr + ']';
String last6Months = '[' + currentDate.minusMonths(6).toString() + nowStr + ']';
String lastYear = '[' + currentDate.minusYears(1).toString() + nowStr + ']';
FacetLabel dateLabel = dateBucketeHandler.getDisplayLabel(yesterday);
assertNotNull(dateLabel); assertNotNull(dateLabel);
assertEquals("faceted-search.date.one-day.label", dateLabel.getLabel()); assertEquals("faceted-search.date.one-day.label", dateLabel.getLabel());
assertEquals("Yesterday date bucket should have a sorting index of 0.", 0, dateLabel.getLabelIndex()); assertEquals("Yesterday date bucket should have a sorting index of 0.", 0, dateLabel.getLabelIndex());
dateLabel = dateBucketeHandler.getDisplayLabel(lastWeek); dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-7DAYS TO NOW/DAY+1DAY]");
assertNotNull(dateLabel); assertNotNull(dateLabel);
assertEquals("faceted-search.date.one-week.label", dateLabel.getLabel()); assertEquals("faceted-search.date.one-week.label", dateLabel.getLabel());
assertEquals("Last week date bucket should have a sorting index of 1.", 1, dateLabel.getLabelIndex()); assertEquals("Last week date bucket should have a sorting index of 1.", 1, dateLabel.getLabelIndex());
dateLabel = dateBucketeHandler.getDisplayLabel(lastMonth); dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1MONTH TO NOW/DAY+1DAY]");
assertNotNull(dateLabel); assertNotNull(dateLabel);
assertEquals("faceted-search.date.one-month.label", dateLabel.getLabel()); assertEquals("faceted-search.date.one-month.label", dateLabel.getLabel());
assertEquals("Last month date bucket should have a sorting index of 2.", 2, dateLabel.getLabelIndex()); assertEquals("Last month date bucket should have a sorting index of 2.", 2, dateLabel.getLabelIndex());
dateLabel = dateBucketeHandler.getDisplayLabel(last6Months); dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]");
assertNotNull(dateLabel); assertNotNull(dateLabel);
assertEquals("faceted-search.date.six-months.label", dateLabel.getLabel()); assertEquals("faceted-search.date.six-months.label", dateLabel.getLabel());
assertEquals("Last 6 months date bucket should have a sorting index of 3.", 3, dateLabel.getLabelIndex()); assertEquals("Last 6 months date bucket should have a sorting index of 3.", 3, dateLabel.getLabelIndex());
dateLabel = dateBucketeHandler.getDisplayLabel(lastYear); dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1YEAR TO NOW/DAY+1DAY]");
assertNotNull(dateLabel); assertNotNull(dateLabel);
assertEquals("faceted-search.date.one-year.label", dateLabel.getLabel()); assertEquals("faceted-search.date.one-year.label", dateLabel.getLabel());
assertEquals("Last year date bucket should have a sorting index of 4.", 4, dateLabel.getLabelIndex()); assertEquals("Last year date bucket should have a sorting index of 4.", 4, dateLabel.getLabelIndex());
} }
/** /**
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test. * Content size buckets display handler test.
* *
* @throws Exception * @throws Exception
* *
@@ -308,10 +253,10 @@ public class SolrFacetHelperTest
@Test @Test
public void testGetContentSizeBucketsDisplayHandler() throws Exception public void testGetContentSizeBucketsDisplayHandler() throws Exception
{ {
// Date buckets handler final String contentSizeField = "@{http://www.alfresco.org/model/content/1.0}content.size";
SolrFacetHelper.FacetLabelDisplayHandler contentSizeBucketeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.size"); FacetLabelDisplayHandler contentSizeBucketeHandler = displayHandlerRegistry.getDisplayHandler(contentSizeField);
assertNotNull(contentSizeBucketeHandler); assertNotNull(contentSizeBucketeHandler);
int KB = 1024; int KB = 1024;
int MB = KB * 1024; int MB = KB * 1024;
int tiny = 10 * KB; int tiny = 10 * KB;
@@ -320,34 +265,56 @@ public class SolrFacetHelperTest
int large = 16 * MB; int large = 16 * MB;
int huge = 128 * MB; int huge = 128 * MB;
FacetLabel sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[0 TO " + tiny + "]");
assertNotNull(sizeLabel); FacetLabel sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[0 TO " + tiny + "]");
assertNotNull(sizeLabel);
assertEquals("faceted-search.size.0-10KB.label", sizeLabel.getLabel()); assertEquals("faceted-search.size.0-10KB.label", sizeLabel.getLabel());
assertEquals("0-10KB size bucket should have a sorting index of 0.", 0, sizeLabel.getLabelIndex()); assertEquals("0-10KB size bucket should have a sorting index of 0.", 0, sizeLabel.getLabelIndex());
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + tiny + " TO " + small + "]"); sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + tiny + " TO " + small + "]");
assertNotNull(sizeLabel); assertNotNull(sizeLabel);
assertEquals("faceted-search.size.10-100KB.label", sizeLabel.getLabel()); assertEquals("faceted-search.size.10-100KB.label", sizeLabel.getLabel());
assertEquals("10-100KB size bucket should have a sorting index of 1.", 1, sizeLabel.getLabelIndex()); assertEquals("10-100KB size bucket should have a sorting index of 1.", 1, sizeLabel.getLabelIndex());
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + small + " TO " + medium + "]"); sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + small + " TO " + medium + "]");
assertNotNull(sizeLabel); assertNotNull(sizeLabel);
assertEquals("faceted-search.size.100KB-1MB.label", sizeLabel.getLabel()); assertEquals("faceted-search.size.100KB-1MB.label", sizeLabel.getLabel());
assertEquals("100KB-1MB size bucket should have a sorting index of 2.", 2, sizeLabel.getLabelIndex()); assertEquals("100KB-1MB size bucket should have a sorting index of 2.", 2, sizeLabel.getLabelIndex());
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + medium + " TO " + large + "]"); sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + medium + " TO " + large + "]");
assertNotNull(sizeLabel); assertNotNull(sizeLabel);
assertEquals("faceted-search.size.1-16MB.label", sizeLabel.getLabel()); assertEquals("faceted-search.size.1-16MB.label", sizeLabel.getLabel());
assertEquals("1-16MB size bucket should have a sorting index of 3.", 3, sizeLabel.getLabelIndex()); assertEquals("1-16MB size bucket should have a sorting index of 3.", 3, sizeLabel.getLabelIndex());
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + large + " TO " + huge + "]"); sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + large + " TO " + huge + "]");
assertNotNull(sizeLabel); assertNotNull(sizeLabel);
assertEquals("faceted-search.size.16-128MB.label", sizeLabel.getLabel()); assertEquals("faceted-search.size.16-128MB.label", sizeLabel.getLabel());
assertEquals("16-128MB size bucket should have a sorting index of 4.", 4, sizeLabel.getLabelIndex()); assertEquals("16-128MB size bucket should have a sorting index of 4.", 4, sizeLabel.getLabelIndex());
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + huge + " TO MAX]"); sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + huge + " TO MAX]");
assertNotNull(sizeLabel); assertNotNull(sizeLabel);
assertEquals("faceted-search.size.over128.label", sizeLabel.getLabel()); assertEquals("faceted-search.size.over128.label", sizeLabel.getLabel());
assertEquals("over128MB size bucket should have a sorting index of 5.", 5, sizeLabel.getLabelIndex()); assertEquals("over128MB size bucket should have a sorting index of 5.", 5, sizeLabel.getLabelIndex());
} }
}
/**
* Site title display handler test.
*
* @throws Exception
*/
@Test
public void testGetSiteTitleDisplayHandler() throws Exception
{
String defaultSiteName= "swsdp";
FacetLabelDisplayHandler siteHandler = displayHandlerRegistry.getDisplayHandler("SITE");
assertNotNull(siteHandler);
String randomSiteName = "randomSiteName" + System.currentTimeMillis();
FacetLabel name = siteHandler.getDisplayLabel(randomSiteName);
assertNotNull(name);
assertEquals("There is no site with the name [" + randomSiteName + "], hence, the handler should return the passed-in short name.", randomSiteName, name.getLabel());
name = siteHandler.getDisplayLabel(defaultSiteName);
assertNotNull(name);
assertEquals("Sample: Web Site Design Project", name.getLabel());
}
}

View File

@@ -37,7 +37,7 @@ public class SolrFacetTestSuite extends TestSuite
public static Test suite() public static Test suite()
{ {
TestSuite suite = new TestSuite(); TestSuite suite = new TestSuite();
suite.addTest(new JUnit4TestAdapter(SolrFacetHelperTest.class)); suite.addTest(new JUnit4TestAdapter(SolrFacetQueriesDisplayHandlersTest.class));
suite.addTest(new JUnit4TestAdapter(SolrFacetServiceImplTest.class)); suite.addTest(new JUnit4TestAdapter(SolrFacetServiceImplTest.class));
suite.addTest(new JUnit4TestAdapter(SolrFacetConfigTest.class)); suite.addTest(new JUnit4TestAdapter(SolrFacetConfigTest.class));

View File

@@ -1,15 +1,15 @@
# Overrides test_filter_creator in the /facets/facets-config-sample.properties # Overrides test_filter_creator in the /facets/facets-config-sample.properties
custom.cm\:creator.__.u.filterID=test_filter_creator custom.cm\:creator.filterID=test_filter_creator
custom.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator custom.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
custom.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters custom.cm\:creator.displayControl=alfresco/search/FacetFilters
custom.cm\:creator.__.u.maxFilters=10 custom.cm\:creator.maxFilters=10
custom.cm\:creator.__.u.hitThreshold=5 custom.cm\:creator.hitThreshold=5
custom.cm\:creator.__.u.minFilterValueLength=14 custom.cm\:creator.minFilterValueLength=14
custom.cm\:creator.__.u.sortBy=ALPHABETICALLY custom.cm\:creator.sortBy=ALPHABETICALLY
custom.cm\:creator.__.u.scope=ALL custom.cm\:creator.scope=ALL
custom.cm\:creator.__.u.scopedSites=site1 custom.cm\:creator.scopedSites=site1
custom.cm\:creator.__.u.index=0 custom.cm\:creator.index=0
custom.cm\:creator.__.u.isEnabled=true custom.cm\:creator.isEnabled=true
# Add a new Filter # Add a new Filter
# Field-Facet-Qname => cm:description.__ # Field-Facet-Qname => cm:description.__

View File

@@ -1,26 +1,26 @@
# Field-Facet-Qname => cm:creator.__.u # Field-Facet-Qname => cm:creator
default.cm\:creator.__.u.filterID=test_filter_creator default.cm\:creator.filterID=test_filter_creator
default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator default.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters default.cm\:creator.displayControl=alfresco/search/FacetFilters
default.cm\:creator.__.u.maxFilters=5 default.cm\:creator.maxFilters=5
default.cm\:creator.__.u.hitThreshold=1 default.cm\:creator.hitThreshold=1
default.cm\:creator.__.u.minFilterValueLength=4 default.cm\:creator.minFilterValueLength=4
default.cm\:creator.__.u.sortBy=ALPHABETICALLY default.cm\:creator.sortBy=ALPHABETICALLY
default.cm\:creator.__.u.scope=ALL default.cm\:creator.scope=ALL
default.cm\:creator.__.u.scopedSites= default.cm\:creator.scopedSites=
default.cm\:creator.__.u.isEnabled=true default.cm\:creator.isEnabled=true
# Field-Facet-Qname => cm:modifier.__.u # Field-Facet-Qname => cm:modifier
default.cm\:modifier.__.u.filterID=test_filter_modifier default.cm\:modifier.filterID=test_filter_modifier
default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier default.cm\:modifier.displayName=faceted-search.facet-menu.facet.modifier
default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters default.cm\:modifier.displayControl=alfresco/search/FacetFilters
default.cm\:modifier.__.u.maxFilters=5 default.cm\:modifier.maxFilters=5
default.cm\:modifier.__.u.hitThreshold=1 default.cm\:modifier.hitThreshold=1
default.cm\:modifier.__.u.minFilterValueLength=4 default.cm\:modifier.minFilterValueLength=4
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY default.cm\:modifier.sortBy=ALPHABETICALLY
default.cm\:modifier.__.u.scope=SCOPED_SITES default.cm\:modifier.scope=SCOPED_SITES
default.cm\:modifier.__.u.scopedSites= default.cm\:modifier.scopedSites=
default.cm\:modifier.__.u.isEnabled=true default.cm\:modifier.isEnabled=true
# Field-Facet-Qname => cm:content.size # Field-Facet-Qname => cm:content.size
default.cm\:content.size.filterID=test_filter_content_size default.cm\:content.size.filterID=test_filter_content_size