/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.synapse.core.axis2;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.util.UIDGenerator;
import org.apache.axiom.util.blob.OverflowBlob;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.context.ServiceContext;
import org.apache.axis2.description.InOutAxisOperation;
import org.apache.axis2.description.TransportInDescription;
import org.apache.axis2.description.TransportOutDescription;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.FaultHandler;
import org.apache.synapse.SynapseHandler;
import org.apache.synapse.Mediator;
import org.apache.synapse.MessageContext;
import org.apache.synapse.ServerContextInformation;
import org.apache.synapse.SynapseConstants;
import org.apache.synapse.SynapseException;
import org.apache.synapse.aspects.AspectConfiguration;
import org.apache.synapse.aspects.ComponentType;
import org.apache.synapse.aspects.flow.statistics.collectors.CloseEventCollector;
import org.apache.synapse.aspects.flow.statistics.collectors.OpenEventCollector;
import org.apache.synapse.aspects.flow.statistics.collectors.RuntimeStatisticCollector;
import org.apache.synapse.aspects.flow.statistics.store.MessageDataStore;
import org.apache.synapse.commons.util.ext.TenantInfoInitiator;
import org.apache.synapse.transport.customlogsetter.CustomLogSetter;
import org.apache.synapse.carbonext.TenantInfoConfigurator;
import org.apache.synapse.config.SynapseConfigUtils;
import org.apache.synapse.config.SynapseConfiguration;
import org.apache.synapse.config.SynapseHandlersLoader;
import org.apache.synapse.continuation.ContinuationStackManager;
import org.apache.synapse.continuation.SeqContinuationState;
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.debug.SynapseDebugManager;
import org.apache.synapse.endpoints.EndpointDefinition;
import org.apache.synapse.endpoints.dispatch.Dispatcher;
import org.apache.synapse.inbound.InboundEndpoint;
import org.apache.synapse.mediators.MediatorFaultHandler;
import org.apache.synapse.mediators.MediatorWorker;
import org.apache.synapse.mediators.base.SequenceMediator;
import org.apache.synapse.rest.RESTRequestHandler;
import org.apache.synapse.task.SynapseTaskManager;
import org.apache.synapse.transport.passthru.util.RelayUtils;
import org.apache.synapse.util.concurrent.InboundThreadPool;
import org.apache.synapse.util.concurrent.SynapseThreadPool;
import org.apache.synapse.util.xpath.ext.SynapseXpathFunctionContextProvider;
import org.apache.synapse.util.xpath.ext.SynapseXpathVariableResolver;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
/**
* This is the Axis2 implementation of the SynapseEnvironment
*/
public class Axis2SynapseEnvironment implements SynapseEnvironment {
private static final Log log = LogFactory.getLog(Axis2SynapseEnvironment.class);
private static final Log trace = LogFactory.getLog(SynapseConstants.TRACE_LOGGER);
private SynapseConfiguration synapseConfig;
private ConfigurationContext configContext;
private ExecutorService executorService;
private ExecutorService executorServiceInbound;
private boolean initialized = false;
private SynapseTaskManager taskManager;
private RESTRequestHandler restHandler;
private List<SynapseHandler> synapseHandlers;
private long globalTimeout = SynapseConstants.DEFAULT_GLOBAL_TIMEOUT;
private SynapseDebugManager synapseDebugManager;
/** The MessageDataStore object*/
private MessageDataStore messageDataStore = new MessageDataStore();
private ServerContextInformation contextInformation;
/** Map containing Xpath Function Context Extensions */
Map<QName, SynapseXpathFunctionContextProvider> xpathFunctionExtensions =
new HashMap<QName, SynapseXpathFunctionContextProvider>();
/** Map containing Xpath Variable Context Extensions */
Map<QName, SynapseXpathVariableResolver> xpathVariableExtensions =
new HashMap<QName, SynapseXpathVariableResolver>();
/** Tenant info configurator */
TenantInfoConfigurator tenantInfoConfigurator;
/** Tenant info initiator */
TenantInfoInitiator tenantInfoInitiator;
/** Call mediators count */
private int callMediatorCount = 0;
/** Continuation is enabled/disabled*/
private boolean continuation = false;
/** Unavailable Artifacts referred in the configuration */
private List<String> unavailableArtifacts = new ArrayList<String>();
/** Debug mode is enabled/disabled*/
private boolean isDebugEnabled = false;
public Axis2SynapseEnvironment(SynapseConfiguration synCfg) {
int coreThreads = SynapseThreadPool.SYNAPSE_CORE_THREADS;
int maxThreads = SynapseThreadPool.SYNAPSE_MAX_THREADS;
long keepAlive = SynapseThreadPool.SYNAPSE_KEEP_ALIVE;
int qLength = SynapseThreadPool.SYNAPSE_THREAD_QLEN;
try {
qLength = Integer.parseInt(synCfg.getProperty(SynapseThreadPool.SYN_THREAD_QLEN));
} catch (Exception ignore) {}
try {
coreThreads = Integer.parseInt(synCfg.getProperty(SynapseThreadPool.SYN_THREAD_CORE));
} catch (Exception ignore) {}
try {
maxThreads = Integer.parseInt(synCfg.getProperty(SynapseThreadPool.SYN_THREAD_MAX));
} catch (Exception ignore) {}
try {
keepAlive = Long.parseLong(synCfg.getProperty(SynapseThreadPool.SYN_THREAD_ALIVE));
} catch (Exception ignore) {}
this.executorService = new SynapseThreadPool(coreThreads, maxThreads, keepAlive, qLength,
synCfg.getProperty(SynapseThreadPool.SYN_THREAD_GROUP,
SynapseThreadPool.SYNAPSE_THREAD_GROUP),
synCfg.getProperty(SynapseThreadPool.SYN_THREAD_IDPREFIX,
SynapseThreadPool.SYNAPSE_THREAD_ID_PREFIX));
int ibCoreThreads = InboundThreadPool.INBOUND_CORE_THREADS;
int ibMaxThreads = InboundThreadPool.INBOUND_MAX_THREADS;
try {
ibCoreThreads = Integer.parseInt(synCfg.getProperty(InboundThreadPool.IB_THREAD_CORE));
} catch (Exception ignore) {
}
try {
ibMaxThreads = Integer.parseInt(synCfg.getProperty(InboundThreadPool.IB_THREAD_MAX));
} catch (Exception ignore) {
}
this.executorServiceInbound =
new InboundThreadPool(
ibCoreThreads,
ibMaxThreads,
InboundThreadPool.INBOUND_KEEP_ALIVE,
InboundThreadPool.INBOUND_THREAD_QLEN,
InboundThreadPool.INBOUND_THREAD_GROUP,
InboundThreadPool.INBOUND_THREAD_ID_PREFIX);
taskManager = new SynapseTaskManager();
restHandler = new RESTRequestHandler();
synapseHandlers = SynapseHandlersLoader.loadHandlers();
this.globalTimeout = SynapseConfigUtils.getGlobalTimeoutInterval();
}
public Axis2SynapseEnvironment(ConfigurationContext cfgCtx,
SynapseConfiguration synapseConfig) {
this(synapseConfig);
this.configContext = cfgCtx;
this.synapseConfig = synapseConfig;
}
public Axis2SynapseEnvironment(ConfigurationContext cfgCtx,
SynapseConfiguration synapseConfig, ServerContextInformation contextInformation) {
this(cfgCtx, synapseConfig);
this.contextInformation = contextInformation;
setSeverDebugMode(contextInformation);
}
/**
* this method is to set the debug mode is enabled and initializes the debug manager
* debug mode is enabled is set for each time Synapse configuration is changed and Synapse
* environment initializes
*/
public void setSeverDebugMode(ServerContextInformation contextInformation) {
if (contextInformation.isServerDebugModeEnabled()) {
setDebugEnabled(true);
synapseDebugManager = contextInformation.getSynapseDebugManager();
contextInformation.getSynapseDebugManager()
.init(synapseConfig, contextInformation.getSynapseDebugInterface(), this, true);
}
}
public boolean injectMessage(final MessageContext synCtx) {
try {
if (log.isDebugEnabled()) {
log.debug("Injecting MessageContext");
}
if (synCtx.getEnvironment().isDebuggerEnabled()) {
SynapseDebugManager debugManager = synCtx.getEnvironment().getSynapseDebugManager();
debugManager.acquireMediationFlowLock();
debugManager.advertiseMediationFlowStartPoint(synCtx);
}
//setting transport-in name as a message context property
TransportInDescription trpInDesc = ((Axis2MessageContext) synCtx).getAxis2MessageContext().getTransportIn();
if (trpInDesc != null) {
synCtx.setProperty(SynapseConstants.TRANSPORT_IN_NAME, trpInDesc.getName());
}
synCtx.setEnvironment(this);
setResponseState(synCtx);
if (!invokeHandlers(synCtx)) {
return false;
}
Mediator mandatorySeq = synCtx.getConfiguration().getMandatorySequence();
// the mandatory sequence is optional and hence check for the existence before mediation
if (mandatorySeq != null) {
if (log.isDebugEnabled()) {
log.debug("Start mediating the message in the " +
"pre-mediate state using the mandatory sequence");
}
if (!mandatorySeq.mediate(synCtx)) {
if (log.isDebugEnabled()) {
log.debug((synCtx.isResponse() ? "Response" : "Request") + " message for the "
+ (synCtx.getProperty(SynapseConstants.PROXY_SERVICE) != null ?
"proxy service " + synCtx.getProperty(SynapseConstants.PROXY_SERVICE) :
"message mediation") + " dropped in the " +
"pre-mediation state by the mandatory sequence : \n" + synCtx);
}
return false;
}
}
String receivingSequence = (String) synCtx.getProperty(SynapseConstants.RECEIVING_SEQUENCE);
Boolean isContinuationCall =
(Boolean) synCtx.getProperty(SynapseConstants.CONTINUATION_CALL);
// clear the message context properties related to endpoint in last service invocation
Set keySet = synCtx.getPropertyKeySet();
if (keySet != null) {
keySet.remove(SynapseConstants.RECEIVING_SEQUENCE);
keySet.remove(SynapseConstants.CONTINUATION_CALL);
}
if (isContinuationCall != null && isContinuationCall && !synCtx.getContinuationStateStack().isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Response received for the Continuation Call service invocation");
}
return mediateFromContinuationStateStack(synCtx);
}
// if this is not a response to a proxy service
String proxyName = (String) synCtx.getProperty(SynapseConstants.PROXY_SERVICE);
if (proxyName == null || "".equals(proxyName)) {
// set default fault handler
synCtx.pushFaultHandler(new MediatorFaultHandler(synCtx.getFaultSequence()));
if (receivingSequence != null) {
if (log.isDebugEnabled()) {
log.debug("Using Sequence with name: " + receivingSequence
+ " for injected message");
}
Mediator seqMediator = synCtx.getSequence(receivingSequence);
if (seqMediator != null) {
return seqMediator.mediate(synCtx);
} else {
log.warn("Cannot find a Sequence with name: " + receivingSequence
+ " for injecting the response message");
return false;
}
} else {
boolean processed = restHandler.process(synCtx);
if (processed) {
return true;
}
if (log.isDebugEnabled()) {
log.debug("Using Main Sequence for injected message");
}
return synCtx.getMainSequence().mediate(synCtx);
}
}
ProxyService proxyService = synCtx.getConfiguration().getProxyService(proxyName);
if (proxyService != null) {
proxyService.registerFaultHandler(synCtx);
Mediator outSequence = getProxyOutSequence(synCtx, proxyService);
if (receivingSequence != null) {
if (log.isDebugEnabled()) {
log.debug("Using Sequence with name: " + receivingSequence
+ " for injected message");
}
Mediator seqMediator = synCtx.getSequence(receivingSequence);
if (seqMediator != null) {
seqMediator.mediate(synCtx);
} else {
log.warn("Cannot find a Sequence with name: " + receivingSequence
+ " for injecting the message");
return false;
}
} else if (outSequence != null) {
outSequence.mediate(synCtx);
} else {
if (log.isDebugEnabled()) {
log.debug(proxyService
+ " does not specifies an out-sequence - sending the response back");
}
Axis2Sender.sendBack(synCtx);
}
}
return true;
} finally {
if (synCtx.getEnvironment().isDebuggerEnabled()) {
SynapseDebugManager debugManager = synCtx.getEnvironment().getSynapseDebugManager();
debugManager.advertiseMediationFlowTerminatePoint(synCtx);
debugManager.releaseMediationFlowLock();
}
}
}
public void injectAsync(final MessageContext synCtx, SequenceMediator seq) {
if (log.isDebugEnabled()) {
log.debug("Injecting MessageContext for asynchronous mediation using the : "
+ (seq.getName() == null? "Anonymous" : seq.getName()) + " Sequence");
}
if (RuntimeStatisticCollector.isStatisticsEnabled()) {
OpenEventCollector.reportFlowAsynchronousEvent(synCtx);
}
synCtx.setEnvironment(this);
executorService.execute(new MediatorWorker(seq, synCtx));
}
/**
*
* Used by inbound polling endpoints to inject the message to synapse engine
*
* @param synCtx message context
* @param sequential whether message should be injected in sequential manner
* without spawning new threads
* @return Boolean - Indicate if were able to inject the message
* @throws SynapseException
* - in case error occured during the mediation
*
*/
public boolean injectInbound(final MessageContext synCtx, SequenceMediator seq,
boolean sequential) throws SynapseException {
String inboundName = null;
boolean isStatisticsEnabled = RuntimeStatisticCollector.isStatisticsEnabled();
AspectConfiguration inboundAspectConfiguration = null;
Integer statisticReportingIndex = null;
if (log.isDebugEnabled()) {
log.debug("Injecting MessageContext for inbound mediation using the : "
+ (seq.getName() == null ? "Anonymous" : seq.getName()) + " Sequence");
}
/*
* If the method is invoked by the inbound endpoint
* Then check for the endpoint name and then set the Log Appender Content
*/
if (synCtx.getProperty(SynapseConstants.INBOUND_ENDPOINT_NAME) != null) {
InboundEndpoint inboundEndpoint = synCtx.getConfiguration().
getInboundEndpoint((String) synCtx.getProperty(SynapseConstants.INBOUND_ENDPOINT_NAME));
if (inboundEndpoint != null) {
CustomLogSetter.getInstance().setLogAppender(inboundEndpoint.getArtifactContainerName());
if (inboundEndpoint.getAspectConfiguration() != null) {
// inboundStatistics = inboundEndpoint.getAspectConfiguration().isStatisticsEnable();
inboundAspectConfiguration = inboundEndpoint.getAspectConfiguration();
}
inboundName = (String) synCtx.getProperty(SynapseConstants.INBOUND_ENDPOINT_NAME);
}
}
synCtx.setEnvironment(this);
if (!invokeHandlers(synCtx)) {
return false;
}
if (!sequential) {
try {
if (isStatisticsEnabled) {
statisticReportingIndex = OpenEventCollector.reportEntryEvent(synCtx, inboundName,
inboundAspectConfiguration, ComponentType.INBOUNDENDPOINT);
}
executorServiceInbound.execute(new MediatorWorker(seq, synCtx));
return true;
} catch (RejectedExecutionException re) {
// If the pool is full complete the execution with the same thread
log.warn("Inbound worker pool has reached the maximum capacity and will be processing current message sequentially.");
} finally {
if (isStatisticsEnabled) {
CloseEventCollector.tryEndFlow(synCtx, inboundName, ComponentType.INBOUNDENDPOINT,
statisticReportingIndex, false);
}
}
}
// Following code is reached if the sequential==true or inbound is
// reached max level
if (isStatisticsEnabled) {
statisticReportingIndex = OpenEventCollector.reportEntryEvent(synCtx, inboundName,
inboundAspectConfiguration, ComponentType.INBOUNDENDPOINT);
}
try {
if (synCtx.getEnvironment().isDebuggerEnabled()) {
SynapseDebugManager debugManager = synCtx.getEnvironment().getSynapseDebugManager();
debugManager.acquireMediationFlowLock();
debugManager.advertiseMediationFlowStartPoint(synCtx);
}
seq.mediate(synCtx);
return true;
} catch (SynapseException syne) {
if (!synCtx.getFaultStack().isEmpty()) {
log.warn("Executing fault handler due to exception encountered");
((FaultHandler) synCtx.getFaultStack().pop()).handleFault(synCtx, syne);
return true;
} else {
log.warn("Exception encountered but no fault handler found - message dropped");
throw syne;
}
} catch (Exception e) {
String msg = "Unexpected error executing task/async inject";
log.error(msg, e);
if (synCtx.getServiceLog() != null) {
synCtx.getServiceLog().error(msg, e);
}
if (!synCtx.getFaultStack().isEmpty()) {
log.warn("Executing fault handler due to exception encountered");
((FaultHandler) synCtx.getFaultStack().pop()).handleFault(synCtx, e);
return true;
} else {
log.warn("Exception encountered but no fault handler found - message dropped");
throw new SynapseException(
"Exception encountered but no fault handler found - message dropped",
e);
}
} catch (Throwable e) {
String msg = "Unexpected error executing inbound/async inject, message dropped";
log.error(msg, e);
if (synCtx.getServiceLog() != null) {
synCtx.getServiceLog().error(msg, e);
}
throw new SynapseException(msg, e);
} finally {
if (isStatisticsEnabled) {
CloseEventCollector.tryEndFlow(synCtx, inboundName, ComponentType.INBOUNDENDPOINT,
statisticReportingIndex, false);
}
if (synCtx.getEnvironment().isDebuggerEnabled()) {
SynapseDebugManager debugManager = synCtx.getEnvironment().getSynapseDebugManager();
debugManager.advertiseMediationFlowTerminatePoint(synCtx);
debugManager.releaseMediationFlowLock();
}
}
}
/**
* This will be used for sending the message provided, to the endpoint specified by the
* EndpointDefinition using the axis2 environment.
*
* @param endpoint - EndpointDefinition to be used to find the endpoint information
* and the properties of the sending process
* @param synCtx - Synapse MessageContext to be sent
*/
public void send(EndpointDefinition endpoint, MessageContext synCtx) {
//removing rampart engaged property, else outgoing security will not work
((Axis2MessageContext) synCtx).getAxis2MessageContext().
removeProperty("rampart_engaged");
if (synCtx.isResponse()) {
if (endpoint != null) {
if (isTransportSwitching(synCtx, endpoint)) {
buildMessage(synCtx);
}
Axis2Sender.sendOn(endpoint, synCtx);
} else {
String proxyName = (String) synCtx.getProperty(SynapseConstants.PROXY_SERVICE);
boolean serviceModuleEngaged = false;
if (proxyName != null) {
ProxyService proxyService = synapseConfig.getProxyService(proxyName);
serviceModuleEngaged = proxyService.isModuleEngaged();
}
if (serviceModuleEngaged || isTransportSwitching(synCtx, null)) {
buildMessage(synCtx);
}
//Build message in the case of inbound jms dual channel
Boolean isInboundJMS = (Boolean)synCtx.getProperty(SynapseConstants.INBOUND_JMS_PROTOCOL);
if (isInboundJMS != null && isInboundJMS) {
buildMessage(synCtx);
}
Axis2Sender.sendBack(synCtx);
}
} else {
// If this request is related to session affinity endpoints - For client initiated session
Dispatcher dispatcher =
(Dispatcher) synCtx.getProperty(
SynapseConstants.PROP_SAL_ENDPOINT_CURRENT_DISPATCHER);
if (dispatcher != null) {
if (!dispatcher.isServerInitiatedSession()) {
dispatcher.updateSession(synCtx);
}
}
synCtx.setProperty(SynapseConstants.SENDING_REQUEST, true);
if (endpoint == null || isTransportSwitching(synCtx, endpoint)) {
buildMessage(synCtx);
}
Axis2Sender.sendOn(endpoint, synCtx);
}
}
/**
* This method will be used to create a new MessageContext in the Axis2 environment for
* Synapse. This will set all the relevant parts to the MessageContext, but for this message
* context to be useful creator has to fill in the data like envelope and operation context
* and so on. This will set a default envelope of type soap12 and a new messageID for the
* created message along with the ConfigurationContext is being set in to the message
* correctly.
*
* @return Synapse MessageContext with the underlying axis2 message context set
*/
public MessageContext createMessageContext() {
if (log.isDebugEnabled()) {
log.debug("Creating Message Context");
}
org.apache.axis2.context.MessageContext axis2MC
= new org.apache.axis2.context.MessageContext();
axis2MC.setConfigurationContext(this.configContext);
ServiceContext svcCtx = new ServiceContext();
OperationContext opCtx = new OperationContext(new InOutAxisOperation(), svcCtx);
axis2MC.setServiceContext(svcCtx);
axis2MC.setOperationContext(opCtx);
MessageContext mc = new Axis2MessageContext(axis2MC, synapseConfig, this);
mc.setMessageID(UIDGenerator.generateURNString());
try {
mc.setEnvelope(OMAbstractFactory.getSOAP12Factory().createSOAPEnvelope());
mc.getEnvelope().addChild(OMAbstractFactory.getSOAP12Factory().createSOAPBody());
} catch (Exception e) {
handleException("Unable to attach the SOAP envelope to " +
"the created new message context", e);
}
return mc;
}
/**
* Factory method to create the TemporaryData object as per on the parameters specified in the
* synapse.properties file, so that the TemporaryData parameters like threshold chunk size
* can be customized by using the properties file. This can be extended to enforce further
* policies if required in the future.
*
* @return created TemporaryData object as per in the synapse.properties file
*/
public OverflowBlob createOverflowBlob() {
String chkSize = synapseConfig.getProperty(SynapseConstants.CHUNK_SIZE);
String chunkNumber = synapseConfig.getProperty(SynapseConstants.THRESHOLD_CHUNKS);
int numberOfChunks = SynapseConstants.DEFAULT_THRESHOLD_CHUNKS;
int chunkSize = SynapseConstants.DEFAULT_CHUNK_SIZE;
if (chkSize != null) {
chunkSize = Integer.parseInt(chkSize);
}
if (chunkNumber != null) {
numberOfChunks = Integer.parseInt(chunkNumber);
}
String tempPrefix = synapseConfig.getProperty(SynapseConstants.TEMP_FILE_PREFIX,
SynapseConstants.DEFAULT_TEMPFILE_PREFIX);
String tempSuffix = synapseConfig.getProperty(SynapseConstants.TEMP_FILE_SUFIX,
SynapseConstants.DEFAULT_TEMPFILE_SUFIX);
return new OverflowBlob(numberOfChunks, chunkSize, tempPrefix, tempSuffix);
}
/**
* This will give the access to the synapse thread pool for the
* advanced mediation tasks.
*
* @return an ExecutorService to execute the tasks in a new thread from the pool
*/
public ExecutorService getExecutorService() {
return executorService;
}
/**
* Has this environment properly initialized?
*
* @return true if ready for processing
*/
public boolean isInitialized() {
return initialized;
}
/**
* Mark this environment as ready for processing
*
* @param state true means ready for processing
*/
public void setInitialized(boolean state) {
this.initialized = state;
}
/**
* Retrieves the {@link SynapseConfiguration} from the <code>environment</code>
*
* @return synapseConfig associated with the environment
*/
public SynapseConfiguration getSynapseConfiguration() {
return this.synapseConfig;
}
@Override
public MessageDataStore getMessageDataStore() {
return messageDataStore;
}
/**
* Retrieve the {@link org.apache.synapse.task.SynapseTaskManager} from the
* <code>environment</code>.
*
* @return SynapseTaskManager of this synapse environment
*/
public SynapseTaskManager getTaskManager() {
return this.taskManager;
}
/**
* Retrieve the {@link org.apache.synapse.ServerContextInformation} from the <code>environment.
*
* @return ServerContextInformation of the environment
*/
public ServerContextInformation getServerContextInformation() {
return contextInformation;
}
/**
* Retrieves the {@link ConfigurationContext} associated with this <code>axis2SynapseEnv</code>
*
* @return configContext of the axis2 synapse environment
*/
public ConfigurationContext getAxis2ConfigurationContext() {
return this.configContext;
}
/**
* Returns all declared xpath Function Extensions
* @return Hash Map Containing Function Extensions with supported QName keys
*/
public Map<QName, SynapseXpathFunctionContextProvider> getXpathFunctionExtensions() {
return xpathFunctionExtensions;
}
/**
* Returns all declared xpath Variable Extensions
* @return Hash Map Containing Variable Extensions with supported QName keys
*/
public Map<QName, SynapseXpathVariableResolver> getXpathVariableExtensions() {
return xpathVariableExtensions;
}
public TenantInfoConfigurator getTenantInfoConfigurator() {
return tenantInfoConfigurator;
}
public TenantInfoInitiator getTenantInfoInitiator() {
return tenantInfoInitiator;
}
public void setXpathFunctionExtensions(SynapseXpathFunctionContextProvider functionExt){
if(functionExt!=null) {
xpathFunctionExtensions.put(functionExt.getResolvingQName(), functionExt);
}
}
public void setXpathVariableExtensions(SynapseXpathVariableResolver variableExt){
if(variableExt!=null) {
xpathVariableExtensions.put(variableExt.getResolvingQName(), variableExt);
}
}
public void setTenantInfoConfigurator(TenantInfoConfigurator configurator) {
if (configurator != null) {
tenantInfoConfigurator = configurator;
}
}
public void setTenantInfoInitiator(TenantInfoInitiator initiator) {
if (initiator != null) {
tenantInfoInitiator = initiator;
}
}
/**
* When request is sent using a Call Mediator, mediate the response message using the
* ContinuationState Stack
* @param synCtx MessageContext
* @return whether mediation is completed
*/
private boolean mediateFromContinuationStateStack(MessageContext synCtx) {
if (log.isDebugEnabled()) {
log.debug("Mediating response using the ContinuationStateStack");
}
if (synCtx.getContinuationStateStack().isEmpty()) {
// ideally this should never happens
log.warn("ContinuationStateStack empty. No ContinuationState to mediate the response ");
return false;
}
if (RuntimeStatisticCollector.isStatisticsEnabled()) {
OpenEventCollector.openContinuationEvents(synCtx);
}
//First push fault handlers for first continuation state.
SeqContinuationState seqContinuationState = (SeqContinuationState) ContinuationStackManager.peakContinuationStateStack(synCtx);
if (seqContinuationState != null) {
ContinuationStackManager.pushFaultHandler(synCtx, seqContinuationState);
} else {
return false;
}
boolean result = false;
do {
seqContinuationState = (SeqContinuationState) ContinuationStackManager.peakContinuationStateStack(synCtx);
if (seqContinuationState != null) {
SequenceMediator sequenceMediator = ContinuationStackManager.retrieveSequence(synCtx, seqContinuationState);
//Report Statistics for this continuation call
result = sequenceMediator.mediate(synCtx, seqContinuationState);
if (RuntimeStatisticCollector.isStatisticsEnabled()) {
sequenceMediator.reportCloseStatistics(synCtx, null);
}
} else {
break;
}
//for any result close the sequence as it will be handled by the callback method in statistics
} while (result && !synCtx.getContinuationStateStack().isEmpty());
return result;
}
private boolean isTransportSwitching(MessageContext synCtx, EndpointDefinition endpoint) {
if (endpoint != null) {
// SendOn transport switching
if (endpoint.getAddress() != null) {
// If the message is sent to an explicit non-HTTP endpoint, build the message
return !endpoint.getAddress().startsWith("http");
} else {
String address = synCtx.getTo().getAddress();
if (address != null) {
// If the message is sent to an implicit non-HTTP endpoint, build the message
return !address.startsWith("http");
}
}
} else {
// SendBack transport switching
TransportOutDescription transportOut =
((Axis2MessageContext) synCtx).getAxis2MessageContext().getTransportOut();
if (transportOut != null) {
String transportOutName = transportOut.getName();
if (transportOutName != null) {
return !transportOutName.startsWith("http");
}
}
}
return false;
}
private void buildMessage(MessageContext synCtx) {
try {
RelayUtils.buildMessage(((Axis2MessageContext) synCtx).getAxis2MessageContext(), false);
} catch (Exception e) {
handleException("Error while building message", e);
}
}
private void handleException(String message, Throwable e) {
log.error(message, e);
throw new SynapseException(message, e);
}
/**
* Helper method to determine out sequence of the proxy service
*
* @param synCtx Current Message
* @param proxyService Proxy Service
* @return Out Sequence of the given proxy service, if there are any, otherwise null
*/
private Mediator getProxyOutSequence(MessageContext synCtx, ProxyService proxyService) {
//TODO is it meaningful to move this method into proxy service or
//TODO a class that Strategically detects out sequence ?
String sequenceName = proxyService.getTargetOutSequence();
if (sequenceName != null && !"".equals(sequenceName)) {
Mediator outSequence = synCtx.getSequence(sequenceName);
if (outSequence != null) {
if (log.isDebugEnabled()) {
log.debug("Using the sequence named " + sequenceName
+ " for the outgoing message mediation of the proxy service "
+ proxyService);
}
return outSequence;
} else {
log.error("Unable to find the out-sequence " +
"specified by the name " + sequenceName);
throw new SynapseException("Unable to find the " +
"out-sequence specified by the name " + sequenceName);
}
} else {
Mediator outSequence = proxyService.getTargetInLineOutSequence();
if (outSequence != null) {
if (log.isDebugEnabled()) {
log.debug("Using the anonymous out-sequence specified in the proxy service "
+ proxyService
+ " for outgoing message mediation");
}
return outSequence;
}
}
return null;
}
/**
* Increment/Decrement the Call mediator count in the environment by 1.
* While Call Mediator count is updated, continuation is enabled/disabled based on the count.
* If Call Mediator count becomes 0 continuation is disabled.
* count cannot get negative values.
*
* @param isIncrement whether to increment the count
*/
public synchronized void updateCallMediatorCount(boolean isIncrement) {
if (isIncrement) {
callMediatorCount++;
continuation = true;
} else {
callMediatorCount--;
if (callMediatorCount == 0) {
continuation = false;
}
}
}
/**
* Whether continuation is enabled in the environment.
* ContinuationState stack operations are done only if continuation is enabled for the
* environment.
*
* @return whether continuation is enabled in the environment
*/
public boolean isContinuationEnabled() {
return continuation;
}
/**
* Add an artifact reference not available in the environment.
* This stored reference will get cleared when artifact becomes available
*
* @param key artifact reference key
*/
public synchronized void addUnavailableArtifactRef(String key) {
unavailableArtifacts.add(key);
updateCallMediatorCount(true);
}
/**
* Remove the artifact reference which is previously marked as unavailable in environment
* from the unavailable list
*
* @param key artifact reference key
*/
public synchronized void removeUnavailableArtifactRef(String key) {
if (unavailableArtifacts.contains(key)) {
unavailableArtifacts.remove(key);
updateCallMediatorCount(false);
}
}
/**
* Clear unavailability of an artifact if it is
* previously marked as unavailable in the environment
*
* @param key artifact reference key
*/
public synchronized void clearUnavailabilityOfArtifact(String key) {
if (!unavailableArtifacts.contains(key)) {
return;
}
for (Iterator<String> itr = unavailableArtifacts.iterator(); itr.hasNext(); ) {
if (key.equals(itr.next())) {
itr.remove();
updateCallMediatorCount(false);
}
}
}
/**
* Get all synapse handlers
*
* @return list of synapse handlers
*/
public List<SynapseHandler> getSynapseHandlers() {
return synapseHandlers;
}
/**
* Register a synapse handler to the synapse environment
*
* @param handler synapse handler
*/
public void registerSynapseHandler(SynapseHandler handler) {
synapseHandlers.add(handler);
}
@Override
public long getGlobalTimeout() {
return globalTimeout;
}
public boolean injectMessage(MessageContext smc, SequenceMediator seq) {
AspectConfiguration inboundAspectConfiguration = null;
String inboundName = null;
boolean isStatisticsEnabled = RuntimeStatisticCollector.isStatisticsEnabled();
Integer statisticReportingIndex = null;
/*
* If the method is invoked by the inbound endpoint
* Then check for the endpoint name and then set the Log Appender Content
*/
if (smc.getProperty(SynapseConstants.INBOUND_ENDPOINT_NAME) != null) {
InboundEndpoint inboundEndpoint = smc.getConfiguration().
getInboundEndpoint((String) smc.getProperty(SynapseConstants.INBOUND_ENDPOINT_NAME));
if (inboundEndpoint != null) {
CustomLogSetter.getInstance().setLogAppender(inboundEndpoint.getArtifactContainerName());
inboundName =(String) smc.getProperty(SynapseConstants.INBOUND_ENDPOINT_NAME);
if (inboundEndpoint.getAspectConfiguration() != null) {
inboundAspectConfiguration = inboundEndpoint.getAspectConfiguration();
}
}
}
if (seq == null) {
log.error("Please provide existing sequence");
return false;
}
if (log.isDebugEnabled()) {
log.debug("Injecting MessageContext for asynchronous mediation using the : "
+ (seq.getName() == null? "Anonymous" : seq.getName()) + " Sequence");
}
smc.setEnvironment(this);
if (!invokeHandlers(smc)) {
return false;
}
try {
if (isStatisticsEnabled && inboundName != null) {
statisticReportingIndex = OpenEventCollector.reportEntryEvent(smc, inboundName, inboundAspectConfiguration,
ComponentType.INBOUNDENDPOINT);
}
seq.mediate(smc);
return true;
} catch (SynapseException syne) {
if (!smc.getFaultStack().isEmpty()) {
warn(false, "Executing fault handler due to exception encountered", smc);
smc.getFaultStack().pop().handleFault(smc, syne);
} else {
warn(false, "Exception encountered but no fault handler found - " +
"message dropped", smc);
}
return false;
} catch (Exception e) {
String msg = "Unexpected error executing injecting message to sequence ," + seq;
log.error(msg, e);
if (smc.getServiceLog() != null) {
smc.getServiceLog().error(msg, e);
}
if (!smc.getFaultStack().isEmpty()) {
warn(false, "Executing fault handler due to exception encountered", smc);
smc.getFaultStack().pop().handleFault(smc, e);
} else {
warn(false, "Exception encountered but no fault handler found - " +
"message dropped", smc);
}
return false;
} catch (Throwable e) {
String msg = "Unexpected error executing injecting message to sequence ," + seq + " message dropped";
log.error(msg, e);
if (smc.getServiceLog() != null) {
smc.getServiceLog().error(msg, e);
}
return false;
} finally {
if (isStatisticsEnabled && inboundName != null) {
CloseEventCollector.tryEndFlow(smc, inboundName, ComponentType.INBOUNDENDPOINT,
statisticReportingIndex, false);
}
}
}
private void warn(boolean traceOn, String msg, MessageContext msgContext) {
if (traceOn) {
trace.warn(msg);
}
log.warn(msg);
if (msgContext.getServiceLog() != null) {
msgContext.getServiceLog().warn(msg);
}
}
/**
* Invoke Synapse Handlers
*
* @param synCtx synapse message context
* @return whether flow should continue further
*/
private boolean invokeHandlers(MessageContext synCtx) {
Iterator<SynapseHandler> iterator =
synCtx.getEnvironment().getSynapseHandlers().iterator();
if (iterator.hasNext()) {
Boolean isContinuationCall =
(Boolean) synCtx.getProperty(SynapseConstants.CONTINUATION_CALL);
if (synCtx.isResponse() || (isContinuationCall != null && isContinuationCall)) {
while (iterator.hasNext()) {
SynapseHandler handler = iterator.next();
if (!handler.handleResponseInFlow(synCtx)) {
return false;
}
}
} else {
while (iterator.hasNext()) {
SynapseHandler handler = iterator.next();
if (!handler.handleRequestInFlow(synCtx)) {
return false;
}
}
}
}
return true;
}
/**
* method to get the reference to debug manager instance which manages debug capabilities in synapse
* kept in environment level, made available who ever has access to message context will be able to
* get access to the debug manager
*
* @return debug manager instance
*/
public SynapseDebugManager getSynapseDebugManager() {
return synapseDebugManager;
}
/**
* sets debug manager when synapse environment initializes if the server instance is started in debug mode
*/
public void setSynapseDebugManager(SynapseDebugManager synapseDebugManager) {
this.synapseDebugManager = synapseDebugManager;
}
/**
* Whether debugging is enabled in the environment.
*
* @return whether debugging is enabled in the environment
*/
public boolean isDebuggerEnabled() {
return isDebugEnabled;
}
/**
* set debugging enabled in the environment. *
* when this is enabled mediation flow can be debugged through a external client
* when this is disabled mediation flow happens normally
*/
public void setDebugEnabled(boolean isDebugEnabled) {
this.isDebugEnabled = isDebugEnabled;
}
/**
* Set the response state of the context
*
* @param synCtx synapse message context
* */
private void setResponseState(MessageContext synCtx) {
Boolean isContinuationCall = (Boolean) synCtx.getProperty(SynapseConstants.CONTINUATION_CALL);
if (!(synCtx.isResponse() || (isContinuationCall != null && isContinuationCall))) {
synCtx.setProperty(SynapseConstants.RESPONSE_STATE, new ResponseState());
}
}
}