Apache jUDDICommunity Documentation

Chapter 7. Using the jUDDI-Client

7.1. Introduction
7.2. Configuration
7.2.1. JAX-WS Transport
7.2.2. RMI Transport
7.2.3. InVM Transport
7.3. UDDI Annotations
7.3.1. Introduction
7.3.2. UDDIService Annotation
7.3.3. UDDIServiceBinding Annotation
7.3.4. WebService Example
7.3.5. Templating keys
7.4. Programmatic use
7.4.1. WSDL Registration
7.4.2. BPEL Process Registration
7.4.3. Conventions around UDDIv3 registration
7.5. Dynamic UDDI Service Lookup
7.6. Dependencies
7.7. Sample Code
7.8. References

The jUDDI project includes UDDI Client code (juddi-client-3.x.jar), which is Java client library to connect to a UDDI Registry, and to manipulate it. The client uses the UDDI v3 API and can be configured to connect to any UDDI v3 compliant registry (it has been tested against jUDDI v3 itself as well as against HP Systenet). This library can be embedded in your own application and used programmatically or by using annotations.

programmatically WSDL BPEL annotations cleint side key generation

For the client to connect to the UDDI server we need to provide it with the correct connection settings, which we call 'Transport' settings. In addition to these transport settings there are other client features that can be configured using the client configuration file META-INF/uddi.xml. You can deploy one of these client configuration files in your deployment archive that is interacting with the UDDI client code. To make sure the configuration is read you need to either call

UDDIClerkManager clerkManager = new UDDIClerkManager("META/myuddi.xml");
clerkManager.start();
		

or you if your application deploys are a war archive, you can add your client config in yourwar/META-INF/myuddi.xml, add in the web.xml specify the context parameters uddi.client.manager.name and uddi.client.xml. In the following example both context parameters are set and on deployment the UDDIClerkServlet takes care of reading the configuration.

<!-- required -->
<context-param>
    <param-name>uddi.client.manager.name</param-name>
    <param-value>example-manager</param-value>
 </context-param>
 
<!-- optional override -->
<context-param>
    <param-name>uddi.client.xml</param-name>
    <param-value>META-INF/myuddi.xml</param-value>
</context-param>

<servlet>
    <servlet-name>UDDIClerkServlet</servlet-name>
    <display-name>Clerk Servlet</display-name>
    <servlet-class>org.apache.juddi.v3.client.config.UDDIClerkServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

The following is an example of a simple client configuration file:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<uddi>
  <reloadDelay>5000</reloadDelay>
  <manager name="example-manager">
    <nodes>
      <node isHomeJUDDI="true">
        <name>default</name>
        <description>jUDDI node</description>  
        <properties>
          <property name="serverName"  value="www.myuddiserver.com"/>
          <property name="serverPort"  value="8080"/>
          <property name="keyDomain"   value="mydepartment.mydomain.org"/>
          <property name="department"  value="mydepartment" />
        </properties>
        <!-- InVM -->
        <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>
        <!-- JAX-WS Transport 
        <proxyTransport>org.apache.juddi.v3.client.transport.JAXWSTransport</proxyTransport>
        <custodyTransferUrl>http://${serverName}:${serverPort}/juddiv3/services/custody-transfer</custodyTransferUrl>
        <inquiryUrl>http://${serverName}:${serverPort}/juddiv3/services/inquiry</inquiryUrl>
        <publishUrl>http://${serverName}:${serverPort}/juddiv3/services/publish</publishUrl>
        <securityUrl>http://${serverName}:${serverPort}/juddiv3/services/security</securityUrl>
        <subscriptionUrl>http://${serverName}:${serverPort}/juddiv3/services/subscription</subscriptionUrl>
        <subscriptionListenerUrl>http://${serverName}:${serverPort}/juddiv3/services/subscription-listener</subscriptionListenerUrl>
        <juddiApiUrl>http://${serverName}:${serverPort}/juddiv3/services/juddi-api?wsdl</juddiApiUrl>
        -->
        <!-- RMI Transport Settings
        <proxyTransport>org.apache.juddi.v3.client.transport.RMITransport</proxyTransport>
        <custodyTransferUrl>/juddiv3/UDDICustodyTransferService</custodyTransferUrl>
        <inquiryUrl>/juddiv3/UDDIInquiryService</inquiryUrl>
        <publishUrl>/juddiv3/UDDIPublicationService</publishUrl>
        <securityUrl>/juddiv3/UDDISecurityService</securityUrl>
        <subscriptionUrl>/juddiv3/UDDISubscriptionService</subscriptionUrl>
        <subscriptionListenerUrl>/juddiv3/UDDISubscriptionListenerService</subscriptionListenerUrl>
        <juddiApiUrl>/juddiv3/JUDDIApiService</juddiApiUrl>
        <javaNamingFactoryInitial>org.jnp.interfaces.NamingContextFactory</javaNamingFactoryInitial>
        <javaNamingFactoryUrlPkgs>org.jboss.naming</javaNamingFactoryUrlPkgs>
        <javaNamingProviderUrl>jnp://${serverName}:1099</javaNamingProviderUrl>
        -->
      </node>
    </nodes>
    <clerks registerOnStartup="true">
      <clerk name="BobCratchit" node="default" publisher="bob" password="bob">
         <class>org.apache.juddi.samples.HelloWorldImpl</class>
      </clerk>
    </clerks>
  </manager>	
</uddi>

The manager element is required element, and the name attribute 'example-manager' should be unique in your deployment environment. The nodes element may contain one or more node elements. Typically you would only need one node, unless you are using subscriptions to transfer updates of entities from one UDDI registry to another. For the 'local' registry you would set isHomeJUDDI="true", while for the 'remote' registries you would set isHomeJUDDI="false".

element namedescriptionrequired
namename of the nodeyes
descriptiondescription of the nodeno
propertiescontainer for properties that will be passed into the clerkno
proxyTransportThe transport protocol used by the client to connect to the UDDI serveryes
custodyTransferUrlConnection settings for custody transferno
inquiryUrlConnection location settings for inquiriesyes
publishUrlConnection location settings for publishingyes
securityUrlConnection location settings for obtaining security tokensyes
subscriptionUrlConnection location settings for registering subscription requestsno
subscriptionListenerUrlConnection location settings receiving subscription notificationsno
juddiApiUrlConnection location settings for the jUDDI specific API for things like publisher managementno

Finally the manager element can contain a 'clerks' element in which one can define one or more clerks.

attribute namedescriptionrequired
namename of the clerkyes
nodename reference to one of the nodes specified in the same manageryes
publishername of an existing publisheryes
passwordpassword credential of the publisheryes

Using the settings in the uddi.xml file from above, the client will use JAX-WS to communicate with the (remote) registry server. This means that the client needs to have access to a JAX-WS compliant WS stack (such as CXF, Axis2 or JBossWS). Note that the juddiApiUrl is a reference to the WSDL endpoint while the others should reference the actual endpoints.

<!-- JAX-WS Transport -->
<proxyTransport>org.apache.juddi.v3.client.transport.JAXWSTransport</proxyTransport>
<custodyTransferUrl>http://${serverName}:${serverPort}/juddiv3/services/custody-transfer</custodyTransferUrl>
<inquiryUrl>http://${serverName}:${serverPort}/juddiv3/services/inquiry</inquiryUrl>
<publishUrl>http://${serverName}:${serverPort}/juddiv3/services/publish</publishUrl>
<securityUrl>http://${serverName}:${serverPort}/juddiv3/services/security</securityUrl>
<subscriptionUrl>http://${serverName}:${serverPort}/juddiv3/services/subscription</subscriptionUrl>
<subscriptionListenerUrl>http://${serverName}:${serverPort}/juddiv3/services/subscription-listener</subscriptionListenerUrl>
<juddiApiUrl>http://${serverName}:${serverPort}/juddiv3/services/juddi-api?wsdl</juddiApiUrl>

pros: Standard way of UDDI communication, should work with all UDDIv3 server implementations.

cons: If the server is deployed on the same application server this may lead to issues when auto-registration on deployment/undeployment is used, since the WS stack may become unavailable during undeployment. A workaround is to host the UDDI server on a different server.

If jUDDI server is deployed to an Application Server it is possible to register the UDDI Services as RMI services. If this is desired you need to edit the juddiv3.war/WEB-INF/classes/juddiv3.properties file, on the server. Add the following setting

juddi.jndi.registration=true

At deployment time the RMI based UDDI services are bound into the Global JNDI namespace.

Next, on the client side you need to comment out the JAXWS section in the uddi.xml file and use the RMI Transport section instead. Optionally you can set the java.naming.* properties. In this case we specified setting for connecting to jUDDIv3 deployed to a JBoss Application Server. You can set the java.naming.* properties in a jndi.xml file, or as System parameters.

<!-- RMI Transport Settings -->
<proxyTransport>org.apache.juddi.v3.client.transport.RMITransport</proxyTransport>
<custodyTransferUrl>/juddiv3/UDDICustodyTransferService</custodyTransferUrl>
<inquiryUrl>/juddiv3/UDDIInquiryService</inquiryUrl>
<publishUrl>/juddiv3/UDDIPublicationService</publishUrl>
<securityUrl>/juddiv3/UDDISecurityService</securityUrl>
<subscriptionUrl>/juddiv3/UDDISubscriptionService</subscriptionUrl>
<subscriptionListenerUrl>/juddiv3/UDDISubscriptionListenerService</subscriptionListenerUrl>
<juddiApiUrl>/juddiv3/JUDDIApiService</juddiApiUrl>
<javaNamingFactoryInitial>org.jnp.interfaces.NamingContextFactory</javaNamingFactoryInitial>
<javaNamingFactoryUrlPkgs>org.jboss.naming</javaNamingFactoryUrlPkgs>
<javaNamingProviderUrl>jnp://${serverName}:1099</javaNamingProviderUrl>

pros: Leight weight, and faster since it does not need a WS stack.

cons: Will only work with a jUDDIv3 server implementation.

If you choose to use InVM Transport this means that the jUDDIv3 server is running in the same VM as you client. If you are deploying to juddi.war the embedded server will be started by the org.apache.juddi.RegistryServlet, but if you are running outside any container, you are responsible for starting and stopping the org.apache.juddi.Registry Service yourself. Make sure to call

Registry.start()

before making any calls to the Registry, and when you are done using the Registry (on shutdown) call

Registry.stop()

so the Registry can release any resources it may be holding. To use InVM Transport uncomment this section in the uddi.properties while commenting out the JAXWS and RMI Transport sections.

<!-- InVM -->
<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>

pros: Lightest weight, and best performant communication, and no deployment order issues when using auto-registration of services during deployment and undeployment.

cons: Will only work with a jUDDIv3 server implementation. Typically one would use a jUDDI server for each application server sharing one common database.

The annotations can be used on any class that defines a service. Here they are added to a WebService, a POJO with a JAX-WS 'WebService' annotation.

package org.apache.juddi.samples;

import javax.jws.WebService;
import org.apache.juddi.v3.annotations.UDDIService;
import org.apache.juddi.v3.annotations.UDDIServiceBinding;

@UDDIService(businessKey="uddi:myBusinessKey", serviceKey="uddi:myServiceKey", description = "Hello World test service")
@UDDIServiceBinding(bindingKey="uddi:myServiceBindingKey", description="WSDL endpoint for the helloWorld Service. This service is used for "
      + "testing the jUDDI annotation functionality",
    accessPointType="wsdlDeployment", accessPoint="http://localhost:8080/juddiv3-samples/services/helloworld?wsdl")
@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;
    }
}

On deployment of this WebService, the juddi-client code will scan this class for UDDI annotations and take care of the registration process. In the configuration file uddi.xml, in the clerk section you need to reference the Service class 'org.apache.juddi.samples.HelloWorldImpl':

<clerks registerOnStartup="true">
  <clerk name="BobCratchit" node="default" publisher="bob" password="bob"> 
    <class>org.apache.juddi.samples.HelloWorldImpl</class>  
  </clerk>
</clerks>
        

which means that Bob is using the node connection setting of the node with name "default", and that he will be using the "bob" publisher, for which the password it "bob". There is some analogy here as to how datasources for database access are defined.

It is also possible to use the jUDDI client code in your application. The first thing to do is to read the client config file, and get a handle to a clerk

UDDIClerkManager clerkManager = new UDDIClerkManager("META/myuddi.xml");
clerkManager.start();

UDDIClerk clerk = clerkManager.getClientConfig().getUDDIClerks().get(clerkName);
        

A UDDIClerk will allow you do make authenticated requests to a UDDI server.

The OASIS UDDI spec TC put out a Techical Note on "Using WSDL in a UDDI Registry" [WSDL-UDDI]. The jUDDI client implements the UDDI v3 version of the WSDL2UDDI mapping as described in this technical note. The registration process registers a BindingTemplate for each WebService EndPoint and if the BusinessService for this BindingTemplate does not yet exist it also registers the BusinessService along with a WSDLPortType TModel for each portType, and a WSDLBinding TModel for each binding. To use it you can use the code in the 'org.apache.juddi.v3.client.mapping' package [WSDL2UDDI] and make the following call to asynchronously register your WebService EndPoint.

//Add the properties from the uddi.xml
properties.putAll(clerk.getUDDINode().getProperties());
RegistrationInfo registrationInfo = new RegistrationInfo();
registrationInfo.setServiceQName(serviceQName);
registrationInfo.setVersion(version);
registrationInfo.setPortName(portName);
registrationInfo.setServiceUrl(serviceUrl);
registrationInfo.setWsdlUrl(wsdlURL);
registrationInfo.setWsdlDefinition(wsdlDefinition);
registrationInfo.setRegistrationType(RegistrationType.WSDL);
registration = new AsyncRegistration(clerk, urlLocalizer, properties, registrationInfo);
Thread thread = new Thread(registration);
thread.start();
        

This does assume that you can pass in a URL to the WSDL file as well as the WSDLDefinition. In most cases you will need to package up the WSDL file you are trying to register in your deployment. You can get a WSDLDefinition using

ReadWSDL readWSDL = new ReadWSDL();
Definition definition = readWSDL.readWSDL("wsdl/HelloWorld.wsdl");
        

where you would pass in the path to the WSDL on the classpath.

To remove a WSDL binding from the Registry you would use

BPEL2UDDI bpel2UDDI = new BPEL2UDDI(clerk, urlLocalizer, properties);
String serviceKey = bpel2UDDI.unRegister(serviceName, portName, serviceURL);
        

If this is the last BindingTemplate for the BusinessService it will also remove the BusinessService along with the WSDLPortType and WSDLBinding TModels. The lifecycle is registration on Endpoint deploy and unregistration on Endpoint undeploy.

Similar to the WSDL to UDDI mapping there is a BPEL to UDDI mapping Technical Note [BPEL-UDDI]. The jUDDI client also implements this mapping. Using it is very similar to code fragment listed for the WSDL Registration, with the only change being that in this case the RegistrationInfo.RegistrationType should be RegistrationType.BPEL. See To use it you can use the code in the 'org.apache.juddi.v3.client.mapping' package [BPEL2UDDI] for more information on the implementation. For an example use of the registration process see the JBoss RiftSaw project [RFTSW-UDDI].

Both the WSDL and BPEL registration code use a key format convention to construct UDDI v3 keys. The format of the keys can be defined in the properties section of the uddi.xml, but they have reasonable defaults. Note that the both the serviceName and portName are obtained from the RegistrationInfo. The nodeName can be obtained from the environment, or set in the uddi.xml.

PropertyDescriptionRequiredDefault Value
langThe language setting used by the registration.noen
businessNameThe business name which is used by.yes
keyDomainThe key domain key part (used by the key formats)yes
businessKeyFormatKey format used to contruct the Business Keynouddi:${keyDomain}:business_${businessName}
serviceKeyFormatKey format used to contruct the BusinessService Keynouddi:${keyDomain}:service_${serviceName}
bindingKeyFormatKey format used to contruct the TemplateBinding Keynouddi:${keyDomain}:binding_${nodeName}_${serviceName}_${portName}
serviceDescriptionDefault BusinessService descriptionnoDefault service description when no <wsdl:document> element is defined inside the <wsdl:service> element.
bindingDescriptionDefault BindingTemplate descriptionnoDefault binding description when no <wsdl:document> element is defined inside the <wsdl:binding> element.

For a client application to invoke a Service it needs to know the actual binding information of the WebService EndPoint. This information can be statically stored at the clientside but this will make the system very rigid. For example if a service moves from one server to another the client will not pick up this change. It therefor makes sense to do a lookup into the UDDI registry to obtain fresh) binding information. This will make the solution dynamic, and allows for clients simply following the changes that occur in the service deployment topology.

The serviceLocator [SERV-LOC] can be used to locate a service binding knowing the service and port name. The following piece of code demonstrates how to do a lookup:

ServiceLocator serviceLocator = new ServiceLocator(clerk, urlLocalizer, properties);
String endPointURL = lookupEndpoint(serviceQName, String portName);
            

When the above UDDI v3 serviceKey conventions are followed, then all the client needs to know is the serviceName and portName it want to invoke and the The downside of doing a service lookup before each service invokation is that it will have a performance inpact.

The UDDI client depends on uddi-ws-3.x.jar, commons-configuration-1.5.jar, commons-collection-3.2.1.jar and log4j-1.2.13.jar, plus

Sample code on how to use the UDDI client can be found in the uddi-client module on the jUDDIv3 project. Usually the first thing you want to is to make a call to the Registry to obtain an Authentication Token. The following code is taken from the unit tests in this module.

public void testAuthToken() {
    try {
        String clazz = ClientConfig.getConfiguration().getString(
            Property.UDDI_PROXY_TRANSPORT,Property.DEFAULT_UDDI_PROXY_TRANSPORT);
        Class<?> transportClass = Loader.loadClass(clazz);
        if (transportClass!=null) {
            Transport transport = (Transport) transportClass.newInstance();
            UDDISecurityPortType securityService = transport.getSecurityService();
            GetAuthToken getAuthToken = new GetAuthToken();
            getAuthToken.setUserID("root");
            getAuthToken.setCred("");
            AuthToken authToken = securityService.getAuthToken(getAuthToken);
            System.out.println(authToken.getAuthInfo());
            Assert.assertNotNull(authToken);
        } else {
            Assert.fail();
        }
    } catch (Exception e) {
        e.printStackTrace();
        Assert.fail();
    } 
}

Make sure that the publisher, in this case “root” is an existing publisher in the Registry and that you are supplying the correct credential to get a successful response. If needed check Chapter 3, Authentication to learn more about this subject.

Another place to look for sample code is the docs/examples/helloword directory. Alternatively you can use annotations.