Apache jUDDICommunity Documentation

jUDDI User Guide

A guide to using jUDDI

by Tom Cunningham, Kurt Stam, Jeff Faath, and The jUDDI Community
and thanks to Darrin Mison

Abstract

This document is a User Guide for jUDDI. jUDDI (pronounced "Judy") is an open source Java implementation of the Universal Description, Discovery, and Integration (UDDI v3) specification for Web Services.


Preface
1. Document Conventions
1.1. Typographic Conventions
1.2. Pull-quote Conventions
1.3. Notes and Warnings
2. We Need Feedback!
1. UDDI Registry
1.1. Introduction
1.2. UDDI Registry
2. Getting Started
2.1. What Should I Download?
2.2. Using the JAR
2.3. Using the WAR File
2.4. Using the Tomcat Bundle
2.5. Using jUDDI Web Services
3. Authentication
3.1. Introduction
3.2. jUDDI Authentication
3.3. XMLDocAuthentication
3.4. CryptedXMLDocAuthentication
3.5. LDAP Authentication
3.6. JBoss Authentication
4. Database Setup
4.1. Derby Out-of-the-Box
4.2. Switch to MySQL
4.3. Switch to Postgres
4.4. Switch to Oracle
4.5. Switch to HSQL
4.6. Switch to <other db>
4.7. Override persistence properties in the juddiv3.properties
5. Root Seed Data
5.1. Introduction
5.2. Seed Data Files
5.3. Token in the Seed Data
5.4. Customer Seed Data
6. jUDDI_Configuration
6.1. Introduction
6.2. Authentication
6.3. Startup
6.4. Queries
6.5. Proxy Settings
6.6. KeyGeneration
6.7. Subscription
6.8. Transfer
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
8. Simple Publishing Using the jUDDI API
8.1. UDDI Data Model
8.2. jUDDI Additions to the Model
8.3. UDDI and jUDDI API
8.4. Getting Started
8.4.1. Simple Publishing Example
8.5. Conclusion
9. Subscription
9.1. Introduction
9.2. Two node example setup: Sales and Marketing
9.3. Deploy the HelloSales Service
9.4. Configure a user to create Subscriptions
9.5. Synchronous Notifications
10. Administration
10.1. Introduction
10.2. Changing the Listener Port
10.3. Changing the Oracle Sequence name
10.4. Persistence
11. Deploying to JBoss 6.0.0.GA
11.1. Introduction
11.2. Add juddiv3.war
11.3. Change web.xml
11.4. Configure Datasource
12. Deploying to Glassfish 2.1.1
12.1. Introduction
12.2. Glassfish jars
12.3. Configure the JUDDI datasource
12.4. Add juddiv3-cxf.war
12.5. Run juddi
A. Revision History

This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information.

In PDF and paper editions, this manual uses typefaces drawn from the Liberation Fonts set. The Liberation Fonts set is also used in HTML editions if the set is installed on your system. If not, alternative but equivalent typefaces are displayed. Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default.

Four typographic conventions are used to call attention to specific words and phrases. These conventions, and the circumstances they apply to, are as follows.

Mono-spaced Bold

Used to highlight system input, including shell commands, file names and paths. Also used to highlight key caps and key-combinations. For example:

The above includes a file name, a shell command and a key cap, all presented in Mono-spaced Bold and all distinguishable thanks to context.

Key-combinations can be distinguished from key caps by the hyphen connecting each part of a key-combination. For example:

The first sentence highlights the particular key cap to press. The second highlights two sets of three key caps, each set pressed simultaneously.

If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in Mono-spaced Bold. For example:

Proportional Bold

This denotes words or phrases encountered on a system, including application names; dialogue box text; labelled buttons; check-box and radio button labels; menu titles and sub-menu titles. For example:

The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in Proportional Bold and all distinguishable by context.

Note the > shorthand used to indicate traversal through a menu and its sub-menus. This is to avoid the difficult-to-follow 'Select Mouse from the Preferences sub-menu in the System menu of the main menu bar' approach.

Mono-spaced Bold Italic or Proportional Bold Italic

Whether Mono-spaced Bold or Proportional Bold, the addition of Italics indicates replaceable or variable text. Italics denotes text you do not input literally or displayed text that changes depending on circumstance. For example:

Note the words in bold italics above username, domain.name, file-system, package, version and release. Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system.

Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. For example:

The UDDI Registry implements the UDDI specification. UDDI is a Web-based distributed directory that enables businesses to list themselves on the Internet and discover each other, similar to a traditional phone book's yellow and white pages. The UDDI registry is both a white pages business directory and a technical specifications library. The Registry is designed to store information about Businesses and Services and it holds references to detailed documentation.


A business publishes services to the UDDI registry. A client looks up the service in the registry and receives service binding information. The client then uses the binding information to invoke the service. The UDDI APIs are SOAP based for interoperability reasons. The UDDI v3 specification defines 9 APIs:

  1. UDDI_Security_PortType, defines the API to obtain a security token. With a valid security token a publisher can publish to the registry. A security token can be used for the entire session.

  2. UDDI_Publication_PortType, defines the API to publish business and service information to the UDDI registry.

  3. UDDI_Inquiry_PortType, defines the API to query the UDDI registry. Typically this API does not require a security token.

  4. UDDI_CustodyTransfer_PortType, this API can be used to transfer the custody of a business from one UDDI node to another.

  5. UDDI_Subscription_PortType, defines the API to register for updates on a particular business of service.

  6. UDDI_SubscriptionListener_PortType, defines the API a client must implement to receive subscription notifications from a UDDI node.

  7. UDDI_Replication_PortType, defines the API to replicate registry data between UDDI nodes.

  8. UDDI_ValueSetValidation_PortType, by nodes to allow external providers of value set validation. Web services to assess whether keyedReferences or keyedReferenceGroups are valid.

  9. UDDI_ValueSetCaching_PortType, UDDI nodes may perform validation of publisher references themselves using the cached values obtained from such a Web service.

In order to enforce proper write access to jUDDI, each request to jUDDI needs a valid authToken. Note that read access is not restricted and therefore queries into the registries are not restricted.

To obtain a valid authToken a getAuthToken() request must be made, where a GetAuthToken object is passed. On the GetAuthToken object a userid and credential (password) needs to be set.

org.uddi.api_v3.GetAuthToken ga = new org.uddi.api_v3.GetAuthToken();
ga.setUserID(pubId);
ga.setCred("");

org.uddi.api_v3.AuthToken token = securityService.getAuthToken(ga);

The property juddi.authenticator in the juddi.properties configuration file can be used to configure how jUDDI is going to check the credentials passed in on the GetAuthToken request. By default jUDDI uses the JUDDIAuthenticator implementation. You can provide your own authentication implementation or use any of the ones mention below. The implementation needs to implement the org.apache.juddi.auth.Authenticator interface, and juddi.authenticator property should refer to the implementation class.

There are two phases involved in Authentication. The authenticate phase and the identify phase. Both of these phases are represented by a method in the Authenticator interface.

The authenticate phase occurs during the GetAuthToken request as described above. The goal of this phase is to turn a user id and credentials into a valid publisher id. The publisher id (referred to as the “authorized name” in UDDI terminology) is the value that assigns ownership within UDDI. Whenever a new entity is created, it must be tagged with ownership by the authorized name of the publisher. The value of the publisher id can be completely transparent to jUDDI – the only requirement is that one exists to assign to new entities. Thus, the authenticate phase must return a non-null publisher id. Upon completion of the GetAuthToken request, an authentication token is issued to the caller.

In subsequent calls to the UDDI API that require authentication, the token issued from the GetAuthToken request must be provided. This leads to the next phase of jUDDI authentication – the identify phase.

The identify phase is responsible for turning the authentication token (or the publisher id associated with that authentication token) into a valid UddiEntityPublisher object. The UddiEntityPublisher object contains all the properties necessary to handle ownership of UDDI entities. Thus, the token (or publisher id) is used to “identify” the publisher.

The two phases provide compliance with the UDDI authentication structure and grant flexibility for users that wish to provide their own authentication mechanism. Handling of credentials and publisher properties can be done entirely outside of jUDDI. However, jUDDI provides the Publisher entity, which is a sub-class of UddiEntityPublisher, to persist publisher properties within jUDDI. This is used in the default authentication and is the subject of the next section.

By default jUDDI uses an embedded Derby database. This allows us to build a downloadable distribution that works out-of-the-box, without having to do any database setup work. We recommend switching to an enterprise-level database before going to production. JUDDI uses the Java Persistence API (JPA) in the back end and we've tested with both OpenJPA and Hibernate. To configure which JPA provider you want to use, you will need to edit the configuration in the persistence.xml. This file can be found in the juddi.war/WEB-INF/classes/META-INF/persistence.xml

For Hibernate the content of this file looks like

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
    version="1.0">
    <persistence-unit name="juddiDatabase" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:comp/env/jdbc/JuddiDS</jta-data-source>
        <!-- entity classes -->
        <class>org.apache.juddi.model.Address</class>
        <class>org.apache.juddi.model.AddressLine</class>
        <class>org.apache.juddi.model.AuthToken</class>
        <class>org.apache.juddi.model.BindingCategoryBag</class>
        <class>org.apache.juddi.model.BindingDescr</class>
        <class>org.apache.juddi.model.BindingTemplate</class>
        <class>org.apache.juddi.model.BusinessCategoryBag</class>
        <class>org.apache.juddi.model.BusinessDescr</class>
        <class>org.apache.juddi.model.BusinessEntity</class>
        <class>org.apache.juddi.model.BusinessIdentifier</class>
        <class>org.apache.juddi.model.BusinessName</class>
        <class>org.apache.juddi.model.BusinessService</class>
        <class>org.apache.juddi.model.CategoryBag</class>
        <class>org.apache.juddi.model.Contact</class>
        <class>org.apache.juddi.model.ContactDescr</class>
        <class>org.apache.juddi.model.DiscoveryUrl</class>
        <class>org.apache.juddi.model.Email</class>
        <class>org.apache.juddi.model.InstanceDetailsDescr</class>
        <class>org.apache.juddi.model.InstanceDetailsDocDescr</class>
        <class>org.apache.juddi.model.KeyedReference</class>
        <class>org.apache.juddi.model.KeyedReferenceGroup</class>
        <class>org.apache.juddi.model.OverviewDoc</class>
        <class>org.apache.juddi.model.OverviewDocDescr</class>
        <class>org.apache.juddi.model.PersonName</class>
        <class>org.apache.juddi.model.Phone</class>
        <class>org.apache.juddi.model.Publisher</class>
        <class>org.apache.juddi.model.PublisherAssertion</class>
        <class>org.apache.juddi.model.PublisherAssertionId</class>
        <class>org.apache.juddi.model.ServiceCategoryBag</class>
        <class>org.apache.juddi.model.ServiceDescr</class>
        <class>org.apache.juddi.model.ServiceName</class>
        <class>org.apache.juddi.model.ServiceProjection</class>
        <class>org.apache.juddi.model.Subscription</class>
        <class>org.apache.juddi.model.SubscriptionChunkToken</class>
        <class>org.apache.juddi.model.SubscriptionMatch</class>
        <class>org.apache.juddi.model.Tmodel</class>
        <class>org.apache.juddi.model.TmodelCategoryBag</class>
        <class>org.apache.juddi.model.TmodelDescr</class>
        <class>org.apache.juddi.model.TmodelIdentifier</class>
        <class>org.apache.juddi.model.TmodelInstanceInfo</class>
        <class>org.apache.juddi.model.TmodelInstanceInfoDescr</class>
        <class>org.apache.juddi.model.TransferToken</class>
        <class>org.apache.juddi.model.TransferTokenKey</class>
        <class>org.apache.juddi.model.UddiEntity</class>
        <class>org.apache.juddi.model.UddiEntityPublisher</class>

        <properties>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.dialect" 
                value="org.hibernate.dialect.DerbyDialect"/>
        </properties>
    </persistence-unit>
</persistence>

The persistence.xml reference a datasource “java:comp/env/jdbc/JuddiDS”. Datasource deployment is Application Server specific. If you are using Tomcat, then the datasource is defined in juddi/META-INF/context.xml which by default looks like

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <!--  -->
    <Resource name="jdbc/JuddiDS" auth="Container"
        type="javax.sql.DataSource" username="" password=""
        driverClassName="org.apache.derby.jdbc.EmbeddedDriver" 
        url="jdbc:derby:juddi-derby-test-db;create=true"
        maxActive="8" 
        />  
</Context>

This was written from a JBoss - jUDDI perspective. Non-JBoss-users may have to tweak this a little bit, but for the most part, the files and information needed is here.

Logged in as postgres user, access psql:

# psql

postgres= CREATE USER juddi with PASSWORD 'password';
postgres= CREATE DATABASE juddi;
postgres= GRANT ALL PRIVILEGES ON DATABASE juddi to juddi;

Note, for this example, my database is called juddi, as is the user who has full privileges to the database. The user 'juddi' has a password set to 'password'.

<datasources>
    <local-tx-datasource>
        <jndi-name>JuddiDS</jndi-name>
        <connection-url>jdbc:postgresql://localhost:5432/juddi</connection-url>
        <driver-class>org.postgresql.Driver</driver-class>
        <user-name>juddi</user-name>
        <password>password</password>
        <!-- sql to call when connection is created.  Can be anything, 
        select 1 is valid for PostgreSQL 
        <new-connection-sql>select 1</new-connection-sql>
        -->
        <!-- sql to call on an existing pooled connection when it is obtained 
        from pool.  Can be anything, select 1 is valid for PostgreSQL
        <check-valid-connection-sql>select 1</check-valid-connection-sql>
        -->
        <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->
        <metadata>
            <type-mapping>PostgreSQL 8.0</type-mapping>
        </metadata>
    </local-tx-datasource>
</datasources>

In persistence.xml, reference the correct JNDI name of the datasource and remove the derby Dialect and add in the postgresql Dialect:

<jta-data-source>java:comp/env/jdbc/JuddiDS</jta-data-source>
    .....
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>

Be sure to have postgresql-8.3-604.jdbc4.jar in the lib folder!

First make sure you have a running hsqldb. For a standalone server startup use:

		java -cp hsqldb.jar org.hsqldb.server.Server --port 1747 --database.0 file:juddi --dbname.0 juddi
		

Next, connect the client manager to this instance using:

		java -classpath hsqldb.jar org.hsqldb.util.DatabaseManagerSwing --driver org.hsqldb.jdbcDriver --url jdbc:hsqldb:hsql://localhost:1747/juddi  -user sa
		

and create the juddi user:

		CREATE USER JUDDI PASSWORD "password"  ADMIN;
		CREATE SCHEMA JUDDI AUTHORIZATION JUDDI;
		SET DATABASE DEFAULT INITIAL SCHEMA JUDDI;
		ALTER USER juddi set initial schema juddi;
		

From now on, one can connect as JUDDI user to that database and the database is now ready to go.

To switch over to HSQL you need to add the hsql driver (i.e. The hsqldb.jar) to the classpath and you will need to edit the persistence.xml

<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>

and the datasource. For tomcat you the context.xml should look something like

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <!-- HSQL data source -->
    <Resource name="jdbc/JuddiDS" auth="Container"
            type="javax.sql.DataSource" username="JUDDI" password="password"
            driverClassName="org.hsqldb.jdbcDriver"
            url="jdbc:hsqldb:hsql://localhost:1747/juddi"
            maxActive="8"
            />
</Context>

For each publisher there are four seed data files that will be read the first time you start jUDDI:

<publisher>_Publisher.xml
<publisher>_tModelKeyGen.xml
<publisher>_BusinessEntity.xml
<publisher>_tModels.xml

For example the content of the root_Publisher.xml looks like

<publisher xmlns="urn:juddi-apache-org:api_v3" authorizedName="root">
    <publisherName>root publisher</publisherName>
    <isAdmin>true</isAdmin>
</publisher>

Each publisher should have its own key generator schema so that custom generated keys cannot end up being identical to keys generated by other publishers. It is therefor that the each publisher need to define their own KenGenerator tModel. The tModel Key Generator is defined in the file root_tModelKeyGen.xml and the content of this file is

<tModel tModelKey="uddi:juddi.apache.org:keygenerator" xmlns="urn:uddi-org:api_v3">
    <name>uddi-org:keyGenerator</name>
    <description>Root domain key generator</description>
    <overviewDoc>
        <overviewURL useType="text">
        http://uddi.org/pubs/uddi_v3.htm#keyGen
        </overviewURL>
    </overviewDoc>
    <categoryBag>
        <keyedReference tModelKey="uddi:uddi.org:categorization:types" 
            keyName="uddi-org:types:keyGenerator"
            keyValue="keyGenerator" />
    </categoryBag>
</tModel>

This means that the legal format of keys used by the root publisher need to be in the form uddi:juddi.apache.org:<text-of-chioce> The use of other types of format will lead to an 'illegal key' error. The root publisher can only own one KeyGenerator while any other publisher can own more then one KeyGenerator. KeyGenerators should not be shared unless there is a good reason to do so. If you want to see your publisher with more then just the one KeyGenerator tModel, you can use the <publisher>_tModels.xml file.

Finally, in the <publisher>_BusinessEntity.xml file can be used to setup Business and Service data. In the root_BusinessEntity.xml we specified the ASF Business, and the UDDI services; Inquiry, Publish, etc.:

<businessEntity xmlns="urn:uddi-org:api_v3" 
    xmlns:xml="http://www.w3.org/XML/1998/namespace" 
    businessKey="uddi:juddi.apache.org:businesses-asf">
    <!-- Change the name field to represent the name of your registry -->
    <name xml:lang="en">An Apache jUDDI Node</name>
        <!-- Change the description field to provided 
        a brief description of your registry -->
        <description xml:lang="en">
            This is a UDDI v3 registry node as implemented by Apache jUDDI.
        </description>
        <discoveryURLs>
        <!-- This discovery URL should point to the home installation URL of jUDDI -->
        <discoveryURL useType="home">
            http://${juddi.server.name}:${juddi.server.port}/juddiv3
        </discoveryURL>
    </discoveryURLs>
    <categoryBag>
        <keyedReference tModelKey="uddi:uddi.org:categorization:nodes" keyValue="node" />
    </categoryBag>

    <businessServices>
    <!-- As mentioned above, you may want to provide user-defined keys for 
    these (and the services/bindingTemplates below.  Services that you
    don't intend to support should be removed entirely -->
        <businessService serviceKey="uddi:juddi.apache.org:services-inquiry" 
            businessKey="uddi:juddi.apache.org:businesses-asf">
            <name xml:lang="en">UDDI Inquiry Service</name>
            <description xml:lang="en">Web Service supporting UDDI Inquiry API</description>
            <bindingTemplates>
                <bindingTemplate bindingKey="uddi:juddi.apache.org:servicebindings-inquiry-ws" 
                    serviceKey="uddi:juddi.apache.org:services-inquiry">
                    <description>UDDI Inquiry API V3</description>
                    <!-- This should be changed to the WSDL URL of the inquiry API.  
                    An access point inside a bindingTemplate will be found for every service
                    in this file.  They all must point to their API's WSDL URL -->
                    <accessPoint useType="wsdlDeployment">
                        http://${juddi.server.name}:${juddi.server.port}/juddiv3/services/inquiry?wsdl
                    </accessPoint>
                    <tModelInstanceDetails>
                        <tModelInstanceInfo tModelKey="uddi:uddi.org:v3_inquiry">
                            <instanceDetails>
                                <instanceParms>
                                <![CDATA[
                                <?xml version="1.0" encoding="utf-8" ?>
                                <UDDIinstanceParmsContainer 
                                    xmlns="urn:uddi-org:policy_v3_instanceParms">
                                    <defaultSortOrder>
                                        uddi:uddi.org:sortorder:binarysort
                                    </defaultSortOrder>
                                </UDDIinstanceParmsContainer>
                                ]]>
                                </instanceParms>
                            </instanceDetails>
                        </tModelInstanceInfo>
                    </tModelInstanceDetails>
                    <categoryBag>
                        <keyedReference keyName="uddi-org:types:wsdl" keyValue="wsdlDeployment" 
                            tModelKey="uddi:uddi.org:categorization:types"/>
                    </categoryBag>
                </bindingTemplate>
            </bindingTemplates>
        </businessService>
        <businessService serviceKey="uddi:juddi.apache.org:services-publish" 
            businessKey="uddi:juddi.apache.org:businesses-asf">
            <name xml:lang="en">UDDI Publish Service</name>
            ...........
        </businessService>
    </businessServices>
</businessEntity>

Note that the seeding process only kicks off if no publishers exist in the database. So this will only work with a clean database, unless you set juddi.seed.always to true. Then it will re-apply all files with the exception of the root data files. Note that this can lead to losing data that was added to entities that are re-seeded, since data is not merged.

# The ${juddi.server.baseurl} token can be referenced in accessPoints and will be resolved at runtime.
juddi.server.baseurl=http://localhost:8080

Token that can be accessed in accessPointURLs and resolved at runtime.

# 
juddi.root.publisher=root

The username for the jUDDI root publisher. This is usually just set to "root".

#
juddi.seed.always=false

Forces seeding of the jUDDI data. This will re-apply all files with the exception of the root data files. Note that this can lead to losing data that was added to the entities that are re-seeded, since data is not merged.

#
juddi.load.install.data=false

This property allows you to cancel loading of the jUDDI install data.

# Default locale
juddi.locale=en_US

The default local to use.

# Name of the persistence unit to use (the default, "juddiDatabase" refers to the unit compiled into the juddi library)
juddi.persistenceunit.name=juddiDatabase

The persistence name for the jUDDI database that is specified in the persistence.xml file.

# Check-the-time-stamp-on-this-file Interval in milli seconds
juddi.configuration.reload.delay=2000

The time in milliseconds in which juddiv3.properties is polled for changes.

# These two tokens are referenced in the install data. Note that you
# can use any tokens, and that their values can be set here or as
# System parameters.
juddi.server.name=macdaddy
juddi.server.port=8080

The server name and port number of the server.

#The UDDI Operator Contact Email Address
juddi.operatorEmailAddress=admin@juddi.org

The jUDDI operator email address.

# The maximum number of UDDI artifacts allowed
# per publisher. A value of '-1' indicates any
# number of artifacts is valid (These values can be
# overridden at the individual publisher level).
juddi.maxBindingsPerService=10

The maximum number of bindings that can be specified per service.

# The maximum number of UDDI artifacts allowed
# per publisher. A value of '-1' indicates any
# number of artifacts is valid (These values can be
# overridden at the individual publisher level).
juddi.maxBusinessesPerPublisher=25

The maximum number of businesses that can be registered per publisher.

# The maximum number of "IN" clause parameters.  Some RDMBS limit the number of
# parameters allowed in a SQL "IN" clause.
juddi.maxInClause=1000

The maximum number of parameters within an IN clause.

# The maximum name size and maximum number
# of name elements allows in several of the
# FindXxxx and SaveXxxx UDDI functions.
juddi.maxNameElementsAllowed=5

Maximum number of name elements allowed in a jUDDI query.

# The maximum name size and maximum number
# of name elements allows in several of the
# FindXxxx and SaveXxxx UDDI functions.
juddi.maxNameLength=255

Maximum name size within a jUDDI query.

# The maximum number of rows returned in a find_* operation.  Each call can set
# this independently, but this property defines a global maximum.
juddi.maxRows=1000

Maximum number of rows within a response.

# The maximum number of UDDI artifacts allowed
# per publisher. A value of '-1' indicates any
# number of artifacts is valid (These values can be
# overridden at the individual publisher level).
juddi.maxServicesPerBusiness=20

Maxmimum number of services in a business.

# The maximum number of UDDI artifacts allowed
# per publisher. A value of '-1' indicates any
# number of artifacts is valid (These values can be
# overridden at the individual publisher level).
juddi.maxTModelsPerPublisher=100

Maximum number of TModels a publisher can create.

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.

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.

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.

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.

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 therefore doesn’t conform to the UDDI specification.

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.

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:

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 an independent 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.

In this example we are setting up a node for 'sales' and a node for 'marketing'. For this you need to deploy jUDDI to two different services, then you need to do the following setup:

Note that we kept the root partition the same as sales and marketing are in the same company, however the Node Id and Name are different and reflect that this node is in 'sales' or 'marketing'.

Finally you will need to replace the sales server's uddi-portlets.war/WEB-INF/classes/META-INF/uddi.xml with uddi-portlets.war/WEB-INF/classes/META-INF/uddi.xml.sales. Then, edit the uddi-portlets.war/WEB-INF/classes/META-INF/uddi.xml and set the following properties:

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

Log into the sales portal: http://sales:8080/pluto with username/password: sales/sales.


Before logging into the marketing portal, replace marketing's uddi-portlet.war/WEB-INF/classes/META-INF/uddi.xml with udd-portlet.war/WEB-INF/classes/META-INF/uddi.xml.marketing. Then you will need to edit the uddi-portlet.war/WEB-INF/classes/META_INF/uddi.xml and set the following properties:

<name>default</name>
<properties>
    <property name="serverName" value="marketing"/>
    <property name="serverPort" value="8080"/>
    <property name="rmiPort" value="1099"/>
</properties>

Now log into the marketing portal http://marketing:8080/pluto with username/password: marketing/ marketing. In the browser for the marketing node we should now see:


Note that the subscriptionlistener is owned by the Marketing Node business (and not the Root Marketing Node). The Marketing Node Business is managed by the marketing publisher.

The sales department developed a service called HelloSales. The HelloSales service is provided in the juddiv3-samples.war, and it is annotated so that it will auto-register. Before deploying the war, edit the juddiv3-samples.war/WEB-INF/classes/META-INF/uddi.xml file to set some property values to 'sales'.

<?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>
    </manager>
</uddi>

Now deploy the juddiv3-samples.war to the sales registry node, by building the juddiv3-samples.war and deploying. The HelloWorld service should deploy


On the Marketing UDDI we'd like to subscribe to the HelloWord service, in the Sales UDDI Node. As mentioned before there are two ways to do this; synchronously and asynchronously.

For a user to create and save subscriptions the publisher needs to have a valid login to both the sales and the marketing node. Also if the marketing publisher is going to create registry objects in the marketing node, the marketing publisher needs to own the sales keygenerator tModel. Check the marketing_*.xml files in the root seed data of both the marketing and sales node, if you want to learn more about this. It is important to understand that the 'marketing' publisher in the marketing registry owns the following tModels:

<save_tModel xmlns="urn:uddi-org:api_v3">

    <tModel tModelKey="uddi:marketing.apache.org:keygenerator" xmlns="urn:uddi-org:api_v3">
        <name>marketing-apache-org:keyGenerator</name>
        <description>Marketing domain key generator</description>
        <overviewDoc>
            <overviewURL useType="text">
                http://uddi.org/pubs/uddi_v3.htm#keyGen
            </overviewURL>
        </overviewDoc>
        <categoryBag>
            <keyedReference tModelKey="uddi:uddi.org:categorization:types" 
                keyName="uddi-org:types:keyGenerator"
                keyValue="keyGenerator" />
        </categoryBag>
    </tModel>
    
    <tModel tModelKey="uddi:marketing.apache.org:subscription:keygenerator" 
        xmlns="urn:uddi-org:api_v3">
        <name>marketing-apache-org:subscription:keyGenerator</name>
        <description>Marketing Subscriptions domain key generator</description>
        <overviewDoc>
            <overviewURL useType="text">
                http://uddi.org/pubs/uddi_v3.htm#keyGen
            </overviewURL>
        </overviewDoc>
        <categoryBag>
            <keyedReference tModelKey="uddi:uddi.org:categorization:types" 
                keyName="uddi-org:types:keyGenerator"
                keyValue="keyGenerator" />
        </categoryBag>
    </tModel>

    <tModel tModelKey="uddi:sales.apache.org:keygenerator" xmlns="urn:uddi-org:api_v3">
        <name>sales-apache-org:keyGenerator</name>
        <description>Sales Root domain key generator</description>
        <overviewDoc>
            <overviewURL useType="text">
                http://uddi.org/pubs/uddi_v3.htm#keyGen
            </overviewURL>
        </overviewDoc>
        <categoryBag>
            <keyedReference tModelKey="uddi:uddi.org:categorization:types" 
                keyName="uddi-org:types:keyGenerator"
                keyValue="keyGenerator" />
        </categoryBag>
    </tModel>
</save_tModel>

If we are going to user the marketing publisher to subscribe to updates in the sales registry, then we need to provide this publisher with two clerks in the uddi.xml of the uddi-portlet.war.

<clerks registerOnStartup="false">
    <clerk  name="MarketingCratchit"    node="default" 
            publisher="marketing"       password="marketing"/>

    <clerk  name="SalesCratchit"        node="sales-ws"   
            publisher="marketing"       password="marketing"/>
    <!--  optional 
    <xregister>
        <servicebinding 
            entityKey="uddi:marketing.apache.org:servicebindings-subscriptionlistener-ws" 
            fromClerk="MarketingCratchit" toClerk="SalesCratchit"/>
    </xregister>
    -->
</clerks>

Here we created two clerks for this publisher called 'MarketingCratchit' and 'SalesCratchit'. This will allow the publisher to check the existing subscriptions owned by this publisher in each of the two systems.

While being logged in as the marketing publisher on the marketing portal, we should see the following when selecting the UDDISubscription Portlet.


When both nodes came up green you can lick on the 'new subscription' icon in the toolbar. Since we are going to use this subscription synchronously only the Binding Key and Notification Interval should be left blank, as shown in Figure 9.7, “Create a New Subscription”. Click the save icon to save the subscription.


Make sure that the subscription Key uses the convention of the keyGenerator of the marketing publisher. You should see the orange subscription icon appear under the “sales-ws” UDDI node.


To invoke a synchronous subscription, click the icon with the green arrows. This will give you the opportunity to set the coverage period.


Click the green arrows icon again to invoke the synchronous subscription request. The example finder request will go out to the sales node and look for updates on the HelloWorld service. The raw XML response will be posted in the UDDISubscriptionNotification Portlet.


The response will also be consumed by the marketing node. The marketing node will import the HelloWorld subscription information, as well as the sales business. So after a successful sync you should now see three businesses in the Browser Portlet of the marketing node, see Figure 9.11, “The registry info of the HelloWorld Service information was imported by the subscription mechanism.”.


If you are using Hibernate as a persistence layer for jUDDI, then Oracle will generate a default sequence for you ("HIBERNATE_SEQUENCE"). If you are using hibernate elsewhere, you may wish to change the sequence name so that you do not share this sequence with any other applications. If other applications try to manually create the default hibernate sequence, you may even run into situations where you find conflicts or a race condition.

The easiest way to handle this is to create an orm.xml file and place it within the classpath in a META-INF directory, which will override the jUDDI persistence annotations and will allow you to specify a specific sequence name for use with jUDDI. The following orm.xml specifies a "juddi_sequence" sequence to be used with jUDDI.

<entity-mappings
  xmlns="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
  version="1.0">
  
  <sequence-generator name="juddi_sequence" sequence-name="juddi_sequence"/>

  <entity class="org.apache.juddi.model.Address">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.AddressLine">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.BindingDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.BusinessDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.BusinessIdentifier">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.BusinessName">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.CategoryBag">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.Contact">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.ContactDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.DiscoveryUrl">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.Email">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.InstanceDetailsDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.InstanceDetailsDocDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

 <entity class="org.apache.juddi.model.KeyedReference">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.KeyedReferenceGroup">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.OverviewDoc">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.OverviewDocDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.PersonName">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.Phone">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.ServiceDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.ServiceName">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.SubscriptionMatch">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.TmodelDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.TmodelIdentifier">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.TmodelInstanceInfo">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.TmodelInstanceInfoDescr">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.TransferTokenKey">
    <attributes>
      <id name="id">
        <generated-value generator="juddi_sequence" strategy="AUTO"/>
      </id>
    </attributes>
  </entity>

  <entity class="org.apache.juddi.model.BindingTemplate">
    <attributes>
      <basic name="accessPointUrl">
        <column name="access_point_url" length="4000"/>
      </basic>
    </attributes>
  </entity>
</entity-mappings>

The first step for configuring a datasource is to copy your JDBC driver into the classpath. Copy your JDBC driver into ${jboss.home.dir}/server/${configuration}/lib, where configuration is the profile you wish to start with (default, all, etc.). Example :

cp mysql-connector-java-5.0.8-bin.jar /opt/jboss-5.1.0.GA/server/default/lib

Next, configure a JBoss datasource file for your db. Listed below is an example datasource for MySQL :

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
 <local-tx-datasource>
   <jndi-name>JuddiDS</jndi-name>
   <connection-url>jdbc:mysql://localhost:3306/juddiv3</connection-url>
   <driver-class>com.mysql.jdbc.Driver</driver-class>
   <user-name>root</user-name>
   <password></password>
   <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>

   <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
   <metadata>
      <type-mapping>mySQL</type-mapping>
   </metadata>
 </local-tx-datasource>
</datasources>

Next, make a few changes to the juddiv3.war/classes/META-INF/persistence.xml. Change the "hibernate.dialect" property to match the database you have chosen for persistence. For MySQL, change the value of hibernate.dialect to "org.hibernate.dialect.MySQLDialect". A full list of dialects available can be found in the hibernate documentation (https://www.hibernate.org/hib_docs/v3/api/org/hibernate/dialect/package-summary.html). Next, change the <jta-data-source> tags so that it reads <non-jta-data-source>, and change the value from java:comp/env/jdbc/JuddiDS to java:/JuddiDS.

Revision History
Revision 1.1Thu Jan 07 2010Tom Cunningham
Translated Dev Guide to docbook
Revision 1.0Mon Nov 16 2009Darrin Mison
Created from community jUDDI Guide