Chose promise, chose due : j'ai enfin décidé de me lancer tête la première dans GWT. Je suis donc en train de mettre en place un site, que j'espère mettre en place dans quelques semaines, concernant la plongée sous-marine. Je vais tout au long du développement de l'application tenter de vous parler de son avancement, des difficultés rencontrées ainsi que des astuces qui pourront être utiles.
Pour vous donner une idée de ce que sera l'application, voici une première ébauche :
Comme vous pouvez le voir, ça reste encore assez sobre mais bon, j'espère bien enrichir l'application rapidement.
Pour manipuler la carte, j'utilise l'API GWT Google Maps 1.0 Library. Cette bibliothèque (encore en bêta) permet une intégration extrêmement simple de Google Maps au sein d'une application développée en GWT.
Voila pour le teasing ! A très bientôt donc...
Saturday, November 15, 2008
Tuesday, November 4, 2008
BreizhJug : Intégration continue
Retour sur le BreizhJug (Jug Rennes) du 3 novembre. Le sujet était l'intégration continue.
Nous avons assisté à une excellente présentation de Philippe Ensarguet et de Thierry Carré de la société Orange B&S.
La première partie présente les différents enjeux de l'intégration continue.
Les deuxième partie consiste en une comparaison de trois des outils d'intégration continue les plus en vue actuellement : CruiseControl, Continuum et Hudson.
Pour résumé, une parfaite introduction à l'indispensable intégration continue
Nous avons assisté à une excellente présentation de Philippe Ensarguet et de Thierry Carré de la société Orange B&S.
La première partie présente les différents enjeux de l'intégration continue.
Les deuxième partie consiste en une comparaison de trois des outils d'intégration continue les plus en vue actuellement : CruiseControl, Continuum et Hudson.
Pour résumé, une parfaite introduction à l'indispensable intégration continue
Thursday, October 16, 2008
Gouvernance SOA : quand ?
Un article très intéressant sur la gouvernance SOA : il s'arrête sur le timing nécessaire à sa mise en place.
c'est ici : http://blogs.progress.com/soa_infrastructure/2008/10/when-do-you-nee.html
c'est ici : http://blogs.progress.com/soa_infrastructure/2008/10/when-do-you-nee.html
Thursday, September 18, 2008
BreizhJug : 1ère séance
Lundi soir a vu l'ouverture du JUG rennais : le BreizhJUG. Nous avons pu assister à une excellente présentation de Didier Girard sur GWT. J'avais déjà jeté un coup d'oeil sur cette technologie mais il faut avouer qu'il m'a donné envie d'approfondir tout ça. Les possibilités offertes par le framework Google sont absolument fantastiques, spécialement quand on le couple à Google Gears (logiciel permettant d'utiliser les applications web en mode déconnecté). Gears que Google a bien entendu intégré à Chrome (étonnant non !?).
Pour finir, un merci tout particulier à Nicolas De loof et Matthieu Jouan, les deux organisateurs.
Pour finir, un merci tout particulier à Nicolas De loof et Matthieu Jouan, les deux organisateurs.
Monday, September 1, 2008
custom interaction with an Oracle BPEL process
For interacting with Oracle BPEL, you can, of course, use the Human Task. The problem is that Human Task is Oracle-dependent and is too complex to implement. So if you want to handle interactions, you simply use custom correlation. Let's see that with an example.
First, we create a simple asynchronous BPEL process which is locked just after the initial Receive task. To lock the process, we use another Receive task which is linked to a second operation called unlock : the process is dehydrated.
the main difference between this task and the initiate receive is that this one do not create a new process instance (ie. the "create instance" property is unchecked). So, this task must be linked to a current instance. To do that, we have to use the custom correlation. We initiate the correlation set with the request id present in the request payload on the initiate task. This correlation set is, in a second time, attached to the lock task and that's all (the id must be unique in Oracle BPEL); Oracle BPEL will manage the interactions.
When an initiate request is coming, Oracle BPEL gets the id and stores it. After that, the process is dehydrated on the lock Receive task. When an unlock message is coming,
the id is checked and Oracle BPEL correlates it with the process. At this moment, the process is rehydrated and its execution is resumed.
Now it's simple for a developer to create an "Unlock client" as you can see in the following code (we are using JAX-WS but you can use what you want to implement a client :
Axis, .Net, Soap-UI...) :
To create a new process, here is the command : java LockClient [wsdl] init [id] (example : http://localhost:8888/orabpel/biosom/Lock/1.0/Lock?wsdl init greg)
To unlock a process, here is the command : java LockClient [wsdl] unlock [id] (example : http://localhost:8888/orabpel/biosom/Lock/1.0/Lock?wsdl unlock greg)
This example is very simple but you can, of course, implement a correlation set more complicated and send more complex messages.
Download sources
First, we create a simple asynchronous BPEL process which is locked just after the initial Receive task. To lock the process, we use another Receive task which is linked to a second operation called unlock : the process is dehydrated.
<definitions
name="Lock"
targetNamespace="http://java-soa.blogspot.com/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
xmlns:pns1="http://java-soa.blogspot.com//correlationset"
xmlns:client="http://java-soa.blogspot.com/"
>
<import namespace="http://java-soa.blogspot.com//correlationset" location="Lock_Properties.wsdl"/>
<types>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://java-soa.blogspot.com/"
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="LockProcessRequest">
<complexType>
<sequence>
<element name="id" type="string"/>
</sequence>
</complexType>
</element>
<element name="UnlockProcessRequest">
<complexType>
<sequence>
<element name="id" type="string"/>
</sequence>
</complexType>
</element>
<element name="LockProcessResponse">
<complexType>
<sequence>
<element name="result" type="string"/>
</sequence>
</complexType>
</element>
</schema>
</types>
<message name="LockRequestMessage">
<part name="payload" element="client:LockProcessRequest"/>
</message>
<message name="UnlockRequestMessage">
<part name="payload" element="client:UnlockProcessRequest"/>
</message>
<message name="LockResponseMessage">
<part name="payload" element="client:LockProcessResponse"/>
</message>
<portType name="Lock">
<operation name="initiate">
<input message="client:LockRequestMessage"/>
</operation>
<operation name="unlock">
<input message="client:UnlockRequestMessage"/>
</operation>
</portType>
<portType name="LockCallback">
<operation name="onResult">
<input message="client:LockResponseMessage"/>
</operation>
</portType>
<plnk:partnerLinkType name="Lock">
<plnk:role name="LockProvider">
<plnk:portType name="client:Lock"/>
</plnk:role>
<plnk:role name="LockRequester">
<plnk:portType name="client:LockCallback"/>
</plnk:role>
</plnk:partnerLinkType>
<bpws:propertyAlias propertyName="pns1:correlationId" messageType="client:LockRequestMessage" part="payload"
query="/client:LockProcessRequest/client:id"/>
<bpws:propertyAlias propertyName="pns1:correlationId" messageType="client:UnlockRequestMessage" part="payload"
query="/client:UnlockProcessRequest/client:id"/>
</definitions>
the main difference between this task and the initiate receive is that this one do not create a new process instance (ie. the "create instance" property is unchecked). So, this task must be linked to a current instance. To do that, we have to use the custom correlation. We initiate the correlation set with the request id present in the request payload on the initiate task. This correlation set is, in a second time, attached to the lock task and that's all (the id must be unique in Oracle BPEL); Oracle BPEL will manage the interactions.
When an initiate request is coming, Oracle BPEL gets the id and stores it. After that, the process is dehydrated on the lock Receive task. When an unlock message is coming,
the id is checked and Oracle BPEL correlates it with the process. At this moment, the process is rehydrated and its execution is resumed.
Now it's simple for a developer to create an "Unlock client" as you can see in the following code (we are using JAX-WS but you can use what you want to implement a client :
Axis, .Net, Soap-UI...) :
package com.javasoa.ws;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Lock client.
*
* @author Grégory LE BONNIEC
*/
public class LockClient {
/** arguments count. */
private static final int ARGS_COUNT = 3;
/** type : initiate. */
private static final String TYPE_INIT = "init";
/** type : unlock. */
private static final String TYPE_UNLOCK = "unlock";
/////////////////////////////////////////////////////////////////////////
/**
* Starts the lock client.
*
* @param args arguments
*/
public static void main(String[] args) {
if (args.length != ARGS_COUNT) {
System.out
.println("[ERR] command : java LockClient [wsdl] [type] [id]");
System.exit(1);
}
String wsdl = args[0];
String type = args[1];
String id = args[2];
URL wsdlURL = null;
try {
wsdlURL = new URL(wsdl);
} catch (MalformedURLException me) {
System.out.println("[ERR] malformed URL");
System.exit(1);
}
LockService service = new LockService(wsdlURL);
if (TYPE_INIT.equals(type)) {
LockProcessRequest request = new LockProcessRequest();
request.setId(id);
service.getLockPort().initiate(request);
} else if (TYPE_UNLOCK.equals(type)) {
UnlockProcessRequest request = new UnlockProcessRequest();
request.setId(id);
service.getLockPort().unlock(request);
} else {
System.out.println("[ERR] unknown type");
System.exit(1);
}
}
}
To create a new process, here is the command : java LockClient [wsdl] init [id] (example : http://localhost:8888/orabpel/biosom/Lock/1.0/Lock?wsdl init greg)
To unlock a process, here is the command : java LockClient [wsdl] unlock [id] (example : http://localhost:8888/orabpel/biosom/Lock/1.0/Lock?wsdl unlock greg)
This example is very simple but you can, of course, implement a correlation set more complicated and send more complex messages.
Download sources
Labels:
bpel,
correlation,
interaction,
jax-ws,
oracle
Saturday, August 9, 2008
Oracle BPEL : JAX-WS Web Service asynchronous call
Today we are going to create an asynchronous JAX-WS web service to interact with Oracle BPEL 10.1.3.
Asynchronous web services are very useful when you want to provide long-running treatments : the client, contrary to synchronous processes, has not to wait actively for the response, that is the server which sends a callback when the operation is finished indeed (the client has just to start a listener which will handle the response).
Oracle BPEL is providing many mechanisms to manage asynchronous web services efficiently :
Here is the WSDL file :
As you can see, this wsdl file provides 2 messages in the request header :
After generating JAX-WS classes, we have now to implement the web service :
As you can see, in a first time, we recover WS-Addressing headers : reply address (ie. RelatesTo element) and correlation id (ie. MessageID element). After that, we are simulating a long operation by starting a wait function. Once the waiting over, we are sending the callback response without forgetting to set the address and the correlation id (ie. RelatesTo element).
The JAX-WS process is now ready, we have got to link it to Oracle BPEL. For this operation, we will just create a simple BPEL process which will call our new web service.
Concerning the WS-Addressing management you have to do anything : Oracle BPEL sets the different informations in the request header and handles the relatesTo header element for correlating responses and requests.
To finish, we have just to test the BPEL process. In the BPEL Console, we are starting this process by setting input informations : per example "Greg" for name and "10" for delay.
And normally, if everything is OK, the BPEL process calls the JAX-WS service, waits for the response and finally receives the callback response.
Download sources
Asynchronous web services are very useful when you want to provide long-running treatments : the client, contrary to synchronous processes, has not to wait actively for the response, that is the server which sends a callback when the operation is finished indeed (the client has just to start a listener which will handle the response).
Oracle BPEL is providing many mechanisms to manage asynchronous web services efficiently :
- dehydration store : this database is the Oracle BPEL core. In the asynchronous case, when a process is waiting for the response, the process is "dehydrated" (ie. the process context is maintained in database, this allows to release resources during response waiting). An internal listener is responsible to receive asynchronous responses and to wake up corresponding processes.
- WS-Addressing : this specification is used by Oracle BPEL to provide to web services the callback informations. When a request is sent, the callback address (ie. callback listener) and a correlation id are provided in the SOAP header. When the service has finished the treatment, it has to use these informations to send the callback. Finally, Oracle BPEL uses the correlation id to identify and wake up the process instance which is the request source.
Here is the WSDL file :
<definitions name="AsyncBPEL" targetNamespace="http://java-soa.blogspot.com/"
xmlns:tns="http://java-soa.blogspot.com/" xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<!-- types -->
<types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing"
schemaLocation="ws-addressing.xsd" />
</xsd:schema>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace="http://java-soa.blogspot.com/">
<element name="request">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string" />
<xsd:element name="delay" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</element>
<element name="response" type="xsd:string" />
</xsd:schema>
</types>
<!-- messages -->
<message name="WSAReplyToHeader">
<part name="ReplyTo" element="wsa:ReplyTo" />
</message>
<message name="WSAMessageIDHeader">
<part name="MessageID" element="wsa:MessageID" />
</message>
<message name="WSARelatesToHeader">
<part name="RelatesTo" element="wsa:RelatesTo" />
</message>
<message name="requestMessage">
<part name="in" element="tns:request" />
</message>
<message name="responseMessage">
<part name="out" element="tns:response" />
</message>
<!-- operations -->
<portType name="RequestPortType">
<operation name="request">
<input message="tns:requestMessage" />
</operation>
</portType>
<portType name="ResponsePortType">
<operation name="response">
<input message="tns:responseMessage" />
</operation>
</portType>
<!-- binding -->
<binding name="RequestBinding" type="tns:RequestPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="request">
<soap:operation soapAction="" />
<input>
<soap:header message="tns:WSAReplyToHeader" part="ReplyTo" use="literal"
encodingStyle="" />
<soap:header message="tns:WSAMessageIDHeader" part="MessageID"
use="literal" encodingStyle="" />
<soap:body use="literal" />
</input>
</operation>
</binding>
<binding name="ResponseBinding" type="tns:ResponsePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="response">
<soap:operation soapAction="" />
<input>
<soap:header message="tns:WSARelatesToHeader" part="RelatesTo"
use="literal" encodingStyle="" />
<soap:body use="literal" />
</input>
</operation>
</binding>
<!-- services -->
<service name="RequestService">
<port name="RequestPort" binding="tns:RequestBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL" />
</port>
</service>
<service name="ResponseService">
<port name="ResponsePort" binding="tns:ResponseBinding">
<soap:address location="http://set.by.caller" />
</port>
</service>
<!-- partnerlink -->
<plnk:partnerLinkType name="asyncPartnerLink">
<plnk:role name="asyncProvider">
<plnk:portType name="tns:RequestPortType" />
</plnk:role>
<plnk:role name="asyncRequester">
<plnk:portType name="tns:ResponsePortType" />
</plnk:role>
</plnk:partnerLinkType>
</definitions>
As you can see, this wsdl file provides 2 messages in the request header :
- WSAReplyToHeader : contains callback address, WS port name and service name.
- WSAMessageIDHeader : contains the correlation id
- RelatesTo : will contain the same correlation id, which allows Oracle BPEL to associate the request and the response
After generating JAX-WS classes, we have now to implement the web service :
package com.javasoa.ws.impl;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.ws.WebServiceContext;
import com.javasoa.ws.RequestPortType;
import com.javasoa.ws.ResponsePortType;
import com.javasoa.ws.ResponseService;
import com.sun.xml.ws.api.message.Header;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.ws.api.message.Headers;
import com.sun.xml.ws.developer.JAXWSProperties;
import com.sun.xml.ws.developer.WSBindingProvider;
/**
* Request Web Service (implementation).
*
* @author greg
*/
@WebService(endpointInterface = "com.javasoa.ws.RequestPortType")
public class RequestPortTypeImpl implements RequestPortType {
/** namespace : addressing 2003. */
private static final String NS_ADDRESSING_2003 =
"http://schemas.xmlsoap.org/ws/2003/03/addressing";
/** header : reply to. */
private static final String HEADER_REPLYTO = "ReplyTo";
/** header : address. */
private static final String HEADER_ADDRESS = "Address";
/** header : message id. */
private static final String HEADER_MESSAGEID = "MessageID";
/** header : relates to. */
private static final String HEADER_RELATESTO = "RelatesTo";
/** response message. */
private static final String RESPONSE_MSG =
"%s has waited during %d seconds";
/** number of milliseconds in one second. */
private static final int MILLI_SECONDS = 1000;
// ///////////////////////////////////////////////////////////////////
@Resource
private WebServiceContext context;
// ///////////////////////////////////////////////////////////////////
/*
* (non-Javadoc)
*
* @see com.javasoa.ws.RequestPortType#request(java.lang.String, int)
*/
public void request(String name, int delay) {
// gets the addressing informations in the SOAP header
HeaderList hl =
(HeaderList) context.getMessageContext().get(
JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
String address = null;
try {
Header replyTo = hl.get(NS_ADDRESSING_2003, HEADER_REPLYTO, false);
XMLStreamReader replyToReader = replyTo.readHeader();
while ((address == null)
&& (replyToReader.getEventType() != XMLStreamConstants.END_DOCUMENT)) {
if (replyToReader.next() == XMLStreamConstants.START_ELEMENT) {
if (replyToReader.getLocalName().equals(HEADER_ADDRESS)) {
replyToReader.next();
address = replyToReader.getText();
}
}
}
} catch (XMLStreamException xe) {
xe.printStackTrace();
return;
}
String messageId =
hl.get(NS_ADDRESSING_2003, HEADER_MESSAGEID, false)
.getStringContent();
// waits during <delay> seconds
try {
Thread.sleep(delay * MILLI_SECONDS);
} catch (InterruptedException ie) {
ie.printStackTrace();
return;
}
// response
String message = String.format(RESPONSE_MSG, name, delay);
// callback service
ResponseService service = new ResponseService();
ResponsePortType portType = service.getResponsePort();
WSBindingProvider bp = (WSBindingProvider) portType;
// sets the callback address
bp.setAddress(address);
// set the WS-addressing correlation id (RelatesTo)
bp.setOutboundHeaders(Headers.create(new QName(NS_ADDRESSING_2003,
HEADER_RELATESTO), messageId));
// sends the callback
portType.response(message);
}
}
As you can see, in a first time, we recover WS-Addressing headers : reply address (ie. RelatesTo element) and correlation id (ie. MessageID element). After that, we are simulating a long operation by starting a wait function. Once the waiting over, we are sending the callback response without forgetting to set the address and the correlation id (ie. RelatesTo element).
The JAX-WS process is now ready, we have got to link it to Oracle BPEL. For this operation, we will just create a simple BPEL process which will call our new web service.
Concerning the WS-Addressing management you have to do anything : Oracle BPEL sets the different informations in the request header and handles the relatesTo header element for correlating responses and requests.
To finish, we have just to test the BPEL process. In the BPEL Console, we are starting this process by setting input informations : per example "Greg" for name and "10" for delay.
And normally, if everything is OK, the BPEL process calls the JAX-WS service, waits for the response and finally receives the callback response.
Download sources
Labels:
address,
asynchronous,
bpel,
correlation,
dynamic,
jax-ws,
oracle,
ws-addressing
Tuesday, July 22, 2008
Parameter customization in JAX-WS
After many months on Oracle BPEL, I am testing Apache ODE (Apache BPEL engine). ODE provides a web service which allows to administer the engine including deployment. To simplify developments, I have decided to create a deployment client by using JAX-WS.
To generate the different classes corresponding to the ODE Web Service, I have used the wsimport tool and the following error is appeared :
the problem is coming from the Apache ODE wsdl and specially from this code :
The error is easy to understand : you cannot transform in a java class an xml element which is named like a java keyword otherwise a compilation error would occur. The problem is that we cannot change the contract, it is Apache which provides it. What can we do ? the solution is JAX-WS Customization : it allows us to adapt the different generated classes.
For our case, we need to rename the package element by, per example, paramPackage. Firstly, we need to create a customization file (we will call it bindings.xml) :
Let's see this file in detail.
indicates that the source wsdl is wsdllocation.
indicates that the target operation the parameter belongs to is deploy and that this operation has DeploymentServicePortType as port type.
indicates to wsimport that the xml element package must be mapped to paramPackage in Java. Moreover it is indicated that package element corresponds to parameters part of deployInput message.
Now you have just to use wsimport with the following options to apply the customization file on generated classes :
Finally, if you look at the generated web service interface, you can see that package parameter is renamed as paramPackage :
To generate the different classes corresponding to the ODE Web Service, I have used the wsimport tool and the following error is appeared :
[ERROR] Invalid operation "deploy", can't generate java method parameter. Local name of the wrapper child "package" in the global element "{http://www.apache.org/ode/pmapi}deploy" is a java keyword. Use customization to change the parameter name.
line 138 of http://localhost:8080/ode/processes/DeploymentService?wsdl
the problem is coming from the Apache ODE wsdl and specially from this code :
...
<xsd:element name="deploy">
<xsd:complexType>
<xsd:sequence>
<xsd:element form="unqualified" name="name" type="xsd:string"/>
<xsd:element form="unqualified" name="package" type="ns30:package"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
...
<wsdl:message name="deployInput">
<wsdl:part name="parameters" element="ns0:deploy"/>
</wsdl:message>
...
<wsdl:portType name="DeploymentServicePortType">
...
<wsdl:operation name="deploy">
<wsdl:input message="tns:deployInput" Action="http://www.apache.org/ode/deployapi/DeploymentPortType/deployRequest"/>
<wsdl:output message="tns:deployOutput" wsaw:Action="http://www.apache.org/ode/deployapi/DeploymentPortType/deployResponse"/>
</wsdl:operation>
...
The error is easy to understand : you cannot transform in a java class an xml element which is named like a java keyword otherwise a compilation error would occur. The problem is that we cannot change the contract, it is Apache which provides it. What can we do ? the solution is JAX-WS Customization : it allows us to adapt the different generated classes.
For our case, we need to rename the package element by, per example, paramPackage. Firstly, we need to create a customization file (we will call it bindings.xml) :
<jaxws:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
wsdlLocation="http://localhost:8080/ode/processes/DeploymentService?wsdl">
<jaxws:bindings node="wsdl:definitions/wsdl:portType[@name='DeploymentServicePortType']/wsdl:operation[@name='deploy']">
<jaxws:parameter
part="wsdl:definitions/wsdl:message[@name='deployInput']/wsdl:part[@name='parameters']"
childElementName="package" name="paramPackage" />
</jaxws:bindings>
</jaxws:bindings>
Let's see this file in detail.
<jaxws:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
wsdlLocation="http://localhost:8080/ode/processes/DeploymentService?wsdl">
indicates that the source wsdl is wsdllocation.
<jaxws:bindings
node="wsdl:definitions/wsdl:portType[@name='DeploymentServicePortType']/wsdl:operation[@name='deploy']">
indicates that the target operation the parameter belongs to is deploy and that this operation has DeploymentServicePortType as port type.
<jaxws:parameter
part="wsdl:definitions/wsdl:message[@name='deployInput']/wsdl:part[@name='parameters']"
childElementName="package" name="paramPackage" />
indicates to wsimport that the xml element package must be mapped to paramPackage in Java. Moreover it is indicated that package element corresponds to parameters part of deployInput message.
Now you have just to use wsimport with the following options to apply the customization file on generated classes :
wsimport -keep -b <PROJECT_ROOT>/jaxws/bindings.xml -d <PROJECT_ROOT>/src -p com.javasoa.ws.ode http://localhost:8080/ode/processes/DeploymentService?wsdl
Finally, if you look at the generated web service interface, you can see that package parameter is renamed as paramPackage :
...
@WebService(name = "DeploymentServicePortType", targetNamespace = "http://www.apache.org/ode/deployapi")
@XmlSeeAlso({
ObjectFactory.class
})
public interface DeploymentServicePortType {
...
public DeployUnit deploy(
@WebParam(name = "name", targetNamespace = "")
String name,
@WebParam(name = "package", targetNamespace = "")
Package paramPackage);
Saturday, July 12, 2008
A simple JAX-WS Web Service with Eclipse
Here I am ! this my first post on my technical blog.
For this one, I am going to show you how to create an HelloWorld WS with JAX-WS RI (2.1.3) and Eclipse (3.4). We will use a contract-first method (WSDL to Java) to develop this first WS. We will deploy the WS on Tomcat (6.0).
Creating an Eclipse Project
Now we are going to configure the different JAX-WS configuration files :
the command wsimport generates the different java classes from the wsdl.
Now the web service the ready ! we just need to deploy it on Tomcat.
Configuring Tomcat in Eclipse
Testing the Web Service
For testing our first web service, we will use SoapUI web service client.
In SoapUI :
Now you can put your name in the SOAP envelope and call the web service !
For this one, I am going to show you how to create an HelloWorld WS with JAX-WS RI (2.1.3) and Eclipse (3.4). We will use a contract-first method (WSDL to Java) to develop this first WS. We will deploy the WS on Tomcat (6.0).
Creating an Eclipse Project
- Select the menu File → Other...
- Select Web → Dynamic Web Project
- Specify paths and Tomcat as the target runtime
- Once you have created the project, copy the jar files from the directory <JAXWS_ROOT>/lib to <ECLIPSE_PROJECT>/WebContent/WEB-INF/lib then refresh the eclipse project
Now we are going to configure the different JAX-WS configuration files :
- Create the file <ECLIPSE_PROJECT>/WebContent/WEB-INF/wsdl/HelloWorld.wsdl (WS contract) :
<definitions name="HelloWorld" targetNamespace="http://java-soa.blogspot.com/"
xmlns:tns="http://java-soa.blogspot.com/" xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<!-- types -->
<types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace="http://java-soa.blogspot.com/">
<element name="name" type="xsd:string" />
<element name="response" type="xsd:string" />
</xsd:schema>
</types>
<!-- messages -->
<message name="name">
<part name="in" element="tns:name" />
</message>
<message name="response">
<part name="out" element="tns:response" />
</message>
<!-- operations -->
<portType name="HelloWorldPortType">
<operation name="hello">
<input message="tns:name" />
<output message="tns:response" />
</operation>
</portType>
<!-- binding -->
<binding name="HelloWorldBinding" type="tns:HelloWorldPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="hello">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<!-- services -->
<service name="HelloWorldService">
<port name="HelloWorldPort" binding="tns:HelloWorldBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL" />
</port>
</service>
</definitions>
- Create the file <ECLIPSE_PROJECT>/WebContent/WEB-INF/web.xml (Web deployment descriptor) :
<web-app version="2.4" mlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<description>HelloWorld</description>
<display-name>HelloWorld</display-name>
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<description>JAX-WS endpoint - HelloWorld</description>
<display-name>HelloWorld</display-name>
<servlet-name>HelloWorldPort</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldPort</servlet-name>
<url-pattern>/helloWorld</url-pattern>
</servlet-mapping>
</web-app>
- Create the file <ECLIPSE_PROJECT>/WebContent/WEB-INF/sun-jaxws.xml (JAX-WS RI deployment descriptor) :
<?xml version="1.0" encoding="UTF-8"?>Configuring WsImport
<endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'>
<endpoint
name="HelloWorld"
implementation="com.javasoa.ws.impl.HelloWorldPortTypeImpl"
wsdl="WEB-INF/wsdl/HelloWorld.wsdl"
service='{http://java-soa.blogspot.com/}HelloWorldService'
port='{http://java-soa.blogspot.com/}HelloWorldPort'
url-pattern="/helloWorld"/>
</endpoints>
the command wsimport generates the different java classes from the wsdl.
- Select the menu Run → External Tools → External Tools Configuration
- Click on Program then on button
- Specify the following informations :
- Name : CreateClassJAXWS
- Location : <JAXWS_ROOT>/bin/wsimport.[bat|sh]
- Working Directory : ${project_loc}
- Arguments : -keep -d ${project_loc}/src -p com.javasoa.ws ${resource_loc}
- Click on Close button
Arguments description :Generating Web Service classes
- keep : without this argument, sources files are deleted after generation
- d : source path
- p : source files target package
- Select the wsdl file
- Select the menu Run → External Tools → CreateClassJAXWS
- Refresh the eclipse project
- com.javasoa.ws.HelloWorldPortType : this class defines the web service interface. The different annotations (WebService,WebMethod,WebParam...) indicates the Web Service informations (JAX-WS annotation list).
- com.javasoa.ws.HelloWorldService : this class provides client methods (we will not use this class in this tutorial).
- com.javasoa.ws.ObjectFactory : this class contains for each XML element a method providing the corresponding Java object.
- Create the class com.javasoa.ws.impl with the following contents :
package com.javasoa.ws.impl;The endpointInterface annotation indicates in which class (interface) find the web services description.
import javax.jws.WebService;
import com.javasoa.ws.HelloWorldPortType;
/**
* HelloWorld WS implementation.
*/
@WebService(endpointInterface = "com.javasoa.ws.HelloWorldPortType")
public class HelloWorldPortTypeImpl implements HelloWorldPortType {
/** suffix : hello. */
private static final String SUFFIX_HELLO = "Hello ";
/////////////////////////////////////////////////////////////////////////
/**
* Say hello to in.
*
* @param in name
*
* @return response
*/
@Override
public String hello(String in) {
return (SUFFIX_HELLO + in);
}
}
Now the web service the ready ! we just need to deploy it on Tomcat.
Configuring Tomcat in Eclipse
- Select the menu Window → Preferences → Server → Runtime Environments
- Click on Add button
- Select Apache Tomcat V6.0 then click on Next button
- In Tomcat Installation directory, specify the tomcat root path
- Click on Finish button then on Ok Button
- Select the menu Window → Show View → Servers
- In the Server view, right-click and select the menu New → Server
- Select Apache Tomcat V6.0 then click on Next button
- Select the HelloWorld project then click on Add → button
- Click on Finish button
- Right-click on the server then select the menu Start
Testing the Web Service
For testing our first web service, we will use SoapUI web service client.
In SoapUI :
- Select the menu File → New WSDL Project
- Specify the following informations :
- Project Name : HelloWorld
- Initial WSDL : http://localhost:8080/HelloWorld/helloWorld?wsdl
- Click on OK button : a default request is created.
Now you can put your name in the SOAP envelope and call the web service !
Subscribe to:
Posts (Atom)