The Architecture Adapter pattern isolates complexity to the adapter and away from client and target service code. When implementing the Architecture Adapter pattern, you should follow a few general rules. Specific scenarios, such as Web Services to Java, drive more implementation details based on the architectural styles involved:
Establish a common pattern for traversals between architectures and build reusable adapters whenever possible: If you traverse between architectures once in a program, you will probably do it repeatedly. There are likely common serialization and de-serialization techniques for moving data into and out of the architectures. Encapsulate these techniques. Reusable adapters will also include a generic dispatcher or mapping table to select the proper target service and invocation method.
Architectures that use different programming paradigms are more difficult to adapt than similar programming
paradigms : Architecture adapters between object-oriented languages will usually be much easier to write than an architecture adapter between an object-oriented language and a procedural language. Although the architectural details may appear simple, leave enough time to address design and implementation complexities for the adapters.Plan for performance concerns: Serialization and de-serialization of data takes time. Be aware that the adapter route can never perform as well as code that is entirely native to an implementation. For example, calling a C function from Java to calculate the first five prime
numbers would bewasteful because of the adapter overhead. Calling a C function to locate the 10,679 th prime number would likely pay off in terms of performance.Architecture adapters should decrease the complexity within a component for accessing functionality in a different architecture: Using an architecture adapter in a component should allow client programmers to program in a single language with method calls that appear as if the programmer is simply calling another class or procedure. Isolating this complexity should make the primary code line easier to read and maintain.
Use prebuilt architecture adapters and platforms, such as Web Services, whenever possible: If you plan, there are few reasons to build your own architecture adapters. The Java Native Interface (JNI) and Web Services are two
excellent technologies for allowing Java to utilize other architectures. Theselayers can be difficult to get right, so try to reuse whenever possible.
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
Figure 4-4:
Java to Web Service sequence diagram
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
To
Figure 4-5:
Customer collection class diagram
Several important design principles within these classes make the transition to Web Services easier:
The customer data classes
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
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
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,
These processes form the
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)
The service
The provider (use the Axis built-in Java RPC provider)
The class name of the target service implementation (
com.serviceroundry.books.
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.
Listing 4-1: WSDD File for CustomerCollectionImpl
|
|
<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,
Without architecture adapters, consuming Web Services would be a difficult and
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
Listing 4-2: Customer Creation Through the Client-Side Architecture Adapter
|
|
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
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.
Figure 4-6:
WSDL high-level depiction of a customer collection
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.