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 update clients, per workspace */
053    protected Map<String, SolrClient> _solrUpdateClients;
054    
055    /** The solr core prefix. */
056    protected String _solrCorePrefix;
057    
058    @Override
059    public void service(ServiceManager serviceManager) throws ServiceException
060    {
061        _workspaceSelector = (WorkspaceSelector) serviceManager.lookup(WorkspaceSelector.ROLE);
062    }
063    
064    @Override
065    public void initialize() throws Exception
066    {
067        String url = Config.getInstance().getValueAsString(__SOLR_URL_CONFIG);
068        _solrCorePrefix = Config.getInstance().getValueAsString(__SOLR_CORE_PREFIX_CONFIG);
069        
070        _solrReadClient = new HttpSolrClient.Builder(url).build();
071        if (_solrUpdateClients == null)
072        {
073            _solrUpdateClients = new HashMap<>();
074            for (String workspaceName : _workspaceSelector.getWorkspaces())
075            {
076                _solrUpdateClients.put(workspaceName, _createUpdateClient(url, workspaceName));
077            }
078        }
079    }
080    
081    private SolrClient _createUpdateClient(String url, String workspaceName)
082    {
083        AmetysConcurrentUpdateSolrClient updateClient = new AmetysConcurrentUpdateSolrClient(url, getCollectionName(workspaceName), 10, 4, getLogger());
084        updateClient.setPollQueueTime(10);
085        return updateClient;
086    }
087    
088    @Override
089    public void dispose()
090    {
091        // Release the solr clients (as a Closeable).
092        IOUtils.closeQuietly(_solrReadClient);
093        for (SolrClient solrUpdateClient : _solrUpdateClients.values())
094        {
095            IOUtils.closeQuietly(solrUpdateClient);
096        }
097        _solrReadClient = null;
098        _solrUpdateClients.clear();
099        _solrUpdateClients = null;
100    }
101    
102    @Override
103    public SolrClient getReadClient()
104    {
105        return _solrReadClient;
106    }
107    
108    @Override
109    public SolrClient getUpdateClient(String workspaceName)
110    {
111        SolrClient updateClient = _solrUpdateClients.get(_nonNullWorkspaceName(workspaceName));
112        if (updateClient == null)
113        {
114            // Perhaps the workspace was created after initializing this component, try to check if JCR workspace exist
115            try
116            {
117                if (ArrayUtils.contains(_workspaceSelector.getWorkspaces(), workspaceName))
118                {
119                    String url = Config.getInstance().getValueAsString(__SOLR_URL_CONFIG);
120                    updateClient = _createUpdateClient(url, workspaceName);
121                    _solrUpdateClients.put(workspaceName, updateClient);
122                }
123            }
124            catch (RepositoryException e)
125            {
126                getLogger().error("An error occurs while trying to return all JCR workspaces", e);
127            }
128        }
129        
130        return updateClient;
131    }
132    
133    @Override
134    public String getCollectionName()
135    {
136        return getCollectionName(_workspaceSelector.getWorkspace());
137    }
138    
139    @Override
140    public String getCollectionName(String workspaceName)
141    {
142        return _solrCorePrefix + _nonNullWorkspaceName(workspaceName);
143    }
144    
145    private String _nonNullWorkspaceName(String workspaceName)
146    {
147        if (workspaceName == null)
148        {
149            getLogger().debug("Passing null workspace name. Switching to current workspace.");
150            return _workspaceSelector.getWorkspace();
151        }
152        else
153        {
154            return workspaceName;
155        }
156    }
157}