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.

32 comments:

Anonymous said...

Tom,

Thanks for this post... without it my upgrade to AXIS 1.3 would have been impossible. That said, it helps to know which of the AXIS files are required for the upgrade.

From the lib folder in the AXIS 1.3 download, you need to drop AXIS.jar, wsdl4j-1.5.1.jar, saaj.jar and jaxrpc.jar into the /web-inf/cfusion/lib folder or cfusionmx7/runtime/lib folder (depending on the install type, web-inf for Jrun/multiserver and runtime for standalone). If you take any of the others, CF will launch but won't run pages.

Once you've edited the properties file in cfmx_bootstrap.jar file in web-inf/lib and dropped the 4 jar files from the AXIS download into your CFMX lib folder, start CFMX and hit a webservice to test. You should see your /web-inf/cfusion/stubs (or cfusionmx7/stubs folder) start filling up with folders and java files that turn into class files as the WSDL is consumed, converted, and compiled.

Thanks for the post, it got me started in the right direction!

Laterz...
J

Anonymous said...

Tom,

I am having an issue with web services, thought I will ask you as you are the Guru on Axis and CF web services ;)

I have DEV and Prodution servers running CF 7.01. Though DEV is generating a WSDL using XSD encoding for return strings, the production one is generating WSDL that returns SOAPENC coded strings. Our world wide client systems can not parse SOAPENC messages, so I need a way to fix this. Macromedia/Adobe Support tean has been struggling since a week to find out what's going on.

Interestingly, when I upgraded the production server to Axis 1.3 like your post, it did generate the WSDL with XSD first but then after a few calls it again got changed to SOAPENC. Is it because I have "save classes" option switched ON. We do have .NET with WSE 2.0 running on our web server. Do you have any idea how I can force XSD encoding for string returns?

Thanks,
Anu

Anonymous said...

Tom,

Thank god for you! You saved me! WOOO! The other references to this issue suck. I was quite happy to find yours and actually be able to read it without having to learn an entirely new language. Good times!

Anonymous said...

Tom trying to get a hold of you with a question about soap types and an error i'm getting. please email me at gigado AT gmail DOT com when you can :)

Anonymous said...

Should this same process work for CFMX 6.1?

Tom said...

No, this will not work for CFMX 6.1.

Grant said...

Tom,

I am finding that CFMX 6.1 is incompatible with web services written in Microsoft .NET Framework 2.0 that return complex types, such as an array. .NET Web Services returning a simple type, such as a bool or a string continue to work fine.

Here is an example of CFCATCH.MESSAGE detail on an exception thrown when CFMX 6.1 is attempting to consume a .NET 2.0 web service returning a complex type:

Could not perform web service invocation "GetContestantByRecID" because AxisFault faultCode: {http://schemas.xmlsoap.org/soap/envelope/}VersionMismatch faultSubcode: faultString: Possible SOAP version mismatch: Envelope namespace http://www.w3.org/2002/12/soap-envelope was unexpected. Expecting http://schemas.xmlsoap.org/soap/envelope/.

I am wondering if upgrading the Axis engine within 6.1 will address this issue, and if so, how do go about doing it?

Anonymous said...

Tom, Grant -

I too am running CFMX 6.1 and am having the same problem as you are Grant. Did you upgrade the Axis engine and if so, did it resolve the problem?

Thanks, Peter

Grant said...

Peter -- Unfortunately I have not found any information that would instruct me on how to upgrade Axis in CFMX 6.1, but have worked around this problem in a fantastically unelegant manner. What I have done is create a .NET 1.1 WebService whose job in life is to act as a bridge between CFMX 6.1 and a .NET 2.0 WebService. So CFMX consumes the 1.1 WebService, and the 1.1 WebService consumes the 2.0 WebService in turn. It's a lot of overhead and I am definitely not happy with it, but it does work reliably.

Tom said...

Sorry that you are having trouble with CFMX 6.1.

Perhaps this would be a perfect opportunity to justify an upgrade to CFMX 7.0.2, which should support consuming your web services.

Why are you stuck on the (very old) 6.1?

Anonymous said...

Tom,

Are you going to attempting the same thing for Axis 1.4??

Tom said...

This fix is in CFMX 7.0.2 so that release should work for Axis 1.3 and 1.4.

Anonymous said...

Perhaps this is unrelated. I'm trying to consume a simple .NET web service and I get: AxisFault
: SimpleDeserializer encountered a child element, which is NOT expected.
The .NET Web Service functions correctly when invoked directly with the browser.

-Andy

Tom said...

Andy,

Yes, that error is unrelated to updating the Axis version in CFMX7.

Prash said...

Hi Tom,

Subject: Coldfusion client not able to invoke .NET web service

I always doubted whether coldfusion can handle/map complex of a complex data as a input to a web service methods.
I have coldfusion 7.0.2 developer verison and I am trying to invoke a .net web service method.
I always get the error web service operation [methodname] could not be found.

I tried invoking all other methods that take simple input parameter, simple structures, but when it comes to structures within arrays within structures, it just gives the above errors.
I really doubt the arrays are not being properly handled here.

Can you please let me know if you have any thoughts on handling arrays of objects to construct the input parameter.

Thanks for reading and your time.

Regards,
Prashant

Tom said...

Prash,

Of course ColdFusion can handle complex argument types. You just have to make sure you are constructing the CFML correctly to match the Java objects that Axis is creating from the WSDL. Check out this posting for a great article.

Anonymous said...

would you mind sharing with me your 1.1 Web service tbat acts as a bridge between cf6 and .NET 2.0?

thanks so much!
Tom

Unknown said...
This comment has been removed by a blog administrator.
Unknown said...

Tom,
I've scoured all over the web for solutions to my problem described by everyone that posted comments to this entry. I didn't think CF (I'm running 7.02) had any issues with complex types but trying to construct the cfml correctly to match the java objects that Axis is creating from the WSDL is proving to be quite a task.

I used the WSDL2Java utility to create the java code so I can inspect it. I've since found out that the method that I post to in the web service in question takes a complex input (a named class) that I can't duplicate because it makes use of other named classes.

Is there another solution? I also tried to access the link that goes to http://hcc.musc.edu/research/shared_resources/xml_complex_types_to_cf_structure_notes.cfm, but apparently it's no longer available.

Tom said...

Serious bummer that the excellent article about CF and complex types has gone missing.

Cheryl, using WSDL2Java is the right move. Then you need to construct a CFML structure for each JavaBean needed for the operation. You then put them all in a top level CFML struct to match the top level JavaBean that is the argument to the operation.

Unknown said...

Tom,
I tried that. But maybe I did it wrong. I created a main structure called the same name as the argument the web service is expecting, and then I created subsequent structures that are nested under the main top level structure.

When I send in the coldfusion structure of structures to the web service I get a Web service operation "name of method" with parameters {parameters} could not be found.

Then I went the hard route and created coldfusion components that matched the java beans created by wsdl2java and in the top level component (the one named the same as the web service is expecting), I instantiated all the other components. So what I ended up having when I did a cfdump was this complicated object with other objects nested inside it. After all that, I get another error, this time stating java.lang.IllegalArgumentException: argument type mismatch.

I'm not sure what else to try. I even tried sending in a coldfusion xml document that matched the example sent by the vendor (because apparently they said they were expecting xml) and that just gave me a new error The argument NAMEOFARGUMENT passed to function nameOfFunction() is not of type struct.

I know I'm missing something small, and I can't believe that ColdFusion can't interface with a .NET web service. I just don't know what I'm missing.

Help!

Anonymous said...

Tom,

I am writing a CF application that consumes an Axis 2 web service and having found issues with CF's Axis 1.2.1 tried to upgrade to version 1.4.

As I'm running CF 7.0.2 there seems to be no need to amend the jrun.properties file contained within cfmx_bootstrap.jar as the exceptions line looked ok. I stopped the CF server and copied the files axis.jar, wsdl4j-1.5.1.jar, saaj.jar and jaxrpc.jar from the Axis 1.4 download into the cfusion/lib directory overwriting the ones that where there. I restarted the CF server and tried to invoke a web service that had been previously working. However I now get the following error: coldfusion.jsp.CompilationFailedException: Errors reported by Java compiler: Found 1 semantic error compiling.......

Please can you shed some light on my problem or have I done something totally wrong?

PS The article on complex type web services and CF mentioned above can be found at http://web.archive.org/web/20070309173903/http://hcc.musc.edu/research/shared_resources/xml_complex_types_to_cf_structure_notes.cfm

MrBuzzy said...

Warning: if you have followed these steps to upgrade your Axis version, the CF 8.0.1 Updater will revert your installation to Axis 1.2.1.

Cheers.

Anonymous said...

OK, I'm trying to consume a web service, and I get an error:

"/usr/local/coldfusion7/stubs/WS-1032875873/com/bemac/vtest/ServiceCodes.java": 288. elemField.setNillable(false); <--------------------------> *** Error: No method named "setNillable" was found in type "org/apache/axis/description/ElementDesc".

I was running CF7, so applied the 7.0.1 and 7.0.2 patches. I still get the error - I thought it might have been down to the fact that AXIS was an older version on 7.0, but seeing as this hasn't fixed it, perhaps I am wrong?

Any suggestions?

Thanks in advance

Unknown said...
This comment has been removed by the author.
Unknown said...

I am trying to invoke a web service I am passing the array of structure to service but it gives me the error
"Cannot perform web service invocation GetQuote.
The fault returned when invoking the web service operation is: java.lang.IllegalArgumentException: argument type mismatch"
legInfo = arrayNew(1);
legInfo[1] = structNew();
legInfo[1].PointOfDeparture = "LGA";
legInfo[1].PointOfArrival = "MIA";
legInfo[1].DepartDateTime = "2008-12-15T14:00:00.000-05:00";
legInfo[1].Duration = "10";
legInfo[1].Distance = "10";
r_varLookupQuote = createObject("webservice", "http://www.segrave.com/saiwebservices/saiquoteservice.asmx?wsdl");
ws= r_varLookupQuote.GetQuote("2508","7D82F3D4-9302-4FE4-8C07D221E2C43B2C","",#legInfo#,"lgt","Nevin","James","B","212-610-5291","212-350-7850","jnevin@digitas.com","7");

Anonymous said...

Hi,

Does anyone know if this upgrade will work on CF 8.01 from Axis 1.2.1 to Axis 1.4?

In my initial tests, it's not working... but I want to know if it's not going to work or if I'm just doing something wrong? ;-)

Tom said...

@Aaron,
I haven't tested this myself, but you should be able to update your Axis jars to 1.4. The delta between 1.3 and 1.4 is small.

We haven't upgraded the CF version of Axis however because in our testing, some things break when moving past 1.2.1. However some things do work better. So upgrade at your own risk.

I will say that all of the bugs that we have fixed in the CF version of Axis 1.2.1 are also fixed in the source tree of Axis 1.x. If they got fixed after 1.4 was released, you may have to build the latest Axis source to get them. And no, I don't have a list handy, you can look through my check ins (tomj) in the SVN tree to get that list though.

Aaron Longnion said...

@Tom - thanks for the quick reply. Following the instructions on this blog and from Jared, I get the following error during CF start-up (CF 8.01 Enterprise Multi-server, with latest hot fixes). Do I need to refresh some type of cache as well, or something?

02/23 16:12:56 user ColdFusionStartUpServlet: ColdFusion: application services are now available
02/23 16:12:56 user CFMxmlServlet: init
02/23 16:12:56 user CFMxmlServlet: Macromedia Flex Build: 87315.134646
02/23 16:12:56 INFO Macromedia Flex Build: 87315.134646
- DDXM_S00004: Error creating JAXB Context
javax.xml.bind.JAXBException
- with linked exception:
[java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "com.sun.xml.bind.DatatypeConverterImpl.parseQName(Ljava/lang/String;Ljavax/xml/namespace/NamespaceContext;)Ljavax/xml/namespace/QName;" the class loader (instance of coldfusion/bootstrap/BootstrapClassLoader) of the current class, com/sun/xml/bind/DatatypeConverterImpl, and the class loader (instance of bootloader>) for interface javax/xml/bind/DatatypeConverterInterface have different Class objects for the type javax/xml/namespace/QName used in the signature]
at com.sun.xml.bind.ContextFactory_1_0_1.createContext(ContextFactory_1_0_1.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:143)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:258)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
at com.adobe.internal.ddxm.Executive.initContext(Executive.java:82)
at com.adobe.internal.ddxm.Executive.clinit>(Executive.java:74)
at coldfusion.document.DocumentServiceImpl.callAssemblerInitFonts(DocumentServiceImpl.java:1124)
at coldfusion.document.DocumentServiceImpl.initializeDocumentService(DocumentServiceImpl.java:210)
at coldfusion.document.DocumentServiceImpl.access$000(DocumentServiceImpl.java:51)
at coldfusion.document.DocumentServiceImpl$1.run(DocumentServiceImpl.java:172)
Caused by: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "com.sun.xml.bind.DatatypeConverterImpl.parseQName(Ljava/lang/String;Ljavax/xml/namespace/NamespaceContext;)Ljavax/xml/namespace/QName;" the class loader (instance of coldfusion/bootstrap/BootstrapClassLoader) of the current class, com/sun/xml/bind/DatatypeConverterImpl, and the class loader (instance of bootloader>) for interface javax/xml/bind/DatatypeConverterInterface have different Class objects for the type javax/xml/namespace/QName used in the signature
at com.adobe.internal.ddxm.model.impl.runtime.DefaultJAXBContextImpl.init>(DefaultJAXBContextImpl.java:50)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.sun.xml.bind.ContextFactory_1_0_1.createContext(ContextFactory_1_0_1.java:50)

Tom said...

From that stack trace, it appears that the definition of QName in Axis conflicts with the definition someplace else (perhaps the Java runtime).

Aaron Longnion said...

@Tom J - so, we haven't been able to find a solution for this. We cannot upgrade to CF 8 until we find a solution. Any information on how to deal with the "definition of QName in Axis" problem? We don't have enough Axis or java expertise on our small dev team to solve this on our own.

Anonymous said...

Has anyone found a solution for this?