JBoss Community Archive (Read Only)

SwitchYard

Debugging

What to do when your application is not behaving as expected?  This section describes a number of mechanisms in SwitchYard that provide more visibility and control into the machinery underneath your application.

Message Tracing

Message tracing provides a view of the content and context of a message exchange on the SwitchYard bus by printing exchange information to the log. The trace is generated from an exchange interceptor which is triggered at the following points:

  • Immediately after the consumer sends the request message.  For example, In the case of a service which is invoked from a service binding, this will be the point at which the gateway binding puts the message onto the bus.

  • Immediately before the service provider is invoked.

  • Immediately after the service provider is invoked.

  • At completion of the exchange before the message is returned to the consumer.

Trace Output

Trace output includes details on the metadata, context properties, payload, and attachments for a message exchange.  Here is an example of a trace entry:

12:48:25,038 INFO  [org.switchyard.handlers.MessageTraceHandler]
------- Begin Message Trace -------
Consumer -> {urn:switchyard-quickstart:bean-service:0.1.0}OrderService
Provider -> [unassigned]
Operation -> submitOrder
MEP -> IN_OUT
Phase -> IN
State -> OK
Exchange Context ->
	org.switchyard.bus.camel.consumer : ServiceReference [name={urn:switchyard-quickstart:bean-service:0.1.0}OrderService, interface=BaseServiceInterface [type=wsdl, operations=[submitOrder : IN_OUT : [{urn:switchyard-quickstart:bean-service:1.0}submitOrder, {urn:switchyard-quickstart:bean-service:1.0}submitOrderResponse, null]]], domain=ServiceDomain [name=org.switchyard.domains.root]]
	org.switchyard.exchangeGatewayName : _OrderService_soap_1
	org.switchyard.bus.camel.securityContext : SecurityContext[credentials=[ConfidentialityCredential [confidential=false]], securityDomainsToSubjects={}]
	org.switchyard.exchangeInitiatedNS : 1375980505021790000
	CamelCreatedTimestamp : Thu Aug 08 12:48:25 EDT 2013
	org.switchyard.bus.camel.phase : IN
	org.switchyard.bus.camel.dispatcher : org.switchyard.bus.camel.ExchangeDispatcher@b4aa453
	org.switchyard.bus.camel.labels : {org.switchyard.exchangeGatewayName=[org.switchyard.label.behavior.transient]}
	CamelToEndpoint : direct://%7Burn:switchyard-quickstart:bean-service:0.1.0%7DOrderService
	org.switchyard.bus.camel.contract : org.switchyard.metadata.BaseExchangeContract@2176feaf
	org.switchyard.bus.camel.replyHandler : org.switchyard.component.common.SynchronousInOutHandler@516a4aef
	CamelFilterMatched : false
Message Context ->
	org.switchyard.bus.camel.labels : {org.switchyard.contentType=[org.switchyard.label.behavior.transient], org.switchyard.bus.camel.messageSent=[org.switchyard.label.behavior.transient]}
	org.switchyard.messageId : ID-kookaburra-local-49858-1375980502093-0-1
	org.switchyard.bus.camel.messageSent : true
	org.switchyard.soap.messageName : submitOrder
	org.switchyard.contentType : {urn:switchyard-quickstart:bean-service:1.0}submitOrder
	breadcrumbId : ID-kookaburra-local-49858-1375980502093-0-1
Message Content ->
<?xml version="1.0" encoding="UTF-8"?><orders:submitOrder xmlns:orders="urn:switchyard-quickstart:bean-service:1.0">
			<order>
				<orderId>PO-19838-XYZ</orderId>
				<itemId>BUTTER</itemId>
				<quantity>200</quantity>
			</order>
		</orders:submitOrder>
------ End Message Trace -------

Enabling Message Tracing

Message tracing is enabled by setting the value of the "org.switchyard.handlers.messageTrace.enabled" property to true in your application domain.  Domain properties are set via entries in the <domain> section of switchyard.xml.  An easy shortcut to enabling tracing is to view the Domain tab of the visual application model in Eclipse and select the "Enable Message Trace" checkbox.

<domain>
   <properties>
      <property name="org.switchyard.handlers.messageTrace.enabled" value="true"/>
   </properties>
</domain>

Exchange Interceptors

ExchangeInterceptors provide a mechanism for injecting logic into the message path of the SwitchYard exchange bus.  You can use an interceptor to read or update message content and context properties, which makes interceptors useful for debugging and for applying logic outside a traditional service implementation in SwitchYard.

Implementing an ExchangeInterceptor

An ExchangeInterceptor is a Java class with the following properties:

The ExchangeInterceptor interface looks like this:

public interface ExchangeInterceptor {
    String CONSUMER = "Consumer";
    String PROVIDER = "Provider";

    void before(String target, Exchange exchange) throws HandlerException;
    void after(String target, Exchange exchange) throws HandlerException;
    List<String> getTargets();
}

An interceptor is invoked for all message exchanges in an application, so if you only care about a specific service you will want to add a conditional to before() and after() to check for service name.  You can restrict the interception points used through the getTargets() method.   The CONSUMER and PROVIDER string constants are provided for use with getTargets() to restrict interception to the consumer, provider, or both.   The CONSUMER target maps to an injection point just after the consumer sends a request and just before the reply is handed back.  The PROVIDER target maps to an injection point just before the provider is called with a request and just after it produces a response.

Here is an example ExchangeInterceptor implementation from the bean-service quickstart:

package org.switchyard.quickstarts.bean.service;

import java.util.Arrays;
import java.util.List;

import javax.inject.Named;

import org.switchyard.Exchange;
import org.switchyard.ExchangeInterceptor;
import org.switchyard.ExchangeState;
import org.switchyard.HandlerException;

/**
 * This is an example of an exchange interceptor which can be used to inject code
 * around targets during a message exchange.  This example updates the content of 
 * OrderAck after the provider has generated a response.
 */
@Named("UpdateStatus")
public class OrderInterceptor implements ExchangeInterceptor {

    @Override
    public void before(String target, Exchange exchange) throws HandlerException {
        // Not interested in doing anything before the provider is invoked
    }

    @Override
    public void after(String target, Exchange exchange) throws HandlerException {
        // We only want to intercept successful replies from OrderService
        if (exchange.getProvider().getName().getLocalPart().equals("OrderService")
                && ExchangeState.OK.equals(exchange.getState())) {
            OrderAck orderAck = exchange.getMessage().getContent(OrderAck.class);
            orderAck.setStatus(orderAck.getStatus() + " [intercepted]");
        }
    }

    @Override
    public List<String> getTargets() {
       return Arrays.asList(PROVIDER);
    }

}

Auditing Exchanges

SwitchYard provides a low-level auditing mechanism intended for application debugging.  Using Auditors to implement application logic is generally discouraged as the set and order of processors which auditors bind to is subject to change at any time.  Auditing support requires a CDI environment to run, so your application must include META-INF/beans.xml.

Mediation states

SwitchYard exchanges sent from a service consumer to a service provider go through a set of handlers:

  • Addressing - addressing handler determines which provider is wired to a consumer reference.

  • Transaction - when service requires transaction this handler starts it

  • Security - verifies contraints related to authentication and authorization

  • General policy - executes other checks different than security and transaction

  • Validation - executes custom validators

  • Transformation - prepare payload for calling providing service

  • Validation - validates transformed payload

  • Provider call - calls providing service

  • Transaction - commits or rollbacks transaction, if necessary

If service consumer is synchronous and exchange pattern is set to in-out then some from these handlers are called once again:

  • Validation - verifies output generated by provider

  • Transformation - converts payload to structure required by consumer

  • Validation - checks output after transformation

  • Consumer callback - returns exchange to service consumer

Writing custom auditors

As said before audit mechanism requires CDI runtime to work. Annotate your Auditor implementations with the @Named annotation in order to have Camel recognise them. Camel Exchange Bus (a default implementation used by SwitchYard) look up for bean definitions with @Audit annotation. Simplest auditor looks following:

@Audit
@Named("custom auditor")
public class SimpleAuditor implements Auditor {

    @Override
    public void beforeCall(Processors processor, Exchange exchange) {
        System.out.println("Before " + processor.name());
    }

    @Override
    public void afterCall(Processors processor, Exchange exchange) {
        System.out.println("After " + processor.name());
    }

}

You will see lots of statements printed in server console like 'Before DOMAIN_HANDLERS', 'Before ADDRESSING' and so on. Every step of mediation is surrounded by this SimpleAuditor class.

Be aware that afterCall method is not called if surrounded step thrown an exception. In this case call of afterCall is skipped.

Chosing exact places for audit

If you are not interested in all these states of SwitchYard mediation process you might provide argument to @Audit annotation. Accepted values must come from org.switchyard.bus.camel.processors.Processors enumeration. For example @Audit(Processors.VALIDATION) will handle only validation occurances.

Please remember that validation is executed twice for in-only exchanges and fourth times for in-out. Validation occurs before transformation of inbound message and after transformation. In case when outgoing message will be sent from SwitchYard service validation is executed before transformation of outbound message and after transformation.

Transformation is executed once for in-only exchanges and twice for in-out exchanges.

Transaction phase is always executed twice.

If you are interested in only one execution of your auditor use following combination @Audit(Processors.PROVIDER_CALLBACK). Auditor will be executed just before sending exchange to service implementation. It's also possible to stick one auditor instance with few mediation steps. For example bean with annotation @Audit({Processors.PROVIDER_CALLBACK, Processors.CONSUMER_CALLBACK}) will be executed twice. One pair of before/after call for provider service and second pair for outgoing response.

Important notes

Custom auditors should not preserve state inside any fields because dispatching order is not guaranteed and only one instance of auditor is created by default. If you would like store some values please use exchange properties or message headers. Example below shows how to count processing time using Exchange properties as temporary storage.

@Named("custom auditor")
public class SimpleAuditor implements Auditor {

    private Logger _logger = Logger.getLogger(SimpleAuditor.class);

    @Override
    public void beforeCall(Processors processor, Exchange exchange) {
        exchange.setProperty("time", System.currentTimeMillis());
    }

    @Override
    public void afterCall(Processors processor, Exchange exchange) {
        long time = System.currentTimeMillis() - exchange.getProperty("time", 0, Long.class);
        _logger.info("Step " + processor.name() + " took " + time + "ms");
    }

}
JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-13 09:45:47 UTC, last content change 2013-08-08 16:25:27 UTC.