EJB - .NET Interoperability by Thomas GIL (thomas.gil@dotnetguru.org)


Introduction

WebServices have initially be introduced as a new tool to improve the interoperability between heterogeneous architectures and environments.

Like CORBA ten years ago.

After some thundering declarations in the media and the launching of some “early adopter” projects, the first experiences have not necessarily been positive about this middleware. What is generally reproached to WebServices is :

We have wanted to come back on some of these topics, not through a conceptual and necessarily subjective article, but with a more pragmatic approach trying to implement a simple example of a hybrid J2EE / .NET architecture that we will probably have to implement more and more in the future (this is a personal feeling).

Of course, don't expect to find here a formal description of SOAP, WSDL, WSIL, UDDI, BPEL4WS... some excellent books present those norms in up to 1000 pages !

Designing WebServices oriented architectures

Without coming back on the formal splitting of multi-tier architectures, let's just ask this question : where is it judicious to use WebServices ? If we really explore this model, we happen to find more candidates than foreseen (by habits).

Between databases and the data access layer ?

Yes, especially to dialog with native XML databases. For example, you typically connect to the eXist database using the SOAP protocol : you send Xquery requests whose result comes as XML fragments.

Why should this database, that is written in Java, be exclusively used in the J2EE context ? There is absolutely no reason since WebServices enable any kind of client (having a SOAP/WSDL stack) to interact with the services the database exposes.

It wouldn't be a big surprise to see a new wave of two tier architectures in a short future, be it in a rich client mode (cf. Figure A) or in a lightweight client mode (cf. Figure B). Multi-tier architectures is not forbidden of course, but taking new technologies as a pretext, we sometimes forget basic architectural principles...


Figure A : Rich .NET client – XML/Java database server





Figure B : Lightweight .NET client – XML/Java database server



Criticism : since transactions are not standardized yet on the SOAP protocol, connecting to a database using WebServices means giving up any transactional interaction. This hasn't posed any problem to PHP Web developers who have been connecting to MySQL without transactional support for some time, however this feature is required in most of the applications.

Some implementations already support transactional invocation of WebServices operations (adding technical information to the headers of SOAP messages) but using those advanced features ties our applications to the WebServices implementation we use and this is quite harmful to interoperability.

Between the service layer and the domain objects ?

No. The object model is often too complex to be directly exposed through distributed interfaces. Both for a performance issue (it is not recommended to invoke too many methods remotely, whatever the middleware) and for a complexity issue (service consumers should not have to understand the underlying implementation of our object model).

Between the presentation layer and the service layer ?

Yes, it is typically where remote service invocation middleware fit. Why not WebServices ?

We'll detail this part in the next section, but let's wonder first whether WebServices are enough to fulfill all our technical needs between those two layers.

Authentication

More than the necessity to invoke remote services (something SOAP can do without problem), the presentation layer will often have to authenticate in order to consume some operations whose visibility is restricted. This need isn't new, but the interoperability and multi-platform aim makes it difficult to implement :

Transactions

We already spoke about this feature about the database connection. If we want to guarantee the interoperability between different technologies and different WebServices stacks, we'd better design our applications so that the presentation layer never has to start or to deal with transactions (this is true at least for today).

Notice that in principle, it is the same recommendation we already give for distributed architectures that use another middleware : if you use MTS or an EJB application server, it is typical to invoke services whose transactions are started and managed by the components container on the server side, and when possible, in memory (without two phase commit). Propagating a transactional context should only be necessary between services implementations, not between the presentation layer and the service layer.

Error management

The SOAP protocol, contrary to what the “O” in its name seems to mean, is absolutely not object oriented. It allows to transport messages, or to remotely invoke functions in its RPC mode. The error management is superficial : only the SOAPFault can inform clients of a problem when they invoke services. Then, the question is : how to transform the Object paradigm of exceptions (available in Java, C++, C#, Eiffel, Python...) into a SOAPFault or another SOAP compatible message (a Response) and how to be sure that the reverse transformations will be feasible on the other side of the network connection.

In practice, it is not possible or at least not standard. Indeed, the WSDL interface doesn't allow to describe the exceptions that the service operations may throw. The interoperability between languages and WebServices stacks is pretty compromised.

Let's wonder as previously. To implement a fine-grained error management, we could :

Conversational state management

At last, but this question isn't only related to using WebServices, where should we handle the users context ? In the presentation layer or in the service layer ? We generally agree to say that in order to get a minimal coupling and a maximal scalability, it is better for the service layer to be stateless (or amnesic). But in some situations when the “context” is too big, it can be unacceptable to systematically re-send it with each service invocation...

Heterogeneous architectures in practice

Now that we have all those constraints in mind, let's try to implement a service in Java (in the form of a Stateless Session EJB) and to consume it from an ASP.NET page that a final client will execute through her browser.

Service layer implementation (EJB)

Infrastructure setup

In terms of tools, we will rely on :

Some development environments directly integrate tools that help developing an EJB (WSAD, Jbuilder) but we experience that in practice, integrating some OpenSource tools is generally answer our needs.

The component design

As a reference to an interesting sales and bookkeeping tool, say an ERP (developed on J2EE by Pascal Coube and available in OpenSource at http://sourceforge.net/projects/oxerp/), we'll design a Stateless Session EJB that sends back an array of account movements that have been made between two dates.

An account movement is an entity of our application and can be represented as a Local Entity EJB or a simple JavaBean that JDO could make persistent. But the service layer will send back to its consumers a simple DTO (Data Transfer Object) and will pay attention to the fact that it is not dependent on any object that is proprietary to the development platform (a collection for example).

Here is a fragment of the design class diagram of such an application :



Figure C : AccountMovement (DTO) and the BookKeeping service (EJB)



Developing the component

The code of the AccountMovement class is trivial, it is a POJO (Plain Old Java Object). But developing an EJB requires to write its business interface (remote in our example), its implementation, the interface of its factory (the “Home”) and the associated deployment descriptor.

To speed up this process, we used Lomboz to create a new Stateless Session EJB. Here is what this plug-in automatically generates (we only enhanced the body of getAccountMovementsBetween(...) by implementing a Mock Service) :

package org.dotnetguru.erp;

import java.util.Date;

import javax.ejb.SessionBean;

/**

* @ejb.bean name="BookKeeping"

* jndi-name="BookKeepingBean"

* type="Stateless"

**/

public abstract class BookKeepingBean implements SessionBean {

/**

* @ejb.interface-method

* view-type="remote"

**/

public AccountMovement[] getAccountMovementsBetween(Date start, Date end) {

// Fake implementation. This methods should probably

// use local EntityBeans or JDO to retrieve data from the

// database

AccountMovement mvt1 = new AccountMovement("Billing an advertising week : Client Foo", 410000, 706000, 2000.00);

AccountMovement mvt2 = new AccountMovement("Buying a new computer : Supplier Bar", 604000, 401000, 2500.00);

return new AccountMovement[]{mvt1, mvt2};

}

}

You certainly recognized the JavaDoc comments : they respect the syntax of Xdoclet, that generates from this “enhanced” file all the dependant artifacts (remote interface, home interface, deployment descriptor). This code generation is triggered from within Eclipse thanks to the Lomboz plug-in :



Figure D : Generating dependant files using Lomboz



Decoration and deployment

Deploying the EJB component itself doesn't pose any problem : Lomboz make it easy as soon as you have configured it to point to the Jboss server installation directory.

What do we have to do to expose this component as a WebService ?

  1. Install Jboss.NET : if you use the « default » Jboss configuration, you'll only have to copy the directory named « .../Jboss/server/all/deploy/jboss-net.sar » into « .../Jboss/server/default/deploy/jboss-net.sar ». This can be done while Jboss runs (hot deploy). After this deployment, the Axis WebService stack will automatically be activated inside Jboss.

  2. Declare the Facade WebService : there are several techniques to do so, but the less intrusive is probably to deploy a « .WSR » archive, which enables to hot deploy WebServices in the application server. In our example, the archive will only play the role of a technical decorator and delegate : it will expose our EJB interface as a WSDL contract and will accept SOAP requests that will dynamically be transformed into RMI invocations to the EJB component.

To implement this second step, the way is easy :

The web-service.xml configuration file (used by Axis) should look like this :

<?xml version="1.0" encoding="iso-8859-1"?>

<deployment   

   xmlns="http://xml.apache.org/axis/wsdd/"

   xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"

   xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"

   xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">

 

       <service name="BookKeeping" provider="java:EJB">

           <parameter name="beanJndiName" value="BookKeepingBean"/>

           <parameter name="homeInterfaceName" value="org.dotnetguru.erp.BookKeepingHome"/>

           <parameter name="remoteInterfaceName" value="org.dotnetguru.erp.BookKeeping"/>

           <parameter name="allowedMethods" value="*"/>

           <parameter name="className" value="org.dotnetguru.BookKeepingBean"/>

           <beanMapping

               xmlns:ns="http://erp.dotnetguru.org"

               qname="ns:AccountMovement"

               languageSpecificType="java:org.dotnetguru.erp.AccountMovement"/>

       </service>     

</deployment>

As for the packaging of a Web Application or an EJB, we only have to compress the content of our working directory into a « BookKeepingDecorator.wsr » file, and to copy-paste this archive file into Jboss deployment directory (../Jboss/server/all/deploy).

Jboss will hot deploy our decorator, and we can make sure that the WebService is ready to go by going to the following address (using a simple Web browser) : http://localhost:8080/jboss-net/services. In our situation, here is what Jboss-net displays :



Figure E : The list of services Jboss.net makes available



Following the « BookKeeping » service hyperlink, we can get its WSDL contract :



Figure F : The WSDL contract as a Facade of our Stateless Session EJB



Now, we only have to consume this service using any technology on the client side.

Implementing a .NET client

Consuming WebServices in .NET is a simple thing to do. For the lucky guys who own VisualStudio.NET or C#Builder, we can even say that it is trivial. Ok, one last time, let's follow the “.NET evangelist” way :

To get a grasp, have a look at the CodeBehind :

namespace ConsumingBookKeeping {

using System;

using BookKeeping;


public class AccountMovementList : System.Web.UI.Page {

protected System.Web.UI.WebControls.DataList listMovements;


private void Page_Load(object sender, System.EventArgs e) {

BookKeepingService service = new BookKeepingService();

listMovements.DataSource = service.getAccountMovementsBetween

(new DateTime(2003, 01, 01), new DateTime(2003, 12, 31));

listMovements.DataBind();

}

}

}

And here is the code of the ASPX page itself :

<%@ Page language="c#" Codebehind="AccountMovementList.aspx.cs"

AutoEventWireup="false"

Inherits="ConsumingBookKeeping.AccountMovementList" %>

<%@ Import namespace="ConsumingBookKeeping.BookKeeping" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >

<HTML>

<HEAD>

<title>AccountMovementList</title>

<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">

<meta content="C#" name="CODE_LANGUAGE">

<meta content="JavaScript" name="vs_defaultClientScript">

<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">

</HEAD>

<body>

<form id="Form1" method="post" runat="server">

<H2>Account movement list</H2>

<asp:datalist id="listMovements" runat="server">

<HeaderTemplate>

<table border="1">

<tr>

<th>

Label</th>

<th>

Credit account #</th>

<th>

Debit account #</th>

<th>

Amount</th>

</tr>

</HeaderTemplate>

<FooterTemplate>

</table>

</FooterTemplate>

<ItemTemplate>

<tr>

<td>

<%# ((AccountMovement)Container.DataItem).label %>

</td>

<td>

<%# ((AccountMovement)Container.DataItem).crebitAccountNumber %>

</td>

<td>

<%# ((AccountMovement)Container.DataItem).debitAccountNumber %>

</td>

<td>

<%# ((AccountMovement)Container.DataItem).amount %>

</td>

</tr>

</ItemTemplate>

</asp:datalist>

</form>

</body>

</HTML>

As you can see, if you respect the usual design and responsibility assignment rules between layers, building hybrid architectures doesn't pose any problem. Indeed, you would have written nearly the same code to consume remote EnterpriseServices or Indigo services tomorrow.

Conclusion

The J2EE platform brings a solid, mature and sexy technical framework to develop the business objects, data access and service layers. On the presentation layer side, till we have JSF and especially the associated tools that should come with this specifications, we are doomed to use quite technical frameworks such as XMLC, Barracuda or Struts.

The .NET platform has a lower cost of ownership, especially to implement the presentation layer (be it for lightweight or heavy clients). Today's ASP.NET are better than their Java competitors (JSP/Servlets) : easier, more abstract, and enabling a lower development time.

It is absolutely natural to use the right tool at the right place. In particular, it isn't astonishing to see that some projects choose ASP.NET as a presentation layer and EJB as a service layer (data access layer can be implemented either by local entity EJB or JDO).

In this article, the example we chose was very simple : data structures exchanged between the presentation and the service layers were independent from any platform and the services were stateless. This is conform to SOA architectures recommendations. If this way of working is compatible with your applications, and after some benchmarking to make sure the overhead isn't too much in terms of performances, it is up to you to adopt this approach and make it an architectural guideline. If the performance part is problematic, you could use an IIOP .NET Remoting channel to establish a communication between .NET and the Session EJBs. But whatever the middleware, the design patterns are the same and so the services interfaces. Using WebServices has nearly no impact on the design of your applications. As we say in French, “que du bonheur” (something that we could literally translate by “only happiness”).



Author: Thomas Gil

Translator (French to English): Thomas Gil

Copyright DotNetGuru April 2004



Source

All the code samples used in this article can be downloaded for free at this address. We declare them to be in the LGPL license. Enjoy.

Tools

http://eclipse.org/

http://jboss.org/index.html

http://www.objectlearn.com/index.jsp (Lomboz)

http://ws.apache.org/axis/