/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.search; import com.liferay.portal.kernel.concurrent.CallerRunsPolicy; import com.liferay.portal.kernel.concurrent.RejectedExecutionHandler; import com.liferay.portal.kernel.concurrent.ThreadPoolExecutor; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.messaging.Destination; import com.liferay.portal.kernel.messaging.DestinationConfiguration; import com.liferay.portal.kernel.messaging.DestinationFactory; import com.liferay.portal.kernel.messaging.DestinationFactoryUtil; import com.liferay.portal.kernel.messaging.InvokerMessageListener; import com.liferay.portal.kernel.messaging.MessageBus; import com.liferay.portal.kernel.messaging.MessageListener; import com.liferay.portal.kernel.model.CompanyConstants; import com.liferay.portal.kernel.search.messaging.BaseSearchEngineMessageListener; import com.liferay.portal.kernel.search.messaging.SearchReaderMessageListener; import com.liferay.portal.kernel.search.messaging.SearchWriterMessageListener; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.PortalRunMode; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.Validator; import com.liferay.registry.Registry; import com.liferay.registry.RegistryUtil; import com.liferay.registry.dependency.ServiceDependencyListener; import com.liferay.registry.dependency.ServiceDependencyManager; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * @author Michael C. Han */ public abstract class AbstractSearchEngineConfigurator implements SearchEngineConfigurator { @Override public void afterPropertiesSet() { final ServiceDependencyManager serviceDependencyManager = new ServiceDependencyManager(); serviceDependencyManager.addServiceDependencyListener( new ServiceDependencyListener() { @Override public void dependenciesFulfilled() { Registry registry = RegistryUtil.getRegistry(); _messageBus = registry.getService(MessageBus.class); initialize(); } @Override public void destroy() { } }); serviceDependencyManager.registerDependencies( DestinationFactory.class, MessageBus.class); } @Override public void destroy() { for (SearchEngineRegistration searchEngineRegistration : _searchEngineRegistrations) { destroySearchEngine(searchEngineRegistration); } _searchEngineRegistrations.clear(); if (Validator.isNotNull(_originalSearchEngineId)) { SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); searchEngineHelper.setDefaultSearchEngineId( _originalSearchEngineId); _originalSearchEngineId = null; } } @Override public void setSearchEngines(Map<String, SearchEngine> searchEngines) { _searchEngines = searchEngines; } protected void createSearchEngineListeners( String searchEngineId, SearchEngine searchEngine, Destination searchReaderDestination, Destination searchWriterDestination) { registerSearchEngineMessageListener( searchEngineId, searchEngine, searchReaderDestination, new SearchReaderMessageListener(), searchEngine.getIndexSearcher()); registerSearchEngineMessageListener( searchEngineId, searchEngine, searchWriterDestination, new SearchWriterMessageListener(), searchEngine.getIndexWriter()); } protected Destination createSearchReaderDestination( String searchReaderDestinationName) { DestinationConfiguration destinationConfiguration = DestinationConfiguration.createSynchronousDestinationConfiguration( searchReaderDestinationName); return DestinationFactoryUtil.createDestination( destinationConfiguration); } protected Destination createSearchWriterDestination( String searchWriterDestinationName) { DestinationConfiguration destinationConfiguration = null; if (PortalRunMode.isTestMode()) { destinationConfiguration = DestinationConfiguration. createSynchronousDestinationConfiguration( searchWriterDestinationName); } else { destinationConfiguration = DestinationConfiguration.createParallelDestinationConfiguration( searchWriterDestinationName); } if (_INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE > 0) { destinationConfiguration.setMaximumQueueSize( _INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE); RejectedExecutionHandler rejectedExecutionHandler = new CallerRunsPolicy() { @Override public void rejectedExecution( Runnable runnable, ThreadPoolExecutor threadPoolExecutor) { if (_log.isWarnEnabled()) { StringBundler sb = new StringBundler(4); sb.append("The search index writer's task queue "); sb.append("is at its maximum capacity. The "); sb.append("current thread will handle the "); sb.append("request."); _log.warn(sb.toString()); } super.rejectedExecution(runnable, threadPoolExecutor); } }; destinationConfiguration.setRejectedExecutionHandler( rejectedExecutionHandler); } return DestinationFactoryUtil.createDestination( destinationConfiguration); } protected void destroySearchEngine( SearchEngineRegistration searchEngineRegistration) { _messageBus.removeDestination( searchEngineRegistration.getSearchReaderDestinationName()); _messageBus.removeDestination( searchEngineRegistration.getSearchWriterDestinationName()); SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); searchEngineHelper.removeSearchEngine( searchEngineRegistration.getSearchEngineId()); if (!searchEngineRegistration.isOverride()) { return; } SearchEngineProxyWrapper originalSearchEngineProxy = searchEngineRegistration.getOriginalSearchEngineProxyWrapper(); Destination searchReaderDestination = getSearchReaderDestination( _messageBus, searchEngineRegistration.getSearchEngineId()); registerInvokerMessageListener( searchReaderDestination, searchEngineRegistration.getOriginalSearchReaderMessageListeners()); Destination searchWriterDestination = getSearchWriterDestination( _messageBus, searchEngineRegistration.getSearchEngineId()); registerInvokerMessageListener( searchWriterDestination, searchEngineRegistration.getOriginalSearchWriterMessageListeners()); setSearchEngine( searchEngineRegistration.getSearchEngineId(), originalSearchEngineProxy); } protected abstract String getDefaultSearchEngineId(); protected abstract IndexSearcher getIndexSearcher(); protected abstract IndexWriter getIndexWriter(); protected abstract ClassLoader getOperatingClassloader(); protected abstract SearchEngineHelper getSearchEngineHelper(); protected Destination getSearchReaderDestination( MessageBus messageBus, String searchEngineId) { SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); String searchReaderDestinationName = searchEngineHelper.getSearchReaderDestinationName(searchEngineId); Destination searchReaderDestination = messageBus.getDestination( searchReaderDestinationName); if (searchReaderDestination == null) { searchReaderDestination = createSearchReaderDestination( searchReaderDestinationName); messageBus.addDestination(searchReaderDestination); } return searchReaderDestination; } protected Destination getSearchWriterDestination( MessageBus messageBus, String searchEngineId) { SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); String searchWriterDestinationName = searchEngineHelper.getSearchWriterDestinationName(searchEngineId); Destination searchWriterDestination = messageBus.getDestination( searchWriterDestinationName); if (searchWriterDestination == null) { searchWriterDestination = createSearchWriterDestination( searchWriterDestinationName); messageBus.addDestination(searchWriterDestination); } return searchWriterDestination; } protected void initialize() { Set<Entry<String, SearchEngine>> entrySet = _searchEngines.entrySet(); for (Entry<String, SearchEngine> entry : entrySet) { initSearchEngine(entry.getKey(), entry.getValue()); } String defaultSearchEngineId = getDefaultSearchEngineId(); if (Validator.isNotNull(defaultSearchEngineId)) { SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); _originalSearchEngineId = searchEngineHelper.getDefaultSearchEngineId(); searchEngineHelper.setDefaultSearchEngineId(defaultSearchEngineId); } _searchEngines.clear(); } protected void initSearchEngine( String searchEngineId, SearchEngine searchEngine) { SearchEngineRegistration searchEngineRegistration = new SearchEngineRegistration(searchEngineId); _searchEngineRegistrations.add(searchEngineRegistration); Destination searchReaderDestination = getSearchReaderDestination( _messageBus, searchEngineId); searchEngineRegistration.setSearchReaderDestinationName( searchReaderDestination.getName()); Destination searchWriterDestination = getSearchWriterDestination( _messageBus, searchEngineId); searchEngineRegistration.setSearchWriterDestinationName( searchWriterDestination.getName()); SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); SearchEngine originalSearchEngine = searchEngineHelper.getSearchEngineSilent(searchEngineId); if (originalSearchEngine != null) { searchEngineRegistration.setOverride(true); searchEngineRegistration.setOriginalSearchEngineProxyWrapper( (SearchEngineProxyWrapper)originalSearchEngine); savePreviousSearchEngineListeners( searchReaderDestination, searchWriterDestination, searchEngineRegistration); _messageBus.removeDestination( searchReaderDestination.getName(), false); searchReaderDestination = getSearchReaderDestination( _messageBus, searchEngineId); _messageBus.removeDestination( searchWriterDestination.getName(), false); searchWriterDestination = getSearchWriterDestination( _messageBus, searchEngineId); } createSearchEngineListeners( searchEngineId, searchEngine, searchReaderDestination, searchWriterDestination); SearchEngineProxyWrapper searchEngineProxyWrapper = new SearchEngineProxyWrapper( searchEngine, getIndexSearcher(), getIndexWriter()); setSearchEngine(searchEngineId, searchEngineProxyWrapper); } protected void registerInvokerMessageListener( Destination destination, List<InvokerMessageListener> invokerMessageListeners) { for (InvokerMessageListener invokerMessageListener : invokerMessageListeners) { destination.register( invokerMessageListener.getMessageListener(), invokerMessageListener.getClassLoader()); } } protected void registerSearchEngineMessageListener( String searchEngineId, SearchEngine searchEngine, Destination destination, BaseSearchEngineMessageListener baseSearchEngineMessageListener, Object manager) { baseSearchEngineMessageListener.setManager(manager); baseSearchEngineMessageListener.setMessageBus(_messageBus); baseSearchEngineMessageListener.setSearchEngine(searchEngine); baseSearchEngineMessageListener.setSearchEngineId(searchEngineId); destination.register( baseSearchEngineMessageListener, getOperatingClassloader()); } protected void savePreviousSearchEngineListeners( Destination searchReaderDestination, Destination searchWriterDestination, SearchEngineRegistration searchEngineRegistration) { Set<MessageListener> searchReaderMessageListeners = searchReaderDestination.getMessageListeners(); for (MessageListener searchReaderMessageListener : searchReaderMessageListeners) { InvokerMessageListener invokerMessageListener = (InvokerMessageListener)searchReaderMessageListener; searchEngineRegistration.addOriginalSearchReaderMessageListener( invokerMessageListener); } Set<MessageListener> searchWriterMessageListeners = searchWriterDestination.getMessageListeners(); for (MessageListener searchWriterMessageListener : searchWriterMessageListeners) { InvokerMessageListener invokerMessageListener = (InvokerMessageListener)searchWriterMessageListener; searchEngineRegistration.addOriginalSearchWriterMessageListener( invokerMessageListener); } } protected void setSearchEngine( String searchEngineId, SearchEngine searchEngine) { SearchEngineHelper searchEngineHelper = getSearchEngineHelper(); searchEngineHelper.setSearchEngine(searchEngineId, searchEngine); searchEngine.initialize(CompanyConstants.SYSTEM); } private static final int _INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE = GetterUtil.getInteger( PropsUtil.get(PropsKeys.INDEX_SEARCH_WRITER_MAX_QUEUE_SIZE)); private static final Log _log = LogFactoryUtil.getLog( AbstractSearchEngineConfigurator.class); private volatile MessageBus _messageBus; private String _originalSearchEngineId; private final List<SearchEngineRegistration> _searchEngineRegistrations = new ArrayList<>(); private Map<String, SearchEngine> _searchEngines; private static class SearchEngineRegistration { public void addOriginalSearchReaderMessageListener( InvokerMessageListener messageListener) { _originalSearchReaderMessageListeners.add(messageListener); } public void addOriginalSearchWriterMessageListener( InvokerMessageListener messageListener) { _originalSearchWriterMessageListeners.add(messageListener); } public SearchEngineProxyWrapper getOriginalSearchEngineProxyWrapper() { return _originalSearchEngineProxyWrapper; } public List<InvokerMessageListener> getOriginalSearchReaderMessageListeners() { return _originalSearchReaderMessageListeners; } public List<InvokerMessageListener> getOriginalSearchWriterMessageListeners() { return _originalSearchWriterMessageListeners; } public String getSearchEngineId() { return _searchEngineId; } public String getSearchReaderDestinationName() { return _searchReaderDestinationName; } public String getSearchWriterDestinationName() { return _searchWriterDestinationName; } public boolean isOverride() { return _override; } public void setOriginalSearchEngineProxyWrapper( SearchEngineProxyWrapper searchEngineProxyWrapper) { _originalSearchEngineProxyWrapper = searchEngineProxyWrapper; } public void setOverride(boolean override) { _override = override; } public void setSearchReaderDestinationName( String searchReaderDestinationName) { _searchReaderDestinationName = searchReaderDestinationName; } public void setSearchWriterDestinationName( String searchWriterDestinationName) { _searchWriterDestinationName = searchWriterDestinationName; } private SearchEngineRegistration(String searchEngineId) { _searchEngineId = searchEngineId; } private SearchEngineProxyWrapper _originalSearchEngineProxyWrapper; private final List<InvokerMessageListener> _originalSearchReaderMessageListeners = new ArrayList<>(); private final List<InvokerMessageListener> _originalSearchWriterMessageListeners = new ArrayList<>(); private boolean _override; private final String _searchEngineId; private String _searchReaderDestinationName; private String _searchWriterDestinationName; } }