Wednesday, November 18, 2009

Use Basic Types for Web Services

Today I encountered the following error message:

org.apache.axis2.databinding.ADBException: Any type element type has not been given

I have defined my Web Service code as follows:

public ArrayList ListNamesService();

When you generate the WSDL using wsdl2java, it creates a data type called, "anyType", which is WSDL's way of saying you'll be passing through an Object (of some indeterminate type). This generates the above runtime error.

The solution is to do this:

public String[] ListNamesService();

which may seem archaic given the Java Collections classes, but at least an array of Strings is compatible across all platforms (which is a great benefit). So, aside from getting the error messages to go away, use basic types for Web Services.

Tuesday, November 17, 2009

It's the CLASSPATH, stupid!

I've been tearing my hair out for the past two days struggling with the Apache Axis2 Web Services engine. After having had figured out how to integrate Axis2 with Tomcat (see prior blog), the next step involved writing a client to access the Web Service, then integrating that functionality into a servlet.

First off, follow this tutorial.

Following are my tips for getting it done the easy way. Note, I'm sure server administrators will cringe when they see some of my solutions but I'm only looking to prove out the code. This is a development setup on my home computer. 'nuff said.
  1. Create a separate project for your Web App (UI, servlets), each Web Service, and each prototype Client code.
  2. Getting the Web Service to work is easy: follow steps 1 through 4 of the tutorial.
  3. When going through step 5 (generating Java code from the WSDL), set the destination directory to your Client project /src directory. Note: the generated package name is "org.apache.ws.axis2". At first I thought this was a bug and it was the single biggest source of my headaches.
  4. In the client project, make 100% certain you've added every-single-jar in $AXIS_HOME/lib to your project CLASSPATH (Project > Properties > Libraries > Add External JARs...). If the Eclipse auto-compiler stops complaining about your imports, you're good to go.
  5. Compile your Client project. Note, in the tutorial, you run your test program at this point and it "just works". That's BS because they took a serious shortcut by putting the Client code in the same package as the Stub code. In real applications, you won't have that luxury. Package the resulting classes using "jar cvf MyJar.jar org". You will need to be in the /bin directory of your client project for this to work correctly.
  6. At this point, you can compile and run your servlet, but you'll get a run-time error. This is because the Tomcat servlet runtime does not have the same CLASSPATH as what you've configured in Eclipse. This is the key point that took me days to discover
  7. Copy that JAR file to $TOMCAT_HOME/lib (yes, you heard correctly... just do it... it works)
  8. Copy all JAR files in $AXIS_HOME/lib to $TOMCAT_HOME/lib (sacrilege!). If it makes you feel better, make a copy of the $TOMCAT_HOME/lib directory before making any changes.
Instead of steps 7 and 8, you can modify the CLASSPATH of the Tomcat servlet runtime. However, I don't know how to do that and was pretty burnt out of the topic by the time I'd figured out the workaround...

It should "just work" now.

Sunday, November 8, 2009

No Targets Available for the Android SDK

The Android SDK uses an integer to identify the minimum SDK version for which your application is compiled. Without it, older versions of the Android OS could attempt to launch a program written for a newer version of Android and it might not be pretty.

When you first install the Android SDK (version 2.0 pre-release) and the Eclipse ADT, then attempt to create a new Android Project, you might see this warning: "Error: Target id is not valid. Use 'android list targets' to get the target ids". Following this instruction leads you to find that no target SDKs have been installed.

I believe Googled has packaged the 2.0 release to be an upgrade to the 1.6 release. However, they don't make that notion clear one way or the other. My solution? Skip it, go to the SDK v1.6 download page and get that instead. This becomes really obvious if you examine the size of the tarballs (2.0 = 24Mb, 1.6 = 573Mb).

Thursday, November 5, 2009

Getting Apache Axis2 to work from within a Tomcat servlet engine

I generally prefer to have my application services hosted from a single source. It seems like overkill to have an Apache server (port 80) a Tomcat servlet engine (port 8080), and an Axis2 Web Services server (also on port 8080). What's even crazier is that all three servers come from the Apache Foundation yet getting them to cooperate can be much more troublesome than you'd expect.

I successfully installed Axis2 using these instructions, which worked well up to and including "Building a Standalone Server". The one caveat being that you need to remember to stop Tomcat:

sudo /etc/init.d/tomcat6 stop

because the Axis2 server is configured to run on port 8080 by default. You could change the port by editing $AXIS2_HOME/conf/axis2.xml... but the instructions don't tell you that. I figured it out on my own.

Moving on... so now I want to run the Axis2 Web Services engine within my servlet context. In other words, I want Tomcat to delegate WS calls to Axis2. The instruction for doing this is to copy the axis2.war file into the webapps directory of Tomcat. Here's the kicker: There are TWO webapps directories! One is located in TOMCAT_HOME (which, on Ubuntu is /usr/share/tomcat6) and the other is located in TOMCAT_BASE (which is /var/lib/tomcat6). The latter is the correct location btw.

If this worked correctly, Tomcat will expand the axis2.war file into a directory structure starting with TOMCAT_BASE/webapps/axis2/.

At this point, the above instruction set said I supposed to see the Axis page magically via Tomcat but what I saw was an HTTP 500 error indicating something about permissions. After some Googling, I found this forum, the final post contained the solution to the last roadblock: to disable TOMCAT6_SECURITY.

It now works, and you get the Axis2 "Happiness Page" as originally indicated in the instructions. Barf.