001/*
002 *  Copyright 2015 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.cms.indexing.solr;
017
018import java.io.IOException;
019import java.util.Set;
020
021import javax.jcr.Repository;
022import javax.jcr.RepositoryException;
023import javax.jcr.Session;
024
025import org.apache.avalon.framework.component.Component;
026import org.apache.avalon.framework.context.Context;
027import org.apache.avalon.framework.context.ContextException;
028import org.apache.avalon.framework.context.Contextualizable;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032import org.apache.cocoon.components.ContextHelper;
033import org.apache.cocoon.environment.Request;
034import org.apache.solr.client.solrj.SolrServerException;
035
036import org.ametys.cms.content.indexing.solr.SolrIndexer;
037import org.ametys.cms.indexing.IndexingException;
038import org.ametys.cms.indexing.WorkspaceIndexer;
039import org.ametys.cms.repository.RequestAttributeWorkspaceSelector;
040import org.ametys.core.ui.Callable;
041import org.ametys.plugins.repository.provider.AbstractRepository;
042import org.ametys.plugins.repository.provider.WorkspaceSelector;
043import org.ametys.runtime.plugin.component.AbstractLogEnabled;
044
045/**
046 * Component indexing a workspace in a Solr server.
047 */
048public class SolrWorkspaceIndexer extends AbstractLogEnabled implements WorkspaceIndexer, Component, Serviceable, Contextualizable
049{
050    /** The repository. */
051    protected Repository _repository;
052    
053    /** The solr indexer. */
054    protected SolrIndexer _solrIndexer;
055    
056    /** The workspace selector. */
057    protected WorkspaceSelector _workspaceSelector;
058    
059    /** Additional documents provider extension point. */
060    protected DocumentProviderExtensionPoint _docProviderEP;
061    
062    /** The component context. */
063    protected Context _context;
064    
065    @Override
066    public void service(ServiceManager manager) throws ServiceException
067    {
068        _repository = (Repository) manager.lookup(AbstractRepository.ROLE);
069        _solrIndexer = (SolrIndexer) manager.lookup(SolrIndexer.ROLE);
070        _workspaceSelector = (WorkspaceSelector) manager.lookup(WorkspaceSelector.ROLE);
071        _docProviderEP = (DocumentProviderExtensionPoint) manager.lookup(DocumentProviderExtensionPoint.ROLE);
072    }
073    
074    @Override
075    public void contextualize(Context context) throws ContextException
076    {
077        _context = context;
078    }
079    
080    @Override
081    @Callable
082    public void indexAllWorkspaces() throws IndexingException
083    {
084        try
085        {
086            // Get all the workspaces and reindex them.
087            Session session = _repository.login();
088            String[] workspaceNames = session.getWorkspace().getAccessibleWorkspaceNames();
089            
090            for (String workspaceName : workspaceNames)
091            {
092                index(workspaceName);
093            }
094        }
095        catch (RepositoryException e)
096        {
097            getLogger().error("Error while indexing the workspaces.", e);
098            throw new IndexingException("Error while indexing the workspaces.", e);
099        }
100    }
101    
102    @Override
103    public void index(String workspaceName) throws IndexingException
104    {
105        try
106        {
107            // Create the core corresponding to the workspace if it doesn't exist.
108            ensureCoreExists(workspaceName);
109            
110            _solrIndexer.sendSchema();
111            
112            getLogger().info("Start indexing workspace {}...", workspaceName);
113            
114            _forceWorkspaceAndDoIndex(workspaceName);
115            
116            getLogger().info("Successfully indexed workspace {}", workspaceName);
117        }
118        catch (IOException | SolrServerException e)
119        {
120            getLogger().error("Error while sending schema.", e);
121            throw new IndexingException("Error while sending schema.", e);
122        }
123    }
124    
125    private void _forceWorkspaceAndDoIndex(String workspaceName) throws IndexingException
126    {
127        Request request = ContextHelper.getRequest(_context);
128        
129        // Retrieve the current workspace.
130        String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
131        
132        try
133        {
134            // Force the workspace.
135            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, workspaceName);
136            doIndex(workspaceName);
137        }
138        finally
139        {
140            // Restore context
141            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp);
142        }
143        
144    }
145    
146    /**
147     * Index the given workspace.
148     * @param workspaceName The workspace name.
149     * @throws IndexingException If an error occurs indexing the workspace.
150     */
151    protected void doIndex(String workspaceName) throws IndexingException
152    {
153        try
154        {
155            // First, unindex all documents.
156            _solrIndexer.unindexAllDocuments(workspaceName, false);
157            
158            // Index all contents.
159            _solrIndexer.indexAllContents(workspaceName, false);
160            
161            // Index all resources.
162            _solrIndexer.indexAllResources(workspaceName, false);
163            
164            // Eventually index additional documents.
165            indexAdditionalDocuments(workspaceName);
166            
167            // Commit changes
168            _solrIndexer.commit(workspaceName);
169            // When done indexing, optimize.
170            _solrIndexer.optimize(workspaceName);
171        }
172        catch (Exception e)
173        {
174            getLogger().error("Error indexing the workspace '" + workspaceName + "'.", e);
175            throw new IndexingException("Error indexing the workspace '" + workspaceName + "'.", e);
176        }
177    }
178    
179    /**
180     * Index additional documents provided by the extensions.
181     * @param workspaceName The workspace name.
182     * @throws IndexingException If an error occurs while indexing.
183     */
184    protected void indexAdditionalDocuments(String workspaceName) throws IndexingException
185    {
186        for (String id : _docProviderEP.getExtensionsIds())
187        {
188            DocumentProvider docProvider = _docProviderEP.getExtension(id);
189            docProvider.indexDocuments(workspaceName);
190        }
191    }
192    
193    /**
194     * Create the given core if it doesn't exist.
195     * @param coreName The core name.
196     * @throws IOException If an I/O error occurs.
197     * @throws SolrServerException If a solr error occurs.
198     */
199    protected void ensureCoreExists(String coreName) throws IOException, SolrServerException
200    {
201        Set<String> coreNames = _solrIndexer.getCoreNames();
202        if (!coreNames.contains(coreName))
203        {
204            _solrIndexer.createCore(coreName);
205        }
206    }
207    
208}