In practical terms, the JAXR information model is based on the ebXML information model. This makes sense from two perspectives: the ebXML v. 2.0 Registry Information Model (RIM) is functionally larger than the UDDI v. 2.0 information model, and developing such detailed models based on community consensus takes time.
As mentioned previously, all the previous discussion about using JAXR and UDDI remains unchanged with an ebXML registry, because of the API's abstraction. In this section, we will discuss how client applications can leverage some of JAXR's level 1 capability features.
One of the significant differences between UDDI and ebXML registries is how client applications are authenticated. While UDDI requires only password-based authentication, the ebXML Registry Service allows for digital certificates to be used in the SOAP headers. The SOAP message in Listing 12.7 shows how the X.509 certificate is included using XML D-Sig specifications.
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"> </ds:CanonicalizationMethod> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"> </ds:SignatureMethod> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"> </ds:Transform> <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"> </ds:DigestMethod> <ds:DigestValue>bT5BLPViSpaLoRE3fjnH0RpQ6Jw=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>YJZAHweU7komyE1p9yOiutWrwZR46/L2GByohkd/b16iVurDQ3ik1g== </ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate> MIIC2DCCApYCBD2WJLAwCwYHKoZIzjgEAwUAMFIxDDAKBgNVBAYTA1VTQTEVMBMGA1UEChMMU cmNlIEZvcmdlMRAwDgYDVQQLEwdlYnhtbHJyMRkwFwYDVQQDExBSZWdpc3RyeU9wZXJhdG9yM DTAyMDkyODIxNTI0OFoXDTAyMTIyNzIxNTI0OFowUjEMMAoGA1UEBhMDVVNBMRUwEwYDVQQKE b3VyY2UgRm9yZ2UxEDAOBgNVBAsTB2VieG1scnIxGTAXBgNVBAMTEFJlZ2lzdHJ5T3BlcmF0b ggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJ XUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V qKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi6 8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAt cSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQi 3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYB19I45gtWIml4LIQXNNZS/u43ams5pjzjD9 dr0voIUc/cWm/odiLnoNj4YNaRKncI8f5o9lQYX4y4QGusbVLVVUd7u4Xby50seu0nvAxh9// BHaQgHA/JTvatcmZwjXqqpZyBYrEYfXpHAFTY6fLJFKpp31Ai045gcXGIzALBgcqhkjOOAQDB LwAwLAIUYODY/SLIho4PAllVC4ZnCavE57cCFCtmGUi+oFftL8m29PdZqkW4XMKl </ds:X509Certificate> </ds:X509Data> <ds:KeyValue> <ds:DSAKeyValue> <ds:P> /X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXg HTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2d K2HXKu/yIgMZndFIAcc= </ds:P> <ds:Q>l2BQjxUjC8yykrmCouuEC/BYHPU=</ds:Q> <ds:G> 9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoF zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfB Zl6Ae1UlZAFMO/7PSSo= </ds:G> <ds:Y> dfSOOYLViJpeCyEFzTWUv7uN2prOaY84w/QlTHa9L6CFHP3Fpv6HYi56DY+GDWkSp3CPH+aPZ +MuEBrrG1S1VVHe7uF28udLHrtJ7wMYff/w9KgR2kIBwPyU72rXJmcI16qqWcgWKxGH16RwBU yyRSqad9QItOOYHFxiM= </ds:Y> </ds:DSAKeyValue> </ds:KeyValue> </ds:KeyInfo> </ds:Signature> </soap-env:Header> <soap-env:Body> <SubmitObjectsRequest xmlns="urn:oasis:names:tc:ebxml-regrep:registry:xsd:2.1"> <LeafRegistryObjectList> <RegistryPackage id="urn:uuid:bfef9997-508d-4131-a826-edebc7a47836" objectType= "RegistryPackage"> <Name> <LocalizedString charset="UTF-8" lang="en-us" value="Flute Bank Agreements"> </LocalizedString> </Name> <Description> <LocalizedString charset="UTF-8" lang="en-us" value=""> </LocalizedString> </Description> </RegistryPackage> </LeafRegistryObjectList> </SubmitObjectsRequest> </soap-env:Body> </soap-env:Envelope>
Let us look at how a client can publish Organization information in the ebXML registry using JAXR. Listing 12.8 shows how the JAXR provider for ebXML (available under open source) can be used. The example is identical to Listing 12.1, which published the information to a UDDI registry. The only difference is the manner in which the connection is passed the user's credentials for authentication. Instead of a username and password, the user sends the X.509 certificate.
import java.security.*; import java.security.cert.X509Certificate; // other imports public class ebXMLPublishOrg { public static void main (String args[]){ // keystore location and alias // Start JAXR provider imsplementation specific code String alias = "mykey"; String location="c:/temp/rr/jaxr/keystore.jks"; String storepass="ebxmlrr"; String keypass="password"; HashSet creds = new HashSet(); // get the keystore KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(location), storepass.toCharArray()); X509Certificate cert =(X509Certificate)keyStore.getCertificate(alias); PrivateKey privateKey= (PrivateKey)keyStore.getKey(alias,keypass.toCharArray()); X500PrivateCredential credential= new X500PrivateCredential(cert,privateKey,alias); // End JAXR provider implementation specific code creds.add(credential); // Create the connection factory, which can be set by the system property //-Djavax.xml.registry.ConnectionFactoryClass= // com.sun.xml.registry.ebxml.ConnectionFactoryImpl ConnectionFactory factory = ConnectionFactory.newInstance(); Connection connection = connFactory.createConnection(); connection.setCredentials(creds); // create organization and other objects with BusinessLifeCyleManager and // use the BusinessLifeCyleManager.saveOrganizations(orgs) method } }
One of the advantages of using an ebXML registry is that it can store arbitrary content, such as business process descriptions (BPML documents), and business agreements, such as the CPP and CPA agreements used in ebXML messaging systems. This is different from storing WSDL in UDDI, in the sense that the actual business document is stored in the repository, which the registry service exposes. For example, the code in Listing 12.3 publishes a URL only to the WSDL document, whereas in an ebXML registry, the actual WSDL document may be published to the registry. In this sense, the ebXML registry plays a sort of content management role.
In JAXR, the ExtrinsicObject is used to model the metadata representing such content. Let us look at some code extracts that show how this can be used. Flute Bank can choose to store its CPP/CPA with OfficeMin as the following code shows.
// Create a connection and authenticate with the registry // Obtain the BusinessLifeCyleManager instance from the connection // Now get the XML file URL url = getClass().getResource("/agreements/officemin.xml"); DataHandler handler = new DataHandler(url); // Create an ExtrinsicObject ExtrinsicObject obj = lifecyclemgr.createExtrinsicObject(handler); obj.setRepositoryItem(handler); // Save the arbitrary content Collection data = new ArrayList(); data.add(obj); BulkResponse response = lifecyclemgr.saveObjects(data); if(response.getStatus()==BulkResponse.STATUS_SUCCESS){ System.out.println("CPP successfully saved"); System.out.println("ID is :+obj.getKey().getId()"); }
Note that in the above example, the resource can be any arbitrary content, such as graphic files, XML schemas, or Word documents.
In practical terms, content will be grouped into RegistryPackage objects that can be associated with any RegistryObject. RegistryPackages are a powerful level 1 feature. Any registry object can have multiple RegistryPackages associated with it and can also be associated with multiple packages. Therefore, business documents such as privacy policies, grouped under a package named "Policies" and associated with an Organization, can be retrieved as shown below:
// Locate the Organization BulkResponse response = querymgr.findOrganizations(findqualifier, searchpattern, null, null, null, // Iterate and get to the individual Organization Organization org = (Organization) orgiterator.next(); Collection packages =org.getRegistryPackages(); // Iterate and get to the package we are interested in if(package.getName().getValue().equals("Policies"){ Collection extobjects=package.getRegistryObjects(); // Iterate and get individual ExtrinsicObject elements ExtrinsicObject obj=eoiter.next(); // get underlying content DataHandler handler= obj.getRepositoryItem();
Documents such as the CPP and CPA, which relate to the Service, can also be queried and stored in a similar manner under the associated Service object (which is also an instance of a RegistryObject).
As a general programming note, while interacting with the ebXML registry, client applications will rely more on the generic methods defined in the LifeCycleManager rather than the subclass BusinessLifeCycleManager to create and save objects. Similarly, they will rely more on the declarative queries and the DeclarativeQueryManager looked at earlier to find data in the registry, as opposed to the BusinessQueryManager looked at for UDDI.
Let us look at a complete example of publishing information to an ebXML registry, using the open source JAXR provider and ebXML registry implementation. We have slightly modified the UDDI example from Listing 12.1, for two reasons: the ebXML registry has tighter validation rules than UDDI (e.g., a contact person for an Organization is required), and we wanted to show the use of some level 1 capabilities.
Listing 12.9 publishes Flute Bank's information, its BillPay service information, some associated documents (we will use Flute's BPSS and CPA XML documents used in Chapter 7), and creates a package object in the registry and an association. For the sake of brevity, we have not included the SOAP messages exchanged between the client and the registry. Upon successful execution, the results can be viewed using the graphical registry browser, as Figure 12.19 shows.
import javax.xml.registry.infomodel.*; import javax.xml.registry.*; import java.util.*; import java.net.URL; import javax.activation.*; import java.security.*; import java.io.FileInputStream; import java.security.cert.X509Certificate; import javax.security.auth.x500.X500PrivateCredential; public class ebXMLPublishOrg{ private static final String QUERY_URL= "http://localhost:9090/ebxmlrr/registry"; private static final String PUBLISH_URL="http://localhost:9090/ebxmlrr/registry"; public static void main(String[] args) throws Exception { // Set the properties for the ConnectionFactory Properties environment = new Properties(); environment.setProperty("javax.xml.registry.queryManagerURL", QUERY_URL); environment.setProperty("javax.xml.registry.lifeCycleManagerURL", PUBLISH_URL); // Instantiate the factory and create a connection from it ConnectionFactory connfactory = ConnectionFactory.newInstance(); connfactory.setProperties(environment); Connection conn = connfactory.createConnection(); // Authenticate the username and password with the registry /////////////// Start JAXR provider implementation-specific code String alias = "mykey"; String location="c:/temp/rr/jaxr/keystore.jks"; String storepass="ebxmlrr"; String keypass="password"; HashSet creds = new HashSet(); // get the keystore KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(location), storepass.toCharArray()); X509Certificate cert =(X509Certificate)keyStore.getCertificate(alias); PrivateKey privateKey = (PrivateKey)keyStore.getKey(alias,keypass.toCharArray()); X500PrivateCredential credential= new X500PrivateCredential(cert,privateKey,alias); creds.add(credential); ////////////// END JAXR provider implementation-specific code conn.setCredentials(creds); // Obtain a reference to the RegistryService, the BusinessLifeCycleManager, and // the BusinessQueryManager RegistryService registryservice = conn.getRegistryService(); BusinessLifeCycleManager lifecyclemgr = registryservice.getBusinessLifeCycleManager(); BusinessQueryManager querymgr = registryservice.getBusinessQueryManager(); // Create a user object User contact = lifecyclemgr.createUser(); PersonName name = lifecyclemgr.createPersonName("John Malkovich"); contact.setPersonName(name); InternationalString contactdescription = lifecyclemgr.createInternationalString ("The primary contact person for Flute Web services"); contact.setDescription(contactdescription); // Create and set the user's telephone number TelephoneNumber telnum = lifecyclemgr.createTelephoneNumber(); telnum.setNumber("1-800-FLUTE-US"); Collection phonenumbers = new ArrayList(); phonenumbers.add(telnum); contact.setTelephoneNumbers(phonenumbers); // Create and set the user's email address EmailAddress email = lifecyclemgr.createEmailAddress( "ebxml-admin@flutebank.com"); Collection emaillist = new ArrayList(); emaillist.add(email); contact.setEmailAddresses(emaillist); PostalAddress addr = lifecyclemgr.createPostalAddress("64"," Bit Street"," Windsor"," CT"," USA","03060"," Office Address"); ArrayList addresses = new ArrayList(); addresses.add(addr); contact.setPostalAddresses(addresses); // Create an organization object Organization company = lifecyclemgr.createOrganization("Flute Bank"); InternationalString description = lifecyclemgr.createInternationalString "A fictitious bank used for examples in the book Java Web Services Architecture, published by Morgan Kaufman, ISBN 1-55860-900-8. The authors can be reached at webservicesbook@yahoogroups.com OR www.javawebservicesarchitecture.com. "); company.setDescription(description); // Set the user as the primary contact for the organization. User's address and // company address are same company.setPrimaryContact(contact); company.setPostalAddress(addr); company.setTelephoneNumbers(phonenumbers); ExternalLink website = lifecyclemgr.createExternalLink("http://www.flutebank.com", "Flute Bank Inc"); website.setValidateURI(false); company.addExternalLink(website); // We now have the objects representing our information model // To publish it, we must classify it. We decide to use the // NAICS scheme ClassificationScheme scheme = querymgr.findClassificationSchemeByName(null," ntis-gov:naics"); // Create the classification using the above scheme and pass the relevant // category code and description Classification classification = (Classification)lifecyclemgr.createClassification(scheme,"Finance and Insurance", "52"); Collection classificationlist = new ArrayList(); classificationlist.add(classification); company.addClassifications(classificationlist); // Create the concrete service (this maps to the businessService) Service service = lifecyclemgr.createService("Billpayservice"); company.addService(service); InternationalString servicedescription = lifecyclemgr.createInternationalString("A Web service allowing account holders to pay bills online"); service.setDescription(servicedescription); ExternalLink link1 = lifecyclemgr.createExternalLink ("http://127.0.0.1:8080/billpayservice/billpayservice.wsdl", "Service WSDL"); link1.setValidateURI(false); service.addExternalLink(link1); // Create the service bindings for the Web service ServiceBinding binding = lifecyclemgr.createServiceBinding(); binding.setValidateURI(false); InternationalString bindingdescription = lifecyclemgr.createInternationalString("HTTP bindings for the Billpayservice Web service"); binding.setDescription(bindingdescription); // replace with the actual URL where the service is deployed binding.setAccessURI("http://127.0.0.1:8080/billpayservice/jaxrpc/BillPay"); service.addServiceBinding(binding); DataHandler upload1 = new DataHandler(new FileDataSource("C:/rr/jaxr/build/test/ classes/bpss.xml")); DataHandler upload2 = new DataHandler(new FileDataSource("C:/rr/jaxr/build/test/ classes/cpa.xml")); // Create an ExtrinsicObject ExtrinsicObject obj1 = lifecyclemgr.createExtrinsicObject(upload1); ExtrinsicObject obj2 = lifecyclemgr.createExtrinsicObject(upload2); RegistryPackage docs =lifecyclemgr.createRegistryPackage("BusinessDocuments"); docs.addRegistryObject(obj1); docs.addRegistryObject(obj2); Concept assType = querymgr.findConceptByPath("/AssociationType/packages"); Association ass = lifecyclemgr.createAssociation(docs, assType); company.addAssociation(ass); // make the final call to the registry and get a response // This could have been used instead //BulkResponse response = lifecyclemgr.saveOrganizations(organizationlist); // We show the more general method below ArrayList objs = new ArrayList(); objs.add(company); objs.add(service); objs.add(binding); objs.add(contact); objs.add(docs); objs.add(website); BulkResponse response = lifecyclemgr.saveObjects(objs); if (response.getStatus()==JAXRResponse.STATUS_SUCCESS) System.out.println("The request was processed successfully"); // Finally, close the connection conn.close(); } }
No mapping is required from the JAXR model to the ebXML Registry Information Model, because they are identical (e.g., Organization interface in JAXR maps to an Organization object in RIM, etc.) Also, JAXR supports all features and functionality defined by OASIS for the ebXML registry.