001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.search;
016    
017    import com.liferay.portal.kernel.concurrent.CallerRunsPolicy;
018    import com.liferay.portal.kernel.concurrent.RejectedExecutionHandler;
019    import com.liferay.portal.kernel.concurrent.ThreadPoolExecutor;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.messaging.Destination;
023    import com.liferay.portal.kernel.messaging.DestinationConfiguration;
024    import com.liferay.portal.kernel.messaging.DestinationFactory;
025    import com.liferay.portal.kernel.messaging.DestinationFactoryUtil;
026    import com.liferay.portal.kernel.messaging.InvokerMessageListener;
027    import com.liferay.portal.kernel.messaging.MessageBus;
028    import com.liferay.portal.kernel.messaging.MessageListener;
029    import com.liferay.portal.kernel.model.CompanyConstants;
030    import com.liferay.portal.kernel.search.messaging.BaseSearchEngineMessageListener;
031    import com.liferay.portal.kernel.search.messaging.SearchReaderMessageListener;
032    import com.liferay.portal.kernel.search.messaging.SearchWriterMessageListener;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.kernel.util.PortalRunMode;
035    import com.liferay.portal.kernel.util.PropsKeys;
036    import com.liferay.portal.kernel.util.PropsUtil;
037    import com.liferay.portal.kernel.util.StringBundler;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.registry.Registry;
040    import com.liferay.registry.RegistryUtil;
041    import com.liferay.registry.dependency.ServiceDependencyListener;
042    import com.liferay.registry.dependency.ServiceDependencyManager;
043    
044    import java.util.ArrayList;
045    import java.util.List;
046    import java.util.Map;
047    import java.util.Map.Entry;
048    import java.util.Set;
049    
050    /**
051     * @author Michael C. Han
052     */
053    public abstract class AbstractSearchEngineConfigurator
054            implements SearchEngineConfigurator {
055    
056            @Override
057            public void afterPropertiesSet() {
058                    final ServiceDependencyManager serviceDependencyManager =
059                            new ServiceDependencyManager();
060    
061                    serviceDependencyManager.addServiceDependencyListener(
062                            new ServiceDependencyListener() {
063    
064                                    @Override
065                                    public void dependenciesFulfilled() {
066                                            Registry registry = RegistryUtil.getRegistry();
067    
068                                            _messageBus = registry.getService(MessageBus.class);
069    
070                                            initialize();
071                                    }
072    
073                                    @Override
074                                    public void destroy() {
075                                    }
076    
077                            });
078    
079                    serviceDependencyManager.registerDependencies(
080                            DestinationFactory.class, MessageBus.class);
081            }
082    
083            @Override
084            public void destroy() {
085                    for (SearchEngineRegistration searchEngineRegistration :
086                                    _searchEngineRegistrations) {
087    
088                            destroySearchEngine(searchEngineRegistration);
089                    }
090    
091                    _searchEngineRegistrations.clear();
092    
093                    if (Validator.isNotNull(_originalSearchEngineId)) {
094                            SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
095    
096                            searchEngineHelper.setDefaultSearchEngineId(
097                                    _originalSearchEngineId);
098    
099                            _originalSearchEngineId = null;
100                    }
101            }
102    
103            @Override
104            public void setSearchEngines(Map<String, SearchEngine> searchEngines) {
105                    _searchEngines = searchEngines;
106            }
107    
108            protected void createSearchEngineListeners(
109                    String searchEngineId, SearchEngine searchEngine,
110                    Destination searchReaderDestination,
111                    Destination searchWriterDestination) {
112    
113                    registerSearchEngineMessageListener(
114                            searchEngineId, searchEngine, searchReaderDestination,
115                            new SearchReaderMessageListener(), searchEngine.getIndexSearcher());
116    
117                    registerSearchEngineMessageListener(
118                            searchEngineId, searchEngine, searchWriterDestination,
119                            new SearchWriterMessageListener(), searchEngine.getIndexWriter());
120            }
121    
122            protected Destination createSearchReaderDestination(
123                    String searchReaderDestinationName) {
124    
125                    DestinationConfiguration destinationConfiguration =
126                            DestinationConfiguration.createSynchronousDestinationConfiguration(
127                                    searchReaderDestinationName);
128    
129                    return DestinationFactoryUtil.createDestination(
130                            destinationConfiguration);
131            }
132    
133            protected Destination createSearchWriterDestination(
134                    String searchWriterDestinationName) {
135    
136                    DestinationConfiguration destinationConfiguration = null;
137    
138                    if (PortalRunMode.isTestMode()) {
139                            destinationConfiguration =
140                                    DestinationConfiguration.
141                                            createSynchronousDestinationConfiguration(
142                                                    searchWriterDestinationName);
143                    }
144                    else {
145                            destinationConfiguration =
146                                    DestinationConfiguration.createParallelDestinationConfiguration(
147                                            searchWriterDestinationName);
148                    }
149    
150                    if (_INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE > 0) {
151                            destinationConfiguration.setMaximumQueueSize(
152                                    _INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE);
153    
154                            RejectedExecutionHandler rejectedExecutionHandler =
155                                    new CallerRunsPolicy() {
156    
157                                            @Override
158                                            public void rejectedExecution(
159                                                    Runnable runnable,
160                                                    ThreadPoolExecutor threadPoolExecutor) {
161    
162                                                    if (_log.isWarnEnabled()) {
163                                                            StringBundler sb = new StringBundler(4);
164    
165                                                            sb.append("The search index writer's task queue ");
166                                                            sb.append("is at its maximum capacity. The ");
167                                                            sb.append("current thread will handle the ");
168                                                            sb.append("request.");
169    
170                                                            _log.warn(sb.toString());
171                                                    }
172    
173                                                    super.rejectedExecution(runnable, threadPoolExecutor);
174                                            }
175    
176                                    };
177    
178                            destinationConfiguration.setRejectedExecutionHandler(
179                                    rejectedExecutionHandler);
180                    }
181    
182                    return DestinationFactoryUtil.createDestination(
183                            destinationConfiguration);
184            }
185    
186            protected void destroySearchEngine(
187                    SearchEngineRegistration searchEngineRegistration) {
188    
189                    _messageBus.removeDestination(
190                            searchEngineRegistration.getSearchReaderDestinationName());
191    
192                    _messageBus.removeDestination(
193                            searchEngineRegistration.getSearchWriterDestinationName());
194    
195                    SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
196    
197                    searchEngineHelper.removeSearchEngine(
198                            searchEngineRegistration.getSearchEngineId());
199    
200                    if (!searchEngineRegistration.isOverride()) {
201                            return;
202                    }
203    
204                    SearchEngineProxyWrapper originalSearchEngineProxy =
205                            searchEngineRegistration.getOriginalSearchEngineProxyWrapper();
206    
207                    Destination searchReaderDestination = getSearchReaderDestination(
208                            _messageBus, searchEngineRegistration.getSearchEngineId());
209    
210                    registerInvokerMessageListener(
211                            searchReaderDestination,
212                            searchEngineRegistration.getOriginalSearchReaderMessageListeners());
213    
214                    Destination searchWriterDestination = getSearchWriterDestination(
215                            _messageBus, searchEngineRegistration.getSearchEngineId());
216    
217                    registerInvokerMessageListener(
218                            searchWriterDestination,
219                            searchEngineRegistration.getOriginalSearchWriterMessageListeners());
220    
221                    setSearchEngine(
222                            searchEngineRegistration.getSearchEngineId(),
223                            originalSearchEngineProxy);
224            }
225    
226            protected abstract String getDefaultSearchEngineId();
227    
228            protected abstract IndexSearcher getIndexSearcher();
229    
230            protected abstract IndexWriter getIndexWriter();
231    
232            protected abstract ClassLoader getOperatingClassloader();
233    
234            protected abstract SearchEngineHelper getSearchEngineHelper();
235    
236            protected Destination getSearchReaderDestination(
237                    MessageBus messageBus, String searchEngineId) {
238    
239                    SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
240    
241                    String searchReaderDestinationName =
242                            searchEngineHelper.getSearchReaderDestinationName(searchEngineId);
243    
244                    Destination searchReaderDestination = messageBus.getDestination(
245                            searchReaderDestinationName);
246    
247                    if (searchReaderDestination == null) {
248                            searchReaderDestination = createSearchReaderDestination(
249                                    searchReaderDestinationName);
250    
251                            messageBus.addDestination(searchReaderDestination);
252                    }
253    
254                    return searchReaderDestination;
255            }
256    
257            protected Destination getSearchWriterDestination(
258                    MessageBus messageBus, String searchEngineId) {
259    
260                    SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
261    
262                    String searchWriterDestinationName =
263                            searchEngineHelper.getSearchWriterDestinationName(searchEngineId);
264    
265                    Destination searchWriterDestination = messageBus.getDestination(
266                            searchWriterDestinationName);
267    
268                    if (searchWriterDestination == null) {
269                            searchWriterDestination = createSearchWriterDestination(
270                                    searchWriterDestinationName);
271    
272                            messageBus.addDestination(searchWriterDestination);
273                    }
274    
275                    return searchWriterDestination;
276            }
277    
278            protected void initialize() {
279                    Set<Entry<String, SearchEngine>> entrySet = _searchEngines.entrySet();
280    
281                    for (Entry<String, SearchEngine> entry : entrySet) {
282                            initSearchEngine(entry.getKey(), entry.getValue());
283                    }
284    
285                    String defaultSearchEngineId = getDefaultSearchEngineId();
286    
287                    if (Validator.isNotNull(defaultSearchEngineId)) {
288                            SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
289    
290                            _originalSearchEngineId =
291                                    searchEngineHelper.getDefaultSearchEngineId();
292    
293                            searchEngineHelper.setDefaultSearchEngineId(defaultSearchEngineId);
294                    }
295    
296                    _searchEngines.clear();
297            }
298    
299            protected void initSearchEngine(
300                    String searchEngineId, SearchEngine searchEngine) {
301    
302                    SearchEngineRegistration searchEngineRegistration =
303                            new SearchEngineRegistration(searchEngineId);
304    
305                    _searchEngineRegistrations.add(searchEngineRegistration);
306    
307                    Destination searchReaderDestination = getSearchReaderDestination(
308                            _messageBus, searchEngineId);
309    
310                    searchEngineRegistration.setSearchReaderDestinationName(
311                            searchReaderDestination.getName());
312    
313                    Destination searchWriterDestination = getSearchWriterDestination(
314                            _messageBus, searchEngineId);
315    
316                    searchEngineRegistration.setSearchWriterDestinationName(
317                            searchWriterDestination.getName());
318    
319                    SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
320    
321                    SearchEngine originalSearchEngine =
322                            searchEngineHelper.getSearchEngineSilent(searchEngineId);
323    
324                    if (originalSearchEngine != null) {
325                            searchEngineRegistration.setOverride(true);
326    
327                            searchEngineRegistration.setOriginalSearchEngineProxyWrapper(
328                                    (SearchEngineProxyWrapper)originalSearchEngine);
329    
330                            savePreviousSearchEngineListeners(
331                                    searchReaderDestination, searchWriterDestination,
332                                    searchEngineRegistration);
333    
334                            _messageBus.removeDestination(
335                                    searchReaderDestination.getName(), false);
336    
337                            searchReaderDestination = getSearchReaderDestination(
338                                    _messageBus, searchEngineId);
339    
340                            _messageBus.removeDestination(
341                                    searchWriterDestination.getName(), false);
342    
343                            searchWriterDestination = getSearchWriterDestination(
344                                    _messageBus, searchEngineId);
345                    }
346    
347                    createSearchEngineListeners(
348                            searchEngineId, searchEngine, searchReaderDestination,
349                            searchWriterDestination);
350    
351                    SearchEngineProxyWrapper searchEngineProxyWrapper =
352                            new SearchEngineProxyWrapper(
353                                    searchEngine, getIndexSearcher(), getIndexWriter());
354    
355                    setSearchEngine(searchEngineId, searchEngineProxyWrapper);
356            }
357    
358            protected void registerInvokerMessageListener(
359                    Destination destination,
360                    List<InvokerMessageListener> invokerMessageListeners) {
361    
362                    for (InvokerMessageListener invokerMessageListener :
363                                    invokerMessageListeners) {
364    
365                            destination.register(
366                                    invokerMessageListener.getMessageListener(),
367                                    invokerMessageListener.getClassLoader());
368                    }
369            }
370    
371            protected void registerSearchEngineMessageListener(
372                    String searchEngineId, SearchEngine searchEngine,
373                    Destination destination,
374                    BaseSearchEngineMessageListener baseSearchEngineMessageListener,
375                    Object manager) {
376    
377                    baseSearchEngineMessageListener.setManager(manager);
378                    baseSearchEngineMessageListener.setMessageBus(_messageBus);
379                    baseSearchEngineMessageListener.setSearchEngine(searchEngine);
380                    baseSearchEngineMessageListener.setSearchEngineId(searchEngineId);
381    
382                    destination.register(
383                            baseSearchEngineMessageListener, getOperatingClassloader());
384            }
385    
386            protected void savePreviousSearchEngineListeners(
387                    Destination searchReaderDestination,
388                    Destination searchWriterDestination,
389                    SearchEngineRegistration searchEngineRegistration) {
390    
391                    Set<MessageListener> searchReaderMessageListeners =
392                            searchReaderDestination.getMessageListeners();
393    
394                    for (MessageListener searchReaderMessageListener :
395                                    searchReaderMessageListeners) {
396    
397                            InvokerMessageListener invokerMessageListener =
398                                    (InvokerMessageListener)searchReaderMessageListener;
399    
400                            searchEngineRegistration.addOriginalSearchReaderMessageListener(
401                                    invokerMessageListener);
402                    }
403    
404                    Set<MessageListener> searchWriterMessageListeners =
405                            searchWriterDestination.getMessageListeners();
406    
407                    for (MessageListener searchWriterMessageListener :
408                                    searchWriterMessageListeners) {
409    
410                            InvokerMessageListener invokerMessageListener =
411                                    (InvokerMessageListener)searchWriterMessageListener;
412    
413                            searchEngineRegistration.addOriginalSearchWriterMessageListener(
414                                    invokerMessageListener);
415                    }
416            }
417    
418            protected void setSearchEngine(
419                    String searchEngineId, SearchEngine searchEngine) {
420    
421                    SearchEngineHelper searchEngineHelper = getSearchEngineHelper();
422    
423                    searchEngineHelper.setSearchEngine(searchEngineId, searchEngine);
424    
425                    searchEngine.initialize(CompanyConstants.SYSTEM);
426            }
427    
428            private static final int _INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE =
429                    GetterUtil.getInteger(
430                            PropsUtil.get(PropsKeys.INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE));
431    
432            private static final Log _log = LogFactoryUtil.getLog(
433                    AbstractSearchEngineConfigurator.class);
434    
435            private volatile MessageBus _messageBus;
436            private String _originalSearchEngineId;
437            private final List<SearchEngineRegistration> _searchEngineRegistrations =
438                    new ArrayList<>();
439            private Map<String, SearchEngine> _searchEngines;
440    
441            private static class SearchEngineRegistration {
442    
443                    public void addOriginalSearchReaderMessageListener(
444                            InvokerMessageListener messageListener) {
445    
446                            _originalSearchReaderMessageListeners.add(messageListener);
447                    }
448    
449                    public void addOriginalSearchWriterMessageListener(
450                            InvokerMessageListener messageListener) {
451    
452                            _originalSearchWriterMessageListeners.add(messageListener);
453                    }
454    
455                    public SearchEngineProxyWrapper getOriginalSearchEngineProxyWrapper() {
456                            return _originalSearchEngineProxyWrapper;
457                    }
458    
459                    public List<InvokerMessageListener>
460                            getOriginalSearchReaderMessageListeners() {
461    
462                            return _originalSearchReaderMessageListeners;
463                    }
464    
465                    public List<InvokerMessageListener>
466                            getOriginalSearchWriterMessageListeners() {
467    
468                            return _originalSearchWriterMessageListeners;
469                    }
470    
471                    public String getSearchEngineId() {
472                            return _searchEngineId;
473                    }
474    
475                    public String getSearchReaderDestinationName() {
476                            return _searchReaderDestinationName;
477                    }
478    
479                    public String getSearchWriterDestinationName() {
480                            return _searchWriterDestinationName;
481                    }
482    
483                    public boolean isOverride() {
484                            return _override;
485                    }
486    
487                    public void setOriginalSearchEngineProxyWrapper(
488                            SearchEngineProxyWrapper searchEngineProxyWrapper) {
489    
490                            _originalSearchEngineProxyWrapper = searchEngineProxyWrapper;
491                    }
492    
493                    public void setOverride(boolean override) {
494                            _override = override;
495                    }
496    
497                    public void setSearchReaderDestinationName(
498                            String searchReaderDestinationName) {
499    
500                            _searchReaderDestinationName = searchReaderDestinationName;
501                    }
502    
503                    public void setSearchWriterDestinationName(
504                            String searchWriterDestinationName) {
505    
506                            _searchWriterDestinationName = searchWriterDestinationName;
507                    }
508    
509                    private SearchEngineRegistration(String searchEngineId) {
510                            _searchEngineId = searchEngineId;
511                    }
512    
513                    private SearchEngineProxyWrapper _originalSearchEngineProxyWrapper;
514                    private final List<InvokerMessageListener>
515                            _originalSearchReaderMessageListeners = new ArrayList<>();
516                    private final List<InvokerMessageListener>
517                            _originalSearchWriterMessageListeners = new ArrayList<>();
518                    private boolean _override;
519                    private final String _searchEngineId;
520                    private String _searchReaderDestinationName;
521                    private String _searchWriterDestinationName;
522    
523            }
524    
525    }