Ok, so recently I had some questions on what is a good/best practice way to develop Java web services, and I explained that in my opinion that would be a combination of a few practices, maybe when we are done here, we could give this pattern a name and coin it.
So, lets first understand the basics of Java EE web service. in theory it exists out of two tiers. the Web interface(WSDL), and the Service Layer(Service and objects that support it). but in my experiences I have come across, and established paterns that work more efficiently than the defacto. Lets get into this.
1. There is the top down way. The developer creates the WDSL, then generates the Java skeleton from that.
2. There is the bottom up way. The developer creates the classes with methods, and generates the WSDL from that.
3. Now My way starts with a combination of the two, since I do not fully accept the result of either these ways.
Lets call it “Ambidextrous Way”
You the Developer will start by developing your Service Class and the DTO’s that will go along with it. (you were going to do most of this either way). Once you have the main structures in place, use the Eclipse to generate the Web service WSDL. The nice thing about generating the WSDL like this, is that most of the grit is done for you.
P.S, be sure to generate the WSDL into a separate WebProject
Now, in the words of JZ… This is where the difference comes.
The WSDL should be a single file containing ALL the expected tags, e.g.; schema, definitions, types, complextypes, simpletypes, messages, operations, bindings, porttypes, serviceses. Now first thing you do is break the WSDL into more practical bits. e.g.: separate the schema(xsd), definition, and intraface. Now you can reuse the xsd if you have some JAXB marshaling to do.
here is a sample:
test1.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:local="http://www.example.org/test1xsd/"
targetNamespace="http://www.example.org/test1xsd/">
<simpleType name="name">
<restriction base="string"></restriction>
</simpleType>
<complexType name="person">
<sequence>
<element name="id" type="long"></element>
<element name="personname" type="local:name"></element>
<element name="personsurname" type="string"></element>
</sequence>
</complexType>
</schema>
test1.wsdl
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="test1wsdl" targetNamespace="http://www.example.org/test1wsdl/" xmlns:local="http://www.example.org/test1wsdl/" xmlns:test1xsd="http://www.example.org/test1xsd/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <xsd:schema targetNamespace="http://www.example.org/test1wsdl/" xmlns:test1xsd="http://www.example.org/test1xsd/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:import namespace="http://www.example.org/test1xsd/" schemaLocation="test1.xsd"/> </xsd:schema> </wsdl:types> <wsdl:message name="personRequest"> <wsdl:part name="id" type="xsd:long"/> </wsdl:message> <wsdl:message name="personResponse"> <wsdl:part name="personOut" type="test1xsd:person"/> </wsdl:message> <wsdl:portType name="PersonPortType"> <wsdl:operation name="getPersonOperation"> <wsdl:input message="local:personRequest"/> <wsdl:output message="local:personResponse"/> </wsdl:operation> </wsdl:portType> </wsdl:definitions>
test1_impl.wsdl
<?xml version="1.0" encoding="UTF-8"?> <definitions name="test1implwsdl" targetNamespace="http://www.example.org/test1implwsdl/" xmlns:test1wsdl="http://www.example.org/test1wsdl/" xmlns:local="http://www.example.org/test1implwsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" > <import namespace="http://www.example.org/test1wsdl/" location="test1.wsdl"/> <binding name="PersonBinding" type="test1wsdl:PersonPortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getPersonOperation"> <soap:operation soapAction="http://c0nan.net/GetLastTradePrice"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="PersonService"> <port name="PersonPort" binding="local:PersonBinding"> <soap:address location="http://c0nan.net/" /> </port> </service> </definitions>
Take NOTE!!!, when importing the XSD, we import it within the <types> tags, and when we import the WSDL, we do so outside of the <types> tags, preferably above.
Now you can go and customize your WSDL as you need, e.g: you can separate your XSD’s into practical groupings, just like you would your package names. you could separate like minded operations into the same WSDL, and bring them together in the implementation WSDL.
Now we use that wonderful feature of eclipse called “Generate Java Bean Skeleton”, once the wizard opens up, I prefer to limit the wizard to only up to Assemble. Click finish.
/**
* Person.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
*/
package org.example.www.test1xsd;
public class Person implements java.io.Serializable {
private long id;
private java.lang.String personname;
private java.lang.String personsurname;
public Person() {
}
public Person(
long id,
java.lang.String personname,
java.lang.String personsurname) {
this.id = id;
this.personname = personname;
this.personsurname = personsurname;
}
...
/**
* PersonPortType.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
*/
package org.example.www.test1wsdl;
public interface PersonPortType extends java.rmi.Remote {
public org.example.www.test1xsd.Person getPersonOperation(long id) throws java.rmi.RemoteException;
}
/**
* PersonBindingImpl.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
*/
package org.example.www.test1implwsdl;
public class PersonBindingImpl implements org.example.www.test1wsdl.PersonPortType{
public org.example.www.test1xsd.Person getPersonOperation(long id) throws java.rmi.RemoteException {
return null;
}
}
If you did not break the WSDL while normalizing it, then you should have successfully generated a skeleton Java structure in the current web project. with objects mapping directly to the complextypes in the XSD’s and these complextypes directly map to the DTO’s from your Service/EJB project, thus now one can easily use a framework like “Beanutils.copyproperties” to tranfer data between the POJOS.
Now that you have the skeleton, it is very easy, all you do is Map to the EJB and call the Service, no need to rewrite the service in the web project, this also adds a higher distributivity on the service object since it is now loosely coupled from the Web Service.

