/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This 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 2.1 of * the License, or (at your option) any later version. * * This software 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 this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.search.solr.internal.reference; import java.lang.reflect.Type; import java.util.Collection; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.apache.commons.lang.LocaleUtils; import org.apache.commons.lang3.StringUtils; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexableField; import org.apache.solr.common.SolrDocument; import org.xwiki.component.annotation.Component; import org.xwiki.component.util.DefaultParameterizedType; import org.xwiki.model.EntityType; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.EntityReference; import org.xwiki.model.reference.EntityReferenceResolver; import org.xwiki.search.solr.internal.api.FieldUtils; /** * Component used to extract an {@link EntityReference} from a {@link SolrDocument}. * * @version $Id: 149d372f107c1800721aa9351f17a1f7ab1881a4 $ * @since 7.2M2 */ @Component @Singleton public class SolrEntityReferenceResolver implements EntityReferenceResolver<SolrDocument> { /** * Helper for unit tests. */ public static final Type TYPE = new DefaultParameterizedType(null, EntityReferenceResolver.class, SolrDocument.class); @Inject @Named("explicit") private EntityReferenceResolver<EntityReference> explicitReferenceEntityReferenceResolver; @Override public EntityReference resolve(SolrDocument solrDocument, EntityType type, Object... parameters) { EntityReference solrEntityReference = getEntityReference(solrDocument, type, parameters); return this.explicitReferenceEntityReferenceResolver.resolve(solrEntityReference, type, parameters); } private EntityReference getEntityReference(SolrDocument solrDocument, EntityType expectedEntityType, Object... parameters) { EntityReference wikiReference = getWikiReference(solrDocument, parameters); EntityReference spaceReference = getSpaceReference(solrDocument, wikiReference, parameters); EntityReference documentReference = getDocumentReferenceWithLocale(solrDocument, spaceReference, parameters); String indexedEntityType = getFieldStringValue(solrDocument, FieldUtils.TYPE); EntityType actualEntityType = StringUtils.isEmpty(indexedEntityType) ? expectedEntityType : EntityType.valueOf(indexedEntityType); switch (actualEntityType) { case ATTACHMENT: return getAttachmentReference(solrDocument, documentReference, parameters); case OBJECT: return getObjectReference(solrDocument, documentReference, parameters); case OBJECT_PROPERTY: EntityReference objectReference = getObjectReference(solrDocument, documentReference, parameters); return getObjectPropertyReference(solrDocument, objectReference, parameters); default: return documentReference; } } private EntityReference getWikiReference(SolrDocument solrDocument, Object... parameters) { String wikiName = getFieldStringValue(solrDocument, FieldUtils.WIKI); if (!StringUtils.isEmpty(wikiName)) { return new EntityReference(wikiName, EntityType.WIKI); } else { return resolveMissingReference(EntityType.WIKI, null, parameters); } } private EntityReference getSpaceReference(SolrDocument solrDocument, EntityReference parent, Object... parameters) { Collection<Object> spaceNames = solrDocument.getFieldValues(FieldUtils.SPACES); if (spaceNames != null && !spaceNames.isEmpty()) { EntityReference spaceReference = parent; for (Object spaceName : spaceNames) { spaceReference = new EntityReference(String.valueOf(spaceName), EntityType.SPACE, spaceReference); } return spaceReference; } else { return resolveMissingReference(EntityType.SPACE, parent, parameters); } } private EntityReference getDocumentReferenceWithLocale(SolrDocument solrDocument, EntityReference parent, Object... parameters) { EntityReference documentReference = getDocumentReference(solrDocument, parent, parameters); String localeString = getFieldStringValue(solrDocument, FieldUtils.DOCUMENT_LOCALE); if (!StringUtils.isEmpty(localeString)) { documentReference = new DocumentReference(documentReference, LocaleUtils.toLocale(localeString)); } return documentReference; } private EntityReference getDocumentReference(SolrDocument solrDocument, EntityReference parent, Object... parameters) { String documentName = getFieldStringValue(solrDocument, FieldUtils.NAME); if (!StringUtils.isEmpty(documentName)) { return new EntityReference(documentName, EntityType.DOCUMENT, parent); } else { return resolveMissingReference(EntityType.DOCUMENT, parent, parameters); } } private EntityReference getAttachmentReference(SolrDocument solrDocument, EntityReference parent, Object... parameters) { String fileName = getFieldFirstStringValue(solrDocument, FieldUtils.FILENAME); if (!StringUtils.isEmpty(fileName)) { return new EntityReference(fileName, EntityType.ATTACHMENT, parent); } else { return resolveMissingReference(EntityType.ATTACHMENT, parent, parameters); } } private EntityReference getObjectReference(SolrDocument solrDocument, EntityReference parent, Object... parameters) { String classReference = getFieldFirstStringValue(solrDocument, FieldUtils.CLASS); Number objectNumber = getFieldNumberValue(solrDocument, FieldUtils.NUMBER); if (!StringUtils.isEmpty(classReference) && objectNumber != null) { return new EntityReference(String.format("%s[%s]", classReference, objectNumber), EntityType.OBJECT, parent); } else { return resolveMissingReference(EntityType.OBJECT, parent, parameters); } } private EntityReference getObjectPropertyReference(SolrDocument solrDocument, EntityReference parent, Object... parameters) { String propertyName = getFieldStringValue(solrDocument, FieldUtils.PROPERTY_NAME); if (!StringUtils.isEmpty(propertyName)) { return new EntityReference(propertyName, EntityType.OBJECT_PROPERTY, parent); } else { return resolveMissingReference(EntityType.OBJECT_PROPERTY, parent, parameters); } } private EntityReference resolveMissingReference(EntityType entityType, EntityReference parent, Object... parameters) { EntityReference entityReference = this.explicitReferenceEntityReferenceResolver.resolve(null, entityType, parameters); return entityReference.replaceParent(entityReference.getParent(), parent); } // Tools to workaround a change in Solr 5.3 which caused SolrDocument to return Field instead of value in some cases private String getFieldStringValue(SolrDocument solrDocument, String fieldName) { Object field = solrDocument.get(fieldName); if (field instanceof Field) { return ((Field) field).stringValue(); } else if (field instanceof IndexableField) { return ((IndexableField) field).stringValue(); } return field != null ? field.toString() : null; } private String getFieldFirstStringValue(SolrDocument solrDocument, String fieldName) { Object field = solrDocument.getFirstValue(fieldName); if (field instanceof Field) { return ((Field) field).stringValue(); } else if (field instanceof IndexableField) { return ((IndexableField) field).stringValue(); } return field != null ? field.toString() : null; } private Number getFieldNumberValue(SolrDocument solrDocument, String fieldName) { Object field = solrDocument.get(fieldName); if (field instanceof Field) { return ((Field) field).numericValue(); } else if (field instanceof IndexableField) { return ((IndexableField) field).numericValue(); } return field != null ? (Number) field : null; } }