Complex Web service objects can be difficult to interpret and display. With ColdFusion MX and its inherent ability to process object method calls with structs and arrays, you can easily view these complexities using the <cfdump> tag.
With ColdFusion MX (CFMX), the most common return type for homegrown Web services is the recordset. Drop the ColdFusion component (CFC) in your site, make a call, and voila—instant data. Where you run into problems is when you try to call non-CFC Web services, such as those served by BEA WebLogic.
Since the Web service has no idea who will call it, it uses an XML-formatted SOAP envelope to send responses. It is within its response that complex objects come into play. For WebLogic, the object returned is a homegrown or extended Java object. The object is comprised of numerous method calls to the data and/or to further embedded objects. For example, a Book object may have a method call getAuthorData() that returns an Author object.
Two predefined objects used in CFMX are structures and arrays. A structure, commonly referred to as a struct, is a container to hold associated data known as elements. Each data element has a label and a value. For example, a struct of type Book could have two elements: Title and Category. In CFScript, you would write this:
book = structnew();
book.Title = "Titan";
book.Category = "Biography";
Arrays are containers as well, but are a little less straightforward. Each item in the list has its own index number. (Arrays can be multidimensional, but that's beyond my scope here). In CFScript, you would write this:
bookTitles = arraynew(1);
bookTitles  = "Titan";
bookTitles  = "House of Morgan";
Where's the data?
After you have the Web service up and working, you should <cfdump> the results to see what you have. You should get something like Figure A.
|Here is Web service test A.|
You can see that CFMX can decipher the object and display its various methods. The one thing you don't see, though, is data. The more you drill down, the more methods you encounter until you finally arrive at data. This is not conducive for quick viewing and debugging.
The returned object has a logical hierarchy. The original BookServiceResponse object returns two objects: a book object and an author object. To get to the information contained in those sub-objects you need to go down another layer. Code wise, this doesn't look pretty. I’ll assume the return variable for your Web service is called results. Here's how you'd access various parts of data:
Seems like a laborious process to do while testing and debugging a Web service. Since the CFC is already a file on its own, it would be great if you could introduce a middle step to ease the data into a more easily understood visual representation. This is where structs and arrays can help you out.
Setting up the visual representation
One reason why queries are so great in representing data is the column-data relationship. If you have a column name of BookTitle, then you know that if you reference that column, you get the title of the book. You don't have to worry about whether the column references a method to retrieve data or a method to retrieve another object. It simply returns the book's title.
Web services do have a way to take the guesswork out of what you're getting. The WSDL will tell you the various methods and objects that particular Web services will return. Therefore, you technically can tell beforehand whether getAuthorData() will return data or an object, but that's beside the point. You want all the data available in a simple manner.
One methodology a coworker of mine used was to create a struct within the CFC and pass that struct back as the return variable. This presented something more like the query result set that you are used to seeing.
Here's CFScript code to show how you could set up the above approach for calls into an easy to understand struct:
book = structnew();
book.title = results.getBookData().getTitle();
book.category = results.getBookData().getCategory();
book.AuthorFirstName = results.getAuthorData().getFirstName();
book.AuthorLastName = results.getAuthorData().getLastName();
book.AuthorFullName = book.AuthorFirstName & book.AuthorLastName;
This is so much like what you are used to with queries that if your query name was book, you'd access the data in the exact same fashion, that is, addressing a specific column (or type of data) book.title, book.category, and so on.
Now that I’m on the subject of queries, what happens if the Web service returns more than one of the same object? If this is the case, then they will be sent to you and displayed in an array.
MyBooks = arraynew(1);
…struct code from above…
This would give you an array of structs, or, in other words, it would give you a collection of book structs in MyBooks array.
There's the data
Using the <cfdump> tag yet again, you can see how much easier it is to see the data. Take a look at Figure B to see the new book struct built off of data returned from the Web service.
|Here is the new book struct.|
As you can see, the data is easy to see and understand. The beauty of this approach is that no matter how many various functions and/or methods that the WebLogic programmer adds to the Web service, the data you care about stays the same. This may seem like an insignificant thing, but building the Web service is only half the job. After the service is built, the fine-tuning stage kicks in where the WebLogic programmer and the DBA put their heads together to try to optimize the service for speed, speed, and more speed. Regardless of those changes, your Web app will keep on trucking, and you can fine-tune the presentation layer and the data integrity. This dual programming path will speed up development significantly.
Communicate without fear
Although CFMX is based on Java and runs through a JVM, it's still not quite there when it comes to user-defined objects. This is quite acceptable though, since CFMX has no problem processing the object method calls, and you have no problem representing the data in a way that's useful to you.
With the proliferation of Web services hype, it is inevitable in an enterprise environment that you will use them. With CFMX's inherent ability to process object method calls, you should have no fear in communicating with Web services. Now, with a new way of processing the Web services output, you should have no problems with interpreting and displaying their data either.