My Environment:
JDK v1.6.x
Axis2 V1.5.4
Weblogic v1.03
1) add 'user'/'user group' in weblogic
login weblogic server administration console
select 'Security Realms' under domain structure on the left of admin console page
click 'myrealm' which is the default realm name in weblogic,and open configuration 'Settings for myrealm'
click tab 'Users and Groups' to add user and user group
click sub-tab 'Groups' first to add one new group
click sub-tab 'Users', and click 'New' button to add new user and key in password here as well.
click the user name which was created above hyperlink, and select 'Groups' tab to assign the user to the user group created above
2) add configuration shown below in web.xml
<security-constraint>
<web-resource-collection>
<web-resource-name>mywsapi</web-resource-name>
<url-pattern>/services/{your service name}</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>{user name configured in Weblogic}</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>myrealm</realm-name> <-- this is the default realm name in weblogic
</login-config>
<security-role>
<role-name>{user name configured in Weblogic}</role-name>
</security-role>
3) add configuration shown below in weblogic.xml
<security-role-assignment>
<role-name>{user name configured in Weblogic}</role-name>
<principal-name>{user group configured in Weblogic}</principal-name>
</security-role-assignment>
4) on stub side, you need to do more to pass user name and password as follows.
Options opt = _stub._getServiceClient().getOptions();
HttpTransportProperties.Authenticator mbAuth = new HttpTransportProperties.Authenticator();
mbAuth.setUsername("{user name configured in weblogic}");
mbAuth.setPassword("{password configured in weblogic}");
mbAuth.setPreemptiveAuthentication(true);
opt.setProperty(HTTPConstants.AUTHENTICATE, mbAuth);
_stub._getServiceClient().setOptions(opt);
Friday, January 21, 2011
Tuesday, January 11, 2011
Develop Web Service With Axis2 #8 - Troubleshooting while working with Axis2
My Environment:
JDK v1.6.x
Axis2 v1.5.4
Ant v1.7.1
Hibernate v3.3.1
Tomcat v6.0.26
Weblogic v1.03
1) tomcat can not start up properly if deploy axis2 project to tomcat
I got the errors as follows
SEVERE: Error in dependencyCheck
java.util.zip.ZipException: invalid bit length repeat
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:147)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:146)
or
Jan 9, 2011 7:35:42 PM org.apache.catalina.core.StandardContext start
SEVERE: Error in dependencyCheck
java.util.zip.ZipException: too many length or distance symbols
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:147)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:146)
or
org.apache.axis2.deployment.DeploymentException: A ClassNotFoundException error occurred in loading the message receiver
Solution:
You must follow up the build.xml provided by axis2 strictly if you write your own build.xml
For example,
<copy todir="${build.dist.dir}/WEB-INF/lib" filtering="true" overwrite="yes">
if filtering="true", the jar file will be not unzipped properly if pack in war file.
2) can not load hibernate
My .aar structure is as follows
.aar
/com --- classes files
/lib --- hibernate jar files and other the 3rd jar files
/META-INF
hibernate.cfg.xml
log4j.properties
in services.xml, add the following configuration
<parameter name="ServiceTCCL">composite</parameter>
if using this configuration, axis2 will load jar files under lib folder inside aar
3) log4j
Finally, I found if put log4j.properties in aar, it will not work, the correct location is %WAR%\WEB-INF\classes
4) jar conflict if deploying to weblogic
These are well-known exceptions if deloying axis2 project into weblogic.
org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken
Solution:
*change the war file struecture
WAR
|- axis2-web
|- WEB-INF
|- classes
|- com/xxx Here is your DAO, business classes, utils,etc
log4j.properties
hibernate.cfg.xml
your own other properties
|- conf
axis2.xml
|- lib
all axis2-related jar files
log4j-related jar files
hibernate-related jar files
other 3rd party jar files
|- modules
|- services
yourservice.aar Only inlcude skeleton classes here, almost generated by axis2
com/...../xxxMessageReceiverInOut.class
com/...../xxxSkeleton.class
META-INF\services.xml
META-INF\wsdl.list
META-INF\xxxx.wsdl
web.xml
weblogic.xml
* in weblogic.xml, should configure
<container-descriptor>
<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>
* in hibernate.cfg.xml, it is not necessary to configure 'hibernate.query.factory_class'
there is a jar ANTLR conflict between hibernate v3.x and weblogic, so someone suggests to configure explicitly 'hibernate.query.factory_class'
for hibernate v3.x query translator,
hibernate.query.factory_class= org.hibernate.hql.ast.ASTQueryTranslatorFactory
for hibernate v2.x query translator
hibernate.query.factory_class= org.hibernate.hql.classic.ClassicQueryTranslatorFactory
It is NOT necessary to do so.
<prefer-web-inf-classes> will ensure weblogic load %WAR%\WEB-INF\lib , let hibernate auto-choose which query translator to use.
5) can not find aar/mar file if deploying to weblogic
need to add aar file name, or mar file name in \services\services.list and \mrodules\modules.list
6) cannot show custom WSDL file, always show auto-generated WSDL file
in your own .aar\META-INF folder to add a file named wsdl.list , and put your wsdl file name in it.
in services.xml , <parameter name="useOriginalwsdl">true</parameter>
7) xerces jar file conflict if deploying to weblogic
java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.xerces.dom.ElementImpl.getSchemaTypeInfo()Lorg/w3c/dom/TypeInfo;" the class loader (instance of weblogic/utils/classloaders/ChangeAwareClassLoader) of the current class, org/apache/xerces/dom/ElementImpl, and the class loader (instance of <bootloader>) for interface org/w3c/dom
/Element have different Class objects for the type org/w3c/dom/TypeInfo used in the signature
Solution: remove xercesImpl-2.8.1.jar from axis2\WEB-INF\lib
JDK v1.6.x
Axis2 v1.5.4
Ant v1.7.1
Hibernate v3.3.1
Tomcat v6.0.26
Weblogic v1.03
1) tomcat can not start up properly if deploy axis2 project to tomcat
I got the errors as follows
SEVERE: Error in dependencyCheck
java.util.zip.ZipException: invalid bit length repeat
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:147)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:146)
or
Jan 9, 2011 7:35:42 PM org.apache.catalina.core.StandardContext start
SEVERE: Error in dependencyCheck
java.util.zip.ZipException: too many length or distance symbols
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:147)
at java.util.zip.ZipInputStream.read(ZipInputStream.java:146)
or
org.apache.axis2.deployment.DeploymentException: A ClassNotFoundException error occurred in loading the message receiver
Solution:
You must follow up the build.xml provided by axis2 strictly if you write your own build.xml
For example,
<copy todir="${build.dist.dir}/WEB-INF/lib" filtering="true" overwrite="yes">
if filtering="true", the jar file will be not unzipped properly if pack in war file.
2) can not load hibernate
My .aar structure is as follows
.aar
/com --- classes files
/lib --- hibernate jar files and other the 3rd jar files
/META-INF
hibernate.cfg.xml
log4j.properties
in services.xml, add the following configuration
<parameter name="ServiceTCCL">composite</parameter>
if using this configuration, axis2 will load jar files under lib folder inside aar
3) log4j
Finally, I found if put log4j.properties in aar, it will not work, the correct location is %WAR%\WEB-INF\classes
4) jar conflict if deploying to weblogic
These are well-known exceptions if deloying axis2 project into weblogic.
org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken
Solution:
*change the war file struecture
WAR
|- axis2-web
|- WEB-INF
|- classes
|- com/xxx Here is your DAO, business classes, utils,etc
log4j.properties
hibernate.cfg.xml
your own other properties
|- conf
axis2.xml
|- lib
all axis2-related jar files
log4j-related jar files
hibernate-related jar files
other 3rd party jar files
|- modules
|- services
yourservice.aar Only inlcude skeleton classes here, almost generated by axis2
com/...../xxxMessageReceiverInOut.class
com/...../xxxSkeleton.class
META-INF\services.xml
META-INF\wsdl.list
META-INF\xxxx.wsdl
web.xml
weblogic.xml
* in weblogic.xml, should configure
<container-descriptor>
<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>
* in hibernate.cfg.xml, it is not necessary to configure 'hibernate.query.factory_class'
there is a jar ANTLR conflict between hibernate v3.x and weblogic, so someone suggests to configure explicitly 'hibernate.query.factory_class'
for hibernate v3.x query translator,
hibernate.query.factory_class= org.hibernate.hql.ast.ASTQueryTranslatorFactory
for hibernate v2.x query translator
hibernate.query.factory_class= org.hibernate.hql.classic.ClassicQueryTranslatorFactory
It is NOT necessary to do so.
<prefer-web-inf-classes> will ensure weblogic load %WAR%\WEB-INF\lib , let hibernate auto-choose which query translator to use.
5) can not find aar/mar file if deploying to weblogic
need to add aar file name, or mar file name in \services\services.list and \mrodules\modules.list
6) cannot show custom WSDL file, always show auto-generated WSDL file
in your own .aar\META-INF folder to add a file named wsdl.list , and put your wsdl file name in it.
in services.xml , <parameter name="useOriginalwsdl">true</parameter>
7) xerces jar file conflict if deploying to weblogic
java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.xerces.dom.ElementImpl.getSchemaTypeInfo()Lorg/w3c/dom/TypeInfo;" the class loader (instance of weblogic/utils/classloaders/ChangeAwareClassLoader) of the current class, org/apache/xerces/dom/ElementImpl, and the class loader (instance of <bootloader>) for interface org/w3c/dom
/Element have different Class objects for the type org/w3c/dom/TypeInfo used in the signature
Solution: remove xercesImpl-2.8.1.jar from axis2\WEB-INF\lib
Tuesday, January 4, 2011
Develop Web Service With Axis2 #7 - Add Custom Soap Header in Response Soap Message
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);
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);
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)