/* * Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.registry.indexing; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.session.UserRegistry; import org.wso2.carbon.registry.indexing.indexer.Indexer; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; /** * This singleton class manages indexing. */ public class IndexingManager { private static final Log log = LogFactory.getLog(IndexingManager.class); private static volatile IndexingManager instance; private UserRegistry registry; private RegistryConfigLoader registryConfig; private AsyncIndexer indexer; private ScheduledExecutorService submittingExecutor; private ScheduledExecutorService indexingExecutor; private Map<Integer, Date> lastAccessTime = new ConcurrentHashMap<Integer, Date>(); private volatile Pattern[] patterns = null; private IndexingManager() { try { registry = Utils.getRegistryService().getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME); registryConfig = RegistryConfigLoader.getInstance(); indexer = new AsyncIndexer(); } catch (RegistryException e) { log.error("Could not initialize registry for indexing", e); } } public static IndexingManager getInstance() { if (instance == null) { synchronized (IndexingManager.class) { if (instance == null) { instance = new IndexingManager(); } } } return instance; } public synchronized void startIndexing() { stopIndexing(); //stop executors if they are already running, otherwise they will never stop if (registryConfig.IsStartIndexing()) { submittingExecutor = Executors.newSingleThreadScheduledExecutor(); submittingExecutor.scheduleWithFixedDelay(new ResourceSubmitter(this), getStartingDelayInSecs(), getIndexingFreqInSecs(), TimeUnit.SECONDS); indexingExecutor = Executors.newSingleThreadScheduledExecutor(); indexingExecutor.scheduleWithFixedDelay(indexer, getStartingDelayInSecs(), getIndexingFreqInSecs(), TimeUnit.SECONDS); readLastAccessTime(); } } public synchronized void restartIndexing() { stopIndexing(); try { registry.delete(getLastAccessTimeLocation()); } catch (RegistryException e) { log.error("Could not delete last activity time to restart indexing", e); } startIndexing(); } public synchronized void stopIndexing() { if (submittingExecutor != null) { submittingExecutor.shutdownNow(); submittingExecutor = null; } if (indexingExecutor != null) { indexingExecutor.shutdownNow(); indexingExecutor = null; } writeLastAccessTime(); } public long getStartingDelayInSecs() { return registryConfig.getStartingDelayInSecs(); } public boolean canIndex(String path) { if (patterns == null) { patterns = registryConfig.getExclusionPatterns(); } for (Pattern pattern : patterns) { if (pattern.matcher(path).matches()) { return false; } } return true; } public long getIndexingFreqInSecs() { return registryConfig.getIndexingFreqInSecs(); } public String getLastAccessTimeLocation() { return registryConfig.getLastAccessTimeLocation(); } private AsyncIndexer getIndexer() { return indexer; } public long getBatchSize() { return registryConfig.getBatchSize(); } /** * This is to get the indexing worker thread pool size. * * @return pool size */ public int getIndexerPoolSize() { return registryConfig.getIndexerPoolSize(); } /** * This method is to get caching enabled or disabled status for indexing purposes when resources are retrieved. * * @return indexing cache status */ public boolean isCacheSkipped() { return registryConfig.isSkipIndexingCache(); } public void deleteFromIndex(String oldPath, int tenantId) throws RegistryException { getIndexer().getClient().deleteFromIndex(oldPath, tenantId); } /** * Method for submit the file for indexing * @param tenantID tenant id * @param tenantDomain tenant domain * @param path resource path * @param sourceURL source url * @throws RegistryException */ public void submitFileForIndexing(int tenantID, String tenantDomain, String path, String sourceURL) throws RegistryException { if (log.isDebugEnabled()) { log.debug("Submitting file " + path + " for Indexing"); } getIndexer().addFile(new AsyncIndexer.File2Index(path, tenantID, tenantDomain, sourceURL)); } /** * Method for get the pre-defined Indexer matches for the resource mediaType. * Reads the registry configurations for indexing in Registry.xml and check for Indexer with mediaType provided. * @param mimeType mediaType * @return Indexer */ public Indexer getIndexerForMediaType(String mimeType) { if (mimeType != null) { for (Map.Entry<String, Indexer> entry : registryConfig.getIndexerMap().entrySet()) { if (Pattern.matches(entry.getKey(), mimeType)) { return entry.getValue(); } } } return null; } public UserRegistry getRegistry(int tenantId) { if (tenantId == MultitenantConstants.SUPER_TENANT_ID) { return registry; } else { try { return Utils.getRegistryService().getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME, tenantId); } catch (RegistryException ignore) { return null; } } } public Date getLastAccessTime(int tenantId) { return lastAccessTime.get(tenantId); } public void setLastAccessTime(int tenantId, Date lastAccessTime) { if (lastAccessTime != null) { this.lastAccessTime.put(tenantId, lastAccessTime); } } private void writeLastAccessTime() { try { if (lastAccessTime.size() > 0) { Resource resource = registry.newResource(); for (Map.Entry<Integer, Date> e : lastAccessTime.entrySet()) { resource.setProperty(String.valueOf(e.getKey()), String.valueOf(e.getValue().getTime())); } registry.put(getLastAccessTimeLocation(), resource); } } catch (RegistryException e) { log.error("Could not write last activity time when stopping indexing", e); } } private void readLastAccessTime() { try { final String lastAccessTimeLocation = getLastAccessTimeLocation(); if (registry.resourceExists(lastAccessTimeLocation)) { Properties properties = registry.get(lastAccessTimeLocation).getProperties(); if (properties != null && properties.size() != 0) { for (Object key : properties.keySet()) { lastAccessTime.put(Integer.parseInt((String)key), new Date(Long.parseLong( (String)((List)properties.get(key)).get(0)))); } } } } catch (RegistryException e) { log.error("Could not read last activity time when starting indexing", e); } } }