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