Creating a WebLogic Web Service: A Simple Example
The following sections describe how to create a simple WebLogic Web Service:
- Overview of the Web Service Example
- Building and Running the Trader WebLogic Web Service Example
- Anatomy of the Example
Overview of the Web Service Example
This example describes the start-to-finish process of implementing, assembling, and deploying the WebLogic Web Service provided as a product example in the directory WL_HOME/samples/server/examples/src/examples/webservices/complex/statelessSession, where WL_HOME refers to the main WebLogic Platform directory, such as d:\beahome\weblogic81.
The example shows how to create a WebLogic Web Service based on a stateless session EJB. The example uses the Trader EJB, one of the EJB 2.0 examples located in the WL_HOME/samples/server/examples/src/examples/ejb20/basic/statelessSession directory.
The Trader EJB defines two methods, buy() and sell(), that take as input a String stock symbol and an int number of shares to buy or sell. Both methods return a non-built-in data type called TradeResult.
When the Trader EJB is converted into a Web Service, the two methods become public operations defined in the WSDL of the Web Service. The Client.java application uses a JAX-RPC style client API to create SOAP messages that invoke the operations.
Building and Running the Trader WebLogic Web Service Example
The procedure below describes how to build and run the WL_HOME/samples/server/examples/src/examples/webservices/complex/statelessSession example, using the build.xml Ant build file in the example directory to perform all the main steps, such as compiling the EJB Java source code into class files, executing the servicegen WebLogic Web Service Ant task, and deploying the Web Service to WebLogic Server. The section Anatomy of the Example describes the main components (such as the stateless session EJB and the non-built-in data type) that make up the example.
Note: It is assumed in this section that you have started the examples WebLogic Server domain that is installed by default with WebLogic Server. The domain directory of the examples server is WL_HOME\samples\domains\examples.
To build and run the sample Trader WebLogic Web Service:
- Open a command window.
- Set up your environment.
On Windows NT, execute the setExamplesEnv.cmd command, located in the directory WL_HOME\samples\domains\examples, where WL_HOME is the main directory of your WebLogic Platform installation, such as d:\beahome\weblogic81.
On UNIX, execute the setEnv.sh command, located in the directory WL_HOME/samples/domains/examples, where WL_HOME is the main directory of your WebLogic Platform installation, such as /beahome/weblogic81.
- Change to the WL_HOME\samples\server\examples\src\examples\webservices\complex\statelessSession directory.
- Assemble and compile the example by executing the Java ant utility at the command line:
prompt> antThe ant utility uses the build.xml build script to perform the following tasks:
- Create an EJB JAR file from the EJB *.java files.
- Execute the servicegen Ant task which automatically generates the serialization class for the TradeResult non-built-in data type, creates the web-services.xml file, and packages all these components into a deployable EAR file.
- Deploy the EAR file on WebLogic Server.
- Execute the clientgen Ant task to create a local client JAR file that contains all the needed classes and interfaces to invoke the Web Service.
- Compile the Client.java client application used to invoke the Web Service.
- In your development shell, run the Client Java application using the following command:
prompt> ant runIf the example runs successfully, you should see the following output in both the window from which you ran the client application and the WebLogic Server console window:
[java] Buying 100 shares of BEAS.
[java] Result traded 100 shares of BEAS
[java] Buying 200 shares of MSFT.
[java] Result traded 200 shares of MSFT
[java] Buying 300 shares of AMZN.
[java] Result traded 300 shares of AMZN
[java] Buying 400 shares of HWP.
[java] Result traded 400 shares of HWP
[java] Selling 100 shares of BEAS.
[java] Result traded 100 shares of BEAS
[java] Selling 200 shares of MSFT.
[java] Result traded 200 shares of MSFT
[java] Selling 300 shares of AMZN.
[java] Result traded 300 shares of AMZN
[java] Selling 400 shares of HWP.
[java] Result traded 400 shares of HWP- Optionally view the Web Service Home Page by entering the following URL in your browser:
http://localhost:port/webservice/TraderServicewhere
- localhost refers to the machine on which WebLogic Server is running.
- port refers to port on which WebLogic Server is listening.
From the Web Service Home Page you can view the generated WSDL, and test the Web service to make sure it is working correctly.
Anatomy of the Example
This section describes the following main components of the example you built and ran in Building and Running the Trader WebLogic Web Service Example:
- The EJB Java Interfaces and Implementation Class
- The Non-Built-In Data Type TraderResult
- The EJB Deployment Descriptors
- The servicegen Ant Task That Assembles the Web Service
- The Client Application to Invoke The Web Service
The EJB Java Interfaces and Implementation Class
The Web Service example is based on a stateless session EJB. This Trader EJB defines two methods, buy() and sell(), that take as input a String stock symbol and an int number of shares to buy or sell. Both methods return a non-built-in data type called TraderResult.
The following Java interfaces and implementation class define the Trader EJB:
- Remote Interface (Trader.java)
- Session Bean Implementation Class (TraderBean.java)
- Home Interface (TraderHome.java)
Remote Interface (Trader.java)
package examples.webservices.complex.statelessSession;import java.rmi.RemoteException;
import javax.ejb.EJBObject;/**
* The methods in this interface are the public face of TraderBean.
* The signatures of the methods are identical to those of the EJBean, except
* that these methods throw a java.rmi.RemoteException.
* Note that the EJBean does not implement this interface. The corresponding
* code-generated EJBObject, TraderBeanE, implements this interface and
* delegates to the bean.
*
* @author Copyright (c) 1999-2003 by BEA Systems, Inc. All Rights Reserved.
*/
public interface Trader extends EJBObject {/** * Buys shares of a stock. * * @param stockSymbol String Stock symbol * @param shares int Number of shares to buy * @return TradeResult Trade Result * @exception RemoteException if there is * a communications or systems failure */ public TradeResult buy (String stockSymbol, int shares) throws RemoteException;/** * Sells shares of a stock. * * @param stockSymbol String Stock symbol * @param shares int Number of shares to sell * @return TradeResult Trade Result * @exception RemoteException if there is * a communications or systems failure */ public TradeResult sell (String stockSymbol, int shares) throws RemoteException;
}
Session Bean Implementation Class (TraderBean.java)
package examples.webservices.complex.statelessSession;import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.InitialContext;
import javax.naming.NamingException;/**
* TraderBean is a stateless Session Bean. This bean illustrates:
* <ul>
* <li> No persistence of state between calls to the Session Bean
* <li> Looking up values from the Environment
* </ul>
*
* @author Copyright (c) 1999-2003 by BEA Systems, Inc. All Rights Reserved.
*/
public class TraderBean implements SessionBean {private static final boolean VERBOSE = true; private SessionContext ctx; private int tradeLimit;// You might also consider using WebLogic's log service private void log(String s) { if (VERBOSE) System.out.println(s); }/** * This method is required by the EJB Specification, * but is not used by this example. * */ public void ejbActivate() { log("ejbActivate called"); }/** * This method is required by the EJB Specification, * but is not used by this example. * */ public void ejbRemove() { log("ejbRemove called"); }/** * This method is required by the EJB Specification, * but is not used by this example. * */ public void ejbPassivate() { log("ejbPassivate called"); }/** * Sets the session context. * * @param ctx SessionContext Context for session */ public void setSessionContext(SessionContext ctx) { log("setSessionContext called"); this.ctx = ctx; }/** * This method corresponds to the create method in the home interface * "TraderHome.java". * The parameter sets of the two methods are identical. When the client calls * <code>TraderHome.create()</code>, the container allocates an instance of * the EJBean and calls <code>ejbCreate()</code>. * * @exception javax.ejb.CreateException if there is * a communications or systems failure * @see examples.ejb11.basic.statelessSession.Trader */ public void ejbCreate () throws CreateException { log("ejbCreate called"); try { InitialContext ic = new InitialContext(); Integer tl = (Integer) ic.lookup("java:/comp/env/tradeLimit"); tradeLimit = tl.intValue(); } catch (NamingException ne) { throw new CreateException("Failed to find environment value "+ne); } }/** * Buys shares of a stock for a named customer. * * @param customerName String Customer name * @param stockSymbol String Stock symbol * @param shares int Number of shares to buy * @return TradeResult Trade Result * if there is an error while buying the shares */ public TradeResult buy(String stockSymbol, int shares) { if (shares > tradeLimit) { log("Attempt to buy "+shares+" is greater than limit of "+tradeLimit); shares = tradeLimit; } log("Buying "+shares+" shares of "+stockSymbol); return new TradeResult(shares, stockSymbol); }/** * Sells shares of a stock for a named customer. * * @param customerName String Customer name * @param stockSymbol String Stock symbol * @param shares int Number of shares to buy * @return TradeResult Trade Result * if there is an error while selling the shares */ public TradeResult sell(String stockSymbol, int shares) { if (shares > tradeLimit) { log("Attempt to sell "+shares+" is greater than limit of "+tradeLimit); shares = tradeLimit; } log("Selling "+shares+" shares of "+stockSymbol); return new TradeResult(shares, stockSymbol); }
}
Home Interface (TraderHome.java)
package examples.webservices.complex.statelessSession;import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;/**
* This interface is the home interface for the TraderBean.java,
* which in WebLogic is implemented by the code-generated container
* class TraderBeanC. A home interface may support one or more create
* methods, which must correspond to methods named "ejbCreate" in the EJBean.
*
* @author Copyright (c) 1998-2003 by BEA Systems, Inc. All Rights Reserved.
*/
public interface TraderHome extends EJBHome { /** * This method corresponds to the ejbCreate method in the bean * "TraderBean.java". * The parameter sets of the two methods are identical. When the client calls * <code>TraderHome.create()</code>, the container * allocates an instance of the EJBean and calls <code>ejbCreate()</code>. * * @return Trader * @exception RemoteException if there is * a communications or systems failure * @exception CreateException * if there is a problem creating the bean * @see examples.ejb11.basic.statelessSession.TraderBean */ Trader create() throws CreateException, RemoteException;
}
The Non-Built-In Data Type TraderResult
The two methods of the EJB return a non-built-in data type called TraderResult. The following Java code describes this data type:
package examples.webservices.complex.statelessSession;import java.io.Serializable;/**
* This class reflects the results of a buy/sell transaction.
*
* @author Copyright (c) 1999-2003 by BEA Systems, Inc. All Rights Reserved.
*/
public final class TradeResult implements Serializable {// Number of shares really bought or sold. private int numberTraded;private String stockSymbol;public TradeResult() {}public TradeResult(int nt, String ss) { numberTraded = nt; stockSymbol = ss; }public int getNumberTraded() { return numberTraded; }public void setNumberTraded(int numberTraded) { this.numberTraded = numberTraded; }public String getStockSymbol() { return stockSymbol; }public void setStockSymbol(String stockSymbol) { this.stockSymbol = stockSymbol; }
}
The EJB Deployment Descriptors
The Trader EJB defines the following two deployment descriptor files to describe itself:
ejb-jar.xml
<?xml version="1.0"?><!DOCTYPE ejb-jar PUBLIC
'-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN'
'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'><ejb-jar> <enterprise-beans> <session> <ejb-name>TraderService</ejb-name> <home>examples.webservices.complex.statelessSession.TraderHome</home> <remote>examples.webservices.complex.statelessSession.Trader</remote> <ejb-class>examples.webservices.complex.statelessSession.TraderBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <env-entry> <env-entry-name>WEBL</env-entry-name> <env-entry-type>java.lang.Double </env-entry-type> <env-entry-value>10.0</env-entry-value> </env-entry> <env-entry> <env-entry-name>INTL</env-entry-name> <env-entry-type>java.lang.Double </env-entry-type> <env-entry-value>15.0</env-entry-value> </env-entry> <env-entry> <env-entry-name>tradeLimit</env-entry-name> <env-entry-type>java.lang.Integer </env-entry-type> <env-entry-value>500</env-entry-value> </env-entry> </session> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>TraderService</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor>
</ejb-jar>
weblogic-ejb-jar.xml
<?xml version="1.0"?><!DOCTYPE weblogic-ejb-jar PUBLIC
'-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN'
'http://www.bea.com/servers/wls700/dtd/weblogic700-ejb-jar.dtd'><weblogic-ejb-jar> <weblogic-enterprise-bean> <ejb-name>TraderService</ejb-name> <jndi-name>webservices-complex-statelessession</jndi-name> </weblogic-enterprise-bean>
</weblogic-ejb-jar>
The servicegen Ant Task That Assembles the Web Service
The Ant build file, build.xml,contains a call to the servicegen Ant task that introspects the trader.jar EJB file and:
- Generates all data type components (such as the serialization class).
- Creates the web-services.xml deployment descriptor file.
- Packages all components into a deployable trader.ear file.
The following snippet from the sample build.xml file contains instructions that will build the EAR file into a temporary build_dir directory:
<target name="build" > <delete dir="build_dir" /> <mkdir dir="build_dir" /> <copy todir="build_dir" file="trader.jar"/> <servicegen destEar="build_dir/trader.ear" warName="trader.war" contextURI="webservice"> <service ejbJar="build_dir/trader.jar" targetNamespace="http://www.bea.com/examples/Trader" serviceName="TraderService" serviceURI="/TraderService" generateTypes="True" expandMethods="True" > </service> </servicegen> </target>
The Client Application to Invoke The Web Service
The following Java client application shows how to use the JAX-RPC API to invoke the buy and sell operations of the deployed Trader Web Service:
package examples.webservices.complex.statelessSession;/**
* This class illustrates how to use the JAX-RPC API to invoke the TraderService* Web service to perform the following tasks:
* <ul>
* <li> Buy 100 shares of some stocks
* <li> Sell 100 shares of some stocks
* </ul>
*
* The TraderService Web service is implemented using the Trader
* stateless session EJB.
* * @author Copyright (c) 1998-2003 by BEA Systems, Inc. All Rights Reserved.
*/public class Client {public static void main(String[] args) throws Exception {// Setup the global JAXM message factory System.setProperty("javax.xml.soap.MessageFactory", "weblogic.webservice.core.soap.MessageFactoryImpl"); // Setup the global JAX-RPC service factory System.setProperty( "javax.xml.rpc.ServiceFactory", "weblogic.webservice.core.rpc.ServiceFactoryImpl");// Parse the argument list Client client = new Client(); String wsdl = (args.length > 0? args[0] : null); client.example(wsdl); }public void example(String wsdlURI) throws Exception {TraderServicePort trader = null; if (wsdlURI == null) { trader = new TraderService_Impl().getTraderServicePort(); } else { trader = new TraderService_Impl(wsdlURI).getTraderServicePort(); } String [] stocks = {"BEAS", "MSFT", "AMZN", "HWP" };// execute some buys for (int i=0; i<stocks.length; i++) { int shares = (i+1) * 100; log("Buying "+shares+" shares of "+stocks[i]+"."); TradeResult result = trader.buy(stocks[i], shares); log("Result traded "+result.getNumberTraded() +" shares of "+result.getStockSymbol()); }// execute some sells for (int i=0; i<stocks.length; i++) { int shares = (i+1) * 100; log("Selling "+shares+" shares of "+stocks[i]+"."); TradeResult result = trader.sell(stocks[i], shares); log("Result traded "+result.getNumberTraded() +" shares of "+result.getStockSymbol());}}private static void log(String s) { System.out.println(s); }}