From 2731b9a7bbae147bebe73eaa83d1f44b58720b84 Mon Sep 17 00:00:00 2001 From: Mark Rogers Date: Sat, 20 Sep 2014 09:02:07 +0000 Subject: [PATCH] Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (5.0/Cloud) 84902: Merged PLATFORM1 (5.0/Cloud) to HEAD-BUG-FIX (5.0/Cloud) 83412: Preliminary implementation of ACE-2639. This check-in allows any user to hit the repo at http://localhost:8080/alfresco/service/api/facet/facetable-properties or at http://localhost:8080/alfresco/service/api/facet/classes/cm:thumbnail/facetable-properties and get details on facetable properties for all properties in the system or all properties on the specified type/aspect, respectively. I'm checking this in in order to start to get some feedback on what the global list contains and how we might restrict it. The JSON response is very basic currently and it will be enhanced also. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85222 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/solr-facets-context.xml | 1 + .../impl/solr/facet/SolrFacetService.java | 25 +++++ .../impl/solr/facet/SolrFacetServiceImpl.java | 93 +++++++++++++++++++ 3 files changed, 119 insertions(+) diff --git a/config/alfresco/solr-facets-context.xml b/config/alfresco/solr-facets-context.xml index 9d96377336..3fb02a4460 100644 --- a/config/alfresco/solr-facets-context.xml +++ b/config/alfresco/solr-facets-context.xml @@ -27,6 +27,7 @@ + diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java index 2d61b5980e..013274909d 100644 --- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java +++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetService.java @@ -20,7 +20,15 @@ package org.alfresco.repo.search.impl.solr.facet; import java.util.List; +import java.util.Set; + +import org.alfresco.repo.dictionary.Facetable; +import org.alfresco.repo.search.impl.solr.facet.Exceptions.DuplicateFacetId; +import org.alfresco.repo.search.impl.solr.facet.Exceptions.MissingFacetId; +import org.alfresco.repo.search.impl.solr.facet.Exceptions.UnrecognisedFacetId; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; /** * Solr Facet service configuration API. @@ -96,4 +104,21 @@ public interface SolrFacetService * @throws DuplicateFacetId if there is a duplicate filter ID in the list. */ public void reorderFacets(List filterIds); + + /** + * This method offers a convenient access point for getting all Facetable + * content properties defined in the repository. + * @return a collection of facetable {@link PropertyDefinition}s. + * @see Facetable + */ + public Set getFacetableProperties(); + + /** + * This method offers a convenient access point for getting all Facetable + * content properties defined on the specified content class (type or aspect). + * @param contentClass the QName of an aspect or type, whose facetable properties are sought. + * @return a collection of facetable {@link PropertyDefinition}s. + * @see Facetable + */ + public Set getFacetableProperties(QName contentClass); } diff --git a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java index 47867549b3..753baf2f9c 100644 --- a/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java +++ b/source/java/org/alfresco/repo/search/impl/solr/facet/SolrFacetServiceImpl.java @@ -38,6 +38,7 @@ import java.util.concurrent.ConcurrentMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.dictionary.Facetable; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy; import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy; @@ -53,6 +54,9 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -91,6 +95,7 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF private static final StoreRef FACET_STORE = new StoreRef("workspace://SpacesStore"); private AuthorityService authorityService; + private DictionaryService dictionaryService; protected NodeService nodeService; private NamespaceService namespaceService; private SearchService searchService; @@ -112,6 +117,14 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF this.authorityService = authorityService; } + /** + * @param dictionaryService the dictionaryService to set + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + /** * @param nodeService the nodeService to set */ @@ -755,4 +768,84 @@ public class SolrFacetServiceImpl extends AbstractLifecycleBean implements SolrF nodeService.setProperty(getFacetsRoot(), SolrFacetModel.PROP_FACET_ORDER, serializableProp); } } + + @Override public Set getFacetableProperties() + { + final Set result = new HashSet<>(); + + final List allContentClasses = CollectionUtils.flatten(dictionaryService.getAllAspects(), dictionaryService.getAllTypes()); + + for (QName contentClass : allContentClasses) + { + result.addAll(getFacetableProperties(contentClass)); + } + + return result; + } + + @Override public Set getFacetableProperties(QName contentClass) + { + final Set result = new HashSet<>(); + + final Map propertyDefs = dictionaryService.getPropertyDefs(contentClass); + + if (propertyDefs != null) + { + for (Map.Entry prop : propertyDefs.entrySet()) + { + final Facetable propIsFacetable = prop.getValue().getFacetable(); + + switch (propIsFacetable) + { + case TRUE: + result.add(prop.getValue()); + break; + case FALSE: + // The value is not facetable. Do nothing. + break; + case UNSET: + // These values may be facetable. + final DataTypeDefinition datatype = prop.getValue().getDataType(); + if (isNumeric(datatype) || isDateLike(datatype) || isFacetableText(datatype)) + { + result.add(prop.getValue()); + break; + } + break; + default: + // This should never happen. If it does, it's a programming error. + throw new IllegalStateException("Failed to handle " + Facetable.class.getSimpleName() + " type: " + propIsFacetable); + } + } + } + + return result; + } + + // TODO Consider moving into dictionary code. + private boolean isNumeric(DataTypeDefinition datatype) + { + boolean result; + try + { + Class clazz = Class.forName(datatype.getJavaClassName()); + result = Number.class.isAssignableFrom(clazz); + } catch (ClassNotFoundException e) + { + result = false; + } + return result; + } + + private boolean isDateLike(DataTypeDefinition datatype) + { + return DataTypeDefinition.DATE.equals(datatype.getName()) || + DataTypeDefinition.DATETIME.equals(datatype.getName()); + } + + private boolean isFacetableText(DataTypeDefinition datatype) + { + // For now at least, we're excluding MLTEXT + return DataTypeDefinition.TEXT.equals(datatype.getName()); + } }