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.search.solr;
017
018import java.util.HashMap;
019import java.util.Map;
020
021import javax.jcr.RepositoryException;
022
023import org.apache.avalon.framework.activity.Disposable;
024import org.apache.avalon.framework.activity.Initializable;
025import org.apache.avalon.framework.component.Component;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.commons.io.IOUtils;
030import org.apache.commons.lang3.ArrayUtils;
031import org.apache.solr.client.solrj.SolrClient;
032import org.apache.solr.client.solrj.impl.HttpSolrClient;
033
034import org.ametys.plugins.repository.provider.WorkspaceSelector;
035import org.ametys.runtime.config.Config;
036import org.ametys.runtime.plugin.component.AbstractLogEnabled;
037
038/**
039 * Component acting as a single entry point to get access to Solr clients.
040 */
041public class DefaultSolrClientProvider extends AbstractLogEnabled implements SolrClientProvider, Component, Serviceable, Initializable, Disposable
042{
043    private static final String __SOLR_URL_CONFIG = "cms.solr.core.url"; 
044    private static final String __SOLR_CORE_PREFIX_CONFIG = "cms.solr.core.prefix"; 
045    
046    /** The workspace selector. */
047    protected WorkspaceSelector _workspaceSelector;
048    
049    /** The Solr read client. */
050    protected SolrClient _solrReadClient;
051    
052    /** The Solr "default" update clients, per workspace */
053    protected Map<String, SolrClient> _solrDefaultUpdateClients;
054    
055    /** The Solr "no auto commit" update clients, per workspace */
056    protected Map<String, SolrClient> _solrNoAutoCommitUpdateClients;
057    
058    /** The solr core prefix. */
059    protected String _solrCorePrefix;
060    
061    @Override
062    public void service(ServiceManager serviceManager) throws ServiceException
063    {
064        _workspaceSelector = (WorkspaceSelector) serviceManager.lookup(WorkspaceSelector.ROLE);
065    }
066    
067    @Override
068    public void initialize() throws Exception
069    {
070        String url = Config.getInstance().getValue(__SOLR_URL_CONFIG);
071        _solrCorePrefix = Config.getInstance().getValue(__SOLR_CORE_PREFIX_CONFIG);
072        
073        _solrReadClient = new HttpSolrClient.Builder(url).build();
074        
075        String[] workspaces = _workspaceSelector.getWorkspaces();
076        _solrDefaultUpdateClients = new HashMap<>();
077        _solrNoAutoCommitUpdateClients = new HashMap<>();
078        for (String workspaceName : workspaces)
079        {
080            _solrDefaultUpdateClients.put(workspaceName, _createDefaultUpdateClient(url, workspaceName));
081            _solrNoAutoCommitUpdateClients.put(workspaceName, _createNoAutoCommitUpdateClient(url, workspaceName));
082        }
083    }
084    
085    private SolrClient _createDefaultUpdateClient(String url, String workspaceName)
086    {
087        AbstractAmetysConcurrentUpdateClient updateClient = new DefaultUpdateClient(url, getCollectionName(workspaceName), 10, 4, getLogger());
088        updateClient.setPollQueueTime(10);
089        return updateClient;
090    }
091    
092    private SolrClient _createNoAutoCommitUpdateClient(String url, String workspaceName)
093    {
094        AbstractAmetysConcurrentUpdateClient updateClient = new NoAutoCommitUpdateClient(url, getCollectionName(workspaceName), 10, 4, getLogger());
095        updateClient.setPollQueueTime(10);
096        return updateClient;
097    }
098    
099    @SuppressWarnings("deprecation")
100    @Override
101    public void dispose()
102    {
103        // Release the solr clients (as a Closeable).
104        IOUtils.closeQuietly(_solrReadClient);
105        _solrReadClient = null;
106        
107        for (SolrClient solrDefaultUpdateClient : _solrDefaultUpdateClients.values())
108        {
109            IOUtils.closeQuietly(solrDefaultUpdateClient);
110        }
111        _solrDefaultUpdateClients.clear();
112        _solrDefaultUpdateClients = null;
113        
114        for (SolrClient solrNoAutoCommitUpdateClient : _solrNoAutoCommitUpdateClients.values())
115        {
116            IOUtils.closeQuietly(solrNoAutoCommitUpdateClient);
117        }
118        _solrNoAutoCommitUpdateClients.clear();
119        _solrNoAutoCommitUpdateClients = null;
120    }
121    
122    @Override
123    public SolrClient getReadClient()
124    {
125        return _solrReadClient;
126    }
127    
128    @Override
129    public SolrClient getUpdateClient(String workspaceName, boolean autoCommit)
130    {
131        Map<String, SolrClient> updateClients = autoCommit ? _solrDefaultUpdateClients : _solrNoAutoCommitUpdateClients;
132        
133        SolrClient updateClient = updateClients.get(_nonNullWorkspaceName(workspaceName));
134        if (updateClient == null)
135        {
136            // Perhaps the workspace was created after initializing this component, try to check if JCR workspace exist
137            try
138            {
139                if (ArrayUtils.contains(_workspaceSelector.getWorkspaces(), workspaceName))
140                {
141                    String url = Config.getInstance().getValue(__SOLR_URL_CONFIG);
142                    updateClient = autoCommit ? _createDefaultUpdateClient(url, workspaceName) : _createNoAutoCommitUpdateClient(url, workspaceName);
143                    updateClients.put(workspaceName, updateClient);
144                }
145            }
146            catch (RepositoryException e)
147            {
148                getLogger().error("An error occurs while trying to return all JCR workspaces", e);
149            }
150        }
151        
152        return updateClient;
153    }
154    
155    @Override
156    public String getCollectionName()
157    {
158        return getCollectionName(_workspaceSelector.getWorkspace());
159    }
160    
161    @Override
162    public String getCollectionName(String workspaceName)
163    {
164        return _solrCorePrefix + _nonNullWorkspaceName(workspaceName);
165    }
166    
167    private String _nonNullWorkspaceName(String workspaceName)
168    {
169        if (workspaceName == null)
170        {
171            getLogger().debug("Passing null workspace name. Switching to current workspace.");
172            return _workspaceSelector.getWorkspace();
173        }
174        else
175        {
176            return workspaceName;
177        }
178    }
179}