001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.workspaces.indexing.solr;
017
018import java.io.IOException;
019
020import org.apache.avalon.framework.component.Component;
021import org.apache.avalon.framework.service.ServiceException;
022import org.apache.avalon.framework.service.ServiceManager;
023import org.apache.avalon.framework.service.Serviceable;
024import org.apache.solr.client.solrj.SolrClient;
025import org.apache.solr.client.solrj.SolrServerException;
026import org.apache.solr.client.solrj.response.UpdateResponse;
027import org.apache.solr.common.SolrInputDocument;
028
029import org.ametys.cms.content.indexing.solr.SolrIndexer;
030import org.ametys.cms.content.indexing.solr.SolrResourceIndexer;
031import org.ametys.cms.search.solr.SolrClientProvider;
032import org.ametys.core.schedule.progression.ProgressionTrackerFactory;
033import org.ametys.core.schedule.progression.SimpleProgressionTracker;
034import org.ametys.plugins.explorer.resources.Resource;
035import org.ametys.plugins.explorer.resources.ResourceCollection;
036import org.ametys.plugins.repository.AmetysObject;
037import org.ametys.plugins.repository.AmetysObjectIterable;
038import org.ametys.plugins.workspaces.project.objects.Project;
039import org.ametys.runtime.plugin.component.AbstractLogEnabled;
040import org.ametys.web.indexing.solr.SolrWebFieldNames;
041import org.ametys.web.repository.site.Site;
042
043/**
044 * Component responsible for indexing a project resource (document)
045 */
046public class SolrProjectResourceIndexer extends AbstractLogEnabled implements Component, Serviceable, SolrWorkspacesConstants
047{
048    /** The avalon role. */
049    public static final String ROLE = SolrProjectResourceIndexer.class.getName();
050    
051    /** The Solr client provider */
052    protected SolrClientProvider _solrClientProvider;
053    /** Solr resource indexer */
054    protected SolrResourceIndexer _solrResourceIndexer;
055    /** Solr indexer */
056    protected SolrIndexer _solrIndexer;
057    
058    @Override
059    public void service(ServiceManager manager) throws ServiceException
060    {
061        _solrClientProvider = (SolrClientProvider) manager.lookup(SolrClientProvider.ROLE);
062        _solrResourceIndexer = (SolrResourceIndexer) manager.lookup(SolrResourceIndexer.ROLE);
063        _solrIndexer = (SolrIndexer) manager.lookup(SolrIndexer.ROLE);
064    }
065    
066    /**
067     * Index the children project resources of the given resource collection
068     * @param collection The collection of project resources
069     * @param project The project whose resources are attached
070     * @param workspaceName The workspace name
071     * @throws Exception if an error occurs when processing the indexation of the project resources
072     */
073    public void indexProjectResources(ResourceCollection collection, Project project, String workspaceName) throws Exception
074    {
075        SolrClient solrClient = _solrClientProvider.getUpdateClient(workspaceName, true);
076        indexProjectResources(collection, project, solrClient);
077    }
078    
079    /**
080     * Index the children project resources of the given resource collection
081     * @param collection The collection of project resources
082     * @param project The project whose resources are attached
083     * @param solrClient The solr client to use
084     * @throws Exception if an error occurs when processing the indexation of the project resources
085     */
086    public void indexProjectResources(ResourceCollection collection, Project project, SolrClient solrClient) throws Exception
087    {
088        indexProjectResources(collection, project, solrClient, ProgressionTrackerFactory.createSimpleProgressionTracker("Index project '" + project.getName() + "' resources", getLogger()));
089    }
090    
091    /**
092     * Index the children project resources of the given resource collection
093     * @param collection The collection of project resources
094     * @param project The project whose resources are attached
095     * @param solrClient The solr client to use
096     * @param progressionTracker The progression tracker
097     * @throws Exception if an error occurs when processing the indexation of the project resources
098     */
099    public void indexProjectResources(ResourceCollection collection, Project project, SolrClient solrClient, SimpleProgressionTracker progressionTracker) throws Exception
100    {
101        if (collection == null)
102        {
103            return;
104        }
105        
106        try (AmetysObjectIterable<AmetysObject> children = collection.getChildren())
107        {
108            long nbOfDocuments = children.getSize();
109            
110            progressionTracker.setSize(nbOfDocuments);
111            for (AmetysObject object : children)
112            {
113                if (object instanceof ResourceCollection)
114                {
115                    indexProjectResources((ResourceCollection) object, project, solrClient);
116                }
117                else if (object instanceof Resource)
118                {
119                    _indexProjectResource((Resource) object, project, solrClient);
120                }
121                
122                progressionTracker.increment();
123            }
124        }
125    }
126    
127    /**
128     * Index a project resource
129     * @param resource The project resource (document)
130     * @param project The project whose the resource is attached
131     * @param workspaceName The workspace name
132     * @throws Exception if an error occurs when processing the indexation of the project resource
133     */
134    public void indexProjectResource(Resource resource, Project project, String workspaceName) throws Exception
135    {
136        SolrClient solrClient = _solrClientProvider.getUpdateClient(workspaceName, true);
137        _indexProjectResource(resource, project, solrClient);
138    }
139    
140    private void _indexProjectResource(Resource resource, Project project, SolrClient solrClient) throws Exception
141    {
142        SolrInputDocument solrDocument = new SolrInputDocument();
143        
144        // Prepare resource doc
145        _indexProjectResource(resource, solrDocument, project);
146        
147        // Indexation of the Solr document
148        _indexResourceSolrDocument(resource, solrDocument, solrClient);
149    }
150    
151    private void _indexProjectResource(Resource resource, SolrInputDocument document, Project project) throws Exception
152    {
153        
154        _solrResourceIndexer.indexResource(resource, document, TYPE_PROJECT_RESOURCE);
155        
156        Site site = project.getSite();
157        
158        if (site != null)
159        {
160            // site name - Store.YES, Index.NOT_ANALYZED
161            document.addField(SolrWebFieldNames.SITE_NAME, site.getName());
162            
163            // site type - Store.YES, Index.NOT_ANALYZED
164            document.addField(SolrWebFieldNames.SITE_TYPE, site.getType());
165        }
166        
167        document.addField(PROJECT_ID, project.getId());
168        document.setField(KEYWORDS, resource.getKeywords());
169    }
170    
171    private void _indexResourceSolrDocument(Resource resource, SolrInputDocument document, SolrClient solrClient) throws SolrServerException, IOException
172    {
173        UpdateResponse solrResponse = solrClient.add(_solrClientProvider.getCollectionName(), document);
174        int status = solrResponse.getStatus();
175        
176        if (status != 0)
177        {
178            throw new IOException("Ametys resource indexing - Expecting status code of '0' in the Solr response but got : '" + status + "'. Resource id : " + resource.getId());
179        }
180        
181        getLogger().debug("Successful resource indexing. Resource identifier : {}", resource.getId());
182    }
183}