SyntaxHighlighter

Thursday, February 25, 2010

Simple Publishing Using the jUDDI API

One of the most common requests we get on the message board is “How do I publish a service using jUDDI?” This question holds a wide berth, as it can result anywhere from not understanding the UDDI data model, to confusion around how jUDDI is set up, to the order of steps required to publish artifacts in the registry, to general use of the API – and everything in between. This article will attempt to answer this “loaded” question and, while not going into too much detail, will hopefully clear some of the confusion about publishing into the jUDDI registry.

UDDI Data Model

Before you begin publishing artifacts, you need to know exactly how to break down your data into the UDDI model. This topic is covered extensively in the specification, particularly in section 3, so I only want to gloss over some for details. Readers interested in more extensive coverage should most definitely take a look at the UDDI specification.

Below is a great diagram of the UDDI data model (taken directly from the specification):


As you can see, data is organized into a hierarchical pattern. Business Entities are at the top of the pyramid, they contain Business Services and those services in turn contain Binding Templates. TModels (or technical models) are a catch-all structure that can do anything from categorize one of the main entities, describe the technical details of a binding (ex. protocols, transports, etc), to registering a key partition. TModels won’t be covered too much in this article as I want to focus on the three main UDDI entities.

The hierarchy defined in the diagram is self-explanatory. You must first have a Business Entity before you can publish any services. And you must have a Business Service before you can publish a Binding Template. There is no getting around this structure; this is the way UDDI works.

Business Entities describe the organizational unit responsible for the services it publishes. It generally consist of a description and contact information. How one chooses to use the Business Entity is really dependent on the particular case. If you’re one small company, you will likely just have one Business Entity. If you are a larger company with multiple departments, you may want to have a Business Entity per department. (The question may arise if you can have one uber-Business Entity and multiple child Business Entities representing the departments. The answer is yes, you can relate Business Entities using Publisher Assertions, but that is beyond the scope of this article.)

Business Services are the cogs of the SOA landscape. They represent units of functionality that are consumed by clients. In UDDI, there’s not much to a service structure; mainly descriptive information like name, description and categories. The meat of the technical details about the service is contained in its child Binding Templates.

Binding Templates, as mentioned above, give the details about the technical specification of the service. This can be as simple as just providing the service’s access point, to providing the location of the service WSDL to more complicated scenarios to breaking down the technical details of the WSDL (when used in concert with tModels). Once again, getting into these scenarios is beyond the scope of this article but may be the subject of future articles.

jUDDI Additions to the Model

Out of the box, jUDDI provides some additional structure to the data model described in the specification. Primarily, this is the concept of the Publisher.

The UDDI specification talks about ownership of the entities that are published within the registry, but makes no mention about how ownership should be handled. Basically, it is left up to the particular implementation to decide how to handle “users” that have publishing rights in the registry.

Enter the jUDDI Publisher. The Publisher is essentially an out-of-the-box implementation of an identity management system. Per the specification, before assets can be published into the registry, a “publisher” must authenticate with the registry by retrieving an authorization token. This authorization token is then attached to future publish calls to assign ownership to the published entities.

jUDDI’s Publisher concept is really quite simple, particularly when using the default authentication. You can save a Publisher to the registry using jUDDI’s custom API and then use that Publisher to publish your assets into the registry. jUDDI allows for integration into your own identity management system, circumventing the Publisher entirely if desired. This is discussed in more detail in the documentation, but for purposes of this article, we will be using the simple out-of-the-box Publisher solution.

One quick note: ownership is essentially assigned to a given registry entity by using its “authorizedName” field. The “authorizedName” field is defined in the specification in the operationalInfo structure which keeps track of operational info for each entity.

UDDI and jUDDI API

Knowing the UDDI data model is all well and good. But to truly interact with the registry, you need to know how the UDDI API is structured and how jUDDI implements this API. The UDDI API is covered in great detail in chapter 5 of the specification but will be summarized here.

UDDI divides their API into several “sets” – each representing a specific area of functionality. The API sets are listed below:
The most commonly used APIs are the Inquiry, Publication and Security APIs. These APIs provide the standard functions for interacting with the registry.

The jUDDI server implements each of these API sets as a JAX-WS compliant web service and each method defined in the API set is simply a method in the corresponding web service. The client module provided by jUDDI uses a “transport” class that defines how the call is to be made. The default transport uses JAX-WS but there are several alternative ways to make calls to the API. Please refer to the documentation for more information.

One final note, jUDDI defines its own API set. This API set contains methods that deal with handling Publishers as well as other useful maintenance functions (mostly related to jUDDI’s subscription model). This API set is obviously proprietary to jUDDI and doesn’t conform to the UDDI specification.

Getting Started

Now that we’ve covered the basics of the data model and API sets, it’s time to get started with the publishing sample. The first thing that must happen is to get the jUDDI server up and running. Please refer to this article that explains how to start the jUDDI server. The source code can be found in the source repository at this location.

Simple Publishing Example

We will now go over the “simple-publish” example found in the documentation. This sample expands upon the HelloWorld example in that after retrieving an authentication token, a Publisher, BusinessEntity and BusinessService are published to the registry.

The sample consists of only one class: SimplePublish. Let’s start by taking a look at the constructor:

public SimplePublish() {
try {
String clazz = UDDIClientContainer.getUDDIClerkManager(null).
getClientConfig().getUDDINode("default").getProxyTransport();
Class transportClass = ClassUtil.forName(clazz, Transport.class);
if (transportClass!=null) {
Transport transport = (Transport) transportClass.getConstructor(String.class).newInstance("default");

security = transport.getUDDISecurityService();
juddiApi = transport.getJUDDIApiService();
publish = transport.getUDDIPublishService();
}
}
catch (Exception e) {
e.printStackTrace();
}
}

The constructor uses the jUDDI client API to retrieve the transport from the default node. You can refer to the documentation if you’re confused about how clerks and nodes work. Suffice it to say, we are simply retrieving the default client transport class which is designed to make UDDI calls out using JAX-WS web services.

Once the transport is instantiated, we grab the three API sets we need for this demo: 1) the Security API set so we can get authorization tokens, 2) the proprietary jUDDI API set so we can save a Publisher and 3) the Publication API set so we can actually publish entities to the registry.

All the magic happens in the publish method. We will look at that next.

Here are the first few lines of the publish method:

// Setting up the values to get an authentication token for the 'root' user ('root' user has admin privileges
// and can save other publishers).
GetAuthToken getAuthTokenRoot = new GetAuthToken();
getAuthTokenRoot.setUserID("root");
getAuthTokenRoot.setCred("");

// Making API call that retrieves the authentication token for the 'root' user.
AuthToken rootAuthToken = security.getAuthToken(getAuthTokenRoot);
System.out.println ("root AUTHTOKEN = " + rootAuthToken.getAuthInfo());

This code simply gets the authorization token for the ‘root’ user. The ‘root’ user (or publisher) is automatically installed in every jUDDI instance and acts as the “administrator” for jUDDI API calls. Additionally, the ‘root’ user is the owning publisher for all the initial services installed with jUDDI. You may be wondering what those “initial services” are. Well, since the UDDI API sets are all implemented as web services by jUDDI, every jUDDI node actually registers those services inside itself. This is done per the specification.

Let’s get back to the code. Now that we have root authorization, we can add a publisher:

// Creating a new publisher that we will use to publish our entities to.
Publisher p = new Publisher();
p.setAuthorizedName("my-publisher");
p.setPublisherName("My Publisher");

// Adding the publisher to the "save" structure, using the 'root' user authentication info and saving away.
SavePublisher sp = new SavePublisher();
sp.getPublisher().add(p);
sp.setAuthInfo(rootAuthToken.getAuthInfo());
juddiApi.savePublisher(sp);

Here we’ve simply used the jUDDI API to save a publisher with authorized name “my-publisher”. Notice how the authorization token for the ‘root’ user is used. Next, we need to get the authorization token for this new publisher:

// Our publisher is now saved, so now we want to retrieve its authentication token
GetAuthToken getAuthTokenMyPub = new GetAuthToken();
getAuthTokenMyPub.setUserID("my-publisher");
getAuthTokenMyPub.setCred("");
AuthToken myPubAuthToken = security.getAuthToken(getAuthTokenMyPub);
System.out.println ("myPub AUTHTOKEN = " + myPubAuthToken.getAuthInfo());

This is pretty straightforward. You’ll note that no credentials have been set on both authorization calls. This is because we’re using the default authenticator which doesn’t require credentials. We have our authorization token for our new publisher, now we can simply publish away:

// Creating the parent business entity that will contain our service.
BusinessEntity myBusEntity = new BusinessEntity();
Name myBusName = new Name();
myBusName.setValue("My Business");
myBusEntity.getName().add(myBusName);

// Adding the business entity to the "save" structure, using our publisher's authentication info and saving away.
SaveBusiness sb = new SaveBusiness();
sb.getBusinessEntity().add(myBusEntity);
sb.setAuthInfo(myPubAuthToken.getAuthInfo());
BusinessDetail bd = publish.saveBusiness(sb);
String myBusKey = bd.getBusinessEntity().get(0).getBusinessKey();
System.out.println("myBusiness key: " + myBusKey);

// Creating a service to save. Only adding the minimum data: the parent business key retrieved from saving the business
// above and a single name.
BusinessService myService = new BusinessService();
myService.setBusinessKey(myBusKey);
Name myServName = new Name();
myServName.setValue("My Service");
myService.getName().add(myServName);
// Add binding templates, etc...

// Adding the service to the "save" structure, using our publisher's authentication info and saving away.
SaveService ss = new SaveService();
ss.getBusinessService().add(myService);
ss.setAuthInfo(myPubAuthToken.getAuthInfo());
ServiceDetail sd = publish.saveService(ss);
String myServKey = sd.getBusinessService().get(0).getServiceKey();
System.out.println("myService key: " + myServKey);

To summarize, here we have created and saved a BusinessEntity and then created and saved a BusinessService. We’ve just added the bare minimum data to each entity (and in fact, have not added any BindingTemplates to the service). Obviously, you would want to fill out each structure with greater information, particularly with services. However, this is beyond the scope of this article, which aims to simply show you how to programmatically publish entities.

There are a couple important notes regarding the use of entity keys. Version 3 of the specification allows for publishers to create their own keys but also instructs implementers to have a default method. Here we have gone with the default implementation by leaving each entity’s “key” field blank in the save call. jUDDI’s default key generator simply takes the node’s partition and appends a GUID. In a default installation, it will look something like this:

uddi:juddi.apache.org:<GUID>

You can, of course, customize all of this, but that is left for another article. The second important point is that when the BusinessService is saved, I’ve had to explicitly set its parent business key (retrieved from previous call saving the business). This is a necessary step when the service is saved in a separate call like this. Otherwise you would get an error because jUDDI won’t know where to find the parent entity. I could have added this service to the BusinessEntity’s service collection and saved it with the call to saveBusiness. In that scenario I would not have to set the parent business key.

Conclusion

That does it for this article. Hopefully I managed to clear some of the confusion around the open-ended question, “How do I publish a service using jUDDI?”.

Tuesday, February 23, 2010

UDDI Annotations Demo to Register a WebService

This demo shows how to use UDDI annotations to register a service into a UDDI v3 compliant registry. For more detailed information see the jUDDI Userguide on annotations.

Part1:






Part2:




UDDI v3 HelloWord

This demo shows a how to obtain an authentication token from a UDDI v3 Server. It is using the juddi-client, which connects to a jUDDI-3.0.1 server over JAX-WS. Note that since it is using the UDDI v3 API this should work using any UDDI v3 compliant server. To bring up a jUDDI server see the GettingStarted demo.





Getting Started with jUDDI v3

A flash demo on how to get started with the jUDDI v3 server.





Monday, February 22, 2010

jUDDI load tested in the Amazon Cloud

Our friends at Global Quality Partners, LLC and Xceptance, Inc posted a nice article on load testing jUDDI 3.0.0 on JBOSS 5.1 (the CXF web services stack) using Red Hat Enterprise Linux 5.3 and MySQL 5.0 all running in the Amazon EC2.

http://www.dzone.com/links/juddiv300_holds_its_own_under_load.html

Great work guys!

--Kurt

p.s. the testsjavascript:void(0) are checked in under the 'qa' directory in the jUDDI source tree. And if you want to run it follow the instructions in the GettingStarted.txt:

1. Start the jUDDI server at port 8080.

2. Place the license.xml.donotcheckin file in the qa/xlt directory. If you are a developer on the jUDDI project you can receive a copy of this file by asking for it on the juddi-dev mailing list. Without the license XLT is limited to running 5 users.

3. Run 'ant loadtest'. This will download XLT, configure the XLT software and start the loadtest

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.

Thursday, October 29, 2009

jUDDI-3.0.0 Released!

I'm proud to announce that jUDDI-3.0.0 is released! jUDDI now supports all the required UDDIv3 APIs. jUDDI-3.0.0 has a lot of new and exiting features, some of which are
  • Implements all the UDDIv3 required APIs.
  • Plugin architecture for Cryption and Authentication.
  • Flexible way of seeding your UDDI node.
  • Using the following specifications to keep the jUDDI code base small
    • JPA (tested with OpenJPA and Hibernate) and
    • JAXB (tested with SUNs implementation, and native JDK6)
    • JAX-WS (tested with CXF)
  • Annotations to Self-Register/UnRegister your services and their Bindings.
  • Support for multi-node UDDI setups using the client and server-side Subscription APIs.
  • Introduction of the "UDDI Clerk" concept to support cross registration of UDDI entities.
  • UDDI Console with GWT based portlets
    • Browse portlet
    • Search portlet
    • Subscription portlet
    • Publisher portlet
  • Ready-to-go bundles: juddi-tomcat and juddi-portal.
  • Run in Embedded mode, RMI or SOAP.
  • Tested to work with Scout-1.2 (JAXR).
  • Integrated into JBossESB.
  • In production for the past 6 months at eSigma.
  • Tested with both SUN and OpenJDK JDKs.
  • Tested under load using XLT test suite.
Each of these bullet-points really needs its own blog post! Until then please check out the User Guide for more details.

cheers,

the jUDDI team