Showing posts with label Axis. Show all posts
Showing posts with label Axis. Show all posts

Friday, March 02, 2007

Apache Axis and Commons HTTPClient

Someone asked me how they could turn on NT Authentication for web service using Apache Axis (the web service used by ColdFusion). By default Axis uses its own HTTP client code, org.apache.axis.transport.http.HTTPSender, to send the XML/SOAP POST requests to a web service. This uses HTTP 1.0 and generally works file.

Axis also supports the Jakarta Commons HTTPClient library, and has since 1.0. To configure Axis to use this instead of its own library you must edit the client-config.wsdd file used by Axis. It gets found on the classpath and generally you don't actually have one and the one built in to axis.jar gets used.
The interesting line is the http transport. To switch Axis to use the HTTPClient jar, you would change this:

<transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"></transport>

To this:

<transport name="http" pivot="java:org.apache.axis.transport.http.CommonsHTTPSender"></transport>

Once you have this code configured, Axis will use the HTTPClient library for it HTTP needs. Since the HTTPClient library supports NT Authentication, you just set the username/password on the Stub object as you would normally do for (say) Basic Authentication and it will just work. If you are talking to a .NET web service, you are done.

BUT switching the line in the client-config.wsdd file alone doesn't do the trick if you are talking to a ColdFusion web service. Talking to a ColdFusion web service via Apache, you will get an "411 - length required" error back that looks like this:

The Apache JRun connector doesn't allow chunked encoding without a content length (generally true for all general pupose connectors, including mod_python) and the CommonsHTTPSender class in Axis does not provide a content-length. Go figure.
Using the built-in JRun web server you get a a "content not allowed in prolog" error because it appears the JRun web service doesn't understand chunked transfer encoding. Go figure again.
I didn't try it with IIS. My guess it that it might work.
To solution? Turn off the chunked encoding, which you can do by setting a property on the web service object in CFML like this:

ws = CreateObject("webservice", "http://localhost/ws/service.cfc?wsdl");
httpheaders = CreateObject("java", "java.util.Hashtable").init();
httpheaders.put("chunked", "false");
ws._setProperty("HTTP-Request-Headers", httpheaders);
result= ws.myOperation();

The Apache code wants a Hashtable, where it should just look for a Map, so you can't just use a CFML structure for the value of the HTTP-Request-Headers.


Friday, December 02, 2005

Changing the target endpoint on a web service object

Just answered a question for a customer that I should probably get out into the googlesphere for others to know.

When you create a web service object in ColdFusion MX, what you are really creating is a Java object that acts as a proxy to the web service. This object derives from an Apache Axis type, org.apache.axis.client.Stub, which in turn implements the standard JAX-RPC type javax.xml.rpc.Stub. Why is this important? Well, these object have an API that you can use to affect the operation of the proxy.

Specifically, you can change the endpoint that the stub will send the HTTP POST that contains the SOAP request. Here is a code snippet that invokes a CFC web service named service.cfc that has an operation "echo" which takes a string and returns it.

ws = CreateObject("webservice", "http://localhost:8500/service.cfc?WSDL");
ret = ws.echo("hello world");


Now lets say we want to watch the request with tcpmon, the TCP/HTTP sniffer that is bundled in with Axis, JRun and ColdFusion. First we start up tcpmon (called 'sniffer' by JRun), on Windows you run c:/CFusionMX7/runtime/bin/sniffer.exe.

Fill in a listener port (try 8501) and then a target hostname (localhost) and port (8500 if CF is running its internal webserver, or port 80 if you are running a standard web server). Click the "Add" button and then switch to the "Port 8501" tab. Just to make the output look nice, check the "XML Format" check box at the bottom so tcpmon will make the SOAP more readable.

Now we can run this CFML cfscript snippet:


ws._setProperty("javax.xml.rpc.service.endpoint.address", "http://localhost:8501/service.cfc");
ret = ws.echo("Through the tunnel");


You will see the SOAP request in the to pane, and the response in the bottom pane.

How does this work? Well JAX-RPC defines a standard property name, "javax.xml.rpc.service.endpoint.address", that will change the URL the stub will send to request to.
Note that we do NOT use "?WSDL" on this URL as this is the endpoint that gets the request, not the URL of the WSDL document.

What else can you do to the Stub? Well, you can read the Javadocs for Stub class in Axis at http://ws.apache.org/axis/java/apiDocs/org/apache/axis/client/Stub.html
and you will see a few interesting APIs. With the addition of the get/set SOAP Header functions in CFMX7 however, ColdFusion already provides access to almost everything via those functions or tag attributes to cfobject or cfinvoke.

Wednesday, September 21, 2005

Upgrading ColdFusion MX 7 to Axis 1.3

The Axis team is poised to create a 1.3 release of Axis shortly. Before we do that, I run the ColdFusion regression tests on the bits to make sure our customers can upgrade without problems.

Well, there is a problem, but it is due to some changes in Axis and wsdl4j, a jar file that Axis uses to process WSDL. Specifically the QName class used to live in wsdl4j.jar and now it lives in jaxrpc.jar. So this isn't a big deal except that the class changed recently to support prefixes. You don't have to care about what that means, but just know that Axis 1.3 calls a prefix API which if the wrong QName class is already loaded you get this error:

500 javax.xml.namespace.QName.getPrefix()Ljava/lang/String;
javax.xml.namespace.QName.getPrefix()Ljava/lang/String

The problem is that we are picking up the wsdl4j classes from runtime/lib/webservices.jar, the JRun supplied copy of Axis and all of its jar files (including wsdl4j.jar). This hasn't been a problem up until now, because the class moved and changed.

Here is how you fix this. It gets pretty messy so make sure you back up cfmx_bootstrap.jar.

  1. Shut down ColdFusion.
  2. Find the file wwwroot/WEB-INF/lib/cfmx_bootstrap.jar, Make a backup copy of it.
  3. Open the file with WinZip
  4. Edit the file jrun.properties. On the last line add the following package names to the end of the "exceptions line: "javax.xml.namespace.,javax.wsdl." Don't forget the comma and the trailing dots. The line will look like this.

    exceptions=javax.xml.messaging.,javax.xml.namespace.,javax.xml.rpc.,javax.xml.soap.,javax.wsdl.

  5. Save this change back in to cfmx_bootstrap.jar
  6. Start ColdFusion

The Gory Details

What this is doing is configuring CF to load the javax.xml.namespace and javax.wsdl packages using the CF classloader, which looks in cfusion/lib first, which is where we want to get the wsdl4j classes from.

Why does it get these classes from werbservices.jar? If you look at the first setting in jrun.properties, you will see that all the classes starting with "javax." are loaded by the Application Servers classloader. Hence JRun goes and loads its QName class (which is in the javax.xml.namespace package).

Whew.

Tuesday, September 06, 2005

SOAP over XMPP

This is a fun specification: http://www.jabber.org/jeps/jep-0072.html

Most people think web services are all about HTTP, but it has always been the case that there are people who want to send their SOAP via other transports.

Thursday, June 23, 2005

Axis 1.2.1 released

In the better late than never category, Apache Axis 1.2.1 was released last week. With the loooong time between 1.1 and 1.2, we are trying to get back to the 'release early, release often' philosophy that is one of the strength of open source.

Update: This version of Axis by the way will be included in the ColdFuison MX 7 updater. "Comming soon".

Monday, April 04, 2005

Consuming complex Types with ColdFusion

Doug James and Larry Afrin have posted a great set of notes on how to use ColdFusion MX to consume Web Services that contain complex types as arguments to their operations. This is information that should have been in the documentation from the start, but Doug and Larry went the extra mile to pull it all together.

We plan on publishing this information as a tech note and I have passed it along to our documentation folks to incorporate in to future CF docs as well.

Friday, October 29, 2004

Converting .NET dataset to ColdFusion Queries

Joe Rinehart has posted on his blog a short UDF that shows how to convert a Dataset to CF queries.
This is something we get asked about all the time: "Do CFMX web services support the Microsoft DataSet object?" I have always recommended that using DataSet is a really good way to screw interop, since it is a Microsoft proprietary data type. The problem with it? The WSDL does not describe the data inside the dataset. There is XML Schema inside the XML on the wire that then describes the types of the data. This requires parsing this Schema at runtime. Something the Axis engine at the heart of the CFMX web services support does not do. Why not? Because it is fairly difficult to do well, slows execution time, and would only be to support this wacky MS specific type.

In any case, I haven't tested Joes implementation, but if you are dealing with a MS specific web service that you have to consume, this should help you out tremendously!

Tuesday, August 17, 2004

Tim Ewald: Messages are the model

Tim Ewald has a very interesting piece about his wish to use Relax NG instead of XML Schema. Tim has an interesting point of view and was one of the first people to clearly explain to me why rpc/encoded was bad and document/literal is good. My first reaction to this was that he has gone off the deep end (again), but as usual he has me thinking. A particularly telling point: "We can do a lot better than RPC. If we don't, then what was the point?"