Apache jUDDICommunity Documentation
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.
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 name | description | required |
---|---|---|
name | name of the node | yes |
description | description of the node | no |
properties | container for properties that will be passed into the clerk | no |
proxyTransport | The transport protocol used by the client to connect to the UDDI server | yes |
custodyTransferUrl | Connection settings for custody transfer | no |
inquiryUrl | Connection location settings for inquiries | yes |
publishUrl | Connection location settings for publishing | yes |
securityUrl | Connection location settings for obtaining security tokens | yes |
subscriptionUrl | Connection location settings for registering subscription requests | no |
subscriptionListenerUrl | Connection location settings receiving subscription notifications | no |
juddiApiUrl | Connection location settings for the jUDDI specific API for things like publisher management | no |
Finally the manager element can contain a 'clerks' element in which one can define one or more clerks.
attribute name | description | required |
---|---|---|
name | name of the clerk | yes |
node | name reference to one of the nodes specified in the same manager | yes |
publisher | name of an existing publisher | yes |
password | password credential of the publisher | yes |
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.
org.jnp.interfaces.NamingContext
)
UDDIPublicationService (class: org.apache.juddi.rmi.UDDIPublicationService
)
UDDICustodyTransferService (class: org.apache.juddi.rmi.UDDICustodyTransferService
)
UDDISubscriptionListenerService (class: org.apache.juddi.rmi.UDDISubscriptionListenerService
)
UDDISecurityService (class: org.apache.juddi.rmi.UDDISecurityService
)
UDDISubscriptionService (class: org.apache.juddi.rmi.UDDISubscriptionService
)
UDDIInquiryService (class: org.apache.juddi.rmi.UDDIInquiryService
)
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.
Conventionally Services (BusinessService) and their EndPoints (BindingTemplates) are registered to a UDDI Registry using a GUI, where an admin user manually adds the necessary info. This process tends to make the data in the Registry rather static and the data can grow stale over time. To make the data in the UDDI more dynamic it makes sense to register and EndPoint (BindingTemplate) when it comes online, which is when it gets deployed. The UDDI annotations are designed to just that: register a Service when it get deployed to an Application Server. There are two annotations: UDDIService, and UDDIServiceBinding. You need to use both annotations to register an EndPoint. Upon undeployment of the Service, the EndPoint will be de-registered from the UDDI. The Service information stays in the UDDI. It makes sense to leave the Service level information in the Registry since this reflects that the Service is there, however there is no EndPoint at the moment ("Check back later"). It is a manual process to remove the Service information. The annotations use the juddi-client library which means that they can be used to register to any UDDIv3 registry.
The UDDIService annotation is used to register a service under an already existing business in the Registry. The annotation should be added at the class level of the java class.
Table 7.3. UDDIService attributes
attribute | description | required |
---|---|---|
serviceName | The name of the service, by default the clerk will use the one name specified in the WebService annotation | no |
description | Human readable description of the service | yes |
serviceKey | UDDI v3 Key of the Service | yes |
businessKey | UDDI v3 Key of the Business that should own this Service. The business should exist in the registry at time of registration | yes |
lang | Language locale which will be used for the name and description, defaults to "en" if omitted | no |
categoryBag | Definition of a CategoryBag, see below for details | no |
The UDDIServiceBinding annotation is used to register a BindingTemplate to the UDDI registry. This annotation cannot be used by itself. It needs to go along side a UDDIService annotation.
Table 7.4. UDDIServiceBinding attributes
attribute | description | required |
---|---|---|
bindingKey | UDDI v3 Key of the ServiceBinding | yes |
description | Human readable description of the service | yes |
accessPointType | UDDI v3 AccessPointType, defaults to wsdlDeployment if omitted | no |
accessPoint | Endpoint reference | yes |
lang | Language locale which will be used for the name and description, defaults to "en" if omitted | no |
tModelKeys | Comma-separated list of tModelKeys key references | no |
categoryBag | Definition of a CategoryBag, see below for further details | no |
The CategoryBag attribute allows you to reference tModels. For example the following categoryBag
<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>
can be put in 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",
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
.
Property | Description | Required | Default Value |
---|---|---|---|
lang | The language setting used by the registration. | no | en |
businessName | The business name which is used by. | yes | |
keyDomain | The key domain key part (used by the key formats) | yes | |
businessKeyFormat | Key format used to contruct the Business Key | no | uddi:${keyDomain}:business_${businessName} |
serviceKeyFormat | Key format used to contruct the BusinessService Key | no | uddi:${keyDomain}:service_${serviceName} |
bindingKeyFormat | Key format used to contruct the TemplateBinding Key | no | uddi:${keyDomain}:binding_${nodeName}_${serviceName}_${portName} |
serviceDescription | Default BusinessService description | no | Default service description when no <wsdl:document> element is defined inside the <wsdl:service> element. |
bindingDescription | Default BindingTemplate description | no | Default binding description when no <wsdl:document> element is defined inside the <wsdl:binding> element. |
The UDDI spec allows for setting a human readable description on both the BusinessService and TemplateBinding. Theses description fields
are important if humans are browsing the registry. A default description can be specific in the uddi.xml
, however
it makes a lot more sense to have a specific description for each service and binding, and so the registration code tries to obtain these
descriptions from the <wsdl:document> tags in the WSDL, which can be nested as a child element inside the
<wsdl:service> and <wsdl:binding> elements.
The setting of the EndPoint URL is obtained from provided WSDL in the <soap:addressbinding> of the <wsdl:port>. The issue with this is that this URL is static, and you it is very useful if it can be made more dynamic. For this reason you can implement your own version of the URLLocalizer interface. In for example the version shipped with RiftSaw the protocol and the host parts of the URL are overriden with the settings obtain from the local WebService Stack.
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
libraries for JAXB if you are not using JDK5.
JAXWS client libraries when using JAXWS transport (like CXF).
RMI and JNDI client libraries when using RMI Transport.
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.
[WSDL-UDDI] Using WSDL in a UDDI Registry, Version 2.0.2. OASIS UDDI Spec TC. 2004.
[WSDL2UDDI] Apache jUDDI WSDL2UDDI Javadoc. Apache jUDDI. 2011.
[BPEL-UDDI] Using BPEL4WS in a UDDI registry. OASIS UDDI Spec TC. 2004.
[BPEL2UDDI] Apache jUDDI BPEL2UDDI Javadoc. Apache jUDDI. 2011.
[RFTSW-UDDI] JBoss RiftSaw UDDI Registration. JBoss Riftsaw. 2011.
[SERV-LOC] Apache jUDDI ServiceLocator Javadoc. Apache jUDDI. 2011.