/** * 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.search.internal; import com.liferay.portal.configuration.metatype.bnd.util.ConfigurableUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.messaging.DestinationNames; import com.liferay.portal.kernel.search.Document; import com.liferay.portal.kernel.search.Indexer; import com.liferay.portal.kernel.search.IndexerRegistryUtil; import com.liferay.portal.kernel.search.SearchEngine; import com.liferay.portal.kernel.search.SearchEngineConfigurator; import com.liferay.portal.kernel.search.SearchEngineHelper; import com.liferay.portal.kernel.search.queue.QueuingSearchEngine; import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission; import com.liferay.portal.kernel.util.ClassUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.search.configuration.SearchEngineHelperConfiguration; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; /** * @author Michael C. Han */ @Component( configurationPid = "com.liferay.portal.search.configuration.SearchEngineHelperConfiguration", immediate = true, service = SearchEngineHelper.class ) public class SearchEngineHelperImpl implements SearchEngineHelper { @Override public void flushQueuedSearchEngine() { synchronized (_queuingSearchEngines) { for (QueuingSearchEngine queuingSearchEngine : _queuingSearchEngines.values()) { queuingSearchEngine.flush(); } _queuingSearchEngines.clear(); } } @Override public void flushQueuedSearchEngine(String searchEngineId) { QueuingSearchEngine queuingSearchEngine = null; synchronized (_queuingSearchEngines) { queuingSearchEngine = _queuingSearchEngines.remove(searchEngineId); } if (queuingSearchEngine != null) { queuingSearchEngine.flush(); } } @Override public Collection<Long> getCompanyIds() { return _companyIds.keySet(); } @Override public String getDefaultSearchEngineId() { if (_defaultSearchEngineId == null) { return SYSTEM_ENGINE_ID; } return _defaultSearchEngineId; } @Override public String[] getEntryClassNames() { Set<String> assetEntryClassNames = new HashSet<>(); for (Indexer<?> indexer : IndexerRegistryUtil.getIndexers()) { for (String className : indexer.getSearchClassNames()) { if (!_excludedEntryClassNames.contains(className)) { assetEntryClassNames.add(className); } } } return assetEntryClassNames.toArray( new String[assetEntryClassNames.size()]); } @Override public SearchEngine getSearchEngine(String searchEngineId) { PortalRuntimePermission.checkSearchEngine(searchEngineId); SearchEngine searchEngine = _searchEngines.get(searchEngineId); if (searchEngine != null) { return searchEngine; } synchronized (_queuingSearchEngines) { searchEngine = _queuingSearchEngines.get(searchEngineId); if (searchEngine == null) { QueuingSearchEngine queuingSearchEngine = new QueuingSearchEngine(_queueCapacity); _queuingSearchEngines.put(searchEngineId, queuingSearchEngine); searchEngine = queuingSearchEngine; } return searchEngine; } } @Override public String getSearchEngineId(Collection<Document> documents) { if (!documents.isEmpty()) { Iterator<Document> iterator = documents.iterator(); Document document = iterator.next(); return getSearchEngineId(document); } return getDefaultSearchEngineId(); } @Override public String getSearchEngineId(Document document) { String entryClassName = document.get("entryClassName"); Indexer<?> indexer = IndexerRegistryUtil.getIndexer(entryClassName); String searchEngineId = indexer.getSearchEngineId(); if (_log.isDebugEnabled()) { _log.debug( "Search engine ID " + searchEngineId + " is associated with " + ClassUtil.getClassName(indexer)); } return searchEngineId; } @Override public Set<String> getSearchEngineIds() { return _searchEngines.keySet(); } @Override public Collection<SearchEngine> getSearchEngines() { return Collections.unmodifiableCollection(_searchEngines.values()); } @Override public SearchEngine getSearchEngineSilent(String searchEngineId) { return _searchEngines.get(searchEngineId); } @Override public String getSearchReaderDestinationName(String searchEngineId) { return DestinationNames.SEARCH_READER.concat(StringPool.SLASH).concat( searchEngineId); } @Override public String getSearchWriterDestinationName(String searchEngineId) { return DestinationNames.SEARCH_WRITER.concat(StringPool.SLASH).concat( searchEngineId); } @Override public synchronized void initialize(long companyId) { if (_companyIds.containsKey(companyId)) { return; } _companyIds.put(companyId, companyId); for (SearchEngine searchEngine : _searchEngines.values()) { searchEngine.initialize(companyId); } } @Override public synchronized void removeCompany(long companyId) { if (!_companyIds.containsKey(companyId)) { return; } for (SearchEngine searchEngine : _searchEngines.values()) { searchEngine.removeCompany(companyId); } _companyIds.remove(companyId); } @Override public SearchEngine removeSearchEngine(String searchEngineId) { PortalRuntimePermission.checkSearchEngine(searchEngineId); return _searchEngines.remove(searchEngineId); } @Override public void setDefaultSearchEngineId(String defaultSearchEngineId) { _defaultSearchEngineId = defaultSearchEngineId; } @Override public void setQueueCapacity(int queueCapacity) { _queueCapacity = queueCapacity; } @Override public void setSearchEngine( String searchEngineId, SearchEngine searchEngine) { PortalRuntimePermission.checkSearchEngine(searchEngineId); _searchEngines.put(searchEngineId, searchEngine); for (Long companyId : _companyIds.keySet()) { searchEngine.initialize(companyId); } synchronized (_queuingSearchEngines) { QueuingSearchEngine queuingSearchEngine = _queuingSearchEngines.get( searchEngineId); if (queuingSearchEngine != null) { try { queuingSearchEngine.invokeQueued( searchEngine.getIndexWriter()); } catch (Exception e) { if (_log.isWarnEnabled()) { _log.warn( "Unable to execute pending write events for " + "engine: " + searchEngineId, e); } } } } } @Activate @Modified protected synchronized void activate(Map<String, Object> properties) { SearchEngineHelperConfiguration searchEngineHelperConfiguration = ConfigurableUtil.createConfigurable( SearchEngineHelperConfiguration.class, properties); Collections.addAll( _excludedEntryClassNames, searchEngineHelperConfiguration.excludedEntryClassNames()); } @Reference( cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, unbind = "removeSearchEngineConfigurator" ) protected void addSearchEngineConfigurator( SearchEngineConfigurator searchEngineConfigurator) { searchEngineConfigurator.afterPropertiesSet(); } protected void removeSearchEngineConfigurator( SearchEngineConfigurator searchEngineConfigurator) { searchEngineConfigurator.destroy(); } private static final Log _log = LogFactoryUtil.getLog( SearchEngineHelperImpl.class); private final Map<Long, Long> _companyIds = new ConcurrentHashMap<>(); private String _defaultSearchEngineId; private final Set<String> _excludedEntryClassNames = new HashSet<>(); private int _queueCapacity = 200; private final Map<String, QueuingSearchEngine> _queuingSearchEngines = new HashMap<>(); private final Map<String, SearchEngine> _searchEngines = new ConcurrentHashMap<>(); }