/* * 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.context.PrivilegedCarbonContext; import org.wso2.carbon.registry.core.ActionConstants; import org.wso2.carbon.registry.core.LogEntry; import org.wso2.carbon.registry.core.internal.RegistryCoreServiceComponent; import org.wso2.carbon.registry.core.session.UserRegistry; import org.wso2.carbon.registry.indexing.internal.IndexingServiceComponent; import org.wso2.carbon.registry.indexing.utils.IndexingUtils; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.utils.WaitBeforeShutdownObserver; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import java.util.*; /** * run() method of this class checks the resources which have been changed since last index time and * submits them for indexing. This uses registry logs to detect resources that need to be indexed. * An instance of this class should be executed with a ScheduledExecutorService so that run() method * runs periodically. */ public class ResourceSubmitter implements Runnable { private static Log log = LogFactory.getLog(ResourceSubmitter.class); private IndexingManager indexingManager; private boolean taskComplete = false; private boolean isShutdown = false; protected ResourceSubmitter(IndexingManager indexingManager) { this.indexingManager = indexingManager; Utils.setWaitBeforeShutdownObserver(new WaitBeforeShutdownObserver() { public void startingShutdown() { isShutdown = true; } public boolean isTaskComplete() { return taskComplete; } }); } /** * This method checks the resources which have been changed since last index time and * submits them for indexing. This uses registry logs to detect resources that need to be * indexed. This method handles interrupts properly so that it is compatible with the * Executor framework */ @SuppressWarnings({ "REC_CATCH_EXCEPTION" }) public void run() { try { PrivilegedCarbonContext.startTenantFlow(); try { Date currentTime = indexingManager.getLastAccessTime(MultitenantConstants.SUPER_TENANT_ID); indexingManager.setLastAccessTime(MultitenantConstants.SUPER_TENANT_ID, submitResource(currentTime, MultitenantConstants.SUPER_TENANT_ID, MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)); } finally { PrivilegedCarbonContext.endTenantFlow(); } Tenant[] allTenants = RegistryCoreServiceComponent.getRealmService().getTenantManager().getAllTenants(); for (Tenant tenant : allTenants) { PrivilegedCarbonContext.startTenantFlow(); try { int tenantId = tenant.getId(); Date currentTime = indexingManager.getLastAccessTime(tenantId); indexingManager.setLastAccessTime(tenantId, submitResource(currentTime, tenantId, tenant.getDomain())); } finally { PrivilegedCarbonContext.endTenantFlow(); } } } catch (UserStoreException ignored) { } } private Date submitResource(Date currentTime, int tenantId, String tenantDomain) { if (!IndexingServiceComponent.canIndexTenant(tenantId)) { return currentTime; } if (isShutdown || Thread.currentThread().isInterrupted()) { // interruption can happen due to shutdown or some other reason. taskComplete = true; return currentTime; // To be compatible with shutdownNow() method on the executor service } PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); carbonContext.setTenantDomain(tenantDomain); carbonContext.setTenantId(tenantId); try { UserRegistry registry = indexingManager.getRegistry(tenantId); if (registry == null) { log.warn("Unable to submit resource for tenant " + tenantId + ". Unable to get registry instance"); return currentTime; } String lastAccessTimeLocation = indexingManager.getLastAccessTimeLocation(); LogEntry[] entries = registry.getLogs(null, LogEntry.ALL, null, indexingManager.getLastAccessTime(tenantId), new Date(), true); if (entries.length > 0) { Date temp = entries[0].getDate(); if (currentTime == null || currentTime.before(temp)) { currentTime = temp; } ArrayList<LogEntry> logEntryList = removeLogEntriesWithDuplicatePaths(entries); for (LogEntry logEntry : logEntryList){ String path = logEntry.getResourcePath(); try { if (path.equals(lastAccessTimeLocation)) { continue; } if (logEntry.getAction() == (LogEntry.DELETE_RESOURCE)) { indexingManager.deleteFromIndex(logEntry.getResourcePath(), tenantId); if (log.isDebugEnabled()) { log.debug("Resource Deleted: Resource at " + path + " will be deleted from Indexing Server"); } } else if (IndexingUtils.isAuthorized(registry, path, ActionConstants.GET) && registry .resourceExists(path)) { if (logEntry.getAction() == LogEntry.UPDATE) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource Updated: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.DELETE_COMMENT) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource comment deleted: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.REMOVE_ASSOCIATION) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource association removed: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.REMOVE_TAG) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource tag removed: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.ADD) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource Inserted: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.TAG) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource tag added: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.COMMENT) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource comment added: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == LogEntry.ADD_ASSOCIATION) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource association added: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == (LogEntry.MOVE)) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); indexingManager.deleteFromIndex(logEntry.getActionData(), tenantId); if (log.isDebugEnabled()) { log.debug("Resource Moved: Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == (LogEntry.COPY)) { path = logEntry.getActionData(); indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource Copied : Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == (LogEntry.RENAME)) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource Renamed : Resource at " + path + " has been submitted to the Indexing Server"); } } else if (logEntry.getAction() == (LogEntry.RESTORE)) { indexingManager.submitFileForIndexing(tenantId, tenantDomain, path, null); if (log.isDebugEnabled()) { log.debug("Resource Res+tore : Resource at " + path + " has been submitted to the Indexing Server"); } } } } catch (Exception e) { // to ease debugging log.warn("An error occurred while submitting the resource for indexing, path: " + path, e); } } } if (log.isTraceEnabled()) { log.trace("last successfully indexed activity time is : " + indexingManager.getLastAccessTime(tenantId).toString()); } } catch (Throwable e) { // Throwable is caught to prevent termination of the executor log.warn("An error occurred while submitting resources for indexing", e); } return currentTime; } /** * removes log entries with duplicate paths and non-indexed actions * preserves time order in reverse in returned ArrayList * * @param logEntries array containing log entries in oldest first order * @return ArrayList<LogEntry> containing time order reversed log entry list with unique path values */ private ArrayList<LogEntry> removeLogEntriesWithDuplicatePaths(LogEntry[] logEntries){ Set set = new HashSet(); ArrayList newList = new ArrayList(); for (int i = 0 ; i < logEntries.length ; i++) { if (!set.contains(logEntries[i].getResourcePath())) { if (logEntries[i].getAction() == LogEntry.DELETE_RESOURCE || logEntries[i].getAction() == LogEntry.UPDATE || logEntries[i].getAction() == LogEntry.DELETE_COMMENT || logEntries[i].getAction() == LogEntry.REMOVE_TAG || logEntries[i].getAction() == LogEntry.ADD || logEntries[i].getAction() == LogEntry.TAG || logEntries[i].getAction() == LogEntry.COMMENT || logEntries[i].getAction() == LogEntry.ADD_ASSOCIATION || logEntries[i].getAction() == LogEntry.MOVE || logEntries[i].getAction() == LogEntry.COPY || logEntries[i].getAction() == LogEntry.RENAME || logEntries[i].getAction() == LogEntry.RESTORE) { if (logEntries[i].getAction() != LogEntry.COPY) { set.add(logEntries[i].getResourcePath()); } newList.add(logEntries[i]); } } } return newList; } }