This documentation is archived and is not being maintained.

Migrating EJB Session Beans with the Microsoft Java Language Conversion Assistant 3.0

Visual Studio .NET 2003
 

Microsoft Corporation

September 2005

Applies to:
   Microsoft Java Language Conversion Assistant 3.0
   Microsoft .NET Framework

Summary: This article describes how to use the Microsoft Java Language Conversion Assistant to convert EJB session beans into their Microsoft .NET Framework equivalents. (8 printed pages)

Note   More information on the Java Language Conversion Assistant (JLCA) can be found on the Microsoft Visual Studio Developer Center here.

Contents

The Business Problem
The Java Technology
The Conversion Process
Leveraging the .NET Framework

The Business Problem

As almost all developers have discovered, distributed computing is difficult. After locating a given business component, you need to then marshal a call to this component across the wire, distribute it to a cluster of like components to provide load balancing, and ensure that the call is made in such a way as to be fault tolerant. In solving this problem, you inevitably expose a service to a potentially wide audience, which means you have to implement authentication and authorization. Already you have yourself a heap of complex programming required to solve these problems. Wouldn't it be nice if there were a framework to solve these problems for you?

The Java Technology

The Java EJB framework provides one solution to these problems. In particular, the Session Bean is a business object that leverages the EJB container to solve all of the common issues associated with distributed computing. The Session Bean framework allows the developer to focus on solving the business problems rather than technical problems. But what is the Microsoft .NET Framework equivalent?

The Basic Stateful Bean

In order to demonstrate how the Microsoft Java Language Conversion Assistant (JLCA: see http://msdn.microsoft.com/jlca) converts a session bean into the .NET Framework, we will use the following simple stateful bean as an example.

public class ShoppingEJB implements SessionBean, IShopping {
    private SessionContext context;
    private List cart;
    public void ejbCreate() throws CreateException {
        cart = new ArrayList();
    }
    public void ejbRemove() {
        cart = null;
    }
    public void ejbActivate() {
        //If this were stateless you would acquire resources here
    }
    public void ejbPassivate() {
        //If this were stateless you would release resources here
    }
    public void setSessionContext(SessionContext context) {
        this.context = context;
    }
    public void unsetSessionContext() {
        this.context = null;
    }
    public void addToCart(CartItem item) {
        cart.add(item);
    }
    public List getCartContents() {
        return cart;
    }
    public BigDecimal getPrice(int itemId) {
        return MyDataLayer.getItemPrice(itemId);
    }
    public void setPrice(int itemId, BigDecimal newPrice) {
        MyDataLayer.setItemPrice(itemId, newPrice);
    }
}

Listing 1. Session Bean

As you can see, there is nothing overly complicated happening here, simply two methods that rely on the state of the session, and two methods that act as proxies to an underlying data access layer.

Transactions

Of interest during the conversion is that the setPrice method should be part of a transaction. This is not evident, because that information is stored in an XML descriptor. Special care must be given to converting transacted methods, because the code won't tell you that a transaction is involved.

The Home Interface

The home interface is an EJB apparatus used to manage locating and then distributing business object to clients. Although simple, the mechanics behind its use are anything but straightforward.

public interface ShoppingHome extends EJBHome {
        public static final String JNDI_NAME = "Shopping.Home";
        public IShopping create() throws RemoteException, CreateException;
}

Listing 2. Home Interface

The EJB framework uses the home interface to create new bean instances, intercept calls to the bean to provide services, and manage the lifecycle of the bean.

The Client Interface

The EJB framework requires that you develop several interfaces. The first one is used by the client.

public interface IShopping {
    void addToCart(CartItem item);
    List getCartContents();
    BigDecimal getPrice(int itemId);
    void setPrice(int itemId, BigDecimal newPrice);
}

Listing 3. Remote Interface

An EJB Client

The last piece of the puzzle is the code that uses the business object. Here you see how the session bean is found and used by client code.

Context context = new InitialContext();

Object shoppingHomeObj = context.lookup(ShoppingHome.JNDI_NAME);
ShoppingHome shoppingHome = (ShoppingHome) PortableRemoteObject.narrow(shoppingHomeObj, ShoppingHome.class);
IShopping iShop = shoppingHome.create();

CartItem cartItem = new CartItem();
BigDecimal itemPrice = iShop.getPrice(cartItem.getId());
if(itemPrice.intValue() < 10) {
    iShop.addToCart(cartItem);
}

Listing 4. Client Code

Note that not only do we have to use JNDI to look up the bean by name, but we also have to use RMI/IIOP to cast the bean to our local object type (the client interface).

The Conversion Process

This section looks at how the JLCA converts the session bean code, and how you have to tweak the resulting code to obtain the desired behavior.

The Implementation Class

To start, let's have a look at how the implementation class is converted.

[PrivateComponent]
[ComponentAccessControl]
[Serializable]
public class ShoppingEJB : System.EnterpriseServices.ServicedComponent, IShopping {

Listing 5. Class Definition

The first thing to notice is that the class has now become a ServicedComponent. This brings the ShoppingEJB into the world of COM+, providing services for transaction support, object pooling and much more. We will explore how these services are leveraged in the .NET Framework to provide some of the functionality that the EJB container provided. Also of note are the attributes applied to the class by default. The [PrivateComponent] attribute restricts component access to other components in the same application. This may or may not be the desired behavior, but for security reasons this is the default behavior for converted components. To enable public calls to the component you need only remove this attribute from the class definition. Next, the [ComponentAccessControl] attribute enables security checking on method calls. This provides further access restriction using role-based authorization. Finally, the [Serializable] attribute indicates that the class can be serialized.

Default EJB Methods

Let's look at some more of the converted implementation class.

  private SessionContext context;
  public virtual void  ejbCreate() {
    cart = new System.Collections.ArrayList();
  }
  new virtual public void Dispose() {
    cart = null;
    base.Dispose();
  }
  public void ejbActivate() {
    //If this were stateless you would acquire resources here
  }
  public void ejbPassivate() {
    //If this were stateless you would release resources here
  }
  public void setSessionContext(SessionContext context) {
    this.context = context;
  }
  public virtual void  unsetSessionContext() {
    this.context = null;
  }

Listing 6. Converted Lifecycle Code

This section of converted code requires some tweaking. To start with, there is no equivalent to the SessionContext in the .NET Framework. The closest thing to it is the System.EnterpriseServices.ContextUtil that is accessed through static methods. Given that the setting and unsetting of this variable is the only purpose of the last two methods in this block, they, along with the member variable itself, can be removed from the class entirely.

EJB Create

The ejbCreate method was previously called by the container to allocate necessary resources and initialize member variables for our stateful beans. In the .NET Framework, there really isn't a direct equivalent for a stateful bean, and therefore this method is no longer useful. Initialization should now be moved to the object constructor. The exception to this rule is if ejbCreate accepts parameters, in which case the logic should be transferred to a new Create method, because a ServicedComponent is not allowed to accept parameters in the constructor.

EJB Remove

Finalization such as that previously defined by ejbRemove should be moved to the Dispose method. This method is analogous to the Java finalize method, getting called by the garbage collector to perform any necessary cleanup.

EJB Activate and Passivate

If this were a stateless bean, ejbActivate and ejbPassivate might well contain logic for bringing the bean into and out of context. EnterpriseServices does offer object pooling, and if used, the ServicedComponent.Activate and ServicedComponent.Deactivate methods can be overridden to implement context-specific initialization. These methods are called automatically when the component is brought into or out of a context.

Object Pooling

Object pooling is achieved by using the ObjectPoolingAttribute. Placing this attribute in front of a ServicedComponent class definition enables it to be pooled. Configuration parameters can be added when defining the attribute, in order to define how the object is pooled.

Business Methods

Next, let's look at the converted Business methods.

  virtual public System.Collections.IList CartContents {
    get {
      return cart;
    }
  }
  private System.Collections.IList cart;
  public virtual void  addToCart(CartItem item) {
    cart.Add(item);
  }
  public virtual System.Decimal getPrice(int itemId) {
    return MyDataLayer.getItemPrice(itemId);
  }
  public virtual void  setPrice(int itemId, System.Decimal newPrice) {
    MyDataLayer.setItemPrice(itemId, newPrice);
  }
}

Listing 7. Converted Business Methods

The only major difference between the converted code and the original code is with CartContents. The JLCA recognized getCartContents as an accessor method. In Microsoft C#, style accessor methods are written in the form of properties like the one you see above. The only difference is that now instead of accessing cart using myCart.getCartContents(), you now use myCart.CartContents. Other than that, the methods maintain pretty much the same structure.

Transactions and Security

One thing that you will need to add by hand for these methods is transaction support and security. In an EJB, transaction and security settings are configured through an XML descriptor file. The EJB container reads the descriptor, and provides transaction and security services accordingly. In the .NET Framework, you don't have a deployment descriptor. Instead, you apply attributes directly to the methods through the C# attribute syntax. For example, you can declare that the setPrice() method must be in a transaction by adding the following attribute before the method declaration.

  [Transaction(TransactionOption.Required)]
  public virtual void  setPrice(int itemId, System.Decimal newPrice) {
    MyDataLayer.setItemPrice(itemId, newPrice);
  }

Listing 8. Adding Transaction Support

You can use similar attributes to provide security and pooling services.

Client Interface

Similarly the interface used by the clients translates pretty well.

public interface IShopping {
  System.Collections.IList CartContents {
    get;
  }
  void  addToCart(CartItem item);
  System.Decimal getPrice(int itemId);
  void  setPrice(int itemId, System.Decimal newPrice);
}

Listing 9. Converted Remote Interface

The only major difference is that the CartContents accessor has been replaced by a property declaration.

The EJBHome Interface

Because the .NET Framework uses a totally different model for remote objects, the EJB home interface does not convert quite as nicely.

public struct ShoppingHome_Fields{
  public readonly static System.String JNDI_NAME = "Shopping.Home";
}
public interface IShoppingHome
{
  IShopping create();
}
[ComponentAccessControl]
public class ShoppingHome:ServicedComponent, IShoppingHome
{
  public IShopping create()
  {
    return null;
  }
}

Listing 10. Converted Home Interface

This whole file should be removed from the new project entirely. It is of no use whatsoever. By making ShoppingEJB a .NET Framework ServicedComponent, the proxy work becomes completely transparent to the client.

The Client Code

To demonstrate why you can delete the home interface, let's look at what happens to the client code.

System.DirectoryServices.DirectoryEntry context = new 
  System.DirectoryServices.DirectoryEntry();
System.Object shoppingHomeObj = Activator.GetObject(typeof(System.MarshalByRefObject), 
  SupportClass.ParseURILookup(ShoppingHome_Fields.JNDI_NAME));
ShoppingHome shoppingHome = (ShoppingHome) shoppingHomeObj;
IShopping iShop = shoppingHome.create();
CartItem cartItem = new CartItem();
System.Decimal itemPrice = iShop.getPrice(cartItem.Id);
if (System.Decimal.ToInt32(itemPrice) < 10)
{
  iShop.addToCart(cartItem);
}

Listing 11. Converted Client Code

The client code now uses .NET Remoting. Because Remoting works quite a bit differently from an EJB, the translated component access code is fairly convoluted. The first six lines above can be reduced to the following.

IShopping iShop = (IShopping)Activator.GetObject(typeof(System.MarshalByRefObject),
   SupportClass.ParseURILookup("Location.Of.ShoppingEJB"));

Listing 12. New Component Access Code

This line creates a proxy for the Shopping object which forwards calls made on the IShopping interface. Once the proxy is obtained, it is used as with the EJB, so the rest of the code in Listing 10 converts pretty simply from the Java version.

Leveraging the .NET Framework

This section looks at what approach you might take to provide a service comparable to that of a session bean if you were designing it in C# from the beginning. Although you can build serviced components and host them on a Microsoft Windows Server, you may want to consider building Microsoft ASP.NET Web Services instead. Web Services provide looser coupling, and allow interoperation between different types of clients on different systems using different languages.

Following the trend towards services-oriented architecture, Web Services completely decouple the client and the server. At the same time, using the Web Services framework built into ASP.NET provides the developer with a wealth or pre-built tools for dealing with transactions, security, state management, and more. Making use of these tools allows a robust, scalable service to be built quickly and effectively. More information on building a Web Service can be found in Building XML Web Services Using ASP.NET.

Show: