| By Robert Munn | Article Rating: |
|
| May 18, 2005 02:15 PM EDT | Reads: |
14,994 |
One of the primary selling points of the ColdFusion platform is the ease of use of the language and the encapsulation of complex programming constructs in easy-to-use tag syntax.
In many cases, you can accomplish programming tasks that would take many lines of code in other languages in one or two lines of code in ColdFusion. Need to query a database?
<cfquery ...> Your database code here </cfquery>
It doesn't get any easier than that. The platform's concept of encapsulating complex constructs in a simple tag-based language has held up remarkably well in most areas. In one important and growing field- Web services- the model has not been as successful as in other areas. In part, this limited success has to do with the inherent complexity of web services and the difficulty in translating that complexity into CF's tag or script-based syntax. The language provides two native methods for connecting to web services, using cfinvoke or createObject():
I. Invoking a Web service using cfinvoke:
<cfinvoke webservice="path_to_wsdl_file" method="someMethod" attributecollection="#myattribStruct#" returnvariable="myresult"/>
II. Invoking a Web service using cfobject:
<cfscript>
ws = createObject("webservice", "path_to_wsdl_file");
res1 = ws.someMethod(params);
res2 = ws.someOtherMethod(params);
</cfscript>
The former method allows you to access a Web service, pass in an arbitrary number of arguments in a structure, and assign the response to a variable- all in one line of code. For Web services that require relatively simple input, such as the Babelfish translation service documented in the CFMX product documentation, this model works exceptionally well. The latter method requires more lines of code, but lets you instantiate a Web service into an object and then access as many methods of the Web service as you need to fulfill the task at hand. The advantage of the latter method becomes obvious when you call more than one method at a time from a Web service. In the former method, you would write two lines of code to execute two methods, but the CFMX server would instantiate the Web service for each method call. In the latter method, you write three lines of code (ok, five if you count the cfscript tags), but the CFMX server only parses the WSDL file once.
These two methods work well for Web services that use basic datatypes for input or that make minimal use of XML attributes in their WSDL files.
Custom Datatypes
Many complex Web services use custom datatypes as part of their request and/or response model. You may have trouble modeling such datatypes in ColdFusion. The CFMX documentation instructs you to model a complex datatype as a structure. This technique works well in theory, but in practice it may lead you to building very large structures in order to satisfy the datatype that the Web service expects. Furthermore, if a Web service method you want to consume expects custom datatypes that are made up of other custom datatypes, you will need to map all of that data into a single structure to pass to the web service.
At first, that may not seem like such a burden. After all, as a software developer, you handle complex tasks all day long. Creating and handling structures is just another complex task for you to tackle. ColdFusion does not offer a lot of detail in debugging the consumption of Web services. If you fail to properly build your structure- even if you only miss one element in a very large structure- ColdFusion will return an error that it was unable to find the method you called with the parameters you specified. The server provides very little other debugging information.
That isn't even the worst part about trying to build and debug consuming a complex Web service in ColdFusion. The worst part of going through such a painful debugging process is that there is an easier way to consume complex Web services in ColdFusion.
Java to the Rescue
As of CFMX 6.0, the ColdFusion platform runs on the Java J2EE architecture. While the ColdFusion platform allows you to do lots of cool and sophisticated stuff without the complexity of Java, it also allows you to drop down into Java for problems that you just can't lick in CF directly. Normally, this sort of thing might mean writing Java code to handle complex tasks that ColdFusion just doesn't do natively- manipulating images, for instance. Ironically, the growth and acceptance of Java as a platform of choice for Web application development has led to the creation of lots of tools that Java developers can use to automate everyday tasks. Apache Axis (www.apache.org) is just such a tool that developers use to automate the process of building and consuming Web services in Java.
WSDL, or Web Services Description Language, is an XML format that describes a web service. By reading the WSDL document for a particular web service, you can tell everything about that service- the datatypes it uses for requests and responses, the methods it exposes, and how to connect to the service, among other things. There are many good books on web services that explain the WSDL format in detail if you would like more information on the subject.
WSDL2Java - Magic Widget Maker
WSDL2Java and its counterpart, Java2WSDL, are components of the Axis package. In essence, they enable you to automatically translate between Java and WSDL. Since you are not building Web services in Java, you need not concern yourself with Java2WSDL. WSDL2Java accepts a valid WSDL file as input. WSDL2Java is HTTP aware, so it will accept a URL to the WSDL file as input. From the WSDL file and any associated references the WSDL file contains, WSDL2Java creates Java classes that encapsulate the Web service described in the WSDL file. Those classes contain all the datatypes you will need, all method calls you can make, and all the classes to find and bind to the web service itself.
Using WSDL2Java with ColdFusion
CFMX comes bundled with a version of Axis running as part of the underlying Java engine, and you can leverage the bundled Axis engine in order to connect to a web service in Java. In order to use CFMX's Axis engine, you need to set your Java classpath to reference the Axis files that CFMX uses. The classpath is where the Java interpreter looks for files that are called as part of a Java program. In this case, there are several Java .jar files (packages) that you will need to reference in order for your code to work both locally and on your CFMX server. Listings 1 and 2 show a batch file that sets the classpath for servers running CFMX J2EE mode and Integrated mode respectively. Many thanks to Tom Jordahl of Macromedia for pointing me in the direction of the correct .jar files:
The common thread in these two listings is that these files, with the exception of jrun.jar, are located in {cfusion_root}/lib, so if these listings don't work for you, modify the paths to point to {cfusion_root} for your CFMX environment. The location of these files in your ultimate production environment is irrelevant at this point; what matters is where you are executing WSDL2Java and building your Java wrapper class. You will need CFMX running on this environment as well. I developed all of this code on my laptop, where I am running the Developer version of CFMX 7 in J2EE mode.
You will also need a Java JVM in order to call WSDL2Java. Since you are running CFMX, you already have a JVM installed, and you can use it if you like. I work with Java directly, and I have the latest Java 5 JRE from Sun, which includes a JVM, installed on my system. You can download the latest JRE from http://java.sun.com.
Now that you have a JVM installed and your classpath mapped, you can execute babelwsdl2j.bat. I recommend you copy babelwsdl2j.bat into its own folder and execute it from the command line. You could just drop the program on your desktop and click on it, but if it errors you will not be able to see the error message returned. babelwsdl2j.bat creates a set of folders and Java classes inside those folders to encapsulate the Babelfish Web service.
By convention, the outer folder will normally be something generic, like com, net, or gov, with an inner folder for the name of the organization or site that owns the Web service. Other nested folders are dictated by the structure of the Web service, as in Figure 2. That structure is a convention, not a rule. The folders could be named anything.
After you have executed the batch file, copy the resulting folder structure into a document directory. I have been using c:\inetpub\wwwroot\java as the base folder for my development. It allows me to have my Java source code and my CFMX code in one place during development.
Eclipse - The IDE of Choice for Java Developers
If you have never programmed in Java, this next part may look intimidating, but trust your skills and you can tackle it. If you do not have Eclipse, you will need to download and install it. If you have it already, you can skip this section. Note that if you are running CFEclipse but you have only installed the minimal install package provided by the CFEclipse team, you will need to download and install a full copy of Eclipse for this exercise.
The Eclipse Foundation (www.eclipse.org) describes the Eclipse IDE as a platform for everything and nothing in particular. Despite the rather enigmatic description, Eclipse is far and away the most popular IDE for Java developers in use today. (Last I checked, more than 50% of Java developers in a recent survey were using Eclipse as their IDE of choice). You can download the latest Eclipse platform from their Web site. As of the writing of this article, the latest Eclipse version is 3.1 M6.
As a CF developer, you may also want to download the CFEclipse plugin (http://cfeclipse.tigris.org). You can get more information about CFEclipse from its Web site, but in short, CFEclipse is a plugin to the Eclipse IDE that adds support for CF development. It is a great plugin and well worth having whether or not you plan to use Eclipse for Java development on a regular basis.
Installing Eclipse
Download the ZIP file. Open the ZIP file and extract the contents to a folder of your choice- e.g. c:\Program Files. Double click on eclipse.exe to get started. Eclipse is will error if it can't find a JVM on your machine but if you installed the Sun JRE back in the previous section, Eclipse should be able to find it.
Setting up Eclipse
Eclipse will ask you to create a default workspace. You can accept the default or change it to suit your environment if you like. From there, you will need to create a project. Eclipse organizes everything into Workspaces and Projects. To create a project, click on New Project and select a new Java project. Uncheck the Use default workspace check box and select the location where you copied the folder structure created by WSDL2Java. Click Finish. You should see a tree view on the left of your project- including the Java classes created by WSDL2Java. You are almost done with the Eclipse setup.
Remember that classpath variable? It becomes very important again at this point. The base Java JRE does not include Apache Axis, and unless you specifically tell Eclipse where to find the Axis packages necessary to compile the generated code from WSDL2Java, you will not be able to compile and run your program.
Click on Project | Properties in Eclipse. Select Java Build Path on the left and click Add External JARs. Select the .jar files that you included in the batch file used by WSDL2Java. The .jar files will appear on the left in the project tree view.
You have now setup Eclipse sufficiently to write, compile, and run a Java program to access your Web service.
Building Your Wrapper Class
A wrapper class is exactly what it sounds like - a Java class that "wraps" functionality from many classes in a single class.
The Java class in Listing 3 is a simple wrapper class that allows you to call the Babelfish translation Web service. Breaking down the program, you will see two primary sections in the code. The first section is a set of import statements. These statements include the parts of the Java class hierarchy you will need to run your program. The first three are standard import declarations in a wrapper class like this one; you can simply copy them wholesale from Listing 3. If you don't include them, Eclipse will let you know they are missing and will even suggest adding the import statements. The next two statements import classes created by WSDL2Java to find and bind to the Babelfish service.
The second section contains the actual Java program. Java classes always start with a class declaration. In this case, public class babel{} is your class declaration. Everything inside the opening and closing curly braces is the core of your Java class.
Next in line is the main() method, public static void main(String[] args){}. Technically, you don't need the main() method in your Java class. However, including it will allow you to test your class from within Eclipse. Before you compile and copy your class files into the ColdFusion environment, you will comment out whatever you put in the main() method. main() is executed whenever a Java class is instantiated, and you don't want anything to just execute on its own when you call your class from ColdFusion.
After main(), you find public babel(), the default constructor for the babel class. A constructor is a method with the same name as the class itself. When the Java interpreter instantiates a new class, the interpreter calls a constructor method as part of the instantiation. For simple examples like this one, you may find that you only need an empty constructor.
Next, you see the heart of the class, public String getBabel(String mode, String inputText). All of the bits of this statement have special meaning. Public means you can call the method from anywhere. That will be important later when you call the method from ColdFusion. String is the datatype returned by the method. In this case, String is a simple datatype, but in more complex Web services, the return datatype could be a custom datatype returned by the Web service. getBabel is the name of the method. String mode, String inputText are the names and datatypes of the arguments the getBabel method expects to receive. As with the String datatype that getBabel returns, the arguments are simple datatypes, but they could be anything, including custom datatypes that the Web service expects as input.
The code in getBabel() is the heart of your wrapper class. Look at it line by line:
BabelFishServiceLocator service = new BabelFishServiceLocator();
This line instantiates a new object of type BabelFishServiceLocator called service using the class BabelFishServiceLocator. This class tells the Java program where to find the Web service you are connecting to.
BabelFishBindingStub wsstub = (BabelFishBindingStub) service.getBabelFishPort();
For non-Java programmers, this line is a little tricky. It creates an object called wsstub of type BabelFishBingdingStub, but it uses a method of the just-created service object to instantiate this new object. The syntax (class) obj.method() tells Java to instantiate the new object using the obj.method, but that the returned object will be of type (class).
String res = wsstub.babelFish(mode,inputText);
Finally! This line calls the babelFish() method of the web service, passing the arguments mode and inputText. It then assigns the result to the String variable res.
return res;
The last line of the getBabel() method returns the variable res to the calling application.
Now that you have a wrapper class written in Java to access the Babelfish web service, you need to write your ColdFusion code to make use of it. This code listing demonstrates how easy it is to use the Java wrapper class you have created.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>babelfish Web services example</title>
</head>
<body>
<cfset res = "">
<cfscript>
wsObj = createObject("java","babel");
ws = wsObj.init();
res = ws.getBabel("en_es","Hello World");
</cfscript>
<cfoutput>
<cfdump var="#res#">
</cfoutput>
</body>
</html>
You use createObject() to instantiate the class. The syntax is createObject(type,name). For Java classes, the type is "java", and the name refers to the name of the compiled Java .class file, without the .class extension. You can use the init() method as in this example to explicitly call a constructor in the Java class. It is worthwhile reading up on this function in the CFMX documentation if you are not familiar with it. Init() is a special method that calls a constructor for the class in question. If you do not init() a class, CFMX will implicitly call the default constructor when you access the first method of the class, but until you call init(), only static methods and properties are available from ColdFusion. (For that reason, I have made the explicit init() call in this example).
After the init() method is called, you can access the getBabel() method of the class. res = ws.getBabel("en_es","Hello World"); uses the popular "Hello World" example to translate Hello World from English to Spanish (en_es). The results of the method call are assigned to res, and the example uses <cfdump> to output the value of res. Going to back to the Java wrapper class, you will recall that getBabel() returns a String, so you could just as easily output res using a straight output, #res#, without <cfdump>. Things get much more interesting when the Java class returns a complex datatype.
If you have never tackled a Java project before now, you may find yourself spending some time just becoming familiar with Java notation and learning about Eclipse (or whatever Java IDE you use). Java is a compiled, heavily typed language. You may need at least a basic understanding of Object-Oriented programming to tackle a Java wrapper like this one on your own. Fortunately, if you need to gain that background knowledge, you can find many resources on the Web to help you learn about OOP and Java.
The sample Babelfish application gives you a good idea of how to create the Java class files for your Web services project, how to write a wrapper in Java to access those classes, and how to access your wrapper class from within ColdFuson. If you have a project that involves connecting to a more complex Web service, especially one that uses custom datatypes, you may find several things you do not see in this example. First, when you run WSDL2Java, you may find that it has created dozens of classes rather than the four classes created for the BabelFish Web service. You may also find a far greater number of methods available in those classes than in the sample application. Before you despair, just keep in mind that you can always go back and look at the WSDL file itself to help sort out what should go in your Java wrapper code. Most of all- persevere. Once you have managed to tackle a single project using this methodology, you will feel a lot more comfortable the next time around.
Published May 18, 2005 Reads 14,994
Copyright © 2005 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Robert Munn
Robert Munn has spent the last ten years designing, building, and managing Web-based applications. He currently manages the IT Web Applications group for Peregrine Systems, an enterprise software company based in San Diego. He has a degree in Classics and Spanish Literature from Tufts University. He wrote his first program in Basic at age 11 on a Tandy Model III and has been hooked on software ever since.
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Reader Sued
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Adobe Flex Developer Earns $100K in New York City
- Adobe LiveCycle Enterprise Suite 2 for Cloud Computing
- Adobe Cans Another 9% of its Workforce
- Adobe Betas Target RIAs and Cloud Computing
- Adobe MAX 2009 Online
- Thinking of Flex in London
- Moyea DVD4Web Converter V2.0 Converts DVD to FLV Fast and Synchronously with Watermarks
- Adobe & Salesforce Cut Cloud Deal
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Is Microsoft as Free as Open Source?
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Reader Sued
- The Planet Named “Bronze Sponsor” of Cloud Computing Expo
- Microsoft Expression Web Has Got Game
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Bruce Chizen Joins Voyager Capital as Venture Partner
- My Top Seven Wishes From Adobe MAX 2009
- Adobe Flex Developer Earns $100K in New York City
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers
- The Asynchronous CFML Gateway
- Web Services Using ColdFusion and Apache CXF



































