SyntaxHighlighter

Friday, November 13, 2009

UDDI Annotations - How do I self-register my service?

So you just installed jUDDI, and you're all proud you managed to get it up and running, but now you're asking yourself: "How do I register my own services?". You have a few options actually.

  • 1. You can do it programmatically using the juddi-client UDDIv3 API library, check out the code in the TckBusinessService class for some inspiration.
  • 2. You can do it programmatically using the JAXR API. Apache Scout supports both the v2 and v3 UDDI protocols.
  • 3. You can use a console, although the current jUDDI-portal based console only supports browsing at the moment, but you could pretty easily extend it and contribute it back.
  • 4. You can use annotations, jUDDI v3 introduces annotations that can be used to register a (web-)service at deploy time. I think that this is by far the easiest way to go about it. This is what I'm going to discuss in the blog post.

Annotations on (Web)Services Example


Let's start with an example: the HelloWorldService. Using the JAX-WS WebService annotation the simplest implementation of this class would look like:

@WebService(
endpointInterface = "org.apache.juddi.samples.HelloWorld",
serviceName = "HelloWorld")

public class HelloWorldImpl implements HelloWorld {

public String sayHi(String text) {
System.out.println("sayHi called");
return "Hello " + text;
}
}

and when using CXF the beans.xml would need the following entry

<jaxws:endpoint id="helloworld" implementor="org.apache.juddi.samples.HelloWorldImpl"
address="/helloworld" />

to bring it up under the http://localhost:8080/juddiv3-samples/helloworld if you deploy the juddiv3-samples war.
To enable registration at deploy time of this service you can use two UDDI annotations; one to register the service and one to register the endpoint, UDDIService and UDDIServiceBinding respectively. For example the annotations may look like

@UDDIService(
businessKey="uddi:myBusinessKey",
serviceKey="uddi:myServiceKey",
description = "Hello World test service")
@UDDIServiceBinding(
bindingKey="uddi:myServiceBindingKey",
description="WSDL endpoint for the hello${department} Service. This service is used for testing the jUDDI annotation functionality",
accessPointType="wsdlDeployment",
accessPoint="http://localhost:8080/juddiv3-samples/services/helloworld?wsdl")

Next you need to instruct a clerk to do the registration at deploy time. A clerk is UDDI publisher that can work from the back office, by candle light, no heat, you get the picture. We call him "BobCratchit". Bob needs to know which UDDI registry to publish to and under what UDDI publisher. All of this is defined in the META-INF/uddi.xml file.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<uddi>
<reloadDelay>5000</reloadDelay>
<manager name="example-manager">
<nodes>
<node>
<name>default</name>
<description>Sales jUDDI node</description>
<properties>
<property name="serverName" value="sales"/>
<property name="serverPort" value="8080"/>
<property name="keyDomain" value="sales.apache.org"/>
<property name="department" value="sales" />
</properties>
<proxyTransport>org.apache.juddi.v3.client.transport.InVMTransport</proxyTransport>
<custodyTransferUrl>org.apache.juddi.api.impl.UDDICustodyTransferImpl</custodyTransferUrl>
<inquiryUrl>org.apache.juddi.api.impl.UDDIInquiryImpl</inquiryUrl>
<publishUrl>org.apache.juddi.api.impl.UDDIPublicationImpl</publishUrl>
<securityUrl>org.apache.juddi.api.impl.UDDISecurityImpl</securityUrl>
<subscriptionUrl>org.apache.juddi.api.impl.UDDISubscriptionImpl</subscriptionUrl>
<subscriptionListenerUrl>org.apache.juddi.api.impl.UDDISubscriptionListenerImpl</subscriptionListenerUrl>
<juddiApiUrl>org.apache.juddi.api.impl.JUDDIApiImpl</juddiApiUrl>
</node>
</nodes>
<clerks registerOnStartup="true">
<clerk name="BobCratchit" node="default" publisher="sales" password="sales">
<class>org.apache.juddi.samples.HelloWorldImpl</class>
</clerk>
</clerks>
</manager>
</uddi>

A uddi.xml file can contain only one manager entry and the manager should have a name that is unique to your deployment environment. Within the manager you can specific as many nodes and clerks as you want. Each node contains the UDDI v3 endpoints of the UDDIv3 internal services. Each clerk must reference a node, and it must be supplied with the credentials of the publisher account. In this example we have:

<clerk name="BobCratchit" node="default" publisher="sales" password="sales">
<class>org.apache.juddi.samples.HelloWorldImpl</class>
</clerk>

which means that Bob is using the node connection setting of the node with name "default", and that he will be using the "sales" publisher, for which the password it "sales". There is some analogy here as to how datasources are defined. Finally you reference the class that contains the annotations in the clerk block. Make sure to have the juddi-client and uddi-ws jars on your classpath and you should be good to go.
Note that the juddiv3-samples.war ships with jUDDI-3.0.0 for you to get started.

UDDIService


serviceNameThe name of the service, by default the clerk will use the one name specified in the WebService annotation.optional
descriptionHuman readable description of the servicerequired
serviceKeyUDDI v3 Key of the Servicerequired
businessKeyUDDI v3 Key of the Business that should own this Service. The business should exist in the registry at time of registrationrequired
langLanguage locale which will be used for the name and description, defaults to "en" if omittedoptional
categoryBagDefinition of a CategoryBag, see below for detailsoptional

UDDIServiceBinding


The UDDIServiceBinding annotation cannot be used by itself at the moment. It needs to go along side a UDDIService annotation.

bindingKeyUDDI v3 Key of the ServiceBindingrequired
descriptionHuman readable description of the servicerequired
accessPointTypeUDDI v3 AccessPointType, defaults to wsdlDeployment if omittedoptional
accessPointEndpoint referencerequired
langLanguage locale which will be used for the name and description, defaults to "en" if omittedoptional
tModelKeysComma-separated list of tModelKeys key referenceoptional
categoryBagDefinition of a CategoryBag, see below for detailsoptional

CategoryBag


The CategoryBag is an optional element in both the UDDIService and UDDIServiceBinding annotation. Represented as XML a CategoryBag can contain a list of keyedReferences, for example
 
<categoryBag>
<keyedReference tModelKey="uddi:uddi.org:categorization:types" keyName="uddi-org:types:wsdl" keyValue="wsdlDeployment" />
<keyedReference tModelKey="uddi:uddi.org:categorization:types" keyName="uddi-org:types:wsdl2" keyValue="wsdlDeployment2" />
</categoryBag>

in the annotation this would look like
 
categoryBag="keyedReference=keyName=uddi-org:types:wsdl;keyValue=wsdlDeployment;tModelKey=uddi:uddi.org:categorization:types," +
"keyedReference=keyName=uddi-org:types:wsdl2;keyValue=wsdlDeployment2;tModelKey=uddi:uddi.org:categorization:types2",

For a complete example you can check one of the unittests.
If you now check the jUDDI portal, in the browser you should see the HelloWorld Service


Dynamic Runtime Properties


The downside of using annotations is that after your class is compiled it is hard to change the values set in the annotations. In particular when a field contains runtime dependent value like the hostname and port this becomes a problem. Therefor we added support to define custom properties in the 'node' section of the uddi.xml.

<properties>
<property name="serverName" value="sales"/>
<property name="serverPort" value="8080"/>
</properties>

These properties are then referenced in the annotation like:

accessPoint="http://${serverName}:${serverPort}/juddiv3-samples/services/helloworld?wsdl")

Summary


jUDDI-3.0.0 introduces a client side library which contain annotations for self-registration of a service and its binding at deployment time, and unregistration of the serviceBinding at undeploy time. This library can be used with any UDDI v3 compliant Registry.