To understand how architecture adapters facilitate better and easier programmer practices, you will look at a slightly more complex Web Service scenario than the previous chapter. You will also fully leverage the facilities in Apache Axis so that you do not have to manually build the architecture adapters. In fact, from here on out, Apache Axis tools allow you to be entirely SOAP ignorant. Instead, you access Web Services from Java method calls using architecture adapters generated from the WSDL interface of a service, as illustrated in Figure 4-4, a sequence diagram based on Figure 4-3.
In Figure 4-4, I took liberties to place the expected Java method call, to the conversion to SOAP, and, finally, to a third, unknown architecture ”the mysterious architecture B.
To illustrate the facilities of Apache Axis for building architecture adapters, you use a set of classes that make up the beginnings of a customer database. Figure 4-5 shows the diagram for the primary classes involved in making up a collection of customers. As you can see, a single class, CustomerCollectionImpl , contains the customer object query methods . Customer data comes from a CustomerImpl class containing basic information, such as their address, and more advanced information, such their primary credit card and Internet address information, which is separated into the CustomerInformationImpl .
Several important design principles within these classes make the transition to Web Services easier:
The customer data classes adhere to the JavaBeans contracts.
There is no operation overloading.
Methods return arrays where multiple values are possible.
The reasons to apply these principles are to create predictability and avoid exploitation of the object-oriented paradigm. In turn , these things are important to help ease the transition from the rich object-oriented paradigm of Java to the flatter component model of Web Services. Although it is possible to build an architecture adapter that makes the transition between architectures possible, the more you exploit one architecture, the more difficult the adapter will be to write. As tools become more advanced, the level of support for conversion between architectures will grow and the complexity of the classes can increase.
As far as the code goes, the most interesting part of the code is the implementation of the CustomerCollectionImpl class. In Figure 4-5, you will notice that there is no explicit containment of CustomerImpl classes from the CustomerCollectionImpl class. This technique is a reflection of using Java Data Objects (JDO) for the persistence mechanism underneath your classes. The CustomerCollectionImpl class uses a series of queries against a CustomerImpl extent rather than explicitly loading the collection and sorting through the objects each time a client requests a single customer.
In terms of architecture adapter responsibilities, Apache Axis uses an inbound/outbound division of labor. One adapter set takes care of Web Services to Java conversions (or to another language), and another adapter takes care of the Java to Web Service conversion. The former takes SOAP messages and converts them to Java method invocations on proper object instances. The latter takes Java method invocations, converts them to SOAP messages, and routes them appropriately.
Apache Axis is, essentially , an implementation of the Architecture Adapter pattern taken to an extreme. Using tools, you can generate an architecture adapter that allows you to call methods in Java and convert them to a Web Service call using SOAP; this is the A architecture adapter from the pattern structure. This SOAP message is received by an Apache Axis implementation running within a Web application server that parses the SOAP message and makes the appropriate method call to the target service. The receiving end is the B architecture adapter from the pattern structure.
These processes form the core of the architecture adapter between SOAP and the target service, or Web Services and the target service, depending on your perspective. Rather than creating a custom adapter for each target service, Apache Axis uses a single generic adapter that leverages plug-in message processing chains and message dispatchers. The entire design is online at the Apache Axis homepage. You are going to view the design from the perspective of a user of Apache Axis.
You deployed a small Web Service in the previous chapter, but it did not have the complexities of the customer collection that you will deploy in this chapter. Recall that the Web Service Deployment Descriptor (WSDD) tells Axis the details about a particular service so that Axis can route messages to the service implementation. This process sets up a generic architecture adapter with specific information about your service. The generic architecture adapter in Axis requires you to give the following:
The service name (call the service CustomerCollection )
The provider (use the Axis built-in Java RPC provider)
The class name of the target service implementation ( com.serviceroundry.books. webservices .entities.CustomerCollectionImpl )
The methods to turn into service targets (expose all methods on the CustomerCollectionImpl class by using *)
Complex data types necessary for a user to access the exposed service
The only significant difference from the previous chapter is the addition of tags to identify the complex data types. Listing 4-1 illustrates a beanMapping tag to identify the AddressImpl JavaBean as a complex data type. Recall from Figure 4-5 that the CustomerImpl class contains a reference to a customer's address. Axis requires the bean mapping tag to have additional data for the Web Service architecture that does not exist in the architecture supported by Java. You must add information about the namespace that the address resides in ”which is a similar concept to packages ”but not enough to allow the engine to use the package name as is. You also must tell the deployment tool the language that the complex data type uses ”in this case, Java. Finally, you could give the Axis engine information about special serializers (Java classes adhering to an Axis class interface) that you write to help move a bean or class from one architecture to the other. In this case, you use the basic JavaBean patterns, and there is not special handling for your classes, so a serializer is unnecessary. In fact, you will not use serializers throughout this entire book.
<service name="CustomerCollection" provider="java:RPC"> // ... <beanMapping qname="myNS:Address" xmlns:myNS="urn:CustomerCollection" languageSpecificType= "java:com.servicefoundry.books.webservices.entities.AddressImpl"/> // ... </service>
Using the Apache Axis administration tool (as shown in the previous chapter), submit the file to Apache Axis for proper configuring of the Axis server-side engine, otherwise known as an architecture adapter.
Without architecture adapters, consuming Web Services would be a difficult and tedious job. Most likely, you would end up writing the architecture adapters yourself as you learned the patterns that your language uses to build SOAP messages and submit them to the Web Service. Fortunately, you do not have to build your own. WSDL's Extensible Markup Language (XML)-based representation and strict definition allows tool vendors to write language-specific tools that build the architecture adapter. The tools convert WSDL into interface and code to turn the language-specific request into a SOAP request to a specific Web Service.
Apache Axis comes with WSDL2Java, a tool that converts a WSDL to a Java interface and architecture adapter implementation; a programmer's job in consuming Web Services just got a lot easier. Instead of constructing SOAP messages, covered in the previous chapter, a consumer manipulates Java classes and objects directly, which then interact with the Web Service environment. Listing 4-2 shows how to create a customer object from a Java program that accesses the Web Service deployed in the previous section. Access occurs through an architecture adapter built using WSDL2Java.
CustomerCollectionImplService service = new CustomerCollectionImplServiceLocator(); CustomerCollectionImpl port = service.getCustomerCollection(); Address ai = new Address(); ai.setAddressLine1("Web Service Line 1"); ai.setAddressLine2("Web Service Line 2"); ai.setCity("Highlands Ranch"); ai.setState("CO"); ai.setZipCode("80129"); Customer ci = new Customer(); ci.setAddress(ai); ci.setFirstName("Paul (Web)"); ci.setLastName("Monday"); port.addCustomer(ci);
Out of the code, the only slightly abnormal calls are the first two lines of code. These lines retrieve the customer collection service offered previously in this chapter. Listing 4-2 is far easier than constructing a SOAP document and submitting it to the customer collection Web Service, and it is much more natural for a Java programmer to manage. In this case, I put the cart before the horse; I decided to illustrate how you use the architecture adapter before showing you how to build the architecture adapter.
Constructing the architecture adapter for a particular Web Service with Apache Axis is as simple as obtaining a WSDL representation of the Web Service and running a tool against the WSDL. It is important to realize that although your service implementation is in Java, the WSDL does not expose any syntax or features that are unique to Java; instead, the WSDL is a pure Web Service construct.
The complete WSDL for the CustomerCollectionImpl is too large to show in this chapter, but Figure 4-6 is a graphical depiction of the WSDL file contents at a high level of abstraction. In it, you should see that the customer collection interface, detailed in Figure 4-6, forms the Web Service itself with the customer data described as a series of data type definitions.
The data type definitions from the WSDL turn into JavaBeans for use in conjunction with the Web Service. Your client may construct the JavaBeans to pass as parameters to the customer collection Web Service, or the JavaBeans are data returned from method calls on the Web Service.
The WSDL file necessary to generate the architecture adapter gets generated when you access the Web Service with the ?wsdl parameter on the end of the Web Service's URL (http://localhost:8080/axis/services/CustomerCollection?wsdl). To have Axis generate the Java-side architecture adapter, run the Apache Axis WSDL2Java tool against the CustomerCollection.wsdl file. The output from the tool is a set of classes that you import into your application if you want to access the Web Service.
WSDL2Java creates several classes that act as the adapter between Java and the Web Service, as well as any classes that are required to interact with the Web Service, such as parameters and return types. The classes include the following:
CustomerCollectionImpl: An interface representing the port types on the CustomerCollection Web Service.
CustomerCollectionImplService: The service interface for a class factory responsible for creating the architecture adapter for the customer collection.
CustomerCollectionImplServiceLocator: The implementation of the service locator that builds an implementation of the customer collection using the location of the service identified in the WSDL as a default or the location identified as a parameter to the creation method.
CustomerCollectionSoapBindingStub: The CustomerCollectionSoapBindingStub is an architecture adapter that the service locator returns to the requesting client. This adapter generates SOAP messages based on the methods and data that are set using the methods in the interface CustomerCollectionImpl .
Address, Customer, CustomerInformation, CustomerKey, InternetAddress: These classes are JavaBeans that represent customer data types in the WSDL file. The CustomerCollectionImpl class serializes these to SOAP contents when the architecture adapter moves information from the client to Web Services.
Early in the chapter, you saw code that creates a new customer. Operations on individual JavaBeans, such as Address and Customer , have no effect on the actual values that the Web Service represents; only operations on the retrieved CustomerCollectionImpl object instance affect server-side data.