Tuesday, October 21, 2008

Apache CXF: Open Source Service Framework - The Client

Earlier this year I posted Apache CXF: Open Source Service Framework to demonstrate how easy it is to create a simple echo Web Service with Apache CXF. Now I would like to post an example client for that service using Apache CXF.

First, we need our dependencies: (download them here)

...
commons-logging-1.1.1.jar
cxf-2.1.2.jar
FastInfoset-1.2.2.jar
geronimo-activation_1.1_spec-1.0.2.jar
geronimo-annotation_1.0_spec-1.1.1.jar
geronimo-javamail_1.4_spec-1.3.jar
geronimo-jaxws_2.1_spec-1.0.jar
geronimo-servlet_2.5_spec-1.2.jar
geronimo-stax-api_1.0_spec-1.0.1.jar
geronimo-ws-metadata_2.0_spec-1.1.2.jar
jaxb-api-2.1.jar
jaxb-impl-2.1.7.jar
jaxen-1.1.jar
jdom-1.0.jar
jetty-6.1.9.jar
jetty-util-6.1.9.jar
neethi-2.0.4.jar
saaj-api-1.3.jar
saaj-impl-1.3.jar
spring-beans-2.0.8.jar
spring-context-2.0.8.jar
spring-core-2.0.8.jar
spring-web-2.0.8.jar
stax-utils-20060502.jar
wsdl4j-1.6.2.jar
wstx-asl-3.2.4.jar
xml-resolver-1.2.jar
XmlSchema-1.4.2.jar
...

Then we need the Echo Service interface (this should be provided for us from our service providers) :

...
package com.thejavajar.service;

import javax.jws.WebService;

@WebService
public interface EchoServiceIfc {

    public String echo(String text);
    }
    ...

The last piece of the pie is our client that makes the call out to http://localhost:9000/echo, where our service lives, in order to invoke an operation on the service.

...
package com.thejavajar.client;

import org.apache.cxf.frontend.ClientProxyFactoryBean;
import com.thejavajar.service.EchoServiceIfc;

public class EchoClient {

    public static void main(String[] args) {

        String request = new String("test 1");

        ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
        factory.setServiceClass(EchoServiceIfc.class);
        factory.setAddress("http://localhost:9000/echo");
        EchoServiceIfc client = (EchoServiceIfc) factory.create();

        System.out.println("Sending: " + request);
        String response = client.echo(request);
        System.out.println("Returned: " + response);

        System.exit(0);
    }
}
...

All we need to do is run our main method in our EchoClient class and we will get something like:

...
Sending: test 1
Returned: test 1
...


That's all folks. Obviously, this example, along with our previously posted service, is not solving complex problems that we might face in our current Java development endeavors but it provides us with peak into Apache CXF and opens up more people to a technology that I enjoy working with.

Eclipse Project: apache-cxf-echo-client.zip

Sunday, October 19, 2008

Editable Flex Datagrid and Grails

I have been really digging into Flex lately and I have been complimenting Flex's incredibly nice UI capabilities with services written on Grails. I am extremely impressed with Flex and Grails really helps me get things up and running very quickly (you already know this if you are using Grails). Let's look at a quick example of where I am using one domain class and a few simple Grails actions in a controller in order to provide search and editing capabilities to a simple Flex application based on a datagrid.

The Grails domain class, Item.groovy:

...
class Item {

    String name
    String brand
    String line
}
...

The Grails controller class ItemController.groovy:

...
class ItemController {

    def search = {
        if(!params.max) {
            params.max = 100
        }
        if(!params.name) {
            params.name = ""
        }

        def itemList = Item.findAllByNameLike("$params.name%",[max:params.max])

        render(contentType:"text/xml") {
            items {
                for(i in itemList) {
                    item {
                        id(i.id)
                        name(i.name)
                        brand(i.brand)
                        line(i.line)
                    }
                }
            }
        }
    }

    def save = {
        if(params.id) {
            def item = Item.get(params.id)

            if(item) {
                item.properties = params
                if(!item.hasErrors() && item.save()) {
                    render ""
                }
                else {
                    render ""
                }
            }
        }
    }
}
...


I also added this to the conf/BootStrap.groovy so I would have some data to work with once I started up the Grails applicaiton. The code below creates 1,000 items during start-up:

...
def init = { servletContext ->

    (1..1000).each {
        new Item(name: "Item $it", brand: "My Brand", line: "My Line").save()
    }
}
...

I mostly worked with only 1,000 items, but I increased this up to 100,000 items to put it through some tests and it worked very nicely.

Now let's dive right into the MXML. Here is the entire itemlist.mxml file:

...
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:Script>
<![CDATA[

import mx.controls.Alert;
import mx.events.DataGridEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;

[Bindable]
private var itemId:String;

[Bindable]
private var itemName:String;

[Bindable]
private var itemBrand:String;

[Bindable]
private var itemLine:String;

private function sendItemData(event:DataGridEvent):void
{
var myEditor:TextInput = TextInput(event.currentTarget.itemEditorInstance);
itemName = myEditor.text;

itemId = event.currentTarget.editedItemRenderer.data["id"];
itemBrand = event.currentTarget.editedItemRenderer.data["brand"];
itemLine = event.currentTarget.editedItemRenderer.data["line"];

itemSaveService.send();
}

protected function filterList():void
{
itemSearchService.send();
}

private function fault_Handler(event:FaultEvent):void
{
Alert.show(event.fault.message, "Could not load items.");
}
]]>
</mx:Script>

<mx:HTTPService
id="itemSaveService"
method="POST"
url="http://localhost:8080/itemlist/item/save"
resultFormat="e4x"
fault="fault_Handler(event);"
showBusyCursor="true">
<mx:request xmlns="">
<id>{itemId}</id>
<name>{itemName}</name>
<brand>{itemBrand}</brand>
<line>{itemLine}</line>
</mx:request>
</mx:HTTPService>

<mx:HTTPService
id="itemSearchService"
method="GET"
url="http://localhost:8080/itemlist/item/search"
resultFormat="e4x"
fault="fault_Handler(event);"
showBusyCursor="true">
<mx:request xmlns="">
<name>{searchBox.text}</name>
</mx:request>
</mx:HTTPService>

<mx:Panel title="Item List" height="100%" width="100%" paddingTop="10" paddingLeft="10" paddingRight="10">

<mx:Label text="Search:"/><mx:TextInput id="searchBox" enter="filterList();"/>

<mx:DataGrid id="dg" width="100%" height="50%" rowCount="5"
dataProvider="{itemSearchService.lastResult.item}"
editable="true"
itemEditEnd="sendItemData(event);">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="Id" editable="false"/>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="brand" headerText="Brand" editable="false"/>
<mx:DataGridColumn dataField="line" headerText="Line" editable="false"/>
</mx:columns>
</mx:DataGrid>

</mx:Panel>
</mx:Application>
...

Now that all of the code is out on the table, we can start to dissect what is happening with the Flex UI.

When the application starts up:




Once we type in "Item " and press enter:




When we click on a value under the "Name" column in our datagrid:




We have 2 HTTPService's setup to send requests back to our Grails controller at http://localhost:8080/itemlist/item/save and http://localhost:8080/itemlist/item/search. The first service call will send all the item data to the ItemController's save action and the second one will send our search box's text to the ItemController's search action. We have ActionScript functions that handle the "Enter" key press event on the search box and we also have a function that will be called after the datagrid field has been edited.

Most of the code is pretty self explanatory but if you have any questions, feel free to contact me. Also, Marcel Overdijk has some great posts on Grails and Flex that can really help out when you get stuck.

Tuesday, September 02, 2008

Apache CXF: Open Source Service Framework

Web Service development has come a long way. I had some experience with XFire a few years ago and thought Web Service development could not get any easier. Then XFire became the Apache CXF project. I wanted to take a peak at Apache CXF so the other night I put together a simple echo Web Service. Alright, if you would like to follow along, you can create a Web Service in about 10 minutes:

First, we need our dependencies: (download them here)

...
commons-logging-1.1.1.jar
cxf-2.1.2.jar
FastInfoset-1.2.2.jar
geronimo-activation_1.1_spec-1.0.2.jar
geronimo-annotation_1.0_spec-1.1.1.jar
geronimo-javamail_1.4_spec-1.3.jar
geronimo-jaxws_2.1_spec-1.0.jar
geronimo-servlet_2.5_spec-1.2.jar
geronimo-stax-api_1.0_spec-1.0.1.jar
geronimo-ws-metadata_2.0_spec-1.1.2.jar
jaxb-api-2.1.jar
jaxb-impl-2.1.7.jar
jaxen-1.1.jar
jdom-1.0.jar
jetty-6.1.9.jar
jetty-util-6.1.9.jar
neethi-2.0.4.jar
saaj-api-1.3.jar
saaj-impl-1.3.jar
spring-beans-2.0.8.jar
spring-context-2.0.8.jar
spring-core-2.0.8.jar
spring-web-2.0.8.jar
stax-utils-20060502.jar
wsdl4j-1.6.2.jar
wstx-asl-3.2.4.jar
xml-resolver-1.2.jar
XmlSchema-1.4.2.jar
...

Second, we need our service interface: (note the @WebService annotation)

...
package com.thejavajar.service;

import javax.jws.WebService;

@WebService
public interface EchoServiceIfc {
    public String echo(String text);
}
...

Next, we need an implementation of our service interface: (note the @WebService annotation)

...
package com.thejavajar.service;

import javax.jws.WebService;

@WebService
public class EchoServiceImpl implements EchoServiceIfc {
    public String echo(String text) {
        return text;
    }
}
...

Finally, we can create a simple Java class that will start a server and expose our service:

...
package com.thejavajar.server;

import org.apache.cxf.frontend.ServerFactoryBean;
import com.thejavajar.service.EchoServiceIfc;
import com.thejavajar.service.EchoServiceImpl;

public class Server {
    public static void main(String[] args) {
        EchoServiceImpl echoServiceImpl = new EchoServiceImpl();

        // Create our Server
        ServerFactoryBean svrFactory = new ServerFactoryBean();
        svrFactory.setServiceClass(EchoServiceIfc.class);
        svrFactory.setAddress("http://localhost:9000/echo");
        svrFactory.setServiceBean(echoServiceImpl);
        svrFactory.create();
    }
}
...

Above, we set a few properties of the ServerFactoryBean that we have instantiated. We basically set up our service interface, our address (URL) to our service endpoint and the implementation class. We can run this as a normal Java application and browse over to http://localhost:9000/echo?wsdl and see our WSDL generated for our echo service.

There is nothing too complicated about the echo service. It is basically a Java interface, an implementation class and a few annotations. This is a great start for any developer who wants to start developing Web Services without getting overwhelmed with the full capabilities and features of Apache CXF or the spec. For more information, head on over to http://cxf.apache.org.

Eclipse Project: apache-cxf-echo-service.zip

Saturday, March 15, 2008

Create Bugs with Bugzilla's XMLRPC Web Service and Groovy

The other day I was looking into moving development bugs from one bug system over to Bugzilla. Someone in my group pointed out that Bugzilla had an XMLRPC Web service exposed at:
http://bugzilla-address/xmlrpc.cgi.

The current bug system had a feature that would export the bugs into XML data. I exported the bug data, moved the XML file to my local machine, and opened the Groovy Console. Let's check out how simple things can be.

Here is sort of what the XML looks like:

...
<issues>
<issue>
<product>Product Name</product>
<component>Component Name</component>
<summary>Summary</summary>
<version>1.0</version>
<description>Description</description>
<opsys>Operating System</opsys>
<platform>Platform</platform>
<priority>High</priority>
<severity>Low</severity>
<status>Open</status>
</issue>
</issues>
...


Here is what we need to import into our Groovy script:

...
import groovy.util.XmlSlurper

import java.util.Map
import java.util.HashMap
import java.net.ServerSocket

import org.apache.commons.httpclient.*
import org.apache.xmlrpc.client.*
...


Here is our class, main method, dependencies, and setup of the XMLRPCClient (I needed the HTTPClient and XMLRpcCommonsTransportFactory because Bugzilla likes to deal with Cookies after logged in):

...
public class BugzillaCreateFromXML {

// get the xml data of our issues in the .xml file
def xmlData = new XmlSlurper().parse(new File("C:/issues.xml"))

def httpClient = new HttpClient()
def rpcClient = new XmlRpcClient()
def factory = new XmlRpcCommonsTransportFactory(rpcClient)
def config = new XmlRpcClientConfigImpl()factory.setHttpClient(httpClient)

rpcClient.setTransportFactory(factory)
config.setServerURL(new URL("http://bugzilla-addres/xmlrpc.cgi"))
rpcClient.setConfig(config)

public static void main(String[] args) {
    // here is where the work getting done
    // map of the login data
    Map loginMap = new HashMap()
    loginMap.put("login", "admin")
    loginMap.put("password", "admin")
    loginMap.put("rememberlogin", "Bugzilla_remember")

    // login to bugzilla
    def loginResult = rpcClient.execute("User.login", loginMap)
    println loginResult

    // map of the bug data
    Map bugMap = new HashMap()

    // iterate through each issue
    xmlData.issue.each {
        bugMap.put("product", it.product.text())
        bugMap.put("component", it.component.text())
        bugMap.put("summary", it.summary.text())
        bugMap.put("version", it.version.text())
        bugMap.put("description", it.description.text())
        bugMap.put("op_sys", it.opsys.text())
        bugMap.put("platform", it.platform.text())
        bugMap.put("priority", it.priority.text())
        bugMap.put("severity", it.severity.text())
        bugMap.put("status", it.status.text())

        // create bug
        def createResult = rpcClient.execute("Bug.create", bugMap)
            println createResult

            // clear bugMap so we can re-populate it with the next issue
            bugMap.clear()
        }
    }
}
...

That is it. It took me about 30 minutes to parse the XML file and loop through each node with Groovy. I spent about an hour finding out that HTTPClient was also needed, I originally started working with Groovy's XMLRPC library. You need to have the appropriate Apache XMLRPC Client libraries in place in your Groovy lib directory. I ran this from the Groovy Console and it did exactly what I needed it to do. The Groovy file is available for download .