/** * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * <p/> * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.das.messageflow.data.publisher.internal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.aspects.flow.statistics.collectors.RuntimeStatisticCollector; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; import org.wso2.carbon.base.ServerConfiguration; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.das.data.publisher.util.DASDataPublisherConstants; import org.wso2.carbon.das.messageflow.data.publisher.observer.DASMediationFlowObserver; import org.wso2.carbon.das.messageflow.data.publisher.observer.MessageFlowObserver; import org.wso2.carbon.das.messageflow.data.publisher.observer.TenantInformation; import org.wso2.carbon.das.messageflow.data.publisher.observer.jmx.JMXMediationFlowObserver; import org.wso2.carbon.das.messageflow.data.publisher.services.MediationConfigReporterThread; import org.wso2.carbon.das.messageflow.data.publisher.services.MessageFlowReporterThread; import org.wso2.carbon.mediation.initializer.services.SynapseEnvironmentService; import org.wso2.carbon.mediation.initializer.services.SynapseRegistrationsService; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.utils.ConfigurationContextService; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import org.wso2.carbon.event.stream.core.EventStreamService; import org.wso2.carbon.das.messageflow.data.publisher.data.MessageFlowObserverStore; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @scr.component name="org.wso2.carbon.das.messageflow.data.publisher" immediate="true" * @scr.reference name="config.context.service" interface="org.wso2.carbon.utils.ConfigurationContextService" * cardinality="1..1" policy="dynamic" bind="setConfigurationContextService" * unbind="unsetConfigurationContextService" * @scr.reference name="org.wso2.carbon.registry.service" * interface="org.wso2.carbon.registry.core.service.RegistryService" cardinality="1..1" * policy="dynamic" bind="setRegistryService" unbind="unsetRegistryService" * @scr.reference name="synapse.env.service" * interface="org.wso2.carbon.mediation.initializer.services.SynapseEnvironmentService" * cardinality="1..1" policy="dynamic" bind="setSynapseEnvironmentService" * unbind="unsetSynapseEnvironmentService" * @scr.reference name="synapse.registrations.service" * interface="org.wso2.carbon.mediation.initializer.services.SynapseRegistrationsService" * cardinality="1..n" policy="dynamic" bind="setSynapseRegistrationsService" * unbind="unsetSynapseRegistrationsService" * @scr.reference name="eventStreamManager.service" * interface="org.wso2.carbon.event.stream.core.EventStreamService" cardinality="1..1" * policy="dynamic" bind="setEventStreamService" unbind="unsetEventStreamService" * unbind="unsetEventStreamService" */ public class MediationStatisticsComponent { private static final Log log = LogFactory.getLog(MediationStatisticsComponent.class); private static boolean flowStatisticsEnabled; private boolean activated = false; private Map<Integer, MessageFlowObserverStore> stores = new HashMap<Integer, MessageFlowObserverStore>(); private Map<Integer, MessageFlowReporterThread> reporterThreads = new HashMap<Integer, MessageFlowReporterThread>(); private Map<Integer, MediationConfigReporterThread> configReporterThreads = new HashMap<Integer, MediationConfigReporterThread>(); private Map<Integer, SynapseEnvironmentService> synapseEnvServices = new HashMap<Integer, SynapseEnvironmentService>(); private ComponentContext compCtx; protected void activate(ComponentContext ctxt) { this.compCtx = ctxt; // Check whether statistic collecting is globally enabled checkPublishingEnabled(); if (!flowStatisticsEnabled){ activated = false; if (log.isDebugEnabled()) { log.debug("DAS Message Flow Publishing Component not-activated"); } return; } int tenantId = MultitenantConstants.SUPER_TENANT_ID; SynapseEnvironmentService synapseEnvService = synapseEnvServices.get(tenantId); // Create observer store for super-tenant createStores(synapseEnvService); activated = true; if (log.isDebugEnabled()) { log.debug("DAS Message Flow Publishing Component activate"); } } /** * Create the observers store using the synapse environment and configuration context. * * @param synEnvService information about synapse runtime */ private void createStores(SynapseEnvironmentService synEnvService) { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); MessageFlowObserverStore observerStore = new MessageFlowObserverStore(); MessageFlowReporterThread reporterThread = null; ServerConfiguration serverConf = ServerConfiguration.getInstance(); // Set a custom interval value if required String interval = serverConf.getFirstProperty(DASDataPublisherConstants.FLOW_STATISTIC_WORKER_IDLE_INTERVAL); long delay = DASDataPublisherConstants.FLOW_STATISTIC_WORKER_IDLE_INTERVAL_DEFAULT; if (interval != null) { try { delay = Long.parseLong(interval); } catch (NumberFormatException ignored) { if (log.isDebugEnabled()) { log.debug("Invalid delay time for mediation-flow-tracer thread. It will use default value - " + DASDataPublisherConstants.FLOW_STATISTIC_WORKER_IDLE_INTERVAL_DEFAULT); } delay = DASDataPublisherConstants.FLOW_STATISTIC_WORKER_IDLE_INTERVAL_DEFAULT; } } String workerCountString = serverConf.getFirstProperty(DASDataPublisherConstants.FLOW_STATISTIC_WORKER_COUNT); int workerCount = DASDataPublisherConstants.FLOW_STATISTIC_WORKER_COUNT_DEFAULT; if (workerCountString != null) { try { workerCount = Integer.parseInt(workerCountString); } catch (NumberFormatException ignored) { if (log.isDebugEnabled()) { log.debug("Invalid StatisticWorkerCount. It will use default value - " + DASDataPublisherConstants.FLOW_STATISTIC_WORKER_COUNT_DEFAULT); } workerCount = DASDataPublisherConstants.FLOW_STATISTIC_WORKER_COUNT_DEFAULT; } } for (int i = 0; i < workerCount; i++) { reporterThread = new MessageFlowReporterThread(synEnvService, observerStore); reporterThread.setName("message-flow-reporter-" + i + "-tenant-" + tenantId); reporterThread.setDelay(delay); reporterThread.start(); reporterThreads.put(tenantId, reporterThread); } String disableJmxStr = serverConf.getFirstProperty(DASDataPublisherConstants.FLOW_STATISTIC_JMX_PUBLISHING); boolean enableJmxPublishing = !Boolean.parseBoolean(disableJmxStr); if (enableJmxPublishing) { JMXMediationFlowObserver jmxObserver = new JMXMediationFlowObserver(tenantId); observerStore.registerObserver(jmxObserver); log.info("JMX mediation statistic publishing enabled for tenant: " + tenantId); } String disableAnalyticStr = serverConf.getFirstProperty(DASDataPublisherConstants.FLOW_STATISTIC_ANALYTICS_PUBLISHING); boolean enableAnalyticsPublishing = !Boolean.parseBoolean(disableAnalyticStr); if (enableAnalyticsPublishing) { DASMediationFlowObserver dasObserver = new DASMediationFlowObserver(); observerStore.registerObserver(dasObserver); dasObserver.setTenantId(tenantId); log.info("DAS mediation statistic publishing enabled for tenant: " + tenantId); } // Engage custom observer implementations (user written extensions) String observers = serverConf.getFirstProperty(DASDataPublisherConstants.STAT_OBSERVERS); if (observers != null && !"".equals(observers)) { String[] classNames = observers.split(","); for (String className : classNames) { try { Class clazz = this.getClass().getClassLoader().loadClass(className.trim()); MessageFlowObserver o = (MessageFlowObserver) clazz.newInstance(); observerStore.registerObserver(o); if (o instanceof TenantInformation) { TenantInformation tenantInformation = (TenantInformation) o; tenantInformation.setTenantId(synEnvService.getTenantId()); } } catch (Exception e) { log.error("Error while initializing the mediation statistics observer : " + className, e); } } } // 'MediationStat service' will be deployed per tenant (cardinality="1..n") if (log.isDebugEnabled()) { log.debug("Registering Observer for tenant: " + tenantId); } stores.put(tenantId, observerStore); // Adding configuration reporting thread MediationConfigReporterThread configReporterThread = new MediationConfigReporterThread(synEnvService); configReporterThread.setName("mediation-config-reporter-" + tenantId); configReporterThread.setTenantId(tenantId); configReporterThread.setPublishingAnalyticESB(enableAnalyticsPublishing); configReporterThread.start(); if (log.isDebugEnabled()) { log.debug("Registering the new mediation configuration reporter thread"); } configReporterThreads.put(tenantId, configReporterThread); } protected void deactivate(ComponentContext ctxt) { Set<Map.Entry<Integer, MessageFlowReporterThread>> threadEntries = reporterThreads.entrySet(); for (Map.Entry<Integer, MessageFlowReporterThread> threadEntry : threadEntries) { MessageFlowReporterThread reporterThread = threadEntry.getValue(); if (reporterThread != null && reporterThread.isAlive()) { reporterThread.shutdown(); reporterThread.interrupt(); // This should wake up the thread if it is asleep // Wait for the reporting thread to gracefully terminate // Observers should not be disengaged before this thread halts // Otherwise some of the collected data may not be sent to the observers for (int i = 0; i < 50; i++) { if (!reporterThread.isAlive()) { break; } if (log.isDebugEnabled()) { log.debug("Waiting for the mediation tracer reporter thread to terminate"); } try { Thread.sleep(100); } catch (InterruptedException ignore) { } } } } // Stops config reporting threads for(MediationConfigReporterThread configReporterThread : configReporterThreads.values()) { if (configReporterThread != null && configReporterThread.isAlive()) { configReporterThread.shutdown(); configReporterThread.interrupt(); // Wait until the thread is gracefully terminates // for (int i = 0; i < 50; i++) { // if (!configReporterThread.isAlive()) { // break; // } // if (log.isDebugEnabled()) { // log.debug("Waiting for the mediation config reporter thread to terminate"); // } // // try { // Thread.sleep(100); // } catch (InterruptedException ignore) { // // } // } } } if (log.isDebugEnabled()) { log.debug("DAS service statistics data publisher bundle is deactivated"); } } protected void setConfigurationContextService(ConfigurationContextService contextService) { MessageFlowDataPublisherDataHolder.getInstance().setContextService(contextService); } protected void unsetConfigurationContextService(ConfigurationContextService contextService) { MessageFlowDataPublisherDataHolder.getInstance().setContextService(null); } protected void setRegistryService(RegistryService registryService) { MessageFlowDataPublisherDataHolder.getInstance().setRegistryService(registryService); } protected void unsetRegistryService(RegistryService registryService) { MessageFlowDataPublisherDataHolder.getInstance().setRegistryService(null); } protected void setEventStreamService(EventStreamService publisherService) { MessageFlowDataPublisherDataHolder.getInstance().setPublisherService(publisherService); } protected void unsetEventStreamService(EventStreamService publisherService) { MessageFlowDataPublisherDataHolder.getInstance().setPublisherService(null); } protected void setSynapseEnvironmentService(SynapseEnvironmentService synapseEnvironmentService) { if (log.isDebugEnabled()) { log.debug("SynapseEnvironmentService bound to the mediation tracer initialization"); } synapseEnvServices.put(synapseEnvironmentService.getTenantId(), synapseEnvironmentService); } protected void unsetSynapseEnvironmentService(SynapseEnvironmentService synapseEnvironmentService) { if (log.isDebugEnabled()) { log.debug("SynapseEnvironmentService unbound from the mediation tracer collector"); } synapseEnvServices.remove(synapseEnvironmentService.getTenantId()); } protected void setSynapseRegistrationsService(SynapseRegistrationsService registrationsService) { ServiceRegistration synEnvSvcRegistration = registrationsService.getSynapseEnvironmentServiceRegistration(); try { if (activated && compCtx != null) { SynapseEnvironmentService synEnvSvc = (SynapseEnvironmentService) compCtx.getBundleContext().getService( synEnvSvcRegistration.getReference()); createStores(synEnvSvc); } } catch (Throwable t) { log.fatal("Error occurred at the osgi service method", t); } } protected void unsetSynapseRegistrationsService(SynapseRegistrationsService registrationsService) { try { int tenantId = registrationsService.getTenantId(); MessageFlowReporterThread reporterThread = reporterThreads.get(tenantId); if (reporterThread != null && reporterThread.isAlive()) { reporterThread.shutdown(); reporterThread.interrupt(); // This should wake up the thread if it is asleep // Wait for the reporting thread to gracefully terminate // Observers should not be disengaged before this thread halts // Otherwise some of the collected data may not be sent to the observers while (reporterThread.isAlive()) { if (log.isDebugEnabled()) { log.debug("Waiting for the trace reporter thread to terminate"); } try { Thread.sleep(100); } catch (InterruptedException ignore) { } } } } catch (Throwable t) { log.error("Fatal error occurred at the osgi service method", t); } } private void checkPublishingEnabled() { flowStatisticsEnabled = RuntimeStatisticCollector.isStatisticsEnabled(); MessageFlowDataPublisherDataHolder.getInstance().setGlobalStatisticsEnabled(flowStatisticsEnabled); if (!flowStatisticsEnabled) { log.info("Global Message-Flow Statistic Reporting is Disabled"); } } }