/* * Copyright (c) 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.inbound.endpoint.common; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.core.SynapseEnvironment; import org.apache.synapse.inbound.InboundRequestProcessor; import org.apache.synapse.startup.quartz.StartUpController; import org.apache.synapse.task.TaskDescription; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.inbound.endpoint.persistence.InboundEndpointsDataStore; /** * This class provides the common implementation for one time trigger protocol processors * Implemented the support if message injection happens in a separate thread. ( using Callbacks ) * One such requirement is loading the tenant when message is injected if at that moment tenant * is unloaded. */ public abstract class InboundOneTimeTriggerRequestProcessor implements InboundRequestProcessor { protected StartUpController startUpController; protected SynapseEnvironment synapseEnvironment; protected String name; protected boolean coordination; private OneTimeTriggerInboundRunner inboundRunner; private Thread runningThread; private static final Log log = LogFactory.getLog(InboundOneTimeTriggerRequestProcessor.class); private InboundEndpointsDataStore dataStore; protected final static String COMMON_ENDPOINT_POSTFIX = "--SYNAPSE_INBOUND_ENDPOINT"; public static final int TASK_THRESHOLD_INTERVAL = 1000; public InboundOneTimeTriggerRequestProcessor() { dataStore = InboundEndpointsDataStore.getInstance(); } /** * Based on the coordination option schedule the task with NTASK or run as a * background thread * * @param task * @param endpointPostfix */ protected void start(OneTimeTriggerInboundTask task, String endpointPostfix) { log.info("Starting the inbound endpoint " + name + ", with coordination " + coordination + ". Type : " + endpointPostfix); if (coordination) { try { TaskDescription taskDescription = new TaskDescription(); taskDescription.setName(name + "-" + endpointPostfix); taskDescription.setTaskGroup(endpointPostfix); taskDescription.setInterval(TASK_THRESHOLD_INTERVAL); taskDescription.setIntervalInMs(true); taskDescription.addResource(TaskDescription.INSTANCE, task); taskDescription.addResource(TaskDescription.CLASSNAME, task.getClass().getName()); startUpController = new StartUpController(); startUpController.setTaskDescription(taskDescription); startUpController.init(synapseEnvironment); } catch (Exception e) { log.error("Error starting the inbound endpoint " + name + ". Unable to schedule the task. " + e.getLocalizedMessage(), e); } } else { PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); int tenantId = carbonContext.getTenantId(); String tenantDomain = null; if (tenantId != MultitenantConstants.SUPER_TENANT_ID) { tenantDomain = carbonContext.getTenantDomain(); if (!dataStore.isPollingEndpointRegistered(tenantDomain, name)) { dataStore.registerPollingingEndpoint(tenantDomain, name); } } inboundRunner = new OneTimeTriggerInboundRunner(task, tenantDomain); if(task.getCallback() != null){ task.getCallback().setInboundRunnerMode(true); } if (task.getCallback() != null) { //this logic introduced if message injection happens in different thread than this //where we do not have access to the carbon context, this is the case for all //inbound endpoints where message injection happens in a different thread // ( callbacks ) but this is not the case for polling based inbound endpoints //later this tenantDomain is used for tenant loading task.getCallback().setTenantDomain(tenantDomain); } runningThread = new Thread(inboundRunner); runningThread.start(); } } /** * Stop the inbound polling processor This will be called when inbound is * undeployed/redeployed or when server stop */ public void destroy() { log.info("Inbound endpoint " + name + " stopping."); PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); int tenantId = carbonContext.getTenantId(); if (tenantId != MultitenantConstants.SUPER_TENANT_ID) { dataStore.unregisterPollingEndpoint(carbonContext.getTenantDomain(), name); } if (startUpController != null) { startUpController.destroy(); } else if (runningThread != null) { try { //this is introduced where the the thread is suspended due to external server is not //up and running and waiting connection to be completed. //thread join waits until that suspension is removed where inbound endpoint //is un deployed that will eventually lead to completion of this thread runningThread.join(); } catch (InterruptedException e) { log.error("Error while stopping the inbound thread."); } } } }