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.cms.search.solr;
017
018import java.io.IOException;
019import java.util.Collection;
020import java.util.Iterator;
021import java.util.List;
022
023import org.apache.commons.lang.StringUtils;
024import org.apache.http.HttpResponse;
025import org.apache.http.StatusLine;
026import org.apache.solr.client.solrj.SolrServerException;
027import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrClient;
028import org.apache.solr.client.solrj.response.UpdateResponse;
029import org.apache.solr.common.SolrException;
030import org.apache.solr.common.SolrInputDocument;
031import org.slf4j.Logger;
032
033/**
034 * Concurrent update solr client specific for Ametys.<br>
035 * Allow operations on only one collection (specified by the constructor),
036 * and forbid operations on all other collections.
037 * Delegate the processing to the ConcurrentUpdateSolrClient (superclass) if the collection is the one in use
038 */
039public abstract class AbstractAmetysConcurrentUpdateClient extends ConcurrentUpdateSolrClient
040{
041    /** Name of the collection, on which operation are allowed */
042    private String _collectionName;
043    
044    private Logger _logger;
045    
046    /**
047     * Constructor
048     * @param solrServerUrl The Solr server URL
049     * @param collectionName The name of the collection, on which operations will be allowed. Operations on other collections will be forbidden.
050     * @param queueSize The buffer size before the documents are sent to the server
051     * @param threadCount The number of background threads used to empty the queue
052     * @param logger internal logger
053     */
054    public AbstractAmetysConcurrentUpdateClient(String solrServerUrl, String collectionName, int queueSize, int threadCount, Logger logger)
055    {
056        super(new Builder(solrServerUrl)
057                .withQueueSize(queueSize)
058                .withThreadCount(threadCount));
059        
060        if (collectionName == null)
061        {
062            throw new IllegalArgumentException("The collection name cannot be null.");
063        }
064        else
065        {
066            _collectionName = collectionName;
067        }
068        
069        _logger = logger;
070    }
071    
072    @Override
073    public void handleError(Throwable t)
074    {
075        StringBuilder msg = new StringBuilder("Solr client indexing error");
076        if (t instanceof SolrException)
077        {
078            msg.append(" caused by the following errors: ").append(((SolrException) t).getMetadata());
079        }
080        msg.append("\nPlease check the Solr logs for more details.");
081        _logger.error(msg.toString(), t);
082    }
083    
084    @Override
085    public void onSuccess(HttpResponse resp)
086    {
087        if (_logger.isDebugEnabled())
088        {
089            StatusLine statusLine = resp.getStatusLine();
090            String reason = statusLine != null ? statusLine.getReasonPhrase() : "";
091            _logger.debug("Successfully processed solr client request and obtained the response : " + StringUtils.defaultIfEmpty(reason, "unknown"));
092        }
093        super.onSuccess(resp);
094    }
095    
096    private void _checkCollectionInUse(String collection) throws SolrServerException
097    {
098        if (collection == null)
099        {
100            throw new UnsupportedOperationException("Collection cannot be null");
101        }
102        
103        if (!StringUtils.equals(_collectionName, collection))
104        {
105            String msg = String.format("Cannot process this update operation for collection '%s' because operations for this client can only be done in '%s'", collection, _collectionName);
106            throw new SolrServerException(msg);
107        }
108    }
109    
110    @Override
111    public UpdateResponse add(String collection, Collection<SolrInputDocument> docs) throws SolrServerException, IOException
112    {
113        _checkCollectionInUse(collection);
114        return super.add(collection, docs);
115    }
116    
117    @Override
118    public UpdateResponse add(Collection<SolrInputDocument> docs) throws SolrServerException, IOException
119    {
120        _checkCollectionInUse(null);
121        return super.add(docs);
122    }
123    
124    @Override
125    public UpdateResponse add(String collection, Collection<SolrInputDocument> docs, int commitWithinMs) throws SolrServerException, IOException
126    {
127        _checkCollectionInUse(collection);
128        return super.add(collection, docs, commitWithinMs);
129    }
130    
131    @Override
132    public UpdateResponse add(Collection<SolrInputDocument> docs, int commitWithinMs) throws SolrServerException, IOException
133    {
134        _checkCollectionInUse(null);
135        return super.add(docs, commitWithinMs);
136    }
137    
138    @Override
139    public UpdateResponse add(String collection, SolrInputDocument doc) throws SolrServerException, IOException
140    {
141        _checkCollectionInUse(collection);
142        return super.add(collection, doc);
143    }
144    
145    @Override 
146    public UpdateResponse add(SolrInputDocument doc) throws SolrServerException, IOException
147    {
148        _checkCollectionInUse(null);
149        return super.add(doc);
150    }
151    
152    @Override
153    public UpdateResponse add(String collection, SolrInputDocument doc, int commitWithinMs) throws SolrServerException, IOException
154    {
155        _checkCollectionInUse(collection);
156        return super.add(collection, doc, commitWithinMs);
157    }
158    
159    @Override
160    public UpdateResponse add(SolrInputDocument doc, int commitWithinMs) throws SolrServerException, IOException
161    {
162        _checkCollectionInUse(null);
163        return super.add(doc, commitWithinMs);
164    }
165    
166    @Override
167    public UpdateResponse add(String collection, Iterator<SolrInputDocument> docIterator) throws SolrServerException, IOException
168    {
169        _checkCollectionInUse(collection);
170        return super.add(collection, docIterator);
171    }
172    
173    @Override
174    public UpdateResponse add(Iterator<SolrInputDocument> docIterator) throws SolrServerException, IOException
175    {
176        _checkCollectionInUse(null);
177        return super.add(docIterator);
178    }
179    
180    @Override
181    public UpdateResponse addBean(String collection, Object obj) throws IOException, SolrServerException
182    {
183        _checkCollectionInUse(collection);
184        return super.addBean(collection, obj);
185    }
186    
187    @Override
188    public UpdateResponse addBean(Object obj) throws IOException, SolrServerException
189    {
190        _checkCollectionInUse(null);
191        return super.addBean(obj);
192    }
193    
194    @Override
195    public UpdateResponse addBean(String collection, Object obj, int commitWithinMs) throws IOException, SolrServerException
196    {
197        _checkCollectionInUse(collection);
198        return super.addBean(collection, obj, commitWithinMs);
199    }
200    
201    @Override
202    public UpdateResponse addBean(Object obj, int commitWithinMs) throws IOException, SolrServerException
203    {
204        _checkCollectionInUse(null);
205        return super.addBean(obj, commitWithinMs);
206    }
207    
208    @Override
209    public UpdateResponse addBeans(String collection, Collection<?> beans) throws SolrServerException, IOException
210    {
211        _checkCollectionInUse(collection);
212        return super.addBeans(collection, beans);
213    }
214    
215    @Override
216    public UpdateResponse addBeans(Collection<?> beans) throws SolrServerException, IOException
217    {
218        _checkCollectionInUse(null);
219        return super.addBeans(beans);
220    }
221    
222    @Override
223    public UpdateResponse addBeans(String collection, Collection<?> beans, int commitWithinMs) throws SolrServerException, IOException
224    {
225        _checkCollectionInUse(collection);
226        return super.addBeans(collection, beans, commitWithinMs);
227    }
228    
229    @Override
230    public UpdateResponse addBeans(Collection<?> beans, int commitWithinMs) throws SolrServerException, IOException
231    {
232        _checkCollectionInUse(null);
233        return super.addBeans(beans, commitWithinMs);
234    }
235    
236    @Override
237    public UpdateResponse addBeans(String collection, final Iterator<?> beanIterator) throws SolrServerException, IOException
238    {
239        _checkCollectionInUse(collection);
240        return super.addBeans(collection, beanIterator);
241    }
242    
243    @Override
244    public UpdateResponse addBeans(final Iterator<?> beanIterator) throws SolrServerException, IOException
245    {
246        _checkCollectionInUse(null);
247        return super.addBeans(beanIterator);
248    }
249    
250    @Override
251    public UpdateResponse commit(String collection) throws SolrServerException, IOException
252    {
253        _checkCollectionInUse(collection);
254        return super.commit(collection);
255    }
256    
257    @Override
258    public UpdateResponse commit() throws SolrServerException, IOException
259    {
260        _checkCollectionInUse(null);
261        return super.commit();
262    }
263    
264    @Override
265    public UpdateResponse commit(String collection, boolean waitFlush, boolean waitSearcher) throws SolrServerException, IOException
266    {
267        _checkCollectionInUse(collection);
268        return super.commit(collection, waitFlush, waitSearcher);
269    }
270    
271    @Override
272    public UpdateResponse commit(boolean waitFlush, boolean waitSearcher) throws SolrServerException, IOException
273    {
274        _checkCollectionInUse(null);
275        return super.commit(waitFlush, waitSearcher);
276    }
277    
278    @Override
279    public UpdateResponse commit(String collection, boolean waitFlush, boolean waitSearcher, boolean softCommit) throws SolrServerException, IOException
280    {
281        _checkCollectionInUse(collection);
282        return super.commit(collection, waitFlush, waitSearcher, softCommit);
283    }
284    
285    @Override
286    public UpdateResponse commit(boolean waitFlush, boolean waitSearcher, boolean softCommit) throws SolrServerException, IOException
287    {
288        _checkCollectionInUse(null);
289        return super.commit(waitFlush, waitSearcher, softCommit);
290    }
291    
292    @Override
293    public UpdateResponse optimize(String collection) throws SolrServerException, IOException
294    {
295        _checkCollectionInUse(collection);
296        return super.optimize(collection);
297    }
298    
299    @Override
300    public UpdateResponse optimize() throws SolrServerException, IOException
301    {
302        _checkCollectionInUse(null);
303        return super.optimize();
304    }
305    
306    @Override
307    public UpdateResponse optimize(String collection, boolean waitFlush, boolean waitSearcher) throws SolrServerException, IOException
308    {
309        _checkCollectionInUse(collection);
310        return super.optimize(collection, waitFlush, waitSearcher);
311    }
312    
313    @Override
314    public UpdateResponse optimize(boolean waitFlush, boolean waitSearcher) throws SolrServerException, IOException
315    {
316        _checkCollectionInUse(null);
317        return super.optimize(waitFlush, waitSearcher);
318    }
319    
320    @Override
321    public UpdateResponse optimize(String collection, boolean waitFlush, boolean waitSearcher, int maxSegments) throws SolrServerException, IOException
322    {
323        _checkCollectionInUse(collection);
324        return super.optimize(collection, waitFlush, waitSearcher, maxSegments);
325    }
326    
327    @Override
328    public UpdateResponse optimize(boolean waitFlush, boolean waitSearcher, int maxSegments) throws SolrServerException, IOException
329    {
330        _checkCollectionInUse(null);
331        return super.optimize(waitFlush, waitSearcher, maxSegments);
332    }
333    
334    @Override
335    public UpdateResponse rollback(String collection) throws SolrServerException, IOException
336    {
337        _checkCollectionInUse(collection);
338        return super.rollback(collection);
339    }
340    
341    @Override
342    public UpdateResponse rollback() throws SolrServerException, IOException
343    {
344        _checkCollectionInUse(null);
345        return super.rollback();
346    }
347    
348    @Override
349    public UpdateResponse deleteById(String collection, String id) throws SolrServerException, IOException
350    {
351        _checkCollectionInUse(collection);
352        return super.deleteById(collection, id);
353    }
354    
355    @Override
356    public UpdateResponse deleteById(String id) throws SolrServerException, IOException
357    {
358        _checkCollectionInUse(null);
359        return super.deleteById(id);
360    }
361    
362    @Override
363    public UpdateResponse deleteById(String collection, String id, int commitWithinMs) throws SolrServerException, IOException
364    {
365        _checkCollectionInUse(collection);
366        return super.deleteById(collection, id, commitWithinMs);
367    }
368    
369    @Override
370    public UpdateResponse deleteById(String id, int commitWithinMs) throws SolrServerException, IOException
371    {
372        _checkCollectionInUse(null);
373        return super.deleteById(id, commitWithinMs);
374    }
375    
376    @Override
377    public UpdateResponse deleteById(String collection, List<String> ids) throws SolrServerException, IOException
378    {
379        _checkCollectionInUse(collection);
380        return super.deleteById(collection, ids);
381    }
382    
383    @Override
384    public UpdateResponse deleteById(List<String> ids) throws SolrServerException, IOException
385    {
386        _checkCollectionInUse(null);
387        return super.deleteById(ids);
388    }
389    
390    @Override
391    public UpdateResponse deleteById(String collection, List<String> ids, int commitWithinMs) throws SolrServerException, IOException
392    {
393        _checkCollectionInUse(collection);
394        return super.deleteById(collection, ids, commitWithinMs);
395    }
396    
397    @Override
398    public UpdateResponse deleteById(List<String> ids, int commitWithinMs) throws SolrServerException, IOException
399    {
400        _checkCollectionInUse(null);
401        return super.deleteById(ids, commitWithinMs);
402    }
403    
404    @Override
405    public UpdateResponse deleteByQuery(String collection, String query) throws SolrServerException, IOException
406    {
407        _checkCollectionInUse(collection);
408        return super.deleteByQuery(collection, query);
409    }
410    
411    @Override
412    public UpdateResponse deleteByQuery(String query) throws SolrServerException, IOException
413    {
414        _checkCollectionInUse(null);
415        return super.deleteByQuery(query);
416    }
417    
418    @Override
419    public UpdateResponse deleteByQuery(String collection, String query, int commitWithinMs) throws SolrServerException, IOException
420    {
421        _checkCollectionInUse(collection);
422        return super.deleteByQuery(collection, query, commitWithinMs);
423    }
424    
425    @Override
426    public UpdateResponse deleteByQuery(String query, int commitWithinMs) throws SolrServerException, IOException
427    {
428        _checkCollectionInUse(null);
429        return super.deleteByQuery(query, commitWithinMs);
430    }
431}