Prev >>> Develop Web Service With Axis2 #6 - Workaround Solution for Custom "Header" on Skeleton/Stub side
This article will talk about how to add soap headers in response soap message, not work around solution mentioned in previous article.
The approach is to use module/handler to inject the soap headers while responding to consumers.
follow this article Develop Web Service With Axis2 #4 - Axis2 Style Interceptor to create a new module.
------ module class
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.modules.Module;
import org.apache.neethi.Assertion;
import org.apache.neethi.Policy;
public class SoapHeaderModule implements Module {
public void init(ConfigurationContext configurationContext,
AxisModule axisModule) throws AxisFault {
System.out.println("Initializing the module");
}
public void engageNotify(AxisDescription axisDescription) throws AxisFault {
}
public boolean canSupportAssertion(Assertion assertion) {
return false;
}
public void applyPolicy(Policy policy, AxisDescription axisDescription)
throws AxisFault {
}
public void shutdown(ConfigurationContext configurationContext)
throws AxisFault {
}
}
-------- handler class
package mypackage;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.handlers.AbstractHandler;
public class HeaderOutHandler extends AbstractHandler {
public InvocationResponse invoke(MessageContext messageContext)
throws AxisFault {
// add an Soap header for the outgoing soap message
SOAPEnvelope soapEnvelope = messageContext.getEnvelope();
if (soapEnvelope.getHeader() == null) {
String soapNamespace = soapEnvelope.getNamespace()
.getNamespaceURI();
// creating a soap factory according the the soap namespce uri
SOAPFactory soapFactory = null;
if (soapNamespace
.equals(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
soapFactory = OMAbstractFactory.getSOAP11Factory();
} else if (soapNamespace
.equals(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
soapFactory = OMAbstractFactory.getSOAP12Factory();
} else {
System.out.println("Unknow soap message");
}
soapFactory.createSOAPHeader(soapEnvelope);
}
OMNamespace omNamespace = OMAbstractFactory.getOMFactory()
.createOMNamespace("http://mycompany.com", "myNs");
SOAPHeaderBlock soapHeaderBlock = soapEnvelope.getHeader()
.addHeaderBlock("responseId", omNamespace);
soapHeaderBlock.setText("11223344");
soapHeaderBlock = soapEnvelope.getHeader().addHeaderBlock(
"resonseTime", omNamespace);
soapHeaderBlock.setText(new java.util.Date().toString());
return InvocationResponse.CONTINUE;
}
}
-------------------- module configuration file
<module name="CustHeaderModule" class="mypackage.SoapHeaderModule">
<OutFlow>
<handler name="OutFlowHeaderOutHandler" class="mypackage.HeaderOutHandler">
<order phase="CustHeaderPhase" />
</handler>
</OutFlow>
</module>
---------------- modify axis2.xml
<phaseOrder type="OutFlow">
<!-- user can add his own phases to this area -->
<phase name="soapmonitorPhase"/>
<phase name="OperationOutPhase"/>
<phase name="CustHeaderPhase"/>
<phase name="auditLogPhase"/>
<!--system predefined phase-->
<!--these phase will run irrespective of the service-->
<phase name="RMPhase"/>
<phase name="PolicyDetermination"/>
<phase name="MessageOut"/>
<phase name="Security"/>
</phaseOrder>
Take note that I put CustHeaderPhase before auditLogPhase, so that inject soap headers first, auditLogPhase show response soap message including soap headers subsequently.
------------- add the module to services.xml
<module ref="auditLogger"/>
<module ref="CustHeaderModule"/>
-------- test it.
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<myNs:responseId xmlns:myNs="http://mycompany.com">11223344</myNs:responseId>
<myNs:resonseTime xmlns:myNs="http://mycompany.com">Tue Jan 04 17:13:16 CST 2011</myNs:resonseTime>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserProfileResponse xmlns:ns2="http://axis.test.com/ws">
<ns2:userProfileResponse>
<<ns1:age xmlns:ns1="http://bean.axis.test.com/xsd">32</ns1:age>
<ns1:userName xmlns:ns1="http://bean.axis.test.com/xsd">dddddddddd</ns1:userName>
</ns2:userProfileResponse>
</soapenv:Body>
</soapenv:Envelope>
============= Reminder ===============
to customize HTTP header is another useful function. refer to
http://www.keith-chapman.org/2008/10/axis2-setting-custom-http-headers-on.html
Example code:
MessageContext responseMessageContext = MessageContext.getCurrentMessageContext().getOperationContext().getMessageContext( WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
List headers = new ArrayList(); headers.add(new Header(HTTPConstants.HEADER_CONTENT_ENCODING, "identity")); responseMessageContext.setProperty(HTTPConstants.HTTP_HEADERS, headers);
Tuesday, January 4, 2011
Monday, January 3, 2011
Develop Web Service With Axis2 #6 - Workaround Solution for Custom "Header" on Skeleton/Stub side
Prev >>> Develop Web Service With Axis2 #5 - Custom Soap Header on Stub side
It is not straightforward to add <soap:header> to response message on skeleton in axis2.
Someone suggests to write own message receiver, or add soap header by module, and someone suggests to convert header information to HTTP header,etc.
There is a workaround solution to put header information to body. Let's start with code-first approach.
---- define header information
package com.test.axis.bean;
import java.util.Date;
public class Header {
private String requestId;
// setter and getter methods
}
----- re-define the interface
package com.test.axis.service;
import com.test.axis.bean.AuthUserRequest;
import com.test.axis.bean.UserInfoRequest;
import com.test.axis.bean.UserInfoResponse;
import com.test.axis.bean.WebServiceFault;
public interface UserServices {
UserInfoResponse getUserInfo(UserInfoRequest infoRequest) throws WebServiceFault;
UserInfoResponse authUser(
AuthUserRequest authRequest)
throws WebServiceFault;
}
---- define userInfoRequest by this way
package com.test.axis.bean;
public class UserInfoRequest {
private Header header;
private String userId;
// setter and getter methods
}
------ re-define UserInfoResponse object, put header inside as well
package com.test.axis.bean;
import java.util.Date;
public class UserInfoResponse {
private Header header;
private String userName;
// setter and getter methods
}
------ generate wsdl based on above java beans and interface
------ request message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws">
<ns2:userInfoRequest>
<header xmlns="http://bean.axis.test.com/xsd">
<requestId>552121</requestId>
</header>
<ns1:userId xmlns:ns1="http://bean.axis.test.com/xsd">user111</ns1:userId>
</ns2:userInfoRequest>
</ns2:getUserInfo>
</soapenv:Body>
</soapenv:Envelope>
------ response soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns2:getUserInfoResponse xmlns:ns2="http://axis.test.com/ws">
<ns2:userInfoResponse>
<header xmlns="http://bean.axis.test.com/xsd">
<requestId>552121</requestId>
</header>
<ns1:userName xmlns:ns1="http://bean.axis.test.com/xsd">dddddddddd</ns1:userName>
</ns2:userInfoResponse>
</ns2:getUserInfoResponse>
</soapenv:Body>
</soapenv:Envelope>
It is not straightforward to add <soap:header> to response message on skeleton in axis2.
Someone suggests to write own message receiver, or add soap header by module, and someone suggests to convert header information to HTTP header,etc.
There is a workaround solution to put header information to body. Let's start with code-first approach.
---- define header information
package com.test.axis.bean;
import java.util.Date;
public class Header {
private String requestId;
// setter and getter methods
}
----- re-define the interface
package com.test.axis.service;
import com.test.axis.bean.AuthUserRequest;
import com.test.axis.bean.UserInfoRequest;
import com.test.axis.bean.UserInfoResponse;
import com.test.axis.bean.WebServiceFault;
public interface UserServices {
UserInfoResponse getUserInfo(UserInfoRequest infoRequest) throws WebServiceFault;
UserInfoResponse authUser(
AuthUserRequest authRequest)
throws WebServiceFault;
}
---- define userInfoRequest by this way
package com.test.axis.bean;
public class UserInfoRequest {
private Header header;
private String userId;
// setter and getter methods
}
------ re-define UserInfoResponse object, put header inside as well
package com.test.axis.bean;
import java.util.Date;
public class UserInfoResponse {
private Header header;
private String userName;
// setter and getter methods
}
------ generate wsdl based on above java beans and interface
------ request message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws">
<ns2:userInfoRequest>
<header xmlns="http://bean.axis.test.com/xsd">
<requestId>552121</requestId>
</header>
<ns1:userId xmlns:ns1="http://bean.axis.test.com/xsd">user111</ns1:userId>
</ns2:userInfoRequest>
</ns2:getUserInfo>
</soapenv:Body>
</soapenv:Envelope>
------ response soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns2:getUserInfoResponse xmlns:ns2="http://axis.test.com/ws">
<ns2:userInfoResponse>
<header xmlns="http://bean.axis.test.com/xsd">
<requestId>552121</requestId>
</header>
<ns1:userName xmlns:ns1="http://bean.axis.test.com/xsd">dddddddddd</ns1:userName>
</ns2:userInfoResponse>
</ns2:getUserInfoResponse>
</soapenv:Body>
</soapenv:Envelope>
Develop Web Service With Axis2 #5 - Custom Soap Header on Stub side
Prev >>> Develop Web Service With Axis2 #4 - Axis2 Style Interceptor
1) if only add a simple string to header
--- stub code
OMFactory omFactory =OMAbstractFactory.getOMFactory();
OMNamespace omNamespace = omFactory.createOMNamespace("http://mycompany.org", "myHeader");
OMElement header = omFactory.createOMElement("header", omNamespace);
header.setText("This is a custom soap header");
_stub._getServiceClient().addHeader(header);
-- soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<myHeader:header xmlns:myHeader="http://mycompany.org">
This is a custom soap header
</myHeader:header>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws" />
</soapenv:Body>
</soapenv:Envelope>
2) to use OMElement object to encapsulate soap header
--- stub code
OMElement header1 = AXIOMUtil.stringToOM("<header1><systemId>system-011</systemId></header1>");
OMElement header2 = AXIOMUtil.stringToOM("<header2><requestTime>"+new java.util.Date()+"</requestTime></header2>");
_stub._getServiceClient().addHeader(header1);
_stub._getServiceClient().addHeader(header2);
--- soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<header1>
<systemId>system-011</systemId>
</header1>
<header2>
<requestTime>Mon Jan 03 14:29:00 CST 2011</requestTime>
</header2>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws" />
</soapenv:Body>
</soapenv:Envelope>
3. SOAPHeaderBlock
--- stub code
OMNamespace omNamespace = OMAbstractFactory.getOMFactory()
.createOMNamespace("http://myCompany.com", "headerNs");
SOAPHeaderBlock header1 = OMAbstractFactory.getSOAP12Factory()
.createSOAPHeaderBlock("header1", omNamespace);
header1.addChild(AXIOMUtil.stringToOM("<header123>header content</header123>"));
_stub._getServiceClient().addHeader(header1);
---- soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<headerNs:header1 xmlns:headerNs="http://myCompany.com">
<header123>header content</header123>
</headerNs:header1>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws" />
</soapenv:Body>
</soapenv:Envelope>
Reference
http://wso2.org/library/3156
1) if only add a simple string to header
--- stub code
OMFactory omFactory =OMAbstractFactory.getOMFactory();
OMNamespace omNamespace = omFactory.createOMNamespace("http://mycompany.org", "myHeader");
OMElement header = omFactory.createOMElement("header", omNamespace);
header.setText("This is a custom soap header");
_stub._getServiceClient().addHeader(header);
-- soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<myHeader:header xmlns:myHeader="http://mycompany.org">
This is a custom soap header
</myHeader:header>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws" />
</soapenv:Body>
</soapenv:Envelope>
2) to use OMElement object to encapsulate soap header
--- stub code
OMElement header1 = AXIOMUtil.stringToOM("<header1><systemId>system-011</systemId></header1>");
OMElement header2 = AXIOMUtil.stringToOM("<header2><requestTime>"+new java.util.Date()+"</requestTime></header2>");
_stub._getServiceClient().addHeader(header1);
_stub._getServiceClient().addHeader(header2);
--- soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<header1>
<systemId>system-011</systemId>
</header1>
<header2>
<requestTime>Mon Jan 03 14:29:00 CST 2011</requestTime>
</header2>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws" />
</soapenv:Body>
</soapenv:Envelope>
3. SOAPHeaderBlock
--- stub code
OMNamespace omNamespace = OMAbstractFactory.getOMFactory()
.createOMNamespace("http://myCompany.com", "headerNs");
SOAPHeaderBlock header1 = OMAbstractFactory.getSOAP12Factory()
.createSOAPHeaderBlock("header1", omNamespace);
header1.addChild(AXIOMUtil.stringToOM("<header123>header content</header123>"));
_stub._getServiceClient().addHeader(header1);
---- soap message
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<headerNs:header1 xmlns:headerNs="http://myCompany.com">
<header123>header content</header123>
</headerNs:header1>
</soapenv:Header>
<soapenv:Body>
<ns2:getUserInfo xmlns:ns2="http://axis.test.com/ws" />
</soapenv:Body>
</soapenv:Envelope>
Reference
http://wso2.org/library/3156
Develop Web Service With Axis2 #4 - Axis2 Style Interceptor
Prev >>> Develop Web Service With Axis2 #3 - Custom Fault Message
If you are familiar with struts2, you would know there are a few of interceptors work together in strut2 framework. Similarly, Axis2 provides 4 flows or execution chains, InFlow, OutFlow, InFaultFlow and OutFaultFlow, which define a series of modules inside, or you can call them interceptors.
This article is strictly to follow the instruction provided by axis2 to implement a handler to print incoming/outgoing soap messages for each web service transactions.
http://axis.apache.org/axis2/java/core/docs/modules.html
1. module class
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.modules.Module;
import org.apache.neethi.Assertion;
import org.apache.neethi.Policy;
public class AuditLogModule implements Module {
// initialize the module
public void init(ConfigurationContext configContext, AxisModule module)
throws AxisFault {
System.out.println("init");
}
public void engageNotify(AxisDescription axisDescription) throws AxisFault {
}
// shutdown the module
public void shutdown(ConfigurationContext configurationContext)
throws AxisFault {
System.out.println("shutdown");
}
public String[] getPolicyNamespaces() {
return null;
}
public void applyPolicy(Policy policy, AxisDescription axisDescription)
throws AxisFault {
}
public boolean canSupportAssertion(Assertion assertion) {
return true;
}
}
2. handler class to print soap messages
------- class to print incoming soap message
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
public class AuditInHandler extends AbstractHandler implements Handler {
public InvocationResponse invoke(MessageContext msgContext)
throws AxisFault {
System.out.println("Request Message :"
+ msgContext.getEnvelope().toString());
return InvocationResponse.CONTINUE;
}
}
------- class to print outgoing soap message
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
public class AuditOutHandler extends AbstractHandler implements Handler {
@Override
public InvocationResponse invoke(MessageContext msgContext)
throws AxisFault {
System.out.println("Response Message :"
+ msgContext.getEnvelope().toString());
return InvocationResponse.CONTINUE;
}
}
3. prepare a module configuration file module.xml
<module name="auditLogger" class="mypackage.AuditLogModule">
<InFlow>
<handler name="InFlowAuditLogHandler" class="mypackage.AuditInHandler">
<order phase="auditLogPhase" />
</handler>
</InFlow>
<OutFlow>
<handler name="OutFlowAuditLogHandler" class="mypackage.AuditOutHandler">
<order phase="auditLogPhase" />
</handler>
</OutFlow>
</module>
4. add the element in red to service.xml which the web service you are going to apply to with the interceptor.
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file was auto-generated from WSDL -->
<!-- by the Apache Axis2 version: 1.5.3 Built on : Nov 12, 2010 (02:24:07 CET) -->
<serviceGroup>
<service name="UserServices">
<messageReceivers>
<messageReceiver mep="http://www.w3.org/ns/wsdl/in-out" class="com.test.axis.ws.skeleton.UserServicesMessageReceiverInOut"/>
</messageReceivers>
<module ref="auditLogger"/>
<parameter name="ServiceClass">com.test.axis.ws.skeleton.UserServicesSkeleton</parameter>
<parameter name="useOriginalwsdl">true</parameter>
<parameter name="modifyUserWSDLPortAddress">true</parameter>
<operation name="authUser" mep="http://www.w3.org/ns/wsdl/in-out" namespace="http://axis.test.com/ws/service">
<actionMapping>urn:authUser</actionMapping>
<outputActionMapping>urn:authUserResp</outputActionMapping>
<faultActionMapping faultName="WebServiceFault">urn:authUserWebServiceFault</faultActionMapping>
</operation>
<operation name="getUserInfo" mep="http://www.w3.org/ns/wsdl/in-out" namespace="http://axis.test.com/ws/service">
<actionMapping>urn:getUserInfo</actionMapping>
<outputActionMapping>urn:getUserInfoResp</outputActionMapping>
<faultActionMapping faultName="WebServiceFault">urn:getUserInfoWebServiceFault</faultActionMapping>
</operation>
</service>
</serviceGroup>
5. deploy module to server.
copy the auditLog.mar file to %tomcat%\webapps\axis2\WEB-INF\modules
or create a folder %tomcat%\webapps\axis2\WEB-INF\modules\auditLog and put all necessary files inside.
<folder auditLog>
|- META-INF
MANIFEST.MF
module.xml
|- com\......\xx.class
6. modify axis2.xml
I am using axis2 v1.5.3. The configuration file axis2.xml of different axis2 version might be a bit different.
add the elements shown in red to axis2.xml
<!-- ================================================= -->
<!-- Phases -->
<!-- ================================================= -->
<phaseOrder type="InFlow">
<!-- System predefined phases -->
<phase name="Transport">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher">
<order phase="Transport"/>
</handler>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher">
<order phase="Transport"/>
</handler>
</phase>
<phase name="Addressing">
<handler name="AddressingBasedDispatcher"
class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
<order phase="Addressing"/>
</handler>
</phase>
<phase name="Security"/>
<phase name="PreDispatch"/>
<phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
<handler name="RequestURIOperationDispatcher"
class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
<handler name="SOAPMessageBodyBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
<handler name="HTTPLocationBasedDispatcher"
class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
<handler name="GenericProviderDispatcher"
class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
<handler name="MustUnderstandValidationDispatcher"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
</phase>
<phase name="RMPhase"/>
<!-- System predefined phases -->
<!-- After Postdispatch phase module author or service author can add any phase he want -->
<phase name="OperationInPhase">
<handler name="MustUnderstandChecker"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker">
<order phase="OperationInPhase"/>
</handler>
</phase>
<phase name="auditLogPhase"/>
<phase name="soapmonitorPhase"/>
</phaseOrder>
<phaseOrder type="OutFlow">
<!-- user can add his own phases to this area -->
<phase name="soapmonitorPhase"/>
<phase name="OperationOutPhase"/>
<phase name="auditLogPhase"/>
<!--system predefined phase-->
<!--these phase will run irrespective of the service-->
<phase name="RMPhase"/>
<phase name="PolicyDetermination"/>
<phase name="MessageOut"/>
<phase name="Security"/>
</phaseOrder>
<phaseOrder type="InFaultFlow">
<phase name="Addressing">
<handler name="AddressingBasedDispatcher"
class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
<order phase="Addressing"/>
</handler>
</phase>
<phase name="Security"/>
<phase name="PreDispatch"/>
<phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
<handler name="RequestURIOperationDispatcher"
class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
<handler name="SOAPMessageBodyBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
<handler name="HTTPLocationBasedDispatcher"
class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
<handler name="GenericProviderDispatcher"
class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
<handler name="MustUnderstandValidationDispatcher"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
</phase>
<phase name="RMPhase"/>
<!-- user can add his own phases to this area -->
<phase name="OperationInFaultPhase"/>
<phase name="soapmonitorPhase"/>
</phaseOrder>
<phaseOrder type="OutFaultFlow">
<!-- user can add his own phases to this area -->
<phase name="soapmonitorPhase"/>
<phase name="OperationOutFaultPhase"/>
<phase name="RMPhase"/>
<phase name="PolicyDetermination"/>
<phase name="MessageOut"/>
<phase name="Security"/>
</phaseOrder>
7.test it. try to call one web service method mentioned in previous article. we can see soap message printed on tomcat console.
Request Message :<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:q0="http://axis.test.com/ws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body>
<q0:getUserInfo>
<q0:userId>aaaa</q0:userId>
</q0:getUserInfo>
</soapenv:Body></soapenv:Envelope>
Response Message :<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns2:getUserInfoResp xmlns:ns2="http://axis.test.com/ws"><ns2:return><ns1:age xmlns:ns1="http://bean.axis.test.com/xsd">22</ns1:age><ns1:userName xmlns:ns1="http://bean.axis.test.com/xsd">test name1</ns1:userName></ns2:return></ns2:getUserInfoResp></soapenv:Body></soapenv:Envelope>
If you are familiar with struts2, you would know there are a few of interceptors work together in strut2 framework. Similarly, Axis2 provides 4 flows or execution chains, InFlow, OutFlow, InFaultFlow and OutFaultFlow, which define a series of modules inside, or you can call them interceptors.
This article is strictly to follow the instruction provided by axis2 to implement a handler to print incoming/outgoing soap messages for each web service transactions.
http://axis.apache.org/axis2/java/core/docs/modules.html
1. module class
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.modules.Module;
import org.apache.neethi.Assertion;
import org.apache.neethi.Policy;
public class AuditLogModule implements Module {
// initialize the module
public void init(ConfigurationContext configContext, AxisModule module)
throws AxisFault {
System.out.println("init");
}
public void engageNotify(AxisDescription axisDescription) throws AxisFault {
}
// shutdown the module
public void shutdown(ConfigurationContext configurationContext)
throws AxisFault {
System.out.println("shutdown");
}
public String[] getPolicyNamespaces() {
return null;
}
public void applyPolicy(Policy policy, AxisDescription axisDescription)
throws AxisFault {
}
public boolean canSupportAssertion(Assertion assertion) {
return true;
}
}
2. handler class to print soap messages
------- class to print incoming soap message
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
public class AuditInHandler extends AbstractHandler implements Handler {
public InvocationResponse invoke(MessageContext msgContext)
throws AxisFault {
System.out.println("Request Message :"
+ msgContext.getEnvelope().toString());
return InvocationResponse.CONTINUE;
}
}
------- class to print outgoing soap message
package mypackage;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
public class AuditOutHandler extends AbstractHandler implements Handler {
@Override
public InvocationResponse invoke(MessageContext msgContext)
throws AxisFault {
System.out.println("Response Message :"
+ msgContext.getEnvelope().toString());
return InvocationResponse.CONTINUE;
}
}
3. prepare a module configuration file module.xml
<module name="auditLogger" class="mypackage.AuditLogModule">
<InFlow>
<handler name="InFlowAuditLogHandler" class="mypackage.AuditInHandler">
<order phase="auditLogPhase" />
</handler>
</InFlow>
<OutFlow>
<handler name="OutFlowAuditLogHandler" class="mypackage.AuditOutHandler">
<order phase="auditLogPhase" />
</handler>
</OutFlow>
</module>
4. add the element in red to service.xml which the web service you are going to apply to with the interceptor.
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file was auto-generated from WSDL -->
<!-- by the Apache Axis2 version: 1.5.3 Built on : Nov 12, 2010 (02:24:07 CET) -->
<serviceGroup>
<service name="UserServices">
<messageReceivers>
<messageReceiver mep="http://www.w3.org/ns/wsdl/in-out" class="com.test.axis.ws.skeleton.UserServicesMessageReceiverInOut"/>
</messageReceivers>
<module ref="auditLogger"/>
<parameter name="ServiceClass">com.test.axis.ws.skeleton.UserServicesSkeleton</parameter>
<parameter name="useOriginalwsdl">true</parameter>
<parameter name="modifyUserWSDLPortAddress">true</parameter>
<operation name="authUser" mep="http://www.w3.org/ns/wsdl/in-out" namespace="http://axis.test.com/ws/service">
<actionMapping>urn:authUser</actionMapping>
<outputActionMapping>urn:authUserResp</outputActionMapping>
<faultActionMapping faultName="WebServiceFault">urn:authUserWebServiceFault</faultActionMapping>
</operation>
<operation name="getUserInfo" mep="http://www.w3.org/ns/wsdl/in-out" namespace="http://axis.test.com/ws/service">
<actionMapping>urn:getUserInfo</actionMapping>
<outputActionMapping>urn:getUserInfoResp</outputActionMapping>
<faultActionMapping faultName="WebServiceFault">urn:getUserInfoWebServiceFault</faultActionMapping>
</operation>
</service>
</serviceGroup>
5. deploy module to server.
copy the auditLog.mar file to %tomcat%\webapps\axis2\WEB-INF\modules
or create a folder %tomcat%\webapps\axis2\WEB-INF\modules\auditLog and put all necessary files inside.
<folder auditLog>
|- META-INF
MANIFEST.MF
module.xml
|- com\......\xx.class
6. modify axis2.xml
I am using axis2 v1.5.3. The configuration file axis2.xml of different axis2 version might be a bit different.
add the elements shown in red to axis2.xml
<!-- ================================================= -->
<!-- Phases -->
<!-- ================================================= -->
<phaseOrder type="InFlow">
<!-- System predefined phases -->
<phase name="Transport">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher">
<order phase="Transport"/>
</handler>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher">
<order phase="Transport"/>
</handler>
</phase>
<phase name="Addressing">
<handler name="AddressingBasedDispatcher"
class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
<order phase="Addressing"/>
</handler>
</phase>
<phase name="Security"/>
<phase name="PreDispatch"/>
<phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
<handler name="RequestURIOperationDispatcher"
class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
<handler name="SOAPMessageBodyBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
<handler name="HTTPLocationBasedDispatcher"
class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
<handler name="GenericProviderDispatcher"
class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
<handler name="MustUnderstandValidationDispatcher"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
</phase>
<phase name="RMPhase"/>
<!-- System predefined phases -->
<!-- After Postdispatch phase module author or service author can add any phase he want -->
<phase name="OperationInPhase">
<handler name="MustUnderstandChecker"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker">
<order phase="OperationInPhase"/>
</handler>
</phase>
<phase name="auditLogPhase"/>
<phase name="soapmonitorPhase"/>
</phaseOrder>
<phaseOrder type="OutFlow">
<!-- user can add his own phases to this area -->
<phase name="soapmonitorPhase"/>
<phase name="OperationOutPhase"/>
<phase name="auditLogPhase"/>
<!--system predefined phase-->
<!--these phase will run irrespective of the service-->
<phase name="RMPhase"/>
<phase name="PolicyDetermination"/>
<phase name="MessageOut"/>
<phase name="Security"/>
</phaseOrder>
<phaseOrder type="InFaultFlow">
<phase name="Addressing">
<handler name="AddressingBasedDispatcher"
class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
<order phase="Addressing"/>
</handler>
</phase>
<phase name="Security"/>
<phase name="PreDispatch"/>
<phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
<handler name="RequestURIBasedDispatcher"
class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
<handler name="SOAPActionBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
<handler name="RequestURIOperationDispatcher"
class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
<handler name="SOAPMessageBodyBasedDispatcher"
class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
<handler name="HTTPLocationBasedDispatcher"
class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
<handler name="GenericProviderDispatcher"
class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
<handler name="MustUnderstandValidationDispatcher"
class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
</phase>
<phase name="RMPhase"/>
<!-- user can add his own phases to this area -->
<phase name="OperationInFaultPhase"/>
<phase name="soapmonitorPhase"/>
</phaseOrder>
<phaseOrder type="OutFaultFlow">
<!-- user can add his own phases to this area -->
<phase name="soapmonitorPhase"/>
<phase name="OperationOutFaultPhase"/>
<phase name="RMPhase"/>
<phase name="PolicyDetermination"/>
<phase name="MessageOut"/>
<phase name="Security"/>
</phaseOrder>
7.test it. try to call one web service method mentioned in previous article. we can see soap message printed on tomcat console.
Request Message :<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:q0="http://axis.test.com/ws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body>
<q0:getUserInfo>
<q0:userId>aaaa</q0:userId>
</q0:getUserInfo>
</soapenv:Body></soapenv:Envelope>
Response Message :<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns2:getUserInfoResp xmlns:ns2="http://axis.test.com/ws"><ns2:return><ns1:age xmlns:ns1="http://bean.axis.test.com/xsd">22</ns1:age><ns1:userName xmlns:ns1="http://bean.axis.test.com/xsd">test name1</ns1:userName></ns2:return></ns2:getUserInfoResp></soapenv:Body></soapenv:Envelope>
Develop Web Service With Axis2 #3 - Custom Fault Message
Prev >>> Develop Web Service With Axis2 #2 - Work on Skeleton Code
public interface UserServices {
UserInfoResp getUserInfo(String userId) throws WebServiceFault;
UserInfoResp authUser(AuthUserReq authReq) throws WebServiceFault;
}
Take note:
All the methods in the interface class,which will be exposed to web service, throw WebServiceFault.
// ==== WebServiceFault.java =====
package com.test.axis.bean;
public class WebServiceFault extends Exception {
private String errCode;
private String errMessage;
// setter and getter methods
}
I want to respond an error code and an error description to web service consumer if something is wrong.
---- wsdl
<wsdl:operation name="getUserInfo">
<soap:operation soapAction="urn:getUserInfo" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="WebServiceFault">
<soap:fault use="literal" name="WebServiceFault"/>
</wsdl:fault>
</wsdl:operation>
---- skeleton code
public com.test.axis.ws.bean.GetUserInfoResp getUserInfo(
com.test.axis.ws.bean.GetUserInfo getUserInfo2)
throws WebServiceFault {
if (getUserInfo2== null || getUserInfo2.getUserId() == null) {
WebServiceFault fault = new WebServiceFault();
com.test.axis.ws.bean.WebServiceFaultE wsFaultE = new com.test.axis.ws.bean.WebServiceFaultE();
com.test.axis.ws.bean.xsd.WebServiceFault param = new com.test.axis.ws.bean.xsd.WebServiceFault();
param.setErrCode("Error Code 9999");
param.setErrMessage("Error Desc: parameter is Null.");
wsFaultE.setWebServiceFault(param);
fault.setFaultMessage(wsFaultE);
throw fault;
}
return null;
}
---- request soap
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://axis.test.com/ws" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:getUserInfo />
</soapenv:Body>
</soapenv:Envelope>
in this case, the request parameter is empty
--- response soap
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>WebServiceFault</faultstring>
<detail>
<ns2:WebServiceFault xmlns:ns2="http://axis.test.com/ws">
<ns2:WebServiceFault xmlns:ns1="http://bean.axis.test.com/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:WebServiceFault">
<ns1:errCode>Error Code 9999</ns1:errCode>
<ns1:errMessage>Error Desc: parameter is Null.</ns1:errMessage>
</ns2:WebServiceFault>
</ns2:WebServiceFault>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
from the elements in blue, we can see error code and message returned successfully.
----- stub code
try {
_stub.getUserInfo(new GetUserInfo());
} catch (RemoteException e) {
e.printStackTrace();
} catch (WebServiceFault e) {
// print the custom error code and error message
System.out.println(e.getFaultMessage().getWebServiceFault().getErrCode());
System.out.println(e.getFaultMessage().getWebServiceFault().getErrMessage());
}
------------------------------------------------------------
TODO:
a> consider to use the following elements to customize fault message
<faultcode>ABC</faultcode>
<faultstring>XYZ</faultstring>
<detail>Detail of Fault</detail>
I have not tried it out.
probably, the following reference websites will be helpful:
http://www.cnblogs.com/huqingyu/archive/2008/04/09/1145868.html
http://apps.hi.baidu.com/share/detail/23219236
http://hi.baidu.com/hero%CD%F5%E6%DD/blog/item/ad3b47107dc024c1f6039eb7.html
public interface UserServices {
UserInfoResp getUserInfo(String userId) throws WebServiceFault;
UserInfoResp authUser(AuthUserReq authReq) throws WebServiceFault;
}
Take note:
All the methods in the interface class,which will be exposed to web service, throw WebServiceFault.
// ==== WebServiceFault.java =====
package com.test.axis.bean;
public class WebServiceFault extends Exception {
private String errCode;
private String errMessage;
// setter and getter methods
}
I want to respond an error code and an error description to web service consumer if something is wrong.
---- wsdl
<wsdl:operation name="getUserInfo">
<soap:operation soapAction="urn:getUserInfo" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="WebServiceFault">
<soap:fault use="literal" name="WebServiceFault"/>
</wsdl:fault>
</wsdl:operation>
---- skeleton code
public com.test.axis.ws.bean.GetUserInfoResp getUserInfo(
com.test.axis.ws.bean.GetUserInfo getUserInfo2)
throws WebServiceFault {
if (getUserInfo2== null || getUserInfo2.getUserId() == null) {
WebServiceFault fault = new WebServiceFault();
com.test.axis.ws.bean.WebServiceFaultE wsFaultE = new com.test.axis.ws.bean.WebServiceFaultE();
com.test.axis.ws.bean.xsd.WebServiceFault param = new com.test.axis.ws.bean.xsd.WebServiceFault();
param.setErrCode("Error Code 9999");
param.setErrMessage("Error Desc: parameter is Null.");
wsFaultE.setWebServiceFault(param);
fault.setFaultMessage(wsFaultE);
throw fault;
}
return null;
}
---- request soap
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://axis.test.com/ws" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:getUserInfo />
</soapenv:Body>
</soapenv:Envelope>
in this case, the request parameter is empty
--- response soap
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>WebServiceFault</faultstring>
<detail>
<ns2:WebServiceFault xmlns:ns2="http://axis.test.com/ws">
<ns2:WebServiceFault xmlns:ns1="http://bean.axis.test.com/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:WebServiceFault">
<ns1:errCode>Error Code 9999</ns1:errCode>
<ns1:errMessage>Error Desc: parameter is Null.</ns1:errMessage>
</ns2:WebServiceFault>
</ns2:WebServiceFault>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
from the elements in blue, we can see error code and message returned successfully.
----- stub code
try {
_stub.getUserInfo(new GetUserInfo());
} catch (RemoteException e) {
e.printStackTrace();
} catch (WebServiceFault e) {
// print the custom error code and error message
System.out.println(e.getFaultMessage().getWebServiceFault().getErrCode());
System.out.println(e.getFaultMessage().getWebServiceFault().getErrMessage());
}
------------------------------------------------------------
TODO:
a> consider to use the following elements to customize fault message
<faultcode>ABC</faultcode>
<faultstring>XYZ</faultstring>
<detail>Detail of Fault</detail>
I have not tried it out.
probably, the following reference websites will be helpful:
http://www.cnblogs.com/huqingyu/archive/2008/04/09/1145868.html
http://apps.hi.baidu.com/share/detail/23219236
http://hi.baidu.com/hero%CD%F5%E6%DD/blog/item/ad3b47107dc024c1f6039eb7.html
Develop Web Service With Axis2 #2 - Work on Skeleton Code
Prev >>> Develop Web Service With Axis2 #1 - Start From Generating WSDL File
1. generate skeleton code based on WSDL file
WSDL2Java Reference
go to %testaxis1_folder% to run this command:
wsdl2java -uri resource\UserServices.wsdl -ss -sd -d adb -S .\src
-R .\resource\META-INF -ssi -p com.test.axis.ws.skeleton
-ns2p http://bean.axis.test.com/xsd=com.test.axis.ws.bean.xsd,http://axis.test.com/ws=com.test.axis.ws.bean
then, you will find
* all generated skeleton source code under this package com.test.axis.ws
* ant build file auto generated
* resource\META-INFO\services.xml and resource\META-INF\UserServices.wsdl
2. put all axis2 related jar files into your project build path.
3. complete your business logic in the skeleton class.
4. run task 'jar.server[default]' in the auto-generated build.xml,
then you can get UserServices.aar under folder %testaxis1_folder%\build\lib
5. deploy the aar file.
5.1 download axis2 war distribution.
5.2 deploy the war file to tomcat.
5.3 copy the aar file to %tomcat%\webapps\axis2\WEB-INF\services
or unzip the aar file and put the whole unzipped folder to %tomcat%\webapps\axis2\WEB-INF\services
6. write a client to call or use a tools to call the first method,you will see this response.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>Please implement com.test.axis.ws.skeleton.UserServicesSkeleton#getUserInfo</faultstring>
<detail />
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
=====================================
Consideration:
a> POJO style web service
http://axis.apache.org/axis2/java/core/docs/pojoguide.html
If your web service is very simple, not necessary to consider customized soap headers and fault, message level security,etc. POJO style web service is a nice choice.
b> JAX-WS style web serivce
http://axis.apache.org/axis2/java/core/docs/jaxws-guide.html
Both Axis2 and Metro support jax-ws API,which use annotation-based model to develop web service.
It seems current Axis2 is not ready to support WS-Security fully for JAX-WS, so I leave it aside first.
c> Data Binding
http://axis.apache.org/axis2/java/core/docs/adb/adb-howto.html
ADB is the data binding approach Axis2 suggests. The other ways are xmlbeans,jixb and jaxbri.
The skeleton and stub code will be different if you select different data binding as they adopt different approach to convert XML data to an object, or vice verse.
1. generate skeleton code based on WSDL file
WSDL2Java Reference
go to %testaxis1_folder% to run this command:
wsdl2java -uri resource\UserServices.wsdl -ss -sd -d adb -S .\src
-R .\resource\META-INF -ssi -p com.test.axis.ws.skeleton
-ns2p http://bean.axis.test.com/xsd=com.test.axis.ws.bean.xsd,http://axis.test.com/ws=com.test.axis.ws.bean
then, you will find
* all generated skeleton source code under this package com.test.axis.ws
* ant build file auto generated
* resource\META-INFO\services.xml and resource\META-INF\UserServices.wsdl
2. put all axis2 related jar files into your project build path.
3. complete your business logic in the skeleton class.
4. run task 'jar.server[default]' in the auto-generated build.xml,
then you can get UserServices.aar under folder %testaxis1_folder%\build\lib
5. deploy the aar file.
5.1 download axis2 war distribution.
5.2 deploy the war file to tomcat.
5.3 copy the aar file to %tomcat%\webapps\axis2\WEB-INF\services
or unzip the aar file and put the whole unzipped folder to %tomcat%\webapps\axis2\WEB-INF\services
6. write a client to call or use a tools to call the first method,you will see this response.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>Please implement com.test.axis.ws.skeleton.UserServicesSkeleton#getUserInfo</faultstring>
<detail />
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
=====================================
Consideration:
a> POJO style web service
http://axis.apache.org/axis2/java/core/docs/pojoguide.html
If your web service is very simple, not necessary to consider customized soap headers and fault, message level security,etc. POJO style web service is a nice choice.
b> JAX-WS style web serivce
http://axis.apache.org/axis2/java/core/docs/jaxws-guide.html
Both Axis2 and Metro support jax-ws API,which use annotation-based model to develop web service.
It seems current Axis2 is not ready to support WS-Security fully for JAX-WS, so I leave it aside first.
c> Data Binding
http://axis.apache.org/axis2/java/core/docs/adb/adb-howto.html
ADB is the data binding approach Axis2 suggests. The other ways are xmlbeans,jixb and jaxbri.
The skeleton and stub code will be different if you select different data binding as they adopt different approach to convert XML data to an object, or vice verse.
Develop Web Service With Axis2 #1 - Start From Generating WSDL File
- Contrast-First VS Code-First
Contract-first development style is to develop web services that start with the XML Schema/WSDL contract first followed by the Java code second.
Code-first development style is to generate web service contract,WSDL and XSD, based on the java code.
- WSDL Knowledge
learn it from
http://www.w3schools.com/wsdl/
http://www.w3school.com.cn/wsdl/index.asp
http://www.w3school.com.cn/schema/index.asp
- Code-First Style to generate WSDL file
1. download axis2 binary distribution.
2. configure environment variables.
If your OS is window vista, control panel - system - advanced system settings - tab 'advanced' - button 'Environment Variables...'
setup the following variables:
AXIS2_HOME= the folder of axis2
PATH = %AXIS2_HOME%\bin
3. create a java project in eclipse, let's say project name testaxis1.
4. define an interface class,which exposes all methods to web service.
package com.test.axis.service;
import com.test.axis.bean.AuthUserReq;
import com.test.axis.bean.UserInfoResp;
import com.test.axis.bean.WebServiceFault;
public interface UserServices {
UserInfoResp getUserInfo(String userId) throws WebServiceFault;
UserInfoResp authUser(AuthUserReq authReq) throws WebServiceFault;
}
5. complete its dependency classes as follows.
// ===== UserInfoResp.java ====
package com.test.axis.bean;
import java.util.Date;
public class UserInfoResp {
private String userName;
// setter and getter methods
}
// ===== AuthUserReq.java====
package com.test.axis.bean;
public class AuthUserReq{
private String userName;
private String password;
// setter and getter methods
}
// ==== WebServiceFault.java =====
package com.test.axis.bean;
public class WebServiceFault extends Exception {
private String errCode;
private String errMessage;
// setter and getter methods
}
6. generate wsdl file with tools java2wsdl.bat
Java2WSDL Reference
java2wsdl -cn com.test.axis.service.UserServices -o ..\resource -of UserServices.wsdl -tn http://axis.test.com/ws/service -stn http://axis.test.com/ws -dlb doc/lit
you will find the WSDL file at %testaxis1_folder%\resource\UserServices.wsdl
Axis2 can not detect the parameter name defined in java interface, but gives a parameter 'args0' instead. It is better to modify the wsdl file and make it meaningful.
so change
<xs:element minOccurs="0" name="args0" nillable="true" type="xs:string"/>
and change
<xs:element minOccurs="0" name="args0" nillable="true" type="ax21:AuthUserReq"/>
It is very troublesome to manually change the name like 'args0', how to do it better?
someone suggests to use -g while compiling the java code, please refer to
http://wso2.org/blog/sumedha/3727
It is not straightforward on my view.
* the xml elements in blue.
By default, axis2 set minOccurs="0" and nillable="true" for all fields. If based on your business logic, userName is mandatory and can not be Null, change the definition
<xs:element minOccurs="0" name="userName" nillable="true" type="xs:string"/>
to
<xs:element minOccurs="1" maxOccurs="1" name="userName" nillable="false" type="xs:string"/>
* -dlb doc/lit
This is a very good article to introduce the style of wsdl
http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/
--- Reference URLs
Contract-first development style is to develop web services that start with the XML Schema/WSDL contract first followed by the Java code second.
Code-first development style is to generate web service contract,WSDL and XSD, based on the java code.
- WSDL Knowledge
learn it from
http://www.w3schools.com/wsdl/
http://www.w3school.com.cn/wsdl/index.asp
http://www.w3school.com.cn/schema/index.asp
- Code-First Style to generate WSDL file
1. download axis2 binary distribution.
2. configure environment variables.
If your OS is window vista, control panel - system - advanced system settings - tab 'advanced' - button 'Environment Variables...'
setup the following variables:
AXIS2_HOME= the folder of axis2
PATH = %AXIS2_HOME%\bin
3. create a java project in eclipse, let's say project name testaxis1.
4. define an interface class,which exposes all methods to web service.
package com.test.axis.service;
import com.test.axis.bean.AuthUserReq;
import com.test.axis.bean.UserInfoResp;
import com.test.axis.bean.WebServiceFault;
public interface UserServices {
UserInfoResp getUserInfo(String userId) throws WebServiceFault;
UserInfoResp authUser(AuthUserReq authReq) throws WebServiceFault;
}
5. complete its dependency classes as follows.
// ===== UserInfoResp.java ====
package com.test.axis.bean;
import java.util.Date;
public class UserInfoResp {
private String userName;
// setter and getter methods
}
// ===== AuthUserReq.java====
package com.test.axis.bean;
public class AuthUserReq{
private String userName;
private String password;
// setter and getter methods
}
// ==== WebServiceFault.java =====
package com.test.axis.bean;
public class WebServiceFault extends Exception {
private String errCode;
private String errMessage;
// setter and getter methods
}
6. generate wsdl file with tools java2wsdl.bat
Java2WSDL Reference
go to %testaxis1_folder%\bin and run this command:
java2wsdl -cn com.test.axis.service.UserServices -o ..\resource -of UserServices.wsdl -tn http://axis.test.com/ws/service -stn http://axis.test.com/ws -dlb doc/lit
you will find the WSDL file at %testaxis1_folder%\resource\UserServices.wsdl
Take note
* the xml elements in red.Axis2 can not detect the parameter name defined in java interface, but gives a parameter 'args0' instead. It is better to modify the wsdl file and make it meaningful.
so change
<xs:element minOccurs="0" name="args0" nillable="true" type="xs:string"/>
to
<xs:element minOccurs="0" name="userId" nillable="true" type="xs:string"/>and change
<xs:element minOccurs="0" name="args0" nillable="true" type="ax21:AuthUserReq"/>
to
<xs:element minOccurs="0" name="authUserReq" nillable="true" type="ax21:AuthUserReq"/>It is very troublesome to manually change the name like 'args0', how to do it better?
someone suggests to use -g while compiling the java code, please refer to
http://wso2.org/blog/sumedha/3727
It is not straightforward on my view.
Actually, just remember DO NOT generate wsdl file based on an interface, based on an implement class instead, then axis2 can detect the real parameter name.
* the xml elements in blue.
By default, axis2 set minOccurs="0" and nillable="true" for all fields. If based on your business logic, userName is mandatory and can not be Null, change the definition
<xs:element minOccurs="0" name="userName" nillable="true" type="xs:string"/>
to
<xs:element minOccurs="1" maxOccurs="1" name="userName" nillable="false" type="xs:string"/>
* -dlb doc/lit
This is a very good article to introduce the style of wsdl
http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/
--- Reference URLs
http://www.keith-chapman.org/2008/10/axis2-wsdl2java-generate-better-code.html
Subscribe to:
Posts (Atom)