Seam and SOA
Tuesday, July 31st, 2007I am in Atlanta for our internal JBoss ESB / SOA training this week. Burr Sutter and his team are doing a great job conveying our SOA vision -- to mesh and reuse services you already built in your "single silo" applications (e.g., a web store and a warehouse management app can share an "order" object when the user confirms an order. Each application then process and save the order in their own ways.).
I have been thinking how Seam fits into this picture. With the support for web services in Seam 2.0, it is actually quite easy to fit a Seam application into a SOA environment. In this post, I'd like to discuss some work I did with the seambay example (a spoof auction site) to make it share its listings with other services, and receive listings from other services.
@Out
To make the seambay application share its auction listings with other services in the SOA environment, we need to serialize the Auction object and push it to the ESB, while it is being saved into the database by the Seam application. The least intrusive way to do this is to use an EJB3 interceptor to "steal" the Auction object when the confirm() method is called. This way, we do not need to make any change to the Seam application code.
-
public class AuctionInterceptor {
-
-
@AroundInvoke
-
-
-
if (target instanceof AuctionAction) {
-
if (ctx.getMethod().getName().equals("confirm")) {
-
Auction auction = ((AuctionAction) target).getAuction ();
-
// Send the following XML string to JMS
-
formatMessage(auction);
-
}
-
}
-
-
try {
-
return ctx.proceed();
-
} finally {
-
}
-
}
-
... ...
-
}
When the user enters a new auction listing on the site, the server console prints the following message.

@In
To make the Seam application as a SOA service end-point requires external applications to invoke its business logic through web services. The challenge here is that most business logic in Seam are managed in "conversations", which holds finer grained application state than Http sessions. How do you keep the conversation state across multiple SOAP calls? Well, here is where the Seam Web Service comes into play.
To expose business logic methods in Seam components as Web Service methods, you need to write a facade SLSB to wrap around the methods you want to expose. You can use the Seam.getComponent() method to get any Seam component by its name and then proceed to invoke any method on the component.
-
@Stateless
-
@WebService(name = "AuctionService", serviceName = "AuctionService")
-
public class AuctionService implements AuctionServiceRemote
-
{
-
@WebMethod
-
{
-
}
-
-
@WebMethod
-
{
-
AuctionActionInt action = getAuctionAction();
-
action.createAuction();
-
action.setDetails(title, description, categoryId);
-
}
-
-
@WebMethod
-
public Auction getNewAuctionDetails()
-
{
-
return getAuctionAction().getAuction();
-
}
-
-
@WebMethod
-
public void setAuctionPrice(double price)
-
{
-
getAuctionAction().getAuction().setPrice(price);
-
}
-
-
@WebMethod
-
public void confirmAuction()
-
{
-
getAuctionAction().confirm();
-
}
-
-
private AuctionActionInt getAuctionAction()
-
{
-
// Get seam component named "auctionAction" from context
-
}
-
... ...
-
}
Notice that the createAuction(), setAuctionDuration(), setAuctionPrice() and confirmAuction() methods all need to happen in the same conversation so that they can access the same "auctionAction" component. But we do not explicitly pass the conversation id to the web service calls. Instead, when the createAuction() method returns, it inserts a conversation id in the SOAP header, and expect the client to use the same conversation id in the header until the caller reaches confirmAuction(), which ends the conversation. The SOAP request inside a conversation looks like the following:
-
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
-
xmlns:seam="http://seambay.example.seam.jboss.org/">
-
<soapenv:Header>
-
<seam:conversationId>2</seam:conversationId>
-
</soapenv:Header>
-
<soapenv:Body>
-
<seam:setAuctionPrice>
-
<arg0>20</arg0>
-
</seam:setAuctionPrice>
-
</soapenv:Body>
-
</soapenv:Envelope>
As a proof of concept to demonstrate that Seam web service is well supported by existing SOAP tools, I build a SoapUI script to demonstrate how to add an auction to the Seam app via web services. Notice the "transfer" elements in the script. They are used to maintain the conversation id header across SOAP requests in a conversation.

Finally, I'd like to make the SOA version of the seambay example available for download. You can find the ready built EAR file in the dist directory, as well as the SoapUI script in the root directory.