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(url);
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        return new AmetysConcurrentUpdateSolrClient(url, getCollectionName(workspaceName), 10, 4, getLogger());
084    }
085    
086    @Override
087    public void dispose()
088    {
089        // Release the solr clients (as a Closeable).
090        IOUtils.closeQuietly(_solrReadClient);
091        for (SolrClient solrUpdateClient : _solrUpdateClients.values())
092        {
093            IOUtils.closeQuietly(solrUpdateClient);
094        }
095        _solrReadClient = null;
096        _solrUpdateClients.clear();
097        _solrUpdateClients = null;
098    }
099    
100    @Override
101    public SolrClient getReadClient()
102    {
103        return _solrReadClient;
104    }
105    
106    @Override
107    public SolrClient getUpdateClient(String workspaceName)
108    {
109        SolrClient updateClient = _solrUpdateClients.get(_nonNullWorkspaceName(workspaceName));
110        if (updateClient == null)
111        {
112            // Perhaps the workspace was created after initializing this component, try to check if JCR workspace exist
113            try
114            {
115                if (ArrayUtils.contains(_workspaceSelector.getWorkspaces(), workspaceName))
116                {
117                    String url = Config.getInstance().getValueAsString(__SOLR_URL_CONFIG);
118                    updateClient = _createUpdateClient(url, workspaceName);
119                    _solrUpdateClients.put(workspaceName, updateClient);
120                }
121            }
122            catch (RepositoryException e)
123            {
124                getLogger().error("An error occurs while trying to return all JCR workspaces", e);
125            }
126        }
127        
128        return updateClient;
129    }
130    
131    @Override
132    public String getCollectionName()
133    {
134        return getCollectionName(_workspaceSelector.getWorkspace());
135    }
136    
137    @Override
138    public String getCollectionName(String workspaceName)
139    {
140        return _solrCorePrefix + _nonNullWorkspaceName(workspaceName);
141    }
142    
143    private String _nonNullWorkspaceName(String workspaceName)
144    {
145        if (workspaceName == null)
146        {
147            getLogger().debug("Passing null workspace name. Switching to current workspace.");
148            return _workspaceSelector.getWorkspace();
149        }
150        else
151        {
152            return workspaceName;
153        }
154    }
155}