UDDI

 

UDDI is an acronym for Universal Description, Discovery, and Integration.  It provides a standards-based way of publishing and locating a Web service.  

For example, a trade organization could develop and publish a standard interface for a service (or set of services) of interest to its members.  Once published, the uddi registry could be searched by a potential vendor, and the information obtained from the registry could then be used by the vendor to obtain a wsdl interface description.  With the interface description in hand, the vendor could implement the interface and then register its service with a  uddi registry. Finally, a business or client in need of such a service could search the uddi registry for all vendors offering the service and, after choosing which one to work with, direct its systems programmatically to the selected vendor's service using information obtained from the uddi.

UDDI registries may be public or private.  Public registries are provided by IBM, Microsoft, and other firms.  These registries are intended primarily for actual business-to-business Web service applications, although most support experimental use as well.  They are offer replicated copies of the sama data.  Thus a service registered on one UDDI service will be available on all the others.  Private registries are run in a variety of contexts for a variety of reasons, just like other servers.  They may be test environments, functioning registries for an organization run behind a firewall, registries restricted to a specified lists of customers, etc.

The discussion here will be concerned with private uddi registration run on a local server for purposes of testing and development.  The particular uddi registry software that will provide a context for this discussion is that that is included as part of  IBM's Web service sdk.  It is supported by a set of Java APIs that greatly simplify interaction with the uddi by insulating the user from much of the wsdl that is involved with the registration process, per se, although not from the description of the Web service, itself.  For that, one must still write or generate the wsdl, as discussed in the lesson on wsdl..  One set provides an object model for wsdl; the other is primarily concerned with providing an api  for interacting with a uddi registry.

In developing uddi resources, you may wish to use IBM's forum on Web services.

The discussion below includes four main sections:


Resources


Concepts and Data Types

The purpose of a UDDI registry, as stated above, is to allow organizations to publish a standard interface for a service and to allow service providers to publish information about the service they offer that implements the interface.  Both must also publish information about the business itself.

To support this function, a uddi registry includes four types of documents, each of which is defined in XML:

BusinessEntity

A BusinessEntity is a uddi record for an organization or business.  In public uddis, a business must first be registered, by constructing a BusinessEntity, before it can register an interface or service.  It provides searchable data about the business/organization.

BusinessService

A BusinessService represents one or more deployed Web services.  The critical information is included in the two-part wsdl description of the service:  the interface.wsdl and the implementation.wsdl documents.  These files, referenced through URLs, are combined with information about the service provider to register the service in the uddi.  The interface is normally registered separately from the implementation.

tModel

The tModel (Technical Model) is the constructed referenced to a uddi object that includes critical ilnformation, such as the address and name of a service or the address of a wsdl description, a unique identifier (UUIS) that can be used as a key to retrieve the object from the uddi database.

BindingTemplate

The BindingTemplate is a document that includes both the access point for a Web service and the key to its tModel, thereby binding the two together.

 


Process

In this discussion, the following topology is used.  A Web service, called MessageObj, was implemented and deployed on a tomcat/axis server.  It was then registered on a private uddi server.  This included publishing its interface, service provider, and implementation documents.  Thereafter, the uddi can be searched for the service, obtaining a reference to the binding template for a given service provider.  From that, one can obtain the address and name of the service to which subsequent SOAP messages can be directed to access the service.

Steps

The following steps can be used to publish and access a web service using uddi:

  1. Develop the Java class that implements the functionality of the service.
  2. Deploy the class.
  3. Use Axis to generate a WSDL for the deployed class and divide it into interface and implementation files.
  4. Register the interface.
  5. Register the  service provider.
  6. Register the implementation.
  7. Access the service.
  8. Working with uddi information.

1. MessageObject Class

This class implements the functionality of the service.  It a large system, it might be one of several such classes or a controller class that provides the interface to multiple classes that implement portions of the overall service.

public class MessageObj extends java.lang.Object
{

protected java.lang.String message;

public MessageObject()
{
    message = "Hello, World, from jbs MessageObj, via UDDI";
}

public void setMessge(java.lang.String message)
{
    this.message = message;
}

public java.lang.String getMessage()
{                        
            return this.message;
}

public java.lang.String getMessageXML()
{
    String xmlString  = "<?xml version='1.0'?>\n";
                   xmlString += "<return_message>"; 
                   xmlString += this.message; 
                   xmlString += "</return_message>\n";
                             
            return xmlString;
}

    }

This class is straight forward.  It includes a getMessage() method that returns an Hello, World message.  


2. Deploy MessageObject

The class representing the service should be explicitly deployed using a Web Service Deployment Descriptor (WSDD) rather than relying on the instant deployment approach used in the SOAP example (e.g., through a .jws source file).

Copy Implementation Class

First, place a copy of the implementation class (i.e., Message.obj.class) in Axis WEB-INF/classes directory so that Axis may access it.  Then write

WSDD File

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
   xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

 <service name="MessageObj" provider="java:RPC">
  <parameter name="className" value="MessageObj"/>
  <parameter name="allowedMethods" value="*"/>
 </service>

</deployment>

 Axis provides a utility to perform the deployment.  An example invocation follows:

java org.apache.axis.client.AdminClient 
-lhttp://localhost:8888/axis/services/AdminService 
deploy.wsdd

This example assues that Axis is running locally on port 8888 and that the deploy.wsdd file is accessible to the JVM.  

Note: deployment provides a convenient mechanism for generating WSDL descriptions.  Under other scenarios, the wsdl descriptions of the service interface would be generated and registered prior to implementation.


3. WSDL Description of MessageObj

WSDL can generated by Axis from the deployed class.  It may be accessed dynamically from http://jbs.cs.unc.edu:8888/axis/services/MessageObj?wsdl.

Following a best practices strategy, the wsdl is divided into service interface and service implementation files, with the second importing the first.

Interface

<?xml version="1.0" encoding="UTF-8"?>

<wsdl:definitions targetNamespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:apachesoap="http://xml.apache.org/xml-soap" 
  xmlns:impl="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj-impl" 
  xmlns:intf="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj-intf" 
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <wsdl:message name="getMessageResponse">
    <wsdl:part name="return" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="getMessageXMLRequest">
  </wsdl:message>
  <wsdl:message name="getMessageRequest">
  </wsdl:message>
  <wsdl:message name="setMessgeRequest">
    <wsdl:part name="in0" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="setMessgeResponse">
  </wsdl:message>
  <wsdl:message name="getMessageXMLResponse">
    <wsdl:part name="return" type="xsd:string"/>
  </wsdl:message>

  <wsdl:portType name="MessageObj">
    <wsdl:operation name="getMessage">
      <wsdl:input message="intf:getMessageRequest" name="getMessageRequest"/>
      <wsdl:output message="intf:getMessageResponse" name="getMessageResponse"/>
    </wsdl:operation>
    <wsdl:operation name="setMessge" parameterOrder="in0">
      <wsdl:input message="intf:setMessgeRequest" name="setMessgeRequest"/>
      <wsdl:output message="intf:setMessgeResponse" name="setMessgeResponse"/>
    </wsdl:operation>
    <wsdl:operation name="getMessageXML">
      <wsdl:input message="intf:getMessageXMLRequest" name="getMessageXMLRequest"/>
      <wsdl:output message="intf:getMessageXMLResponse" name="getMessageXMLResponse"/>
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="MessageObjSoapBinding" type="intf:MessageObj">
    <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="getMessage">
      <wsdlsoap:operation soapAction=""/>
      <wsdl:input name="getMessageRequest">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" use="encoded"/>
      </wsdl:input>
      <wsdl:output name="getMessageResponse">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" use="encoded"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="setMessge">
      <wsdlsoap:operation soapAction=""/>
      <wsdl:input name="setMessgeRequest">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" use="encoded"/>
      </wsdl:input>
      <wsdl:output name="setMessgeResponse">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" use="encoded"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="getMessageXML">
      <wsdlsoap:operation soapAction=""/>
      <wsdl:input name="getMessageXMLRequest">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" use="encoded"/>
      </wsdl:input>
      <wsdl:output name="getMessageXMLResponse">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" use="encoded"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

</wsdl:definitions>

Implementation

<?xml version="1.0" encoding="UTF-8"?>

<wsdl:definitions targetNamespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj" 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:apachesoap="http://xml.apache.org/xml-soap" 
  xmlns:impl="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj-impl" 
  xmlns:intf="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj-intf" 
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<wsdl:import namespace="http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj-intf" 
  location="http://localhost:8888/MessageObj/wsdl/MessageObj-Interface.wsdl"/> 

  <wsdl:service name="MessageObjService">
    <wsdl:port binding="intf:MessageObjSoapBinding" name="MessageObj">
      <wsdlsoap:address location="http://localhost:8888/axis/services/MessageObj"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

4. Register the Interface

Registration is normally done programatically, in this case, from within a Java program.  The code fragment includes the critical method used for registration as well as the imports and variables used in this and following uddi publishing interactions.

/*
 * (Modification of IBM SimpleApp publish/client program
 */
import com.ibm.uddi4j.wsdl.definition.ServiceInterface;
import com.ibm.uddi4j.wsdl.definition.ServiceDefinition;
import com.ibm.uddi4j.wsdl.client.UDDIWSDLProxy;
import com.ibm.uddi4j.wsdl.client.ServiceProviderNotFoundException;
import com.ibm.uddi4j.wsdl.provider.ServiceProvider;
import com.ibm.uddi4j.wsdl.util.TModelKeyTable;

import com.ibm.uddi4j.wsdl.definition.ServiceImplementation;
import org.uddi4j.datatype.binding.BindingTemplate;
import java.util.*;
import org.uddi4j.util.*;
import org.uddi4j.*;

import org.uddi4j.util.KeyedReference;
import org.uddi4j.util.CategoryBag;
import org.uddi4j.datatype.Name;

import org.apache.axis.client.AdminClient;
import org.apache.axis.client.Service;
import org.apache.axis.client.Call;
import org.apache.axis.AxisFault;

import javax.xml.rpc.namespace.QName;

import java.util.Vector;
import java.net.URL;
import java.net.MalformedURLException;

public class MessageObjPublish {

    private static String wsdlServiceInterfaceURL  = "http://localhost:8888/MessageObj/wsdl/MessageObj-Interface.wsdl";
    private static String serviceInterfaceName     = "http://localhost:8888/axis/services/MessageObj/axis/services/MessageObj";
    private static String serviceProviderName      = "Whatever name you want.";
    private static String wsdlServiceImplURL	   = "http://localhost:8888/MessageObj/wsdl/MessageObj-Impl.wsdl";
    private static String soapServerURL		       = "http://localhost:80/MessageObj/services/AdminService";
    private static String soapDeploymentDescriptor = "../wsdl/deploy.wsdd"; 
    private static String serviceName;
    
    // needed for the UDDI key element
    private String tModelKey;
    private String keyName;
    private String keyValue;

    // required for creating a proxy to the UDDI service registry
    private static String UDDI_INQUIRY_URL	="http://localhost:80/uddisoap/inquiryapi";
    private static String UDDI_PUBLISH_URL	="http://localhost:80/uddisoap/publishapi";
    private static String UDDI_USERID		="demo";
    private static String UDDI_CRED		="pwd";
    private static String TRANSPORT_CLASS	="org.uddi4j.transport.ApacheAxisTransport";

    // to store the category bag representing the UDDI entry
    private CategoryBag categoryBag; 
    
    // store the UDDIWSDLProxy
    private UDDIWSDLProxy uddiWsdlProxy;
    
    // store the Call object for invocations
    private Call call=null;
    
    
    
// ******************  constructor  **************************
    
    public MessageObjPublish() {
        
	// initialize the elements needed for the UDDI key element
	tModelKey = TModelKeyTable.getTModelKey("NAICS");
	keyName   = "Whatever you want.";
	keyValue  = "12345";  // any number

   	// create the UDDI key element
	KeyedReference keyedReference = new KeyedReference(keyName, keyValue);
	keyedReference.setTModelKey(tModelKey);

	// create a CategoryBag and set the keyed reference
	categoryBag = new CategoryBag();
	categoryBag.add(keyedReference);
	
	System.out.println("Constructor: tModelKey = " + tModelKey + "keyName" + keyName + "keyValue" + keyValue );

	// create proxy interface to the UDDI service registry
	try {
	    uddiWsdlProxy = 
		new UDDIWSDLProxy(UDDI_INQUIRY_URL,
				  UDDI_PUBLISH_URL,
				  UDDI_USERID,
				  UDDI_CRED,
				  TRANSPORT_CLASS);
	} catch(Exception e) {
	    e.printStackTrace();
	}
    }  // end MessageObjPublish

The imports, declaration, and constructor are common to this and subsequent uddi publishing methods.

    public void publishServiceInterface() {
	System.out.println("Publishing service interface ...");

	try {
	    	    
	    //  create the service interface
	    ServiceInterface serviceInterface = new ServiceInterface(wsdlServiceInterfaceURL, categoryBag);
            System.out.println("serviceInterface created");
     
	    // Publish the service interface
	    serviceInterface = uddiWsdlProxy.publish(serviceInterface);
    
	    System.out.println("<<< Service interface "+wsdlServiceInterfaceURL+" was published. >>>\n\n");
	} catch(com.ibm.uddi4j.wsdl.client.UDDIWSDLProxyException e) {
	    System.out.println("<<< Service interface "+wsdlServiceInterfaceURL+" was NOT published. UDDIWSDLProxyException >>>"+e);
	} catch(com.ibm.uddi4j.wsdl.definition.InvalidServiceDefinitionException ex) {
	    System.out.println("<<< Service interface "+wsdlServiceInterfaceURL+" was NOT published. InvalidServiceDefinitionException >>> "+ex);
	}
    }  // end publishServiceInterface

5. Register the Service Provider

Presumes the imports, variables, and constructor from 4, above.

    public void publishServiceProvider() {

	// create a vector to use for the proxy find
	Vector providerNameVector = new Vector();
	providerNameVector.add(new Name(serviceProviderName));

	try {
	    // Find the service provider
	    ServiceProvider[] serviceProviderList = 
		uddiWsdlProxy.findAllServiceProviders(null, providerNameVector, null, null, null, null, true);
    
	    // if no service provider found create one
	    if (serviceProviderList == null) {
		// Create service provider
		ServiceProvider serviceProvider = 
		    new ServiceProvider(serviceProviderName,
					serviceProviderName,
					categoryBag);
    
		// Publish the service provider
		uddiWsdlProxy.publish(serviceProvider);
    
		// Display publish completed message
		System.out.println("Service provider "+serviceProviderName+" was published.\n\n");
	    }
	    else  {
		// service provider already created
		System.out.println("Service provider "+serviceProviderName+" already published.\n\n");
	    }
	} catch(com.ibm.uddi4j.wsdl.client.UDDIWSDLProxyException e) {
	    System.out.println("<<< Service provider "+serviceProviderName+" was NOT published. >>> "+e);
	} 
    }


6. Register the Implementation

Presumes the imports, variables, and constructor from 4, above.

  public void publishServiceImplementation() {
	System.out.println("Publishing service implementation ...");

	ServiceDefinition serviceDef=null;
	try {
	    // create a service definition, using same category bag created in publishServiceInterface()
	    serviceDef = new ServiceDefinition(wsdlServiceImplURL, categoryBag);
	} catch(com.ibm.uddi4j.wsdl.definition.InvalidServiceDefinitionException ex) {
	    System.out.println("<<< Service implementation "+wsdlServiceImplURL+" was NOT found. >>> "+ex);
	    return;
	}
	
	/* publish the service to the UDDIWSDLProxy */

	// create the vector
	Vector providerNameVector = new Vector();
	providerNameVector.add(new Name(serviceProviderName));

	try {
	    // Find service provider
	    ServiceProvider[] serviceProviderList =
		uddiWsdlProxy.findAllServiceProviders(null, providerNameVector, null, null, null, null, true);
    
	    if (serviceProviderList != null) {
		// Publish the service
		serviceDef = uddiWsdlProxy.publish(serviceProviderList[0], serviceDef);
		
		// get the service name and store it
		serviceName	= serviceDef.getName();
    
		System.out.println("<<< Service "+wsdlServiceImplURL+" published. >>>\n\n");
	    }
	    else  {
		System.out.println("<<< Service Provider "+wsdlServiceImplURL+" not found. >>>\n\n");
	    }
	} catch(com.ibm.uddi4j.wsdl.client.UDDIWSDLProxyException e) {
	    System.out.println("<<< Service provider "+wsdlServiceImplURL+" was NOT published. >>> "+e);
	} catch(com.ibm.uddi4j.wsdl.definition.InvalidServiceDefinitionException ex) {
	    System.out.println("<<< Service provider "+wsdlServiceImplURL+" was NOT published. >>> "+ex);
	}
    }

7. Access the Service

It is important to keep in mind the context from which the service is accessed.  In this case, the service is being called from a servlet running in tomcat. Below are the critical methods.

public static String callService()
    {
        String msg = null;
        try {
                        
           String endpoint = getEndpoint();
                               
           Service  service = new Service();
           Call     call    = (Call) service.createCall();

           call.setTargetEndpointAddress( new java.net.URL(endpoint) );
           call.setOperationName(new QName("http://MessageObj", "getMessage") );

           msg = (String) call.invoke( new Object[]{}  );
           
       } catch (Exception e) {
           System.err.println(e.toString());
       }
       return msg;
           }

The getEndpoint method is responsible for obtaining the URL from the uddi registry for the service.  To do so, it must first create a proxy or stub with wich to interact with the registry.  These two methods are shown next.


    private static String getEndpoint()
    {
        
        String tModelKey = TModelKeyTable.getTModelKey("NAICS");
	    String keyName   = "Whatever you want.";
	    String keyValue  = "12345";  // any number

	    KeyedReference keyedReference = new KeyedReference(keyName, keyValue);
	    keyedReference.setTModelKey(tModelKey);

	    CategoryBag categoryBag = new CategoryBag();
	    categoryBag.add(keyedReference);

        try {
            
            UDDIWSDLProxy uddiWsdlProxy = getUddiProxy();

	        ServiceProvider serviceProviderList[] = 
		    uddiWsdlProxy.findAllServiceProviders(null, null, null, null, categoryBag, null, true);
    
	        if ( serviceProviderList == null )
		    System.out.println("No service providers found.");
		    else {
		        ServiceDefinition serviceDefinition[] = serviceProviderList[0].getServiceDefinitions();
		        ServiceImplementation serviceImplementation = serviceDefinition[0].getServiceImplementation();
		        Vector bindingTemplates = serviceImplementation.getBindingTemplateList();
		  
		        BindingTemplate bt = (BindingTemplate)bindingTemplates.get(0);
		        return bt.getAccessPoint().getText();
		        
		    }
	    
        } catch(Exception e) {
	        System.out.println("<<<  Exception. >>> "+e);
	    }
        return null;
    }

//************************************************

    private static UDDIWSDLProxy getUddiProxy() {
        
    String UDDI_INQUIRY_URL	= "http://localhost:80/uddisoap/inquiryapi";
    String UDDI_PUBLISH_URL	= "http://localhost:80/uddisoap/publishapi";
    String UDDI_USERID		= "demo";
    String UDDI_CRED		    = "pwd";
    String TRANSPORT_CLASS	= "org.uddi4j.transport.ApacheAxisTransport";
    
	try {
	    
	    UDDIWSDLProxy uddiWsdlProxy = 
		new UDDIWSDLProxy(UDDI_INQUIRY_URL,
				  UDDI_PUBLISH_URL,
				  UDDI_USERID,
				  UDDI_CRED,
				  TRANSPORT_CLASS);
				  
		return uddiWsdlProxy;
		
	} catch(Exception e) {
	    e.printStackTrace();
	}
	return null;
    }

8. Working with UDDI Information

A number of methods are available in the apis to work iwth uddi information.  Below are some sequences that illustrate some of the possibilities.

Find service providers.

ServiceProvider serviceProviderList[] = 
  uddiWsdlProxy.findAllServiceProviders(null, null, null, null, categoryBag, null, true);

String name = serviceProviderList[0].getName();

Find service descriptions for given service provider

ServiceDefinition serviceDefinition[] = serviceProviderList[0].getServiceDefinitions();


Find service implementation for a given service

ServiceImplementation serviceImplementation = serviceDefinition[0].getServiceImplementation();
String name = serviceImplementation.getName();

Find name and access poidnt for a given service

Vector bindingTemplates = serviceImplementation.getBindingTemplateList();
BindingTemplate bt = (BindingTemplate)bindingTemplates.get(0);
String accessPoint = bt.getAccessPoint().getText();
 

Examples

This program simply returns a Hello, World message from a deployed service by, first, looking up the service in the uddi registry and, second, making a SOAP call to the deployed service.

Run the program.

This program is an IBM demonstration that shows a client interacting with a broker to request bids from three vendors before makeing a purchase from the lowest bidder.

Run the program.