Вы находитесь на странице: 1из 16

Developers Corner Tutorial

An Introduction to Web Services:


Part Four - Web Services & J2EE

Copyright 2003, Systinet Corp. Page 1 of 16


> Developers Corner: Web Services & J2EE

Contents Contents ................................................................................ 2

Introduction........................................................................... 3
About this tutorial 3
Installing software 3

Standard J2EE Processing ................................................... 4

J2EE Integration - Basic Approaches .................................. 5

The Simple Stock Quote EJB Wrapper Demo ...................... 6


Introduction 6
Installing 6
The EJB wrapper code 7

Transparent J2EE integration.............................................. 9

Transparent J2EE Integration Example ............................11

Cleanup & Review...............................................................15


Clean Up 15
Review 15

Copyright and Disclaimer ...................................................16

Copyright 2003, Systinet Corp. Page 2 of 16


Introduction About this tutorial
Welcome to the fourth installment in our series of articles explaining how
to build and use Web services. In previous articles we've learned how to
develop, deploy, and use simple Web services. We also looked at some
advanced Web services concepts including stateful Web services, remote
references, and Web services security. In this article we'll begin to explore
how Web services work within a J2EE environment.

Understanding Web Services & J2EE Integration Basics

Today, many applications implement third-tier business logic as standard


J2EE components. Exposing these components as SOAP Web services
makes them almost universally accessible - and provides a simple
mechanism for integrating these components. The modular J2EE
architecture makes this process relatively easy.

In this article we show how to expose J2EE components as Web services.


We will mainly discuss Enterprise Java Beans (EJBs), because they are the
most widely used J2EE components for business logic implementation, but
all demonstrated techniques are applicable to other J2EE components, such
as JDBC data sources, JCA adapters, and JMS queues.

NOTE: If you haven't already downloaded the software used to create the
tutorial examples, then please refer to the installing software section
(below.) You will also need to download the tutorial sources. All Java
sources mentioned in the tutorial examples can be found in the src
subdirectory of the unpacked tutorial sources archive. They all reside in the
com.systinet.demos package.

IMPORTANT: Please set the WASP_HOME environment variable to point to


the WASP Server root directory.

Installing software
REQUIREMENTS: We assume that you have a Java 1.4 or later SDK and a
standard HTTP browser installed on your system and the JAVA_HOME
system variable points to the Java root directory.

If you want to follow along with the demo, you'll need to download WASP
Server for Java, 4.5
(http://www.systinet.com/products/wasp_jserver/overview ) from the
Systinet Web site. Unpack the downloaded package to a local disk and run
the install script from the bin subdirectory of the WASP Server installation.
You'll need to agree to the product license and then please answer with
default options to all installation questions (simply press Enter multiple
times).

IMPORTANT: Please set the WASP_HOME environment variable to point to


the WASP Server root directory.

You'll also need to download the tutorial sources


(http://dev.systinet.com/get&dl=dHV0b3JpYWxzLnppcA) and unpack it on
the local disk.

Copyright 2003, Systinet Corp. Page 3 of 16


> Developers Corner: Web Services & J2EE

Standard J2EE Processing Let's first summarize some important facts about the J2EE platform.
Traditionally, a J2EE client application uses the Java Naming and Directory
Interface (JNDI) to find J2EE components on the server-side. For example,
the client application looks up the EJB reference in JNDI and receives an
EJB client proxy in return. The client uses this EJB client proxy later to
access the EJB component. All J2EE communication normally occurs over
RMI.

Copyright 2003, Systinet Corp. Page 4 of 16


J2EE Integration - Basic There are two basic approaches to accessing J2EE resources via SOAP.

Approaches First, we'll demonstrate the most obvious approach, creating a Web service
wrapper around the EJB. This approach is particularly appropriate in
situations where the Web service application does not map directly to the
capabilities of an individual EJB and requires some additional orchestration
of the J2EE components.

In our second example, we will introduce a codeless, transparent


integration approach. Its main goal is to expose existing J2EE applications
as Web services as quickly and as dynamically as possible. This approach
allows us to effectively access existing J2EE resource over SOAP without
writing or modifying any code.

Copyright 2003, Systinet Corp. Page 5 of 16


> Developers Corner: Web Services & J2EE

The Simple Stock Quote EJB Introduction


Wrapper Demo
In this demo we will introduce the EJB wrapper Web service approach to
access a stateless session bean, the stock quote EJB. The wrapper
approach is very simple, and it is widely used by many SOAP frameworks.
(There are slight differences among the various implementations, which
generally pertain to the level of automation of the development process.)

The wrapper approach requires development of a Web service that wraps


one or more existing J2EE components. This wrapper acts as a bridge
between the SOAP and RMI. Clients send SOAP requests to the wrapper,
and the wrapper translates them into RMI requests to the EJB components.
This approach is recommended for use mainly with stateless J2EE
resources, such as stateless session beans.

To access stateful resources using this technique you would need to set up
additional lifecycle services to manage the proper removal of orphaned
stateful resources.

We first need to perform some simple installation and configuration steps.

NOTE: If you haven't already downloaded the software used to create the
tutorial examples, please refer to the installation section at the start of this
document. You'll also need to download the tutorial sources (. All Java
sources mentioned in the tutorial examples can be found in the src
subdirectory of the unpacked tutorial sources archive. They all reside in the
com.systinet.demos package. Similarly all scripts used in the examples are
located in the bin subdirectory.

NOTE: Please remember to set your WASP_HOME environment variable to


the directory where WASP for Java 4.5 has been installed.

NOTE: We're using MS Windows notation for our command-line


commands. If you are using a UNIX-based environment, please use the
appropriate .sh script instead of the Windows .bat version.

ADDITIONAL INSTALLATION STEPS: We will use the JBOSS 3 for our


J2EE environment. It is available for download from JBoss's Web site
(http://jboss.org/downloads.jsp). After you installed JBOSS 3, and make
sure that it is not running, you must configure the WASP Web service
runtime to use JBoss.

Installing
First, invoke the J2eeIntegrate.bat script that is located in the bin
subdirectory of your WASP Server installation. The basic syntax is:

WASP_HOME\bin > J2eeIntegrate -i jboss3 --shared

Modify JBOSS's start-up script by to supplying some additional libraries to


JBOSS's runtime. These include:

• WASP_HOME\lib\xercesImpl.jar,

• WASP_HOME\lib\xmlParserAPIs.jar

• WASP_HOME\lib\security-ng.jar

• WASP_HOME\lib\xalan.jar

Any references to JAXP or to Crimson should be removed from the


CLASSPATH.

Copyright 2003, Systinet Corp. Page 6 of 16


Copy the generated WASP_HOME\conf\porting\jboss\build\wasp.war file
into the JBOSS distribution deployment directory. We recommend using
JBOSS_HOME\server\default\deploy. JBOSS monitors this directory and
automatically attempts to deploy any .war, .ear, or .jar files copied here.

Restart JBOSS using the modified run script. When JBOSS is booting, you
will notice a series of "ERROR" messages as it brings up WASP. This is
because WASP sends all of its boot event status messages to STDERR.
They are no cause for concern. You can verify that WASP has been properly
deployed by bringing up the WASP admin-console. If you are working
locally and JBOSS has been installed and started with its default settings,
this URL will be correct: http://localhost:8080/wasp/admin/console

The EJB wrapper code


You can view the Java sources in the com.systinet.demos.stock package to
find that the StockQuote, StockQuoteHome and StockQuoteBean classes
implement a stateless session bean with one simple getQuote method. Run
make_ejb_stock to compile the bean and package it to the
DEMO_HOME\build\Stock.ear file. Copying this file to the
JBOSS_HOME\server\default\deploy directory, will normally lead to
deployment in JBOSS. Check the console where the server is running for a
message like this:

INFO [MainDeployer] Deployed package:


file:/C:/jboss-3-
04/server/default/deploy/Stock.ear

Now let's concentrate on the wrapper Web service implementation, listed in


Figure 2. It implements a getQuote method, which contains a simple EJB
invocation. First it looks up the EJB home in JNDI and creates an EJB
instance. Then it invokes the getQuote method on the EJB, and removes
the EJB. Finally the invocation result is returned back to the Web service
client.

You can see these steps in the code starting on the next page:

Copyright 2003, Systinet Corp. Page 7 of 16


> Developers Corner: Web Services & J2EE

Example 1: Simple Web Service EJB wrapper (StockQuoteService.java)


package com.systinet.demos.stockbean;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import java.rmi.RemoteException;

public class StockQuoteService {

public double getQuote(String symbol) throws Exception


{

// get the JNDI initial context


System.err.println("Getting J2EE initial
context");
Context jndiContext = new InitialContext();
// lookup the EJB home
System.err.println("Looking up EJB Home");
Object homeRef = jndiContext.lookup("Stock");
StockQuoteHome home =
(StockQuoteHome)javax.rmi.PortableRemoteObject.narrow(
homeRef, StockQuoteHome.class);
// create the EJB instance
System.err.println("Creating EJB");
StockQuote ejb = home.create();
// call the getQuote method
System.err.println("Calling getQuote");
double quote = ejb.getQuote("SUNW");
System.err.println("SUNW "+quote);
// remove the EJB
System.err.println("Removing EJB");
ejb.remove();
return quote;
}
}
We can deploy the EJB wrapper Web service by running the run.bat
deploy_stockbean command. Next we can use the run.bat run_stockbean
command to start the Web service client that invokes the EJB through the
wrapper Web service.

NOTE: We've made this demo simple to illustrate the basic principles of
the wrapper approach. However real-life applications are usually a bit more
complex. A wrapper service is often used to assemble functionality from a
number of EJBs and other J2EE resources. In such cases, the wrapper
service usually exposes different programmatic interfaces than the original
beans.

Copyright 2003, Systinet Corp. Page 8 of 16


Transparent J2EE Another way to access J2EE resources is to use a transparent integration
framework. By transparent we mean that it isn't necessary to write a
integration wrapper service or to change the original J2EE code. This approach is most
useful if you have existing J2EE resources that you want to make available
to SOAP clients or if you have J2EE clients that need to access J2EE
resources across the Internet.

The WASP transparent J2EE integration framework described below


exploits the strengths of the JNDI architecture, which provides an abstract
mechanism to access J2EE resources. As we said earlier, in normal J2EE
processing, a J2EE client calls the JNDI lookup method, and the client's
JNDI provider passes this request over RMI to the JNDI service within the
J2EE server. JNDI returns a J2EE proxy to the client. The client
subsequently uses this proxy to invoke methods on the remote J2EE
resource over RMI.

In this example, we will use a JNDI provider on the client side that speaks
SOAP rather than RMI. As you can see in Figure 2,

1. when the client issues a JNDI call using this provider, the
request is sent over SOAP to a JNDI Web service.

2. This JNDI Web service performs the actual lookup in the


application server JNDI, obtaining the J2EE proxy.

3. The JNDI Web service dynamically generates a SOAP interface


to the J2EE proxy and returns a SOAP-based remote reference
for the J2EE proxy to the client.

4. The client application can then use this remote reference to


access the business logic in the EJB component.

Each method invocation is transported over SOAP to the J2EE proxy, which
redirects the request to the actual EJB component.

You'll notice that no code modifications are required in either the EJB
component or in the client code. Only a configuration change is required in
the client to point to the SOAP-based JNDI provider.

Figure 2: Web service access to JNDI

NOTE: Most Web service runtime servers operate in the same context as
the application server, so the redirected method invocation is very fast and
won't degrade performance.

This approach also works for non-Java clients. Since the JNDI Web service
is a standard SOAP service, any SOAP client can take advantage of its

Copyright 2003, Systinet Corp. Page 9 of 16


> Developers Corner: Web Services & J2EE

transparent invocation framework. For example, a Microsoft Visual Basic


client can call the lookup method on the JNDI Web service and obtain a
Web service proxy to the requested J2EE resource.

The JNDI Web service performs automatic remote garbage collection of all
components created in the Web service runtime. Each component is given
a set life span, or time in which it can expect to live--Time to Live (TTL).
This attribute is reset each time the component is accessed. Once the
component's TTL reaches zero, WASP automatically collects it and frees the
system resources.

The major advantage of the transparent invocation approach is that it


provides immediate and transparent SOAP access to any J2EE resource
registered in JNDI, including all types of EJB components (stateless and
stateful session beans, entity beans, and message-driven beans), plus JMS,
JDBC, JCA, and other J2EE resources. No modifications or wrappers need to
be made for the J2EE resources. This approach is obviously very useful to
provide quick and easy access to existing systems via SOAP. Let's look at
an example.

Copyright 2003, Systinet Corp. Page 10 of 16


Transparent J2EE This example shows a Web service calling an EJB running in Sun's J2EE 1.3
Reference Implementation engine.
Integration Example
First, let's look at the server-side EJB code. As you can see in the following
code listing, it's a simple stateful session bean that keeps track of a
counter.

Example 2: Simple Counter EJB (CounterEJB.java) - the server-side


EJB code
package com.systinet.demos.counter;

import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.SessionSynchronization;

public class CounterEJB implements SessionBean {

private SessionContext context;

private int count = 0;

/**
* No argument constructor required by container.
*/
public CounterEJB() {
}

/**
* Create method specified in EJB 1.1 section 6.10.3
*/
public void ejbCreate() {
}

/* Methods required by SessionBean Interface. EJB 1.1


section 6.5.1. */

/**
* @see
javax.ejb.SessionBean#setContext(javax.ejb.SessionContext)
*/
public void setSessionContext(SessionContext context){
this.context = context;
}

/**
* @see javax.ejb.SessionBean#ejbActivate()
*/
public void ejbActivate() {

Copyright 2003, Systinet Corp. Page 11 of 16


> Developers Corner: Web Services & J2EE

/**
* @see javax.ejb.SessionBean#ejbPassivate()
*/
public void ejbPassivate() {
}

/**
* @see javax.ejb.SessionBean#ejbRemove()
*/
public void ejbRemove() {
}

public long getCount() {


return count++;
}

The other EJB sources are fairly obvious. You can see the code of the
Counter remote and CounterHome home interfaces. We can build the
counter bean by invoking the run make_ejb_counter command.

As with the Stock.ear file, copy the DEMO_HOME\build\Counter.ear to the


correct JBOSS deployment directory to make it available to the JNDI
Context. Please note that we don't need to deploy any additional Web
services to the WASP Server.

The client application shown in Example 3 is a standard EJB client with the
exception that it uses different JNDI properties in the getInitialContext
method.

Copyright 2003, Systinet Corp. Page 12 of 16


Example 3: Simple Counter EJB Client (CounterClient.java)
package com.systinet.demos.counter;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import java.rmi.RemoteException;
import java.net.InetAddress;

public class CounterClient {

public CounterClient() {
}

public static void main(String [] args){


try {

// get the JNDI initial context


System.err.println("Getting J2EE initial
context");
Context jndiContext = getInitialContext();
// lookup the EJB home
System.err.println("Looking up EJB Home");
Object homeRef = jndiContext.lookup("Counter");
CounterHome home =

(CounterHome)javax.rmi.PortableRemoteObject.narrow(homeRef,

CounterHome.class);
// create the EJB instance
System.err.println("Creating EJB");
Counter ejb = home.create();
System.out.println("Calling count
"+ejb.getCount());
System.out.println("Calling count
"+ejb.getCount());
System.out.println("Calling count
"+ejb.getCount());
// remove the EJB
System.err.println("Removing EJB");
ejb.remove();

}
catch(java.rmi.RemoteException re) {
re.printStackTrace();
}
catch(Throwable t) {

Copyright 2003, Systinet Corp. Page 13 of 16


> Developers Corner: Web Services & J2EE

t.printStackTrace();
}

static public Context getInitialContext() throws


javax.naming.NamingException,

java.net.UnknownHostException {

String localhost =
InetAddress.getLocalHost().getHostName();

java.util.Properties jndiProperties = new


java.util.Properties();

jndiProperties.put("java.naming.factory.initial",

"com.idoox.jndi.InitialContextFactoryImpl");
//Preset to JBOSS3 Defaults.
//You need to set this to a valid URI for your J2EE
App. Server

jndiProperties.put("java.naming.provider.url","http://" +
localhost +
":8080/wasp");

return new InitialContext(jndiProperties);


}
}

For the sake of simplicity, we've hard coded all JNDI specific parameters.
There are two parameters that must be defined in order to redirect the
JNDI query to the JNDI Web service:

• java.naming.factory.initial, and

• java.naming.provider.url.

These parameters are usually stored in an application .properties file rather


than hard coded in the client application. In such a case, recompilation of
the code is not necessary.

The next step is to compile and run the J2EE client application using the
run.bat make_counter and run.bat run_counter commands. You should see
the EJB's getCount method called three times. All communication between
the client application and the server-side is through SOAP messages. You
can also see that the state (counter value) is properly maintained.

Copyright 2003, Systinet Corp. Page 14 of 16


Cleanup & Review Clean Up
Now that we've completed our example, remove the EJB from the
JBOSS_HOME/server/default/deploydirectory. If you are using a different
J2EE server use their recommended method. Finally, use the run.bat
undeploy_stockbean script in the tutorial's bin directory to undeploy the
StockBean Web service from the WASP runtime.

Review
In this part of the Web services tutorial we learned about two ways to
integrate Web services with J2EE. We introduced the basic wrapper Web
service and the transparent integration framework and explained the
situations in which each approach provides substantial advantages.

Copyright 2003, Systinet Corp. Page 15 of 16


> Developers Corner: Web Services & J2EE

Copyright and Disclaimer This document and the information contained herein are the property of
Systinet Corporation and shall not be reproduced or copied in whole or in
part without written permission of Systinet Corp.

Copyright © 2003 Systinet Corp. All Rights Reserved.

The information in this document is preliminary and is subject to change


without notice and should not be construed as a commitment by Systinet
Corporation.

SYSTINET CORPORATION SHALL HAVE NO LIABILITY FOR THIS


DOCUMENT, INCLUDING ANY LIABILITY FOR NEGLIGENCE. SYSTINET
CORPORATION MAKES NO WARRANTIES, EXPRESS, IMPLIED, STATUTORY,
OR IN ANY OTHER COMMUNICATION. SYSTINET CORPORATION
SPECIFICALLY DISCLAIMS ANY WARRANTY OF MERCHANTABILITY OR
SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
AND NON-INFRINGEMENT.

Systinet, WASP, "The Web Services Infrastructure Company" and "Web


Services That Work" are trademarks of Systinet Corp.

Java and all Java-based marks are trademarks or registered trademarks of


Sun Microsystems, Inc. in the U.S. and other countries.

Microsoft, Windows and Windows NT and the Windows logo are trademarks
or registered trademarks of Microsoft Corporation in the United States and
other countries.

UNIX is a registered trademark of The Open Group in the United States and
other countries.

Other company, product, and service names mentioned in these


documents may be trademarks or service marks of others.

Systinet Corp.
Five Cambridge Center, 8th Floor
Cambridge, MA 02142
Phone: 1.617.868.2224
www.systinet.com

Copyright 2003, Systinet Corp. Page 16 of 16

Вам также может понравиться