Showing posts with label Axis2. Show all posts
Showing posts with label Axis2. Show all posts

Thursday, March 5, 2009

Axis2 - First Element must contain the local name, Envelope

This Exception could occur on both the server side or the client side. This exception is thrown when trying to build the SOAP envelope from the response (or request in the case of server side). The server is expecting a SOAP response but it receives something else (That does not have a SOAP envelope).

The easiest way to resolve this issue is to use a tool such as TCPMonitor and monitor the request and response. That will help you diagnose where the problem is.

Wednesday, February 18, 2009

How does Apache Axis2 Differentiate SOAP from REST

Apache Axis2 supports both SOAP as well as REST. The default behaviour is that any service deployed on Axis2 can be accessed as using SOAP or REST style request. So how does Axis2 differentiate SOAP from REST request?

It first looks at the HTTP Method of the incoming request. If its GET, PUT or DELETE it is processed assuming its a REST request, but if its POST we need to do some checks. These include checking the content-type of the incoming request. SOAP 1.2 uses the content-type of application/soap+xml while SOAP 1.1 uses text/xml as its content-type. Hence using this we could differentiate SOAP request from REST style request. Does that mean that we are done? Well no. There is a little glitch though. The content-type text/xml is used to send REST (POX to be exact) style request as well. So if the content-type is text/xml we need to do further processing. The field we look for in such cases is the SOAPAction header. According to the SOAP 1.1 spec the SOAPAction header is mandatory (Its optional in SOAP 1.2 though). Therefore if a request comes in with the content-type text/xml that has a SOAPAction header it is treated as SOAP.

Axis2 - How to set the SOAP Version on a client

There may be instances where you want your Axis2 client to send request in a specific SOAP Version. Axis2 supports both SOAP 1.1 as well as SOAP 1.2. The default used is SOAP 1.2.

Setting the SOAP version can be done as follows, for SOAP 1.1
serviceClient.getOptions().setSoapVersionURI(org.apache.axiom.soap.SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);

for SOAP 1.2
serviceClient.getOptions().setSoapVersionURI(org.apache.axiom.soap.SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);

Monday, February 9, 2009

Axis2 - ADBException: Unexpected subelement

This is another common issue that Apache Axis2 users face.

org.apache.axis2.AxisFault: org.apache.axis2.databinding.
ADBException: Unexpected subelement someElementName

Again the solution to this is simple. This exception could occur when a request is been sent (Before the request is sent) or when a response is arrived (Or alternatively it could occur on the server side when a request is received). Therefore it makes life easy to know where things really went wrong. And again TCPMonitor comes to the rescue. Simply send your request through TCPMonitor. This will help you diagnose whether the exception was thrown when sending the request or receiving the response.

Now lets figure out why this exception could occur. When a stub (or Skeleton) is generated using adb as the data binding framework (If no option (-d) is provided for the databinding framework Axis2 uses adb by default) it performs validation on the request it sends and the response it receives. The validation is performed based on the XML Schema for the request or response message. Hence if a response is to have three elements named a,b,c in a sequence and the response contains somethinglike a,d,c Axis2 would complain saying that it received an Unexpected element named d.

So this issue can be solved easily by comparing the request/response messages against the Schema that defines those messages. This could be tricky sometimes especially if you are not familiar with XML Schema.

This error could occur when there are namespace mismatches as well and spoting these could proove to be tricky as as a user found out over here.

Axis2 - The endpoint reference (EPR) for the Operation not found

Well if you've ever used Apache Axis2, I'm sure you would have faced this at some time or another.

The endpoint reference (EPR) for the
Operation not found is http://localhost:8080/services/someService
and the WSA Action = someAction

There has been a number of occasions where this question has been asked on the Axis2 mailing list as well. The answer to this is pretty simple though (Simple for someone who knows a bit of Axis2).

This exception simply means that Axis2 could not find the service and the operation that this request is headed to.

Several services can be hosted in Axis2, and these services could have several operations. Hence when Axis2 gets a request it should first search for the service and then the operation that the request is headed to. In Order to achieve this it uses some hints. This article from Chinthaka explains these in detail.

So if you hit this problem my advice is this. Try using TCPMonitor to intercept the request going into Axis2, have a look at it and make sure that the request contains some information that Axis2 could use to dispatch the request to the correct service and operation.

Saturday, January 17, 2009

WSO2 Carbon & Axis2 Cluster Configuration Guide

Clustering for high availability and scalability is one of the main requirements of any enterprise deployment. Afkham Azeez, Architect and Product Manager of WSO2 WSAS has written a couple of articles that explain how WSO2 Carbon based products (This articles apply to Apache Axis2 as well) can be clustered.

In the first article titled "Introduction to WSO2 Carbon Clustering" he explains the core concepts of clustering an in the second article titled "WSO2 Carbon Cluster Configuration Language" he explains in detail as to how WSO2 Carbon based products can be clustered.

Tuesday, October 14, 2008

How to Embed Axis2 into a Existing Web Application

This article by Deepal explains how you could embed Axis2 into a Existing Web Application. Its pretty straight forward and simple. Its a good resource for anyone who is trying to expose web services out of an existing web app.

Wednesday, October 8, 2008

Apache Axis2 Tips and Tricks

Recently I've been blogging extensively on some tips and tricks related to Apache Axis2. Here's a summary of them,

Axis2 - Setting the HTTP Method when sending request

Apache Axis2 supports sending (and receiving) requests over GET, POST, PUT and DELETE. This can be done by setting the "Constants.Configuration.HTTP_METHOD" property on the options object. If the HTTP Method is not set explicitly then it defaults to POST.

Most often that not when changing the HTTP Method you may want to change the serialization format as well. This can be done by setting the "Constants.Configuration.MESSAGE_TYPE" property on the options object (You can change the Serialization format even without changing the HTTP Method. For e.g Send a POX message via POST).

The following code Snippet shows how to send a message as "application/x-www-form-urlencoded" over GET.

options.setProperty(Constants.Configuration.HTTP_METHOD,HTTPConstants.HTTP_METHOD_GET);
options.setProperty(Constants.Configuration.MESSAGE_TYPE,HTTPConstants.MEDIA_TYPE_X_WWW_FORM);

Tuesday, October 7, 2008

Axis2 - Adding custom SOAP Headers to a request using ServiceClient

The Axis2 ServiceClient API provides three main ways of adding SOAP Headers to a request. Lets take a look at how this could be done,

  • Add a simple header which contains a String to the request


serviceClient.addStringHeader(new QName("http://wso2.org", "ThirdHeader"), "This is a sample Header");

This is the simplest method of adding a header. But this method restricts you to simple String headers.

  • Creating a header as a OMElement and adding it to the request


OMElement firstHeader = AXIOMUtil.stringToOM(
"This is a sample Header");
serviceClient.addHeader(firstHeader);

Users are expected to create the complete header themselves using Axiom's OMElement APIs.

  • Creating a header as a SOAPHeaderBlock and adding it to the request


OMNamespace omNamespace =
OMAbstractFactory.getOMFactory().createOMNamespace("http://wso2.com", "ws");
SOAPHeaderBlock secondHeader = OMAbstractFactory.getSOAP12Factory().createSOAPHeaderBlock("SecondHeader", omNamespace);
secondHeader.addChild(AXIOMUtil.stringToOM("This is a sample Header"));
//secondHeader.setMustUnderstand(true);
serviceClient.addHeader(secondHeader);

Users are expected to create the header using Axiom's SOAP APIs. Users could use the API to set various options on the header such as the MustUnderstand Attribute.

Monday, October 6, 2008

Axiom - How to create a OMElement from a String

If someone is using Axis2's ServiceClient to send a request to a service they will have to deal with OMElements. That is because ServiceClient accepts the payload as a OMElement. Using Axiom API's to create this OMElement could be time consuming and may take several lines of code. Alternatively users could create this OMElement from a String as follows,

OMElement payload = AXIOMUtil.stringToOM("Hi! This is a sample Request.");

This utility method that comes with Axiom takes in a String as the argument and returns an OMElement.

Axis2 - Setting custom HTTP Headers on a response

There may be instances where users would want to add a custom HTTP header to the response message in Apache Axis2. The following shows how this could be achieved,

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 method could be used to add multiple headers to the response message. This also should how a service could get hold of the response message context.

Friday, October 3, 2008

How to run Axis2 behind a proxy and Bypass the Proxy for some Domains

I'm sure some of you might already know how to set proxy details in Axis2. Even nandana had blogged about it some time ago. For those who are not familiar with it here is how you could do it. You need to add the following parameter into your clients axis2.xml,

<parameter name="Proxy">

<Configuration>

<ProxyHost>proxy.wso2.org</ProxyHost>

<ProxyPort>5678</ProxyPort>

<ProxyUser>EXAMPLE\keith</ProxyUser>

<ProxyPassword>keithsPassword</ProxyPassword>

</Configuration>

</parameter>

There may be instances where you do not want some request to go through the proxy. For e.g lets imaging you do not want to go through the proxy on a localhost call or when you are calling foo.com. Is it possible to do this? Of course and you could do it by adding the following system property "http.nonProxyHosts",

-Dhttp.nonProxyHosts=localhost|foo.com

The http.nonProxyHosts can be set to specify the hosts which should be connected to directly (not through the proxy server). The value of the http.nonProxyHosts property can be a list of hosts, each separated by | (the pipe character). It can also take a regular expression for matches for example: *.sfbay.sun.com would match any fully qualified hostname in the sfbay domain.

For more information you could refer http://java.sun.com/features/2002/11/hilevel_network.html.

Thursday, October 2, 2008

Axis2 - Calling a Service which is Protected by HTTP Basic Authentication

If you need to call a service which is protected using HTTP Basic Authentication with Apache Axis2, then you could do so by setting the following property on the options object.

HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
authenticator.setUsername("keith");
authenticator.setPassword("keith");
authenticator.setPreemptiveAuthentication(true);
options.setProperty(HTTPConstants.AUTHENTICATE, authenticator);

If you are using a generated stub you could get hold of the options object as,

stub._serviceClient.getOptions();

Axis2 wsdl2java - Generate Better Code with -uw

This is a question asked regularly on the axis-user list. "Code generated by the wsdl2java tool is hard to use. Is there any better way that I can generate code?".

The answer to this is that you could actually use wsdl2java to generate better code. Lets take an example scenario. For this I will be using a Service that I have deployed on Mooshup.com. This simple service has a operation called demo which accepts three parameters (firstParam, secondParam and thirdParam). I will be using the wsdl of this service for explanation. Lets first try to use wsdl2java on this wsdl and see what happens and how -uw can help.

If i was to generate a stub for this using the following command,

sh wsdl2java.sh -uri http://mooshup.com/services/keith/DemoService?wsdl -o /home/keith/projects/demo

I would have to use this stub as follows,

DemoServiceStub stub = new DemoServiceStub();
DemoServiceStub.Demo demo = new DemoServiceStub.Demo();
DemoServiceStub.DemoType demoType = new DemoServiceStub.DemoType();
demo.setDemo(demoType);
demoType.setFirstParam("firstParam");
demoType.setSecondParam(10.0);
demoType.setThirdParam(true);
stub.demo(demo);

Now this does not look too elegant, but if I were to generate code using the -uw option with the following command,

sh wsdl2java.sh -uri http://mooshup.com/services/keith/DemoService?wsdl -o /home/keith/projects/demo -uw

I would be able to use the stub as,

DemoServiceStub stub = new DemoServiceStub();
stub.demo("firstParam", 20.0, true);

Now what is more elegant and easier? Its a easy answer.

The secret to this lies in the schema. You wont be able to generate easy to use stubs such as this all the time. What gets unwrapped (when -uw is used) is the sequence within the complex type. In our case the schema was as follows,


<xs:complexType name="demoType">

<xs:sequence>

<xs:element name="firstParam" type="xs:string" />

<xs:element name="secondParam" type="xs:double" />

<xs:element name="thirdParam" type="xs:boolean" />

</xs:sequence>

</xs:complexType>

<xs:element name="demo" type="ws:demoType" />



So the bottom line is use the -uw option when generating code with wsdl2java, this would generate code that is easy to use. (This should have been the default in wsdl2java ;))

Most users are not aware of the set of options that wsdl2java offer (Will cover that in another post).

Monday, September 29, 2008

Apache Axis2 Changing the Content-type of the Response

There are a couple of mechanisms that can be used to change the content-type of the response in Apache Axis2. They are,
  • Using HTTP Content Negotiation. Please refer HTTP Content Negotiation with Apache Axis2 for details.
  • Changing the content-type of the response explicitly by setting it to the response message context as follows,
      MessageContext messageContext = MessageContext.getCurrentMessageContext();
OperationContext operationContext = messageContext.getOperationContext();
MessageContext outMessageContext = operationContext.getMessageContext(
WSDL2Constants.MESSAGE_LABEL_OUT);
// responseFormat is the content type of the outgoing message
outMessageContext.setProperty(Constants.Configuration.MESSAGE_TYPE, responseFormat);

Friday, September 26, 2008

RESTful Web Services with Apache Axis2

RESTful Web Services with Apache Axis2 is powered by the WSDL 2.0 HTTPBinding, hence as of now (1.4.1 release of Axis2) users need to deploy there services using WSDL 2.0 to write truly RESTfull services in Axis2. I agree that there aren't too many people who are familiar with WSDL 2.0. Therefore I put together an article that helps you through the process of taking your Java code, generating a WSDL 2.0 from it and hand editing it to suit your needs. The article "RESTful Web Services with Apache Axis2" is now available on the WSO2 oxygen tank.

I plan on making it simpler to author RESTfull services in Axis2 in future.

Axis2 & Rampart - Access Username used for Authentication in a Web Service

Nandana in his blog post has explained how you could do this (Axis2 & Rampart - Access Username used for Authentication in a Web Service) with the latest Rampart code. But if you are using Rampart 1.4 that method will not work. Those users can use the following method,

MessageContext msgCtx = MessageContext.getCurrentMessageContext();

Vector results = (Vector) msgCtx
.getProperty(WSHandlerConstants.RECV_RESULTS);

if (results != null) {

WSHandlerResult result = (WSHandlerResult) results.get(0);
WSSecurityEngineResult wsSecurityEngineResult =
(WSSecurityEngineResult) result.getResults().get(1);
String username =
((Principal) wsSecurityEngineResult.get(WSSecurityEngineResult.TAG_PRINCIPAL))
.getName();
}

Thursday, September 25, 2008

Enabling JSON in Apache Axis2

Apache Axis2 can handle several message formats. JSON is just one of them. Axis2 supports two notations of JSON, they are known as mapped and Badgerfish. Namespaces are not handled in the mapped notation while the Badgerfish notations supports it.

The default Axis2 installation has all the binaries needed to process JSON messages but you need to enable it in order to use JSON. This can be done by adding the following sections to your axis2.xml.

Add the following section to the messageFormatters section in the axis2.xml,

<messageFormatter contentType="application/json"

class="org.apache.axis2.json.JSONMessageFormatter"/>

<messageFormatter contentType="application/json/badgerfish"

class="org.apache.axis2.json.JSONBadgerfishMessageFormatter"/>

<messageFormatter contentType="text/javascript"

class="org.apache.axis2.json.JSONMessageFormatter"/>

And the following to the messageBuilders section of the axis2.xml

<messageBuilder contentType="application/json"

class="org.apache.axis2.json.JSONOMBuilder"/>

<messageBuilder contentType="application/json/badgerfish"

class="org.apache.axis2.json.JSONBadgerfishOMBuilder"/>

<messageBuilder contentType="text/javascript"

class="org.apache.axis2.json.JSONOMBuilder"/>

Now you are all set to invoke services as well as respond using JSON. You would notice that the notation of JSON used depends on the content-type of the message.

HTTP Content Negotiation with Apache Axis2

Since the 1.3 release of Axis2, it supports HTTP Content Negotiation. It is not turned on by default but can be done so by adding the following parameter to your axis2.xml.

<parameter name="httpContentNegotiation">true</parameter>

Axis2 does not honor the content-type text/xml when its in the Accept Header. This is because the content-type text/xml is primarily used for SOAP 1.1 but when a request is sent via the browser it has the Accept header as "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 ". If we were to honor text/xml this would result in a SOAP 1.1 response. Not too good for a REST scenario ha! This is the result of the same content-type (text/xml) been used for two message formats (SOAP 1.1 and POX).

Now lets get back to HTTP Content Negotiation with Apache Axis2. Performing a GET request on the version service would result in the following request and response. You could capture them by using TCPMonitor.


Now try editing the Accept header to "application/json/badgerfish". You should have enabled JSON support for this to work. This would result in,


A blog post on how to enable JSON on Axis2 will follow. This configuration can be used to enable HTTP Content Negotiation on WSO2 WSAS as well as the Mashup Server. It should work with Synapse and the WSO2 ESB too but I haven't checked it.