Chapter 5, "Connectivity with XML Web Services, Part 1," demonstrated how to create an XML Web service using both the Microsoft .NET Framework and GLUE for Java. For each of the Web services created in Chapter 5, you saw a client written in both .NET and Java, looked at how proxy files were generated, and saw some of the compensations that had to be made in order to return data in the correct format and type.
We'll now look at some common challenges that affect interoperability with Web services, especially in a production environment. As we did with the .NET Remoting samples in Chapter 4, "Connectivity with .NET Remoting," we'll look at the requirements of hosting these components using different containers ”for example, Enterprise JavaBeans (EJBs) ”and some of the authentication and exception issues that can arise. To conclude this topic, I'll introduce recommendations for designing solutions that require interoperability using Web services.
For a look at a more realistic Java environment, we'll use the same EJB deployment (a stateless session and bean-managed entity) that was used in Chapter 4 ” only this time, we'll expose the components as Web services. Figure 6.1 illustrates this.
The EJBs that we'll use contain both a stateless Session Bean and an Entity Bean in order to simulate the "sell stocks" method. All incoming requests are written to the console for demonstration purposes. For further details on how the EJBs work in the sample, refer to the ".NET Client to EJB, Hosted by J2EE Application Server" section in Chapter 4.
The sample code to show this is located in the C:\Interoperability\Samples\Point\WebServices\JavaEJB\StockServiceEJB subdirectory of your sample code installation. Build the source in this directory by running ant package in this directory at a command prompt. This will produce a SampleEJB.jar file in the Deploy subdirectory. Deploy this Java Archive (JAR) file to the Java 2 Enterprise Edition (J2EE) application server that you're using. If you're using JBoss 3.0.7, simply run ant deploy , which will copy the SampleEJB.jar file to the server\default\deploy directory and the required GLUE libraries to the server\default\lib directory of your JBoss installation.
In Chapter 4, to expose the EJBs using .NET Remoting, we ran a third- party tool to create a wrapper , or listener , that would accept incoming .NET Remoting calls and perform the necessary calls in order to invoke the EJBs. Using the GLUE toolkit, we now perform a very similar operation. We create a Web Archive (WAR) file that holds the configuration information for our EJBs, and this exposes the required Web services interfaces to the client.
To create this WAR file, navigate to the C:\Interoperability\Samples\Point\WebServices\JavaEJB directory, and run the following command:
The newapp command-line tool in GLUE is used to create a new application structure (a set of directories) that can be deployed to a J2EE application server. When this command is run, a directory named GlueStockService is created that contains a single subdirectory named WEB-INF. Within this subdirectory are additional subdirectories (classes, lib, maps, security, and services), some of which will look familiar to anyone who has seen the structure of a WAR file.
After running this command, navigate to the WEB-INF\services directory within the GlueStockService directory. In this directory, using an editor of your choice, create a new file named StockService.xml. This is the service deployment descriptor that will be used to configure which EJBs are mapped to the service.
Create the following XML structure within this file. (Instead of typing this code, you can copy it from the C:\Interoperability\Samples\Point\WebServices\JavaEJB\Templates directory.)
<?xml version="1.0"?> <service> <constructor> <class> electric.service.ejb.StatelessSessionBeanService </class> <args> <contextFactory> org.jnp.interfaces.NamingContextFactory </contextFactory> <url>localhost:1099</url> <jndiName>StockSession</jndiName> <homeInterfaceName> com.microsoft.samples.ejb.StockSessionHome </homeInterfaceName> </args> </constructor> </service>
This deployment descriptor has five key elements that perform the mapping between the EJBs and the Web services that will be exposed by GLUE:
class Determines which class from the GLUE toolkit should be used to expose the EJB. The electric.service.ejb.StatelessSessionBeanService element is used for Session Beans and shouldn't need to be changed unless the documentation suggests otherwise .
contextFactory and url Both are specific to the J2EE application server that you're using. Recall how in the .NET Remoting sample in Chapter 4, we also had to specify the context factory and URL. The settings shown in the previous XML document are valid for a JBoss 3.0.7 implementation, although the GLUE documentation offers default settings for J2EE application servers from Sun Microsystems (ONE), BEA (WebLogic), and IBM (WebSphere).
jndiName The Java Naming and Directory Interface (JNDI) name of the exposed Session Bean.
homeInterfaceName The name of the home interface for the Session Bean.
If you're using an application server other than JBoss 3.0.7, supply the context factory and URL settings suitable for your application server and save the file. (Table 4-1 in Chapter 4 lists some other J2EE application servers.)
To complete the deployment, you simply package the directory structure into a WAR file and deploy it to the J2EE application server. To do this, navigate to the C:\Interoperability\Samples\Point\WebServices\JavaEJB\GlueStockService directory and run the following command:
jar cvf GlueStockService.war .\
This will create a WAR file in the current directory. Deploy this WAR file to publish the EJBs, and expose the interfaces using Web services. To deploy to JBoss 3.0.7, you can use the deploy-warfile target with the Ant build script in the JavaEJB\StockServiceEJB directory. This will copy the WAR file to the server\default\deploy directory of your JBoss installation. For other application servers, you should follow the deployment instructions that were used for deploying the previous JAR file.
To test that the deployment was successful, the J2EE application server must be started (or restarted if it was already running). You can now navigate to the URL of the exposed Web Services Description Language (WSDL) file: http://localhost:8080/GlueStockService/services/StockService.wsdl . If the deployment was successful, the generated WSDL for the StockSession Session Bean will be displayed.
The consumption of the exposed Session Bean with a .NET client is straightforward and similar to the consumption of a standalone Java Web service. The client sample code, which can be found in the C:\Interoperability\Samples\Point\WebServices\JavaEJB\dotNETClient directory, uses a proxy class that was generated with the WSDL.EXE tool using the exposed WSDL. The client simply creates a new instance of the StockService (which is the exposed Session Bean) and calls the sellStocks method:
StockService ss = new StockService(); Console.WriteLine(ss.sellStocks("CONT", 100));
To test the .NET client, compile and run using the run target with the provided NAnt script. If the simulated sale was successful, the following message is displayed in the console window of the J2EE application server:
Incoming request to sell 100 common shares of Contoso (CONT)
As with the EJB sample shown in Chapter 4, the J2EE console also displays how the bean is activated and loaded.
To test consuming the EJB by using Web services from the Java platform, use the sample code in C:\Interoperability\Samples\Point\WebServices\JavaEJB\JavaClient. As with the .NET code, this sample relies on a preconfigured proxy class that was generated using the wsdl2java tool, which we covered in Chapter 5. The client binds to the Web service and calls the sellStocks method of the EJB. This is done with a StockSessionHelper , a class that's automatically created with the wsdl2java tool. This class has a private field for the target URL and a bind method which loads all the required registry classes from the GLUE libraries.
IStockSession ss = StockSessionHelper.bind(); System.out.println(ss.sellStocks("FTHC",200));
Execute the Java sample by using the run target with the provided Ant script. Again, if the simulated sale was successful, this is displayed in the console window of the J2EE application server:
Incoming request to sell 200 common shares of Fourth Coffee (FTHC)
In this section, we have looked at a process in which a collection of EJBs (in this case, an Entity Bean fronted by a Session Bean) can be exposed by using Web services. The result, especially in the context of interoperability, is that we can use this process to consume any exposed EJB by using any client that supports Web services.
This technique is obviously of great advantage to clients built on the .NET Framework because it allows EJB methods to be called from .NET without relying on any custom client implementations or connectors. In addition, this technique can offer a layer of abstraction and simplicity for Java clients . The proxy class that's generated from the WSDL provides for a clean and formalized way of calling EJBs from a Java client without having to rely on any JNDI lookups, the creation of a home interface, and so on.
In essence, exposing EJBs by using Web services moves a Java-centric technology to a more loosely coupled model, which has a significant impact on and benefits for both Java and non-Java consumers.