/* * 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.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map.Entry; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; import org.apache.solr.client.solrj.util.ClientUtils; import org.xwiki.component.annotation.Component; import org.xwiki.model.EntityType; import org.xwiki.model.reference.AttachmentReference; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.EntityReference; import org.xwiki.search.solr.internal.api.FieldUtils; import org.xwiki.search.solr.internal.api.SolrIndexerException; import com.google.common.collect.Iterables; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiAttachment; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.objects.BaseObject; import com.xpn.xwiki.objects.BaseObjectReference; /** * Resolve document references. * * @version $Id: 25aaa72288aad6f30d3ac0b704e45ef014712db6 $ * @since 5.1M2 */ @Component @Named("document") @Singleton public class DocumentSolrReferenceResolver extends AbstractSolrReferenceResolver { /** * Used to resolve object references. */ @Inject @Named("object") private Provider<SolrReferenceResolver> objectResolverProvider; /** * Used to resolve space references. */ @Inject @Named("space") private Provider<SolrReferenceResolver> spaceResolverProvider; /** * Used to resolve attachment references. */ @Inject @Named("attachment") private Provider<SolrReferenceResolver> attachmentResolverProvider; @Override public List<EntityReference> getReferences(EntityReference reference) throws SolrIndexerException { List<EntityReference> result = new ArrayList<EntityReference>(); XWikiContext xcontext = this.xcontextProvider.get(); DocumentReference documentReference = new DocumentReference(reference); if (xcontext.getWiki().exists(documentReference, xcontext)) { // Document itself result.add(documentReference); // FIXME: Assumption - Only original documents contain objects and attachments, because objects are // not translatable. // https://jira.xwiki.org/browse/XWIKI-69 is the long standing issue on which the second assumption relies. if (documentReference.getLocale() == null || documentReference.getLocale().equals(Locale.ROOT)) { XWikiDocument document; try { document = getDocument(documentReference); } catch (Exception e) { throw new SolrIndexerException(String.format("Failed to get document [%s]", documentReference), e); } // Document translations List<Locale> translatedLocales; try { translatedLocales = document.getTranslationLocales(xcontext); } catch (XWikiException e) { throw new SolrIndexerException(String.format("Failed to get document [%s] translations", documentReference), e); } for (Locale translatedLocale : translatedLocales) { DocumentReference translatedDocumentReference = new DocumentReference(documentReference, translatedLocale); result.add(translatedDocumentReference); } // Attachments addAttachmentsReferences(document, result); // Objects addObjectsReferences(document, result); } } return result; } /** * @param document the document * @param result the list to add reference to */ private void addAttachmentsReferences(XWikiDocument document, List<EntityReference> result) { List<XWikiAttachment> attachments = document.getAttachmentList(); for (XWikiAttachment attachment : attachments) { AttachmentReference attachmentReference = attachment.getReference(); try { Iterables.addAll(result, this.attachmentResolverProvider.get().getReferences(attachmentReference)); } catch (Exception e) { this.logger.error("Failed to resolve references for attachment [" + attachmentReference + "]", e); } } } /** * @param document the document * @param result the list to add reference to */ private void addObjectsReferences(XWikiDocument document, List<EntityReference> result) { for (Entry<DocumentReference, List<BaseObject>> entry : document.getXObjects().entrySet()) { List<BaseObject> objects = entry.getValue(); for (BaseObject object : objects) { if (object != null) { BaseObjectReference objectReference = object.getReference(); try { Iterables.addAll(result, this.objectResolverProvider.get().getReferences(objectReference)); } catch (Exception e) { this.logger.error("Failed to resolve references for object [" + objectReference + "]", e); } } } } } @Override public String getId(EntityReference reference) throws SolrIndexerException { DocumentReference documentReference = new DocumentReference(reference); String result = super.getId(reference); // Document IDs also contain the locale code to differentiate between them. // Objects, attachments, etc. don`t need this because the only thing that is translated in an XWiki document // right now is the document title and content. Objects and attachments are not translated. result += FieldUtils.USCORE + getLocale(documentReference); return result; } /** * @param documentReference reference to the document. * @return the locale code of the referenced document. * @throws SolrIndexerException if problems occur. */ protected Locale getLocale(DocumentReference documentReference) throws SolrIndexerException { Locale locale = null; try { if (documentReference.getLocale() != null && !documentReference.getLocale().equals(Locale.ROOT)) { locale = documentReference.getLocale(); } else { XWikiContext xcontext = this.xcontextProvider.get(); locale = xcontext.getWiki().getDocument(documentReference, xcontext).getRealLocale(); } } catch (Exception e) { throw new SolrIndexerException(String.format("Exception while fetching the locale of the document '%s'", documentReference), e); } return locale; } @Override public String getQuery(EntityReference reference) throws SolrIndexerException { StringBuilder builder = new StringBuilder(); EntityReference spaceReference = reference.extractReference(EntityType.SPACE); builder.append(spaceResolverProvider.get().getQuery(spaceReference)); builder.append(QUERY_AND); builder.append(FieldUtils.NAME_EXACT); builder.append(':'); builder.append(ClientUtils.escapeQueryChars(reference.getName())); return builder.toString(); } }