The process of creating a Web Service from a Stateless Session Bean is pretty straightforward. Implement the bean and create its JAR file. Listing 30.7 contains the code for the DoctorInfoBean. Running the EJBGen tool against it will create the EJB support classes and the EJB JAR file.
Place the JAR file in a staging directory and create an Ant script that contains the servicegen task, as shown in Listing 30.8. Here you can see that the EJB JAR file is listed.
<project name="buildWebservice" default="ear"> <target name="ear"> <servicegen destEar="DoctorInfoWS.ear" contextURI="MedicalServices" > <classpath> <pathelement path="${java.class.path}" /> <pathelement path="." /> </classpath> <service ejbJar="DoctorInfo.jar" targetNamespace="http://www.getgamma.com/webservices/ejb" serviceName="DoctorInfoWS" serviceURI="/DoctorInfoWS" generateTypes="True" expandMethods="True" style="rpc" > <client packageName="com.wls8unleashed.webservices.ejb" /> </service> </servicegen> </target> </project> |
When you run the script file, the DoctorInfoWS.ear will be created. Deploy this file and the embedded DoctorInfo EJB will be deployed as well. The Web Service home page is located at http://host:port/MedicalServices/DoctorInfoWS.
In the TestWS Web Service, getGreeting accepts a String as input and returns a String as output. String is a commonly used data type and is considered a built-in data type. However, Web Services deployed in the real world have more complex data type requirements. WebLogic Server defines three types of Web Service operation parameters:
Built-in data types are automatically converted between Java and XML by WebLogic Server. This includes the following Java data types: int, short, long, float, double, byte, boolean, char, java.lang.Integer, java.lang.Short, java.lang.Long, java.lang.Float, java.lang.Double, java.lang.Byte, java.lang.Boolean, java.lang.Character, java.lang.String, java.math.BigInteger, java.math.BigDecimal, java.lang.String, java.util.Calendar, java.util.Date, and byte[].
Supported data types that are not built in require special components (such as a serializer class) to be used as Web Service parameters. However, the servicegen and autotype Ant tasks can generate these components automatically. This includes the following Java data types: an array of any built-in Java data type, JavaBean whose properties are any built-in Java data type, java.util.List, java.util.ArrayList, java.util.LinkedList, java.util.Vector, and java.lang.Object (in some cases).
Not supported and not built-in data types require special components to be used as Web Service parameters. These components must be generated manually.
Let's create a Web Service that returns six numbers suitable for playing lotto, except that the same number can show up more than once. Our Web Service returns these numbers as a vector, as shown in Listing 30.9.
import java.util.Date; import java.util.Vector; public class LottoWebService { public LottoWebService () { } public Vector getLottoNumbers() { Vector vec = new Vector(); for(int i=0; i<6; i++) { Integer lottoNumber = new Integer((int)(Math.random()*60)+1); vec.add(lottoNumber); } return vec; } } |
If we run the build.xml that contains the Ant servicegen task, we will generate a new testWebService.ear file. Just as before, there will be a TestWS_client.jar in the web-services.war within the EAR file. There will now be two extra classes: VectorHolder and VectorCodec. These files will be used to convert between the Java data type Vector and XML.
We can now create a static Java client that calls the getLottoNumbers operation as shown in Listing 30.10. The JAX-RPC runtime handles all the code required to convert between the Vector data type and XML. In this case, it has converted the Vector to an array of Objects.
Creating a Web Service with a user-defined data type requires the following information:
A Java class to represent the user-defined data type
An XML schema to describe the Java class
A serialization class to convert between the Java class and XML
The data mapping information for the Java class
In some cases, this information can be automatically generated with the autotype Ant task. For example, suppose that we want to return a variable of type DoctorInfo from a Web Service operation, as shown in Listing 30.11. This class must implement Serializable and must contain a no-argument constructor.
package com.wls8unleashed.webservices.autotype; import java.io.Serializable; public class DoctorInfo implements Serializable { public int id; public String firstName; public String lastName; public float officeVisitCharge; public DoctorInfo() { } public DoctorInfo(int id, String firstName, String lastName, float officeVisitCharge) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.officeVisitCharge = officeVisitCharge; } } |
To generate the required information, create an Ant build script that calls the autotype Ant task. An example of this is shown in Listing 30.12.
<project name="createAutotype" default="createautotype"> <target name="createautotype"> <autotype javatypes="com.wls8unleashed.webservices.autotype.DoctorInfo" targetNamespace="http://www.getgamma.com/autotyper" packageName="com.wls8unleashed.webservices.autotype" destDir="d: empautotype" > <classpath> <pathelement path="${java.class.path}" /> <pathelement path="." /> </classpath> </autotype> </target> </project> |
This script instructs autotype to create the data typing components for the DoctorInfo class in the com.wls8unleashed.webservices.autotype package. It will place these components in the d: empautotype directory. The following components will be generated:
A XML schema and mapping file called types.xml that describes the DoctorInfo class and how to map from the Java class to XML
The files DoctorInfoHolder.java and DoctorInfoCodec.java, which are used as serialization classes
For a list of supported data types and other information about autotype, please visit http://e-docs.bea.com/wls/docs81/webserv/assemble.html#1060696.
We're now going to create a Web Service based on the Java class file in Listing 30.13. In previous releases of WebLogic Server, we used the servicegen Ant task to create the entire Web Service, including the EAR file, its internal WAR file, and the Web Service deployment descriptor, web-services.xml. Now that we have a user-defined data type, we have to perform some of this by hand.
package com.wls8unleashed.webservices.autotype; import java.util.Hashtable; public class DoctorWebService { Hashtable doctorHash = null; public DoctorWebService() { doctorHash = new Hashtable(); DoctorInfo di = new DoctorInfo(1, "Troy", "Chin", 89.25f); doctorHash.put(new Integer(1), di); di = new DoctorInfo(2, "Rina", "Caprario", 95.72f); doctorHash.put(new Integer(2), di); } public DoctorInfo getDoctorInfo(int doctorID) { Object key = new Integer(doctorID); DoctorInfo di = (DoctorInfo)doctorHash.get(key); return di; } } |
We need to generate a web-services.xml deployment descriptor for our Web Service. WebLogic comes with an Ant task called source2wsdd that can create a web-services.xml file from a Java class. Because we're using a Java class back end for our Web Service, we can use source2wsdd as shown in Listing 30.14.
<project name="createWSDD" default="WSDD"> <target name="WSDD"> <source2wsdd javaSource="DoctorWebService.java" typesInfo="d: empautotype ypes.xml" ddFile="web-services.xml" serviceURI="/DoctorAutoTypeService"> <classpath> <pathelement path="${java.class.path}" /> <pathelement path="." /> </classpath> </source2wsdd> </target> </project> |
Listing 30.14 uses the XML schema information for DoctorInfo that's contained in types.xml, which was generated by autotype. When this script is executed, it will create a web-services.xml file that contains our XML schema information.
More information about source2wsdd can be found at http://e-docs.bea.com/wls/docs81/webserv/assemble.html#1056639.
At this point, you have all the elements of the Web Service:
Deployment descriptor— web-service.xml, which was created with source2wsdd
User-defined data type components— XML schema (now in web-services.xml) and codec classes created with autotype
Java backend component— Some Java component that implements the business logic for the Web Service
You can assemble these by hand into a deployable EAR file, or you can use the wspackage Ant task. A build script that uses wspackage is shown in Listing 30.15.
<project name="createWSDD" default="WSDD"> <target name="WSDD"> <wspackage output="DoctorWebService.ear" contextURI="DoctorWebService" codecDir="d: empautotype" webAppClasses="com.wls8unleashed.webservices.autotype.DoctorWebService" ddFile="web-services.xml"> <classpath> <pathelement path="${java.class.path}" /> <pathelement path="." /> </classpath> </wspackage> </target> </project> |
In Listing 30.15, we specify the location of web-services.xml, the Java backend class for the Web Service, where the codecs (serialization classes) are stored, and the contextURI of the Web Service. After this script has been executed, you'll have a DoctorWebService.ear file that can then be deployed. After the EAR file has been deployed, the Web Service home page will be located at http://host:port/DoctorWebService/DoctorAutoTypeService.
TIP
We've used Ant tasks to automate generation of the web-services.xml file, XML schema and data mapping, and serialization classes. If you need to perform these tasks manually, please visit the following URL for more information: http://e-docs.bea.com/wls/docs81/webserv/customdata.html.