What is SOAP?
SOAP is an XML-based communication protocol and encoding format for inter-application communication.
What is Axis?
Axis is essentially a SOAP engine -- a framework for constructing SOAP processors such as clients, servers, gateways, etc.
Publishing Web Services with Axis
1. JWS (Java Web Service) Files - Instant Deployment
copy the java file into your webapp directory, and rename it to " *.jws"
Important: JWS web services are intended for simple web services. You cannot use packages in the pages, and as the code is compiled at run time you can not find out about errors until after deployment.
2. Custom Deployment - Introducing WSDD
a. using the the Axis Web Service Deployment Descriptor (WSDD) define the service . generate kinds of * wsdd files
% java org.apache.axis.client.AdminClient deploy.wsdd
http://localhost:8080/axis/services/MyService "test me!"
Service Styles - RPC, Document, Wrapped, and Message
There are four "styles" of service in Axis. RPC services use the SOAP RPC conventions, and also the SOAP "section 5" encoding. Document services do not use any encoding (so in particular, you won't see multiref object serialization or SOAP-style arrays on the wire) but DO still do XML<->Java databinding. Wrapped services are just like document services, except that rather than binding the entire SOAP body into one big structure, they "unwrap" it into individual parameters. Message services receive and return arbitrary XML in the SOAP Envelope without any type mapping / data binding. If you want to work with the raw XML of the incoming and outgoing SOAP Envelopes, write a message service.Using WSDL with Axis
The Web Service Description Language is a specification authored by IBM and Microsoft, and supported by many other organizations. WSDL serves to describe Web Services in a structured way. A WSDL description of a service tells us, in a machine-understandable way, the interface to the service, the data types it uses, and where the service is located. Please see the spec (follow the link in the first sentence) for details about WSDL's format and options.
Axis supports WSDL in three ways:
- When you deploy a service in Axis, users may then access your service's URL with a standard web browser and by appending "?WSDL" to the end of the URL, they will obtain an automatically-generated WSDL document which describes your service.
- We provide a "WSDL2Java" tool which will build Java proxies and skeletons for services with WSDL descriptions.
- We provide a "Java2WSDL" tool which will build WSDL from Java classes.
WSDL2Java: Building stubs, skeletons, and data types from WSDL
Client-side bindings
You'll find the Axis WSDL-to-Java tool in "org.apache.axis.wsdl.WSDL2Java". The basic invocation form looks like this:
% java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL)
Server-side bindings
Just as a stub is the client side of a Web Service represented in Java, a skeleton is a Java framework for the server side. To make skeleton classes, you just specify the "--server-side --skeletonDeploy true" options to WSDL2Java. For instance, using the AddressBook.wsdl as we had above:
% java org.apache.axis.wsdl.WSDL2Java --server-side --skeletonDeploy true AddressBook.wsdl
Java2WSDL: Building WSDL from Java
The Java2WSDL and WSDL2Java emitters make it easy to develop a new web service. The following sections describe the steps in building a web service from a Java interface.
Step 1: Provide a Java interface or class
Write and compile a Java interface (or class) that describes the web service interface. Here is an example interface that describes a web services that can be used to set/query the price of widgets (samples/userguide/example6/WidgetPrice.java):
package samples.userguide.example6; /** * Interface describing a web service to set and get Widget prices. **/ public interface WidgetPrice { public void setWidgetPrice(String widgetName, String price); public String getWidgetPrice(String widgetName); }
Note: If you compile your class with debug information, Java2WSDL will use the debug information to obtain the method parameter names.
Step 2: Create WSDL using Java2WSDL
Use the Java2WSDL tool to create a WSDL file from the interface above.
Here is an example invocation that produces the wsdl file (wp.wsdl) from the interface described in the previous section (entered all on one line):
% java org.apache.axis.wsdl.Java2WSDL -o wp.wsdl -l"http://localhost:8080/axis/services/WidgetPrice" -n "urn:Example6" -p"samples.userguide.example6" "urn:Example6" samples.userguide.example6.WidgetPrice
Where:
- -o indicates the name of the output WSDL file
- -l indicates the location of the service
- -n is the target namespace of the WSDL file
- -p indicates a mapping from the package to a namespace. There may be multiple mappings.
- the class specified contains the interface of the webservice.
WSDL clause | Java class(es) generated |
---|---|
For each entry in the type section | A java class |
A holder if this type is used as an inout/out parameter | |
For each portType | A java interface |
For each binding | A stub class |
For each service | A service interface |
A service implementation (the locator) |
There is an Ant Task to integrate this action with an Ant based build process.
Types
The Java class generated from a WSDL type will be named from the WSDL type. This class will typically, though not always, be a bean. For example, given the WSDL (the WSDL used throughout the WSDL2Java discussion is from the Address Book sample):
<xsd:complexType name="phone"> <xsd:all> <xsd:element name="areaCode" type="xsd:int"/> <xsd:element name="exchange" type="xsd:string"/> <xsd:element name="number" type="xsd:string"/> </xsd:all> </xsd:complexType>
WSDL2Java will generate:
public class Phone implements java.io.Serializable { public Phone() {...} public int getAreaCode() {...} public void setAreaCode(int areaCode) {...} public java.lang.String getExchange() {...} public void setExchange(java.lang.String exchange) {...} public java.lang.String getNumber() {...} public void setNumber(java.lang.String number) {...} public boolean equals(Object obj) {...} public int hashCode() {...} }
Holders
This type may be used as an inout or out parameter. Java does not have the concept of inout/out parameters. In order to achieve this behavior, JAX-RPC specifies the use of holder classes. A holder class is simply a class that contains an instance of its type. For example, the holder for the Phone class would be:
package samples.addr.holders; public final class PhoneHolder implements javax.xml.rpc.holders.Holder { public samples.addr.Phone value; public PhoneHolder() { } public PhoneHolder(samples.addr.Phone value) { this.value = value; } }
A holder class is only generated for a type if that type is used as an inout or out parameter. Note that the holder class has the suffix "Holder" appended to the class name, and it is generated in a sub-package with the "holders".
The holder classes for the primitive types can be found in javax.xml.rpc.holders.
PortTypes
The Service Definition Interface (SDI) is the interface that's derived from a WSDL's portType. This is the interface you use to access the operations on the service. For example, given the WSDL:
<message name="empty"> <message name="AddEntryRequest"> <part name="name" type="xsd:string"/> <part name="address" type="typens:address"/> </message> <portType name="AddressBook"> <operation name="addEntry"> <input message="tns:AddEntryRequest"/> <output message="tns:empty"/> </operation> </portType>
WSDL2Java will generate:
public interface AddressBook extends java.rmi.Remote { public void addEntry(String name, Address address) throws java.rmi.RemoteException; }
A note about the name of the SDI. The name of the SDI is typically the name of the portType. However, to construct the SDI, WSDL2Java needs information from both the portType and the binding. (This is unfortunate and is a topic of discussion for WSDL version 2.)
JAX-RPC says (section 4.3.3): "The name of the Java interface is mapped from the name attribute of the wsdl:portType element. ... If the mapping to a service definition interface uses elements of the wsdl:binding ..., then the name of the service definition interface is mapped from the name of the wsdl:binding element."
Note the name of the spec. It contains the string "RPC". So this spec, and WSDL2Java, assumes that the interface generated from the portType is an RPC interface. If information from the binding tells us otherwise (in other words, we use elements of the wsdl:binding), then the name of the interface is derived instead from the binding.
Why? We could have one portType - pt - and two bindings - bRPC and bDoc. Since document/literal changes what the interface looks like, we cannot use a single interface for both of these bindings, so we end up with two interfaces - one named pt and another named bDoc - and two stubs - bRPCStub (which implements pt) and bDocStub (which implements bDoc).
Ugly, isn't it? But you can see why it's necessary. Since document/literal changes what the interface looks like, and we could have more than one binding referring to a single portType, we have to create more than one interface, and each interface must have a unique name.
Bindings
A Stub class implements the SDI. Its name is the binding name with the suffix "Stub". It contains the code which turns the method invocations into SOAP calls using the Axis Service and Call objects. It stands in as aproxy (another term for the same idea) for the remote service, letting you call it exactly as if it were a local object. In other words, you don't need to deal with the endpoint URL, namespace, or parameter arrays which are involved in dynamic invocation via the Service and Call objects. The stub hides all that work for you.
Given the following WSDL snippet:
<binding name="AddressBookSOAPBinding" type="tns:AddressBook"> ... </binding>
WSDL2Java will generate:
public class AddressBookSOAPBindingStub extends org.apache.axis.client.Stub implements AddressBook { public AddressBookSOAPBindingStub() throws org.apache.axis.AxisFault {...} public AddressBookSOAPBindingStub(URL endpointURL, javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {...} public AddressBookSOAPBindingStub(javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {...} public void addEntry(String name, Address address) throws RemoteException {...} }
Services
Normally, a client program would not instantiate a stub directly. It would instead instantiate a service locator and call a get method which returns a stub. This locator is derived from the service clause in the WSDL. WSDL2Java generates two objects from a service clause. For example, given the WSDL:
<service name="AddressBookService"> <port name="AddressBook" binding="tns:AddressBookSOAPBinding"> <soap:address location="http://localhost:8080/axis/services/AddressBook"/> </port> </service>
WSDL2Java will generate the service interface:
public interface AddressBookService extends javax.xml.rpc.Service { public String getAddressBookAddress(); public AddressBook getAddressBook() throws javax.xml.rpc.ServiceException; public AddressBook getAddressBook(URL portAddress) throws javax.xml.rpc.ServiceException; }
WSDL2Java will also generate the locator which implements this interface:
public class AddressBookServiceLocator extends org.apache.axis.client.Service implements AddressBookService { ... }
The service interface defines a get method for each port listed in the service element of the WSDL. The locator is the implementation of this service interface. It implements these get methods. It serves as a locator for obtaining Stub instances. The Service class will by default make a Stub which points to the endpoint URL described in the WSDL file, but you may also specify a different URL when you ask for the PortType.
A typical usage of the stub classes would be as follows:
public class Tester { public static void main(String [] args) throws Exception { // Make a service AddressBookService service = new AddressBookServiceLocator(); // Now use the service to get a stub which implements the SDI. AddressBook port = service.getAddressBook(); // Make the actual call Address address = new Address(...); port.addEntry("Russell Butek", address); } }