SwitchYard JSF Integration tutorial

In this tutorial we will discuss about JSF integration with SwitchYard using the Order example contained in the distribution.

The Bean Component is the core SwitchYard component. Built as an extension to Weld component it allows you to use the same programming model of CDI beans, with a few extra annotations. By adding Switchyard annotations you are able to expose your existing CDI beans as services to the outside world, or consume as well services from your beans.

How to expose SwitchYard Services ?

Providing a service using Switchyard’s Bean component just requires adding a @Service annotation to your bean.


import org.switchyard.component.bean.Service;

 

@Service(Simple.class)

public class SimpleService implements Simple {

    public void doSomething() {

       .....

    }

}

How to consume a SwitchYard Service from a CDI Bean?

In order to consume a SwitchYard service from within a CDI bean you need to apply a @Reference annotation to it. Supposing that we want to use from our SimpleService an external Service:


import org.switchyard.component.bean.Service;

import org.switchyard.component.bean.Reference;

 

@Service(Simple.class)

public class SimpleService implements Simple {

   @Inject @Reference ExternalService extService;

    public void doSomething() {

        extService.execute();

    }

}

The reference can point to any service hosted outside of Switchyard, for example an external JMS Provider.

The reference to the external service via @Reference annotation, is not a reference to the actual Service implementation. Instead, it is an Exchange proxy that is provided by Switchyard to contact  that Service implementation.

So let’s see a concrete example of a JSF application which will use SwitchYard Service. This application is contained in Switchyard distribution and you can check for more information about it on GitHub: https://github.com/jboss-switchyard/quickstarts/tree/master/demos/orders

So we will start from the view which is a simple JSF pages referencing some attributes and the create method of the Order bean


<div id="content">
    <h1>New Order</h1>
 
    <div style="color: red">
       <h:messages id="messages" globalOnly="false" />
    </div>
 
    <h:form id="newOrder">
        <div>
            Order ID:
            <h:inputText id="orderID" value="#{order.orderId}" required="true"/>
            <br/>
            Item ID:
            <h:inputText id="itemID" value="#{order.itemId}" required="true"/>
            <br/>
            Quantity:
            <h:inputText id="quantity" value="#{order.quantity}" required="true"/>
            <p/>
            <h:commandButton id="createOrder" value="Create" action="#{order.create}"/>
        </div>
    </h:form>
 
</div>

The Order bean is a plain CDI bean annotated with @Named which is used to mediate between the JSF page and the SwitchYard Service:


@Named
@RequestScoped
public class Order implements Serializable {
 
    @Inject
    @Reference
    private OrderService orderService;
 
    private String orderId;
    private String itemId;
    private int quantity = 1;
 
    // Getters and Setters here
 
    public void create() {
        OrderAck serviceAck = orderService.submitOrder(this);
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(serviceAck.toString()));
    }
}

Notice the @Reference annotation which is used to consume the SwitchYard service.

More interesting for us is the OrderServiceBean which contains the Service to be exposed via JSF. It uses in turn another Service named InventoryService which barely contains a Collection of Items which can be ordered:


@Service(OrderService.class)
@ApplicationScoped
public class OrderServiceBean implements OrderService {
    
    @Inject @Reference
    private InventoryService _inventory;
    
    @Override
    public OrderAck submitOrder(Order order) {
        // Create an order ack
        OrderAck orderAck = new OrderAck().setOrderId(order.getOrderId());
        // Check the inventory
        try {
            Item orderItem = _inventory.lookupItem(order.getItemId());
            // Check quantity on hand and generate the ack
            if (orderItem.getQuantity() >= order.getQuantity()) {
                orderAck.setAccepted(true).setStatus("Order Accepted");
            } else {
                orderAck.setAccepted(false).setStatus("Insufficient Quantity");
            }
        } catch (ItemNotFoundException infEx) {
            orderAck.setAccepted(false).setStatus("Item Not Available");
        }
        return orderAck;
    }

}

Here’s a picture which summarizes the relation between the components:

switchyard tutorial jboss as 7 switchyard tutorial jboss as 7

 


Running the example

In order to run the example you need a JBoss AS 7 installation- the simplest way is to pickup the switchyard-as7-0.6.0.Final.zip from http://www.jboss.org/switchyard/downloads which already contains all modules bundled into the AS 7 installation.

Once you are done with unzipping and starting Switchyard AS 7, compile and package the project using Maven:


C:\switchyard-as7-0.6\quickstarts\demos\orders mvn install

This will create a file named switchyard-quickstart-demo-orders.war which needs to be deployed on your Switchyard AS 7’s deployment folder. Once deployed you can test your Service using a variety of approaches.

Testing the example using JSF

Switchyard jsf tutorial soa jboss esb

At the moment the only Item which is accepted (contained in the InventoryService) is “BUTTER”

Testing the Service using SOAP clients

One thing we have not mentioned yet is that our Service is including a Transformer class. Transformers are a key feature of every integration software since the format of the message is often different from service consumers and providers. So if we want to provide an additional channel to the Service, for example if we want to allow to be consumed it by SOAP clients, we can just write a trasnformer which converts from Java Objects to XML Element and viceversa.

Coding the Trasnformation in a separate class (not in the business class itself) allows a clean separation of the trasnformation logic from the business methods.

Tip

Here’s the core section of the Transformers class:


public class Transformers {

    // Element names in XML document
    private static final String ORDER_ID = "orderId";
    private static final String ITEM_ID = "itemId";
    private static final String QUANTITY = "quantity";

    /**
     * Transform from a DOM element to an Order instance.
     * <p/>
     * No need to specify the "to" type because Order is a concrete type.
     * @param from Order element.
     * @return Order instance.
     */
    @Transformer(from = "{urn:switchyard-quickstart-demo:orders:1.0}submitOrder")
    public Order transform(Element from) {
        Order order = new Order();

        order.setOrderId(getElementValue(from, ORDER_ID));
        order.setItemId(getElementValue(from, ITEM_ID));
        order.setQuantity(Integer.valueOf(getElementValue(from, QUANTITY)));

        return order;
    }

    /**
     * Transform from an OrderAck to an Element.
     * <p/>
     * No need to specify the "from" type because OrderAck is a concrete type.
     * @param orderAck OrderAck.
     * @return Order response element.
     */
    @Transformer(to = "{urn:switchyard-quickstart-demo:orders:1.0}submitOrderResponse")
    public Element transform(OrderAck orderAck) {
        StringBuffer ackXml = new StringBuffer()
            .append("<orders:submitOrderResponse xmlns:orders=\"urn:switchyard-quickstart-demo:orders:1.0\">")
            .append("<orderAck>")
            .append("<orderId>" + orderAck.getOrderId() + "</orderId>")
            .append("<accepted>" + orderAck.isAccepted() + "</accepted>")
            .append("<status>" + orderAck.getStatus() + "</status>")
            .append("</orderAck>")
            .append("</orders:submitOrderResponse>");

        return toElement(ackXml.toString());
    }

}

As you can see from the server logs, Apache CXF has associated a Web service to your Order Service and exposed a WSDL of it at http://localhost:8080/demo-orders/OrderService?wsdl

10:03:29,801 INFO  [org.apache.cxf.service.factory.ReflectionServiceFactoryBean] (MSC service thread 1-8) Creating Service {urn:switchyard-quickstart-demo:orders:1.0}OrderService from WSDL: vfs:/C:/switchyard-as7-0.6/bin/content/switchyard-quickstart-demo-orders.war/WEB-INF/classes/wsdl/OrderService.wsdl
10:03:30,737 INFO  [org.apache.cxf.endpoint.ServerImpl] (MSC service thread 1-8) Setting the server’s publish address to be http://localhost:8080/demo-orders/OrderService
10:03:31,048 INFO  [org.jboss.wsf.stack.cxf.deployment.WSDLFilePublisher] (MSC service thread 1-8) WSDL published to: file:/C:/switchyard-as7-0.6/standalone/data/wsdl/demo-orders.deployment/OrderService.wsdl

Now you can use any SOAP client utility to test the Web service, such as SOAP ui (See a tutorial about SOAP ui and Eclipse here )

Enter the WSDL in your SOAP ui project: http://localhost:8080/demo-orders/OrderService?wsdl

soa switchyard tutorial soa JSF jboss soa

Finally, if you are not willing to use Eclipse ui, you can still run the built-in SOAP client contained in the Project. Just reference it via Maven as it is:

mvn exec:java

SOAP Reply:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <orders:submitOrderResponse xmlns:orders="urn:switchyard-quickstart-demo:orders:1.0">
      <orderAck>
        <orderId>PO-19838-XYZ</orderId>
        <accepted>true</accepted>
        <status>Order Accepted</status>
      </orderAck>
    </orders:submitOrderResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Found the article helpful? if so please follow us on Socials