package org.apache.synapse.util; import org.apache.axiom.attachments.Attachments; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.OMNode; import org.apache.axiom.om.util.ElementHelper; import org.apache.axiom.soap.SOAP11Constants; import org.apache.axiom.soap.SOAPEnvelope; import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPFault; import org.apache.axiom.soap.SOAPFaultCode; import org.apache.axiom.soap.SOAPFaultDetail; import org.apache.axiom.soap.SOAPFaultNode; import org.apache.axiom.soap.SOAPFaultReason; import org.apache.axiom.soap.SOAPFaultRole; import org.apache.axiom.soap.SOAPFaultText; import org.apache.axiom.soap.SOAPFaultValue; import org.apache.axiom.soap.SOAPHeader; import org.apache.axiom.soap.SOAPHeaderBlock; import org.apache.axiom.util.UIDGenerator; import org.apache.axis2.AxisFault; import org.apache.axis2.Constants; import org.apache.axis2.addressing.AddressingConstants; import org.apache.axis2.client.Options; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.nio.NHttpServerConnection; import org.apache.neethi.Policy; import org.apache.neethi.PolicyEngine; import org.apache.synapse.ContinuationState; import org.apache.synapse.FaultHandler; import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseConstants; import org.apache.synapse.SynapseException; import org.apache.synapse.commons.json.JsonUtil; import org.apache.synapse.continuation.ContinuationStackManager; import org.apache.synapse.continuation.SeqContinuationState; import org.apache.synapse.core.axis2.Axis2MessageContext; import org.apache.synapse.core.axis2.ResponseState; import org.apache.synapse.debug.constants.SynapseDebugCommandConstants; import org.apache.synapse.debug.constructs.SynapseMediationFlowPoint; import org.apache.synapse.mediators.eip.EIPConstants; import org.apache.synapse.mediators.template.TemplateContext; import org.apache.synapse.transport.http.conn.SynapseDebugInfoHolder; import org.apache.synapse.transport.http.conn.SynapseWireLogHolder; import org.apache.synapse.transport.passthru.PassThroughConstants; import org.apache.synapse.transport.passthru.Pipe; import org.apache.synapse.transport.passthru.config.SourceConfiguration; import org.apache.synapse.transport.passthru.util.RelayUtils; import javax.xml.stream.XMLStreamException; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.TreeMap; import java.util.regex.Matcher; import static org.apache.synapse.SynapseConstants.PASSWORD_PATTERN; import static org.apache.synapse.SynapseConstants.URL_PATTERN; /** * */ public class MessageHelper { private static Log log = LogFactory.getLog(MessageHelper.class); /** * This method will simulate cloning the message context and creating an exact copy of the * passed message. One should use this method with care; that is because, inside the new MC, * most of the attributes of the MC like opCtx and so on are still kept as references inside * the axis2 MessageContext for performance improvements. (Note: U dont have to worrie * about the SOAPEnvelope, it is a cloned copy and not a reference from any other MC) * @param synCtx - this will be cloned * @param cloneSoapEnvelope whether to clone the soap envelope * @return cloned Synapse MessageContext * @throws AxisFault if there is a failure in creating the new Synapse MC or in a failure in * clonning the underlying axis2 MessageContext * * @see MessageHelper#cloneAxis2MessageContext */ public static MessageContext cloneMessageContext(MessageContext synCtx, boolean cloneSoapEnvelope) throws AxisFault { // creates the new MessageContext and clone the internal axis2 MessageContext // inside the synapse message context and place that in the new one MessageContext newCtx = synCtx.getEnvironment().createMessageContext(); Axis2MessageContext axis2MC = (Axis2MessageContext) newCtx; axis2MC.setAxis2MessageContext( cloneAxis2MessageContext(((Axis2MessageContext) synCtx).getAxis2MessageContext(), cloneSoapEnvelope)); newCtx.setConfiguration(synCtx.getConfiguration()); newCtx.setEnvironment(synCtx.getEnvironment()); newCtx.setContextEntries(synCtx.getContextEntries()); // set the parent correlation details to the cloned MC - // for the use of aggregation like tasks newCtx.setProperty(EIPConstants.AGGREGATE_CORRELATION, synCtx.getMessageID()); // copying the core parameters of the synapse MC newCtx.setTo(synCtx.getTo()); newCtx.setReplyTo(synCtx.getReplyTo()); newCtx.setSoapAction(synCtx.getSoapAction()); newCtx.setWSAAction(synCtx.getWSAAction()); newCtx.setResponse(synCtx.isResponse()); // copy all the synapse level properties to the newCtx for (Object o : synCtx.getPropertyKeySet()) { // If there are non String keyed properties neglect them rather than trow exception if (o instanceof String) { String strkey = (String) o; Object obj = synCtx.getProperty(strkey); if (obj instanceof String) { // No need to do anything since Strings are immutable } else if (obj instanceof ArrayList) { if (log.isDebugEnabled()) { log.debug("Deep clone Started for ArrayList property: " + strkey + "."); } // Call this method to deep clone ArrayList obj = cloneArrayList((ArrayList) obj); if (log.isDebugEnabled()) { log.debug("Deep clone Ended for ArrayList property: " + strkey + "."); } } else if (obj instanceof Stack && strkey.equals(SynapseConstants.SYNAPSE__FUNCTION__STACK)) { if (log.isDebugEnabled()) { log.debug("Deep clone for Template function stack"); } obj = getClonedTemplateStack((Stack<TemplateContext>) obj); } else if (obj instanceof OMElement) { if (log.isDebugEnabled()) { log.debug("Deep clone for OMElement"); } obj = (OMElement) ((OMElement) obj).cloneOMElement(); } else if (obj instanceof ResponseState) { // do nothing and let the same reference to go to the cloned context } else{ /** * Need to add conditions according to type if found in * future */ if (log.isDebugEnabled()) { log.warn("Deep clone not happened for property : " + strkey + ". Class type : " + obj.getClass().getName()); } } newCtx.setProperty(strkey, obj); } } // Make deep copy of fault stack so that parent will not be lost it's fault stack Stack<FaultHandler> faultStack = synCtx.getFaultStack(); if (!faultStack.isEmpty()) { List<FaultHandler> newFaultStack = new ArrayList<FaultHandler>(); newFaultStack.addAll(faultStack); for (FaultHandler faultHandler : newFaultStack) { if (faultHandler != null) { newCtx.pushFaultHandler(faultHandler); } } } Stack<TemplateContext> functionStack = (Stack) synCtx.getProperty(SynapseConstants.SYNAPSE__FUNCTION__STACK); if (functionStack != null) { newCtx.setProperty(SynapseConstants.SYNAPSE__FUNCTION__STACK, functionStack.clone()); } if (log.isDebugEnabled()) { log.info("Parent's Fault Stack : " + faultStack + " : Child's Fault Stack :" + newCtx.getFaultStack()); } // Copy ContinuationStateStack from original MC to the new MC if (synCtx.isContinuationEnabled()) { Stack<ContinuationState> continuationStates = synCtx.getContinuationStateStack(); newCtx.setContinuationEnabled(true); for (ContinuationState continuationState : continuationStates) { if (continuationState != null) { newCtx.pushContinuationState( ContinuationStackManager.getClonedSeqContinuationState( (SeqContinuationState) continuationState)); } } } newCtx.setMessageFlowTracingState(synCtx.getMessageFlowTracingState()); return newCtx; } /** * This method does exactly what {@link MessageHelper#cloneMessageContext(MessageContext)} does, * other than cloning the SOAP envelop based on the {@code cloneSOAPEnvelope} argument. * @param synCtx Synapse message context to be cloned. * @return The cloned Synapse Message Context. * @throws AxisFault If something goes wrong with message cloning. */ public static MessageContext cloneMessageContext(MessageContext synCtx) throws AxisFault { return cloneMessageContext(synCtx, true); } public static MessageContext cloneMessageContextForAggregateMediator(MessageContext synCtx) throws AxisFault { // creates the new MessageContext and clone the internal axis2 MessageContext // inside the synapse message context and place that in the new one MessageContext newCtx = synCtx.getEnvironment().createMessageContext(); Axis2MessageContext axis2MC = (Axis2MessageContext) newCtx; axis2MC.setAxis2MessageContext( cloneAxis2MessageContextForAggregate(((Axis2MessageContext) synCtx).getAxis2MessageContext())); newCtx.setConfiguration(synCtx.getConfiguration()); newCtx.setEnvironment(synCtx.getEnvironment()); newCtx.setContextEntries(synCtx.getContextEntries()); // set the parent correlation details to the cloned MC - // for the use of aggregation like tasks newCtx.setProperty(EIPConstants.AGGREGATE_CORRELATION, synCtx.getMessageID()); // copying the core parameters of the synapse MC newCtx.setTo(synCtx.getTo()); newCtx.setReplyTo(synCtx.getReplyTo()); newCtx.setSoapAction(synCtx.getSoapAction()); newCtx.setWSAAction(synCtx.getWSAAction()); newCtx.setResponse(synCtx.isResponse()); // copy all the synapse level properties to the newCtx for (Object o : synCtx.getPropertyKeySet()) { // If there are non String keyed properties neglect them rather than // throw exception if (o instanceof String) { /** * Clone the properties and add to new context * If not cloned can give errors in target configuration */ String strkey = (String) o; Object obj = synCtx.getProperty(strkey); if (obj instanceof String) { // No need to do anything since Strings are immutable } else if (obj instanceof ArrayList) { if (log.isDebugEnabled()) { log.warn("Deep clone Started for ArrayList property: " + strkey + "."); } // Call this method to deep clone ArrayList obj = cloneArrayList((ArrayList) obj); if (log.isDebugEnabled()) { log.warn("Deep clone Ended for ArrayList property: " + strkey + "."); } } else { /** * Need to add conditions according to type if found in * future */ if (log.isDebugEnabled()) { log.warn("Deep clone not happened for property : " + strkey + ". Class type : " + obj.getClass().getName()); } } newCtx.setProperty(strkey, obj); } } // Make deep copy of fault stack so that parent will not be lost it's fault stack Stack<FaultHandler> faultStack = synCtx.getFaultStack(); if (!faultStack.isEmpty()) { List<FaultHandler> newFaultStack = new ArrayList<FaultHandler>(); newFaultStack.addAll(faultStack); for (FaultHandler faultHandler : newFaultStack) { if (faultHandler != null) { newCtx.pushFaultHandler(faultHandler); } } } Stack<TemplateContext> functionStack = (Stack) synCtx .getProperty(SynapseConstants.SYNAPSE__FUNCTION__STACK); if (functionStack != null) { newCtx.setProperty(SynapseConstants.SYNAPSE__FUNCTION__STACK, functionStack.clone()); } if (log.isDebugEnabled()) { log.info("Parent's Fault Stack : " + faultStack + " : Child's Fault Stack :" + newCtx.getFaultStack()); } // Copy ContinuationStateStack from original MC to the new MC if (synCtx.isContinuationEnabled()) { Stack<ContinuationState> continuationStates = synCtx.getContinuationStateStack(); newCtx.setContinuationEnabled(true); for (ContinuationState continuationState : continuationStates) { if (continuationState != null) { newCtx.pushContinuationState(ContinuationStackManager .getClonedSeqContinuationState((SeqContinuationState) continuationState)); } } } newCtx.setMessageFlowTracingState(synCtx.getMessageFlowTracingState()); return newCtx; } /** * Get a clone of a Template Function stack * * @param oriTemplateStack original template function stack to be cloned * @return clone of a Template Function stack */ public static Stack<TemplateContext> getClonedTemplateStack( Stack<TemplateContext> oriTemplateStack) { Stack<TemplateContext> clonedTemplateStack = new Stack<TemplateContext>(); for (TemplateContext oriTemplateCtx : oriTemplateStack) { TemplateContext clonedTemplateCtx = new TemplateContext(oriTemplateCtx.getName(), oriTemplateCtx.getParameters()); Map oriValueMap = oriTemplateCtx.getMappedValues(); Map clonedValueMap = new HashMap(); for (Object key : oriValueMap.keySet()) { Object value = oriValueMap.get(key); if (value instanceof ArrayList) { value = cloneArrayList((ArrayList<Object>) value); } clonedValueMap.put(key, value); } clonedTemplateCtx.setMappedValues(clonedValueMap); clonedTemplateStack.push(clonedTemplateCtx); } return clonedTemplateStack; } /* * This method will deep clone array list by creating a new ArrayList and cloning and adding each element in it * */ public static ArrayList<Object> cloneArrayList(ArrayList<Object> arrayList) { ArrayList<Object> newArrayList = null; if (arrayList != null) { newArrayList = new ArrayList<Object>(); for (Object obj : arrayList) { if (obj instanceof SOAPHeaderBlock) { SOAPFactory fac = (SOAPFactory) ((SOAPHeaderBlock) obj).getOMFactory(); obj = ((SOAPHeaderBlock) obj).cloneOMElement(); try { obj = ElementHelper.toSOAPHeaderBlock((OMElement) obj, fac); } catch (Exception e) { handleException(e); } } else if (obj instanceof SOAPEnvelope) { SOAPEnvelope enve = (SOAPEnvelope) obj; obj = MessageHelper.cloneSOAPEnvelope(enve); } else if (obj instanceof OMElement) { obj = ((OMElement) obj).cloneOMElement(); } else { if (log.isDebugEnabled()) { log.error("Array List deep clone not implemented for Class type : " + obj.getClass().getName()); } } newArrayList.add(obj); } } return newArrayList; } /** * This method will simulate cloning the message context and creating an exact copy of the * passed message. One should use this method with care; that is because, inside the new MC, * most of the attributes of the MC like opCtx and so on are still kept as references. Otherwise * there will be perf issues. But ..... this may reveal in some conflicts in the cloned message * if you try to do advanced mediations with the cloned message, in which case you should * manually get a clone of the changing part of the MC and set that cloned part to your MC. * Changing the MC after doing that will solve most of the issues. (Note: You don't have to worry * about the SOAPEnvelope, it is a cloned copy and not a reference from any other MC) * * @param mc - this will be cloned for getting an exact copy * @param cloneSoapEnvelope The flag to say whether to clone the SOAP envelope or not. * @return cloned MessageContext from the given mc * @throws AxisFault if there is a failure in copying the certain attributes of the * provided message context */ public static org.apache.axis2.context.MessageContext cloneAxis2MessageContext( org.apache.axis2.context.MessageContext mc, boolean cloneSoapEnvelope) throws AxisFault { //building the message payload since buffer can not be cloned. otherwise cloned message will have //empty buffer in PASS_THROUGH_PIPE without the message payload. try { RelayUtils.buildMessage(mc, false); } catch (IOException e) { handleException(e); } catch (XMLStreamException e) { handleException(e); } org.apache.axis2.context.MessageContext newMC = clonePartially(mc); if (cloneSoapEnvelope) { newMC.setEnvelope(cloneSOAPEnvelope(mc.getEnvelope())); } // XXX: always this section must come after the above step. ie. after applying Envelope. // That is to get the existing headers into the new envelope. JsonUtil.cloneJsonPayload(mc, newMC); newMC.setOptions(cloneOptions(mc.getOptions())); newMC.setServiceContext(mc.getServiceContext()); newMC.setOperationContext(mc.getOperationContext()); newMC.setAxisMessage(mc.getAxisMessage()); if (newMC.getAxisMessage() != null) { newMC.getAxisMessage().setParent(mc.getAxisOperation()); } newMC.setAxisService(mc.getAxisService()); // copying transport related parts from the original newMC.setTransportIn(mc.getTransportIn()); newMC.setTransportOut(mc.getTransportOut()); newMC.setProperty(org.apache.axis2.Constants.OUT_TRANSPORT_INFO, mc.getProperty(org.apache.axis2.Constants.OUT_TRANSPORT_INFO)); newMC.setProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS, getClonedTransportHeaders(mc)); if(newMC.getProperty(PassThroughConstants.PASS_THROUGH_PIPE) != null){ //clone passthrough pipe here..writer... //newMC.setProperty(PassThroughConstants.CLONE_PASS_THROUGH_PIPE_REQUEST,true); NHttpServerConnection conn = (NHttpServerConnection) newMC.getProperty("pass-through.Source-Connection"); if(conn != null){ SourceConfiguration sourceConfiguration = (SourceConfiguration) newMC.getProperty( "PASS_THROUGH_SOURCE_CONFIGURATION"); Pipe pipe = new Pipe(conn, sourceConfiguration.getBufferFactory().getBuffer(), "source", sourceConfiguration); newMC.setProperty(PassThroughConstants.PASS_THROUGH_PIPE,pipe); } else { newMC.removeProperty(PassThroughConstants.PASS_THROUGH_PIPE); } } return newMC; } /** * This method does exactly what {@link MessageHelper#cloneAxis2MessageContext(org.apache.axis2.context.MessageContext)} does, * other than cloning the SOAP envelop based on the {@code cloneSOAPEnvelope} argument. * * @param mc Axis2 message context * @return The cloned Axis2 message context. * @throws AxisFault If something goes wrong during cloning. */ public static org.apache.axis2.context.MessageContext cloneAxis2MessageContext( org.apache.axis2.context.MessageContext mc) throws AxisFault { return cloneAxis2MessageContext(mc, true); } private static org.apache.axis2.context.MessageContext cloneAxis2MessageContextForAggregate( org.apache.axis2.context.MessageContext mc) throws AxisFault { org.apache.axis2.context.MessageContext newMC = clonePartiallyForAggregate(mc); newMC.setEnvelope(cloneSOAPEnvelope(mc.getEnvelope())); newMC.setOptions(cloneOptions(mc.getOptions())); newMC.setServiceContext(mc.getServiceContext()); newMC.setOperationContext(mc.getOperationContext()); newMC.setAxisMessage(mc.getAxisMessage()); if (newMC.getAxisMessage() != null) { newMC.getAxisMessage().setParent(mc.getAxisOperation()); } newMC.setAxisService(mc.getAxisService()); // copying transport related parts from the original newMC.setTransportIn(mc.getTransportIn()); newMC.setTransportOut(mc.getTransportOut()); newMC.setProperty(org.apache.axis2.Constants.OUT_TRANSPORT_INFO, mc.getProperty(org.apache.axis2.Constants.OUT_TRANSPORT_INFO)); newMC.setProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS, getClonedTransportHeaders(mc)); if(newMC.getProperty(PassThroughConstants.PASS_THROUGH_PIPE) != null){ //clone passthrough pipe here..writer... //newMC.setProperty(PassThroughConstants.CLONE_PASS_THROUGH_PIPE_REQUEST,true); NHttpServerConnection conn = (NHttpServerConnection) newMC.getProperty("pass-through.Source-Connection"); if(conn != null){ SourceConfiguration sourceConfiguration = (SourceConfiguration) newMC.getProperty( "PASS_THROUGH_SOURCE_CONFIGURATION"); Pipe pipe = new Pipe(conn, sourceConfiguration.getBufferFactory().getBuffer(), "source", sourceConfiguration); newMC.setProperty(PassThroughConstants.PASS_THROUGH_PIPE,pipe); } } return newMC; } public static Map getClonedTransportHeaders(org.apache.axis2.context.MessageContext msgCtx) { Map headers = (Map) msgCtx. getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); Map<String, Object> clonedHeaders; if (headers instanceof TreeMap) { clonedHeaders = new TreeMap<String, Object>(new Comparator<String>() { public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); } }); } else { clonedHeaders = new HashMap<String, Object>(); } if (headers != null && !headers.isEmpty()) { for (Object o : headers.keySet()) { String headerName = (String) o; clonedHeaders.put(headerName, headers.get(headerName)); } } return clonedHeaders; } public static org.apache.axis2.context.MessageContext clonePartially( org.apache.axis2.context.MessageContext ori) throws AxisFault { org.apache.axis2.context.MessageContext newMC = new org.apache.axis2.context.MessageContext(); // do not copy options from the original newMC.setConfigurationContext(ori.getConfigurationContext()); newMC.setMessageID(UIDGenerator.generateURNString()); newMC.setTo(ori.getTo()); newMC.setSoapAction(ori.getSoapAction()); newMC.setProperty(org.apache.axis2.Constants.Configuration.CHARACTER_SET_ENCODING, ori.getProperty(org.apache.axis2.Constants.Configuration.CHARACTER_SET_ENCODING)); newMC.setProperty(org.apache.axis2.Constants.Configuration.ENABLE_MTOM, ori.getProperty(org.apache.axis2.Constants.Configuration.ENABLE_MTOM)); newMC.setProperty(org.apache.axis2.Constants.Configuration.ENABLE_SWA, ori.getProperty(org.apache.axis2.Constants.Configuration.ENABLE_SWA)); newMC.setProperty(Constants.Configuration.HTTP_METHOD, ori.getProperty(Constants.Configuration.HTTP_METHOD)); //coping the Message type from req to res to get the message formatters working correctly. newMC.setProperty(Constants.Configuration.MESSAGE_TYPE, ori.getProperty(Constants.Configuration.MESSAGE_TYPE)); newMC.setDoingREST(ori.isDoingREST()); newMC.setDoingMTOM(ori.isDoingMTOM()); newMC.setDoingSwA(ori.isDoingSwA()); // if the original request carries any attachments, copy them to the clone // as well, except for the soap part if any Attachments attachments = ori.getAttachmentMap(); if (attachments != null && attachments.getAllContentIDs().length > 0) { String[] cIDs = attachments.getAllContentIDs(); String soapPart = attachments.getSOAPPartContentID(); for (String cID : cIDs) { if (!cID.equals(soapPart)) { newMC.addAttachment(cID, attachments.getDataHandler(cID)); } } } Iterator itr = ori.getPropertyNames(); while (itr.hasNext()) { String key = (String) itr.next(); if (key != null) { // In a clustered environment, all the properties that need to be replicated, // are replicated explicitly by the corresponding Mediators (Ex: throttle, // cache), and therefore we should avoid any implicit replication newMC.setNonReplicableProperty(key, ori.getPropertyNonReplicable(key)); } } newMC.setServerSide(false); return newMC; } public static org.apache.axis2.context.MessageContext clonePartiallyForAggregate( org.apache.axis2.context.MessageContext ori) throws AxisFault { org.apache.axis2.context.MessageContext newMC = new org.apache.axis2.context.MessageContext(); // do not copy options from the original newMC.setConfigurationContext(ori.getConfigurationContext()); newMC.setMessageID(UIDGenerator.generateURNString()); newMC.setTo(ori.getTo()); newMC.setSoapAction(ori.getSoapAction()); newMC.setProperty(org.apache.axis2.Constants.Configuration.CHARACTER_SET_ENCODING, ori.getProperty(org.apache.axis2.Constants.Configuration.CHARACTER_SET_ENCODING)); newMC.setProperty(org.apache.axis2.Constants.Configuration.ENABLE_MTOM, ori.getProperty(org.apache.axis2.Constants.Configuration.ENABLE_MTOM)); newMC.setProperty(org.apache.axis2.Constants.Configuration.ENABLE_SWA, ori.getProperty(org.apache.axis2.Constants.Configuration.ENABLE_SWA)); newMC.setProperty(Constants.Configuration.HTTP_METHOD, ori.getProperty(Constants.Configuration.HTTP_METHOD)); //coping the Message type from req to res to get the message formatters working correctly. newMC.setProperty(Constants.Configuration.MESSAGE_TYPE, ori.getProperty(Constants.Configuration.MESSAGE_TYPE)); newMC.setDoingREST(ori.isDoingREST()); newMC.setDoingMTOM(ori.isDoingMTOM()); newMC.setDoingSwA(ori.isDoingSwA()); // if the original request carries any attachments, copy them to the clone // as well, except for the soap part if any Attachments attachments = ori.getAttachmentMap(); if (attachments != null && attachments.getAllContentIDs().length > 0) { String[] cIDs = attachments.getAllContentIDs(); String soapPart = attachments.getSOAPPartContentID(); for (String cID : cIDs) { if (!cID.equals(soapPart)) { newMC.addAttachment(cID, attachments.getDataHandler(cID)); } } } Iterator itr = ori.getPropertyNames(); while (itr.hasNext()) { String key = (String) itr.next(); if (key != null) { // In a clustered environment, all the properties that need to be replicated, // are replicated explicitly by the corresponding Mediators (Ex: throttle, // cache), and therefore we should avoid any implicit replication newMC.setNonReplicableProperty(key, ori.getPropertyNonReplicable(key)); } } newMC.setServerSide(ori.isServerSide()); return newMC; } /** * This method will clone the provided SOAPEnvelope and returns the cloned envelope * as an exact copy of the provided envelope * * @param envelope - this will be cloned to get the new envelope * @return cloned SOAPEnvelope from the provided one */ public static SOAPEnvelope cloneSOAPEnvelope(SOAPEnvelope envelope) { SOAPFactory fac; if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI .equals(envelope.getBody().getNamespace().getNamespaceURI())) { fac = OMAbstractFactory.getSOAP11Factory(); } else { fac = OMAbstractFactory.getSOAP12Factory(); } SOAPEnvelope newEnvelope = fac.getDefaultEnvelope(); Iterator childIterator; if (envelope.getHeader() != null) { SOAPHeader body = envelope.getHeader(); childIterator = body.getChildren(); while (childIterator.hasNext()) { Object bodyNs = childIterator.next(); if (bodyNs instanceof SOAPHeaderBlock) { try { newEnvelope.getHeader() .addChild(ElementHelper.toSOAPHeaderBlock(((OMElement) bodyNs).cloneOMElement(), fac)); } catch (Exception e) { handleException(e); } } else if (bodyNs instanceof OMElement) { newEnvelope.getHeader().addChild(((OMElement) bodyNs).cloneOMElement()); } } } if (envelope.getBody() != null) { // treat the SOAPFault cloning as a special case otherwise a cloning OMElement as the // fault would lead to class cast exceptions if accessed through the getFault method if (envelope.getBody().getFirstElement() instanceof SOAPFault && envelope.getBody().hasFault()) { SOAPFault fault = envelope.getBody().getFault(); newEnvelope.getBody().addFault(cloneSOAPFault(fault)); } else { OMElement body = envelope.getBody().cloneOMElement(); Iterator ns = body.getAllDeclaredNamespaces(); OMNamespace bodyNs = body.getNamespace(); String nsUri = bodyNs.getNamespaceURI(); String nsPrefix = bodyNs.getPrefix(); while (ns.hasNext()) { OMNamespace namespace = ((OMNamespace)ns.next()); if (nsUri != null && !nsUri.equals(namespace.getNamespaceURI()) && nsPrefix != null && !nsPrefix.equals(namespace.getPrefix())) { newEnvelope.getBody().declareNamespace(namespace); } ns.remove(); } Iterator attributes = body.getAllAttributes(); while (attributes.hasNext()) { OMAttribute attrb = (OMAttribute) attributes.next(); newEnvelope.getBody().addAttribute(attrb); attributes.remove(); } Iterator itr = body.getChildren(); while (itr.hasNext()) { OMNode node = (OMNode) itr.next(); itr.remove(); newEnvelope.getBody().addChild(node); } } } return newEnvelope; } /** * Clones the given {@link org.apache.axis2.client.Options} object. This is not a deep copy * because this will be called for each and every message going out from synapse. The parent * of the cloning options object is kept as a reference. * * @param options cloning object * @return cloned Options object */ public static Options cloneOptions(Options options) { // create new options object and set the parent Options clonedOptions = new Options(options.getParent()); // copy general options clonedOptions.setCallTransportCleanup(options.isCallTransportCleanup()); clonedOptions.setExceptionToBeThrownOnSOAPFault(options.isExceptionToBeThrownOnSOAPFault()); clonedOptions.setManageSession(options.isManageSession()); clonedOptions.setSoapVersionURI(options.getSoapVersionURI()); clonedOptions.setTimeOutInMilliSeconds(options.getTimeOutInMilliSeconds()); clonedOptions.setUseSeparateListener(options.isUseSeparateListener()); // copy transport related options clonedOptions.setListener(options.getListener()); clonedOptions.setTransportIn(options.getTransportIn()); clonedOptions.setTransportInProtocol(options.getTransportInProtocol()); clonedOptions.setTransportOut(options.getTransportOut()); // copy username and password options clonedOptions.setUserName(options.getUserName()); clonedOptions.setPassword(options.getPassword()); // cloen the property set of the current options object for (Object o : options.getProperties().keySet()) { String key = (String) o; clonedOptions.setProperty(key, options.getProperty(key)); } return clonedOptions; } /** * Removes Submission and Final WS-Addressing headers and return the SOAPEnvelope from the given * message context * * @param axisMsgCtx the Axis2 Message context * @return the resulting SOAPEnvelope */ public static SOAPEnvelope removeAddressingHeaders( org.apache.axis2.context.MessageContext axisMsgCtx) { SOAPEnvelope env = axisMsgCtx.getEnvelope(); SOAPHeader soapHeader = env.getHeader(); ArrayList addressingHeaders; if (soapHeader != null) { addressingHeaders = soapHeader.getHeaderBlocksWithNSURI(AddressingConstants.Submission.WSA_NAMESPACE); if (addressingHeaders != null && addressingHeaders.size() != 0) { detachAddressingInformation(addressingHeaders); } else { addressingHeaders = soapHeader.getHeaderBlocksWithNSURI(AddressingConstants.Final.WSA_NAMESPACE); if (addressingHeaders != null && addressingHeaders.size() != 0) { detachAddressingInformation(addressingHeaders); } } } return env; } /** * Remove WS-A headers * * @param headerInformation headers to be removed */ private static void detachAddressingInformation(ArrayList headerInformation) { for (Object o : headerInformation) { if (o instanceof SOAPHeaderBlock) { SOAPHeaderBlock headerBlock = (SOAPHeaderBlock) o; headerBlock.detach(); } else if (o instanceof OMElement) { // work around for a known addressing bug which sends non SOAPHeaderBlock objects OMElement om = (OMElement) o; OMNamespace ns = om.getNamespace(); if (ns != null && ( AddressingConstants.Submission.WSA_NAMESPACE.equals(ns.getNamespaceURI()) || AddressingConstants.Final.WSA_NAMESPACE.equals(ns.getNamespaceURI()))) { om.detach(); } } } } /** * Get the Policy object for the given name from the Synapse configuration at runtime * * @param synCtx the current synapse configuration to get to the synapse configuration * @param propertyKey the name of the property which holds the Policy required * @return the Policy object with the given name, from the configuration */ public static Policy getPolicy(org.apache.synapse.MessageContext synCtx, String propertyKey) { Object property = synCtx.getEntry(propertyKey); if (property != null && property instanceof OMElement) { return PolicyEngine.getPolicy((OMElement) property); } else { handleException("Cannot locate policy from the property : " + propertyKey); } return null; } /** * Clones the SOAPFault, fault cloning is not the same as cloning the OMElement because if the * Fault is accessed through the SOAPEnvelope.getBody().getFault() method it will lead to a * class cast because the cloned element is just an OMElement but not a Fault. * * @param fault that needs to be cloned * @return the cloned fault */ public static SOAPFault cloneSOAPFault(SOAPFault fault) { SOAPFactory fac; int soapVersion; final int SOAP_11 = 1; final int SOAP_12 = 2; if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI .equals(fault.getNamespace().getNamespaceURI())) { fac = OMAbstractFactory.getSOAP11Factory(); soapVersion = SOAP_11; } else { fac = OMAbstractFactory.getSOAP12Factory(); soapVersion = SOAP_12; } SOAPFault newFault = fac.createSOAPFault(); SOAPFaultCode code = fac.createSOAPFaultCode(); SOAPFaultReason reason = fac.createSOAPFaultReason(); switch (soapVersion) { case SOAP_11: code.setText(fault.getCode().getTextAsQName()); reason.setText(fault.getReason().getText()); break; case SOAP_12: SOAPFaultValue value = fac.createSOAPFaultValue(code); value.setText(fault.getCode().getTextAsQName()); for (Object obj : fault.getReason().getAllSoapTexts()) { SOAPFaultText text = fac.createSOAPFaultText(); text.setText(((SOAPFaultText) obj).getText()); reason.addSOAPText(text); } break; } newFault.setCode(code); newFault.setReason(reason); if (fault.getNode() != null) { SOAPFaultNode soapfaultNode = fac.createSOAPFaultNode(); soapfaultNode.setNodeValue(fault.getNode().getNodeValue()); newFault.setNode(soapfaultNode); } if (fault.getRole() != null) { SOAPFaultRole soapFaultRole = fac.createSOAPFaultRole(); soapFaultRole.setRoleValue(fault.getRole().getRoleValue()); newFault.setRole(soapFaultRole); } if (fault.getDetail() != null) { SOAPFaultDetail soapFaultDetail = fac.createSOAPFaultDetail(); for (Iterator itr = fault.getDetail().getAllDetailEntries(); itr.hasNext();) { Object element = itr.next(); if (element instanceof OMElement) { soapFaultDetail.addDetailEntry(((OMElement) element).cloneOMElement()); } } newFault.setDetail(soapFaultDetail); } return newFault; } /** * Remove the headers that are marked as processed. * @param axisMsgCtx the Axis2 Message context * @param preserveAddressing if true preserve the addressing headers */ public static void removeProcessedHeaders(org.apache.axis2.context.MessageContext axisMsgCtx, boolean preserveAddressing) { SOAPEnvelope env = axisMsgCtx.getEnvelope(); SOAPHeader soapHeader = env.getHeader(); if (soapHeader != null) { Iterator it = soapHeader.getChildElements(); while (it.hasNext()) { Object o = it.next(); if (o instanceof SOAPHeaderBlock) { SOAPHeaderBlock headerBlock = (SOAPHeaderBlock) o; if (!preserveAddressing) { // if we don't need to preserve addressing headers remove without checking if (headerBlock.isProcessed()) { headerBlock.detach(); } } else { // else remove only if not an addressing header if (!isAddressingHeader(headerBlock)) { if (headerBlock.isProcessed()) { headerBlock.detach(); } } } } } } } /** * Return true if the SOAP header is an addressing header * @param headerBlock SOAP header block to be checked * @return true if the SOAP header is an addressing header */ private static boolean isAddressingHeader(SOAPHeaderBlock headerBlock) { OMNamespace ns = headerBlock.getNamespace(); return ns != null && ( AddressingConstants.Submission.WSA_NAMESPACE.equals(ns.getNamespaceURI()) || AddressingConstants.Final.WSA_NAMESPACE.equals(ns.getNamespaceURI())); } private static void handleException(String msg) { log.error(msg); throw new SynapseException(msg); } private static void handleException(Exception e) { log.error(e); throw new SynapseException(e); } /** * This method is to set mediatorId property to axis2 message context. This Id will be copied to iosession from the DeliveryAgent.java * class and it will be used at wire level to identify to which mediator the wirelogs belongs. * * @param synCtx */ public static void setWireLogHolderProperties(MessageContext synCtx, boolean isBreakPoint, SynapseMediationFlowPoint mediationFlowPoint) { if (isBreakPoint) { String mediatorId = synCtx.getEnvironment().getSynapseDebugManager().createDebugMediationFlowPointJSONForWireLogs(mediationFlowPoint).toString(); ((Axis2MessageContext) synCtx).getAxis2MessageContext().setProperty(SynapseDebugInfoHolder.SYNAPSE_WIRE_LOG_MEDIATOR_ID_PROPERTY, mediatorId); } else { /** * this is to be used when there are mediators which sends back-end requests, but not a break point. */ ((Axis2MessageContext) synCtx).getAxis2MessageContext().setProperty(SynapseDebugInfoHolder.SYNAPSE_WIRE_LOG_MEDIATOR_ID_PROPERTY, SynapseDebugInfoHolder.DUMMY_MEDIATOR_ID); // } } /** * Mask the password of the connection url with *** * @param url the actual url * @return the masked url */ public static String maskURLPassword(String url) { final Matcher urlMatcher = URL_PATTERN.matcher(url); String maskUrl; if (urlMatcher.find()) { final Matcher pwdMatcher = PASSWORD_PATTERN.matcher(url); maskUrl = pwdMatcher.replaceFirst("\":***@\""); return maskUrl; } return url; } }