5.6. Enterprise Integration Features

Apart from the Spring/JSF/EJB integration, the Sportsclub application suite provides a few other examples of integrating Spring and JBoss. Since all the features are Spring-based, they have been included as business services of the Invoicing web application. All the definitions for the following examples can be found in the /WEB-INF/spring-business-context.xml file, defined in the spring-invoicing-webmvc module.

5.6.1. Payment processing: JMS integration through JCA

JMS integration can be enabled or disabled in the application, in order to allow it to run in environments that do not have a message broker. Take, for example, the Web Profile of JBoss Enterprise Application Server. For details on how to do that, please consult section Section 3.2, “Building the application” of the current guide.
Besides displaying the current status of invoices and payments for a given account and generating invoices through the web interface, the Sportsclub application can also process payments for various accounts. The assumption of this scenario is that the system can receive payment notifications asynchronously, through a JMS queue. When a payment has been received, it can be processed by a message-driven component, which in this case is a Spring bean. In order to take full advantage of the managed environment provided by the application server, the Spring bean will be invoked in a JCA context.
The paymentNotificationProcessor component processes JMS messages is a POJO, and is registered in the spring-messaging-context.xml file:
@Component
public class PaymentNotificationProcessor
{
    private static final Log LOG = LogFactory.getLog(PaymentNotificationProcessor.class);

    @Autowired
    private PaymentProcessor paymentProcessor;

    public void processPaymentNotification(PaymentNotification paymentNotification)
    {
        LOG.info(paymentNotification + " received");
        paymentProcessor.processPayment(paymentNotification.getAccountNumber(), paymentNotification.getAmount());
        LOG.info(paymentNotification + " processed");
    }

}
It delegates the actual processing of a PaymentNotification to a different component, the PaymentProcessor, which is injected in the PaymentNotificationProcessor. This is done in order to maintain a degree of separation between the way data may be represented when exchanged over the messaging system (that is, encapsulated in a PaymentNotification object), and the contract of the internal component which actually does the processing. The PaymentProcessor instance injected into the PaymentNotificationProcessor is reused by the PaymentNotificationService web service implementation (whose contract does not depend on the PaymentNotification entity).
The arrival of messages and their processing can be traced by examining the application log.
Spring will instantiate a bean named "paymentNotificationProcessor" which will be registered as a processor for JMS message as follows:
<jms:jca-listener-container resource-adapter="resourceAdapter" acknowledge="auto"
      activation-spec-factory="activationSpecFactory">
    <jms:listener destination="/queue/sportsclub" ref="paymentNotificationProcessor"
        method="processPaymentNotification"/>
</jms:jca-listener-container>
This type of configuration uses the JCA infrastructure to deliver messages to the listener, as opposed to the DefaultMessageListenerContainer which is effectively polling the destination for incoming messages. Using JCA will ensure better performance, as well as the ability to integrate with the JTA transaction manager out of the box.
In order to be able to test this feature, messages have to be sent to the message queue. This can be done by using a special MBean defined by the application, accessible from a management console. The name of the bean is "sportsclub:name=paymentNotificationTrigger" and has an operation called 'sendPaymentNotification' with two arguments:
  • a long value, which is the accountId for making the payment;
  • a double value, which represents the amount to be paid;
Once the JMX operation is invoked, a message is sent to the queue and a confirmation message will be displayed in the JBoss log.

5.6.2. Aspects and auditing

Payments must be audited. Besides keeping a record of payments associated with an account, it is possible to set up an auditing service that will audit every attempt of making a payment. In the simplest case that information can just be logged, although in a real life scenario things may be more sophisticated. In order to do so, set up a PaymentAuditor aspect that intercepts every call made to the PaymentProcessor.
The aspect is a simple POJO:
public class PaymentAuditor
{
    /* code ommitted */

    public void auditPayment(Long accountId, BigDecimal amount)
        {
        System.out.println("AUDIT ENABLED! A payment has been made to account "
            + accountId + " for the amount of " + amount);
        }
}
The aspect is applied through the following definitions:
<aop:config>
    <aop:aspect ref="paymentAuditor">
        <aop:pointcut id="processingPayment" 
            expression="execution(* *..PaymentProcessor+.*(..)) &amp;&amp; 
            args(accountId, amount)"/>
        <aop:before arg-names="accountId, amount" 
            pointcut-ref="processingPayment" method="auditPayment"/> 
    </aop:aspect>
</aop:config>

<bean id="paymentAuditor" class="org.jboss.snowdrop.samples.sportsclub.audit.PaymentAuditor"/>
The aspect is defined as a bean and applied as an aspect through the Spring aop namespace. The pointcut definition is an AspectJ expression.

5.6.3. Configuring Spring beans through JMX

JMX is an important tool for monitoring and configuring Java applications. Collecting information about the system and the ability of making configuration at runtime are important administration features. For this example, the requirement is to be able to turn auditing on and off, at runtime, whenever required. Removing an aspect once it has been applied by Spring is not possible, so the solution in this case is to define a flag property on the aspect, which controls whether the auditing functionality will be invoked or not.
In order to be able to make changes at runtime, the Spring bean which implements the aspect will be configured as a JMX bean and registered in the MBean server of JBoss. In this example, annotations are used to define Spring-specific JMX metadata. The complete definition for the PaymentAuditor is:
@ManagedResource(objectName = "sportsclub:name=paymentAuditor", description = "Payment Auditor")
@Component
public class PaymentAuditor
{

    private static final Log LOG = LogFactory.getLog(PaymentAuditor.class);

    private boolean enabled = true;

    @ManagedAttribute(description = "Audit enabled")
    public void setEnabled(boolean enabled)
    {
        LOG.info("Audit " +  (enabled ? "enabled":"disabled"));
        this.enabled = enabled;
    }

    @ManagedAttribute(description = "Audit enabled")
    public boolean getEnabled()
    {
         return this.enabled;
    }

    public void auditPayment(Long accountId, BigDecimal amount)
    {
        if (this.enabled)
        {
            LOG.info("A payment has been made to account " + accountId + " for the amount of " + amount);
        }
    }
}
The annotations ManagedResource and ManagedAttribute are used to indicate what classes and properties are JMX-managed. In order to expose the bean through JMX, it must be exported using Spring's MBean Exporter.
<bean id="attributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>

    <bean class="org.springframework.jmx.export.MBeanExporter">
        <property name="autodetectModeName" value="AUTODETECT_ASSEMBLER"/>
        <property name="ensureUniqueRuntimeObjectNames" value="true"/>
        <property name="namingStrategy">
            <bean class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
                <property name="attributeSource" ref="attributeSource"/>
            </bean>
        </property>
        <property name="assembler">
            <bean class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
                <property name="attributeSource" ref="attributeSource"/>
            </bean>
        </property>
    </bean>
As a result, this functionality can be turned on and off directly from the JBoss Enterprise Application Platform JMX administration console, using the "sportsclub:name=paymentAuditor" bean to interact with the payment auditor.
As explained in the JMS section, a separate MBean is set up for setting messages to the payment notifications message queue.

5.6.4. Payment processing: exposing a JAX-WS web service

Another way of interacting with external applications, is by exposing a web service. In this scenario, payment notifications may not arrive only as asynchronous events on a message queue, but also as synchronous web service invocations. For this purpose, the application will expose a Spring bean with JAX-WS annotations as a web service.
To that end, a JAX-WS annotated class is provided by the application:
@WebService
public class PaymentNotificationService extends SpringBeanAutowiringSupport
{

   @Autowired
   private PaymentProcessor paymentProcessor;

   @WebMethod
   public Long notifyPayment(@WebParam(name="accountNumber") Long accountNumber, @WebParam(name="amount") BigDecimal amount)
   {
      return paymentProcessor.processPayment(accountNumber, amount);
   }

}
By extending SpringBeanAutowiringSupport, the class PaymentNotificationService will be injected automatically with the same PaymentProcessor instance that is used by the JMS notification processor, and defined in the application context created from WEB-INF/spring-business-context.xml. This is necessary, because no bean of the type PaymentNotificationService is defined in the application context. Instead, the web service is defined and mapped as a servlet in /WEB-INF/web.xml:
<servlet>
    <servlet-name>PaymentNotificationService</servlet-name>
    <servlet-class>org.jboss.snowdrop.samples.sportsclub.ws.PaymentNotificationService</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>PaymentNotificationService</servlet-name>
    <url-pattern>/ws/payment</url-pattern>
</servlet-mapping>
As a result, the JAX-WS web service can be accessed at http://localhost:8080/sportsclub/invoicing/ws/payment. The service can be tested using a free SOAP testing tool such as SOAP UI.

5.6.5. Implementing a Spring Web Services web service

Spring Web Services is focused on implementing contract-first web services, as opposed to the contract-last approach taken in the JAX-WS example (although it should be noted that JAX-WS can support contract-first web services too). In the contract-first development style, the WSDL and request/reply document schemas are produced first, and define the contract between the service client and implementor. It is the responsibility of the service supplier to handle the request and reply documents appropriately.
The structure of the Spring-WS based web service is similar to a Spring MVC application. The entry point is a distinct type of dispatcher servlet, backed by an application context definition, as follows:
<servlet>
    <servlet-name>spring-ws-servlet</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-ws-config.xml</param-value>
        </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>spring-ws-servlet</servlet-name>
    <url-pattern>/spring-ws/payment</url-pattern>
</servlet-mapping>
The actual endpoint that handles the SOAP requests is defined as follows:
@Endpoint
public class PaymentNotificationHandler
{
    @Autowired
    private PaymentProcessor paymentProcessor;

    @PayloadRoot(localPart = "notifyPayment", namespace = "http://ws.sportsclub.samples.snowdrop.jboss.org/")
    public PaymentResponse notifyPayment(PaymentRequest paymentNotification)
    {
    Long paymentId = paymentProcessor.processPayment(paymentNotification.getAccountNumber(), paymentNotification.getAmount());
    return new PaymentResponse(paymentId);
    }

}
The @Endpoint annotation indicates that this class contains web service endpoint methods and allows for this component to be detected as a Spring bean through classpath scanning. The @PayloadRoot anotation indicates that any SOAP request submitted to the dispatcher servlet will be routed to the notifyPayment method if the root element of the payload is {http://ws.sportsclub.samples.snowdrop.jboss.org/}notifyPayment. The request payload will be automatically unmarshalled in a PaymentRequest object sent as argument to the method. The return value is a PaymentResponse object which will be automatically marshalled as XML content and will become the payload of the SOAP response that gets sent back. The Spring Web Services configuration indicates that a JAXB marshaller should be used specifically in this case.
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>org.jboss.snowdrop.samples.sportsclub.ws.PaymentRequest</value>
            <value>org.jboss.snowdrop.samples.sportsclub.ws.PaymentResponse</value>
        </list>
    </property>
</bean>
The detailed application context definition can be found in the src/webapp/WEB-INF/spring-ws-config.xml file of the context configuration.