This documentation is archived and is not being maintained.

Migrating Message Driven 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 Java Message Driven Beans to Microsoft .NET Framework Queued Components. (6 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 J2EE Solution
Converting the Code
Leveraging the .NET Framework

The Business Problem

One of the many ways to solve distributed computing problems is to use an asynchronous messaging system. Each distributed component must listen for, and respond to, messages sent to the component. Message-driven systems offer many advantages over traditional coupling mechanisms such as CORBA, because the components are loosely coupled. That is, not all components have to be using the same technology or running on the same systems. The components all just have to be able to listen to the message queue and send messages.

The J2EE Solution

In J2EE, message-driven systems are generally built on a combination of two different APIs: the Java Messaging System (JMS) and the Message Driven Bean (MDB) portion of the Enterprise Java Bean framework. Ultimately, both of these systems depend on the J2EE server framework for providing message queue lookup functions and maintaining the lifecycle of the bean.

Because of this mix of systems, you are required to implement one interface from the MDB specification, and one interface from the JMS specification, in order to create a bean that can both send and receive messages. Once you have the bean developed, you have to create a deployment descriptor that identifies the messaging system that JMS should use.

The Message Driven Bean

A typical listener bean might look like the Order Processor example shown in Listing 1. This example waits for an incoming message, and then writes out a message. In a business application, the incoming message would trigger a business function such as writing to a database.

package com.companyx.message;

import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.naming.*;
import javax.jms.*;

public class OrderProcessorBean implements MessageDrivenBean, MessageListener {

    public OrderProcessorBean() {
    }

    public void setMessageDrivenContext(MessageDrivenContext mdc) {
    }

    /**
     * @ejb.create-method
     */
    public void ejbCreate() {
    }

    public void onMessage(Message inMessage) {
        TextMessage msg = null;

        try {
            if (inMessage instanceof TextMessage) {
                msg = (TextMessage) inMessage;
                StringBuffer rcvMsg = new StringBuffer();
                rcvMsg.append("MESSAGE BEAN: Message received: ");
                rcvMsg.append(msg.getText());
                System.out.println(rcvMsg);
            } else {
                StringBuffer errMsg = new StringBuffer();
                errMsg.append("Message of wrong type: ");
                errMsg.append(inMessage.getClass().getName());
                System.out.println(errMsg);
            }
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (Throwable te) {
            te.printStackTrace();
        }
    }

    public void ejbRemove() {
    }
}

Listing 1. OrderProcessor.java

The most important part is that the bean implements javax.jms.MessageListener, which includes an OnMessage method for accepting incoming messages. In our example, we accept the message and simply write the contents to the standard output.

The other methods in the bean are very similar to standard Session bean methods. You can use a MessageDrivenContext for accessing the EJB context to get the caller identity, transaction context, and so on. You can also use ejbCreate() and ejbRemove() to initialize and destroy any setup you need to do in order to process your messages.

Converting the Code

One of the tricks to converting MDB code is realizing that the Microsoft .NET Framework treats messaging in an entirely different way than J2EE. Specifically, the .NET Framework has Queued Components, which are similar in many ways to MDBs. However, Queued Components do not use a system like JMS, where you can plug in any number of messaging systems. Queued Components are designed to work expressly with Microsoft Message Queuing, which is built into Microsoft Windows Server 2003.

When you convert your MDBs, you have to ask yourself whether or not you are committed to your current messaging system. If, for example, you are using a messaging platform such as Tibco to transmit messages throughout your company, you won't be able to use Queued Components. You will have to find a .NET Framework version of the Tibco adapter and write your own Enterprise Service (Microsoft COM+) managed components to listen and respond to Tibco messages. The Microsoft Java Language Conversion Assistant (JLCA: see http://msdn.microsoft.com/jlca) will help you convert your business logic, but you will have to throw away the converted messaging portions.

Creating a Queued Component

After you run the JLCA on your MDB, you will find that the resulting code actually has a bunch of logic that was added specifically to make a Queued Component look like an MDB. Although this extra logic may keep your code looking familiar, it comes at the cost of cluttering up the logic of what you need to do to create a Queued Component. Listing 2 shows a cleaned up, post-conversion equivalent to our original Order Processor example.

using System;
using System.Windows.Forms;
using System.EnterpriseServices;

[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationQueuing(QueueListenerEnabled=true)]
[assembly: ApplicationAccessControl(Value=false,
  Authentication=AuthenticationOption.None)]

namespace OrderProcessorQC
{
  [InterfaceQueuing]
  public interface IOrderProcessor
  {void CreateOrder(string orderInfo);}

  public class OrderProcessor : ServicedComponent, IOrderProcessor
  {
  public void CreateOrder(string orderInfo)
    {
      MessageBox.Show(orderInfo, "Order Message");
    }
  }
}

Listing 2. OrderProcesserQC.cs

Notice that most of the information from your MDB deployment descriptor now takes the form of Microsoft C# attributes that decorate the class. The attributes at the top of the class indicate that OrderProcessorQC should be activated by the server, should listen to the queue, and should not perform any special authentication or access control.

Within the actual class, you can see that an interface has been created to allow the class to live inside the COM+ framework as a Queued Component. The interface is implemented by the OrderProcesser class, which must inherit from the ServicedComponent class to gain the COM+ functionality.

Deploying the Component

Once you have the component created, you must sign it, compile it, and deploy it to COM+. In the .NET Framework, all COM+ components must be signed with a strong name, to guarantee version and authenticity. Once you have signed your application, you can deploy it to the Global Assembly Cache and register it with COM+.

Signing the Application

To sign your application, you must generate a public/private key encryption pair and link the key to your code. When the .NET Framework compiles your code, it will use the encryption key to create a digital signature that ties together the application name, the version number, the public key, and (optionally) any culture information.

To generate a key, open a Microsoft Visual Studio .NET 2003 command window in the OrderProcessorQC project directory, and run the following command.

sn –k OrderProcessorQC.snk

Listing 3. Generating a Key Pair

Once you have the key, go back into Visual Studio .NET and find the AssemblyINfo.cs class in your project. Go to the line where AssemblyKeyFile is declared, and specify a value of @"..\..\OrderProcessorQC.snk" for the key file. The entire line should look like Listing 4.

[assembly: AssemblyKeyFile(@"..\..\OrderProcessorQC.snk")]

Listing 4. Linking the Key

Once you have the key in place, you will automatically generate a strong name whenever you compile the application.

Deploying the Application

Once you have a signed and compiled application, you need to deploy it to COM+. Open a Visual Studio .NET 2003 command window to the OrderProcessorQC project output directory, and then run the following command to deploy the application to COM+.

regsvcs OrderProcessorQC.dll

Listing 5. Registering the Component

To view the queues that were automatically created for the application:

  • Open the Computer Management snap-in from your Administrative Tools folder.
  • Expand Services and Applications, Message Queuing, Public Queues, and orderprocessorqc.
  • Select the Queue messages node to view the messages that have been queued for the component.

To view the application that was created in COM+:

  • Open the Component Services snap-in from your Administrative Tools folder.
  • Expand Computers, My Computer, COM+ Applications, OrderProcessorQC.
  • Note that the OrderProcessorQC.OrderProcessor component has been added to the application.

Leveraging the .NET Framework

As you can see, Queued Components are, in many ways, much more streamlined than MDBs. All of your configuration and setup is performed by adding attribute decorators directly to the class. The Microsoft Queuing framework and Enterprise Services (COM+) support are built directly into the operating system.

Using COM+ Queued Components (QC) greatly simplifies the process of allowing methods on components to be invoked asynchronously. There is no need to create queues or messages, or to build the framework to allow messages to be created and sent between the client application and the component. QC is a component-centric approach to providing loosely coupled services. The developer only needs to focus on the business logic for the Queued Component, and use a moniker to bind to the component and invoke the method asynchronously.

QC uses Microsoft Message Queuing (MSMQ) to provide this loosely coupled service framework, and thus it is not suitable to use if another message-oriented middleware (MOM) is desired. The JMS specification, however, is message-centric and does not assume any particular MOM; therefore, it allows for changing the MOM used by an application, without having to change the application itself. Since the JLCA generates code which is more in line with JMS, this utility should be leveraged whenever there may be a need to interoperate with a MOM other than MSMQ. Applications would have to be re-factored to integrate directly with another messaging system. For example, to use Tibco Rendezvous (TIB/RV) from .NET, applications would have to use the TIB/RV .NET library to send and receive messages. All additional functionality, such as message addressing, parsing and dispatching, would be the responsibility of the application developer.

There are times when it may be necessary to interact directly with the underlying messaging system. For example, more messaging control over routing or quality of service may be desired, or the messaging system may need to be exploited in a way which is not accessible through a higher-level framework such as QC. However, this comes at a cost—additional development and testing time is required to build the orthogonal messaging infrastructure. Many messaging solution conversions are therefore better performed without the JLCA. You can use the JLCA to convert the business logic, but throw away the messaging portions. There is no need to develop an application using a message-centric approach if the QC framework already abstracts it. The developer must determine whether the priority is to have object-centric developer productivity at the cost of relying on a particular messaging system, or to have message-centric application interoperability at the cost of additional development and testing time.

Show: