Retrieving Metadata from a Custom Lookup Implementation

The Business Components for Java framework owes much of its flexibility to its metadata-driven architecture. Business Components metadata is described in XML, while their companion Java classes provide component implementations.

By default, the framework locates XML Component Definition Files by looking for XML files as resources in the CLASSPATH. However, advanced users can provide a custom metadata lookup implementation that retrieves the metadata from anywhere you want.

The following figure shows the classes and interfaces involved in Business Components metadata lookup:

Given a request to lookup the metadata for the component named oracle.apps.requisition.LineItem, the default implementation of the getMetaDataStream() method calls getResourceAsStream() to open the file /oracle/apps/requisition/LineItem.xml from the CLASSPATH.

To provide a custom metadata lookup mechanism you need to provide a class that implements the oracle.jbo.server.xml.XMLContext interface. For convenience, we provide a base implementation of such a class in oracle.jbo.server.xml.XMLContextImpl that you can extend rather than writing the implementation of every method in the XMLContext interface yourself.

Most custom lookup schemes can be achieved by extending XMLContextImpl and overriding the following method:

public InputStream getMetaDataStream(url)

The lookup method in XMLContextImpl implements a component name substitution mechanism based on entries in the XMLContext interface's namespace that have been bound to new names through calls to:

XMLContext.bind("oldname","newname")

that the framework makes upon finding:

  <Substitutes>
  <Substitute OldName="x.y.Department" NewName="q.p.NewDepartment"/>
  <Substitute OldName="a.b.Employee" NewName="c.e.Employee"/>
  </Substitutes>

in the project file (*.jpx) whose name is provided by the value of the Factory-Substitution-List property in the /oracle/jbo/server/jboserver.properties property file.

Note: Setting the Factory-Substitution-List can be performed with the
-Djbo.project=mypackage.MyProject option on the command line.

Currently, the lookup implementation also translates the component name into a URL path name so that a request by the framework to lookup the component name:

oracle.apps.requisition.LineItem

will be passed to getMetaDataStream as the String:

/oracle/apps/requisition/LineItem.xml

and a request by the framework to lookup a project metadata file like:

mypackage.MyProject.jpx

will be passed to getMetaDataStream as the String:

/mypackage/MyProject.jpx

Note: In future releases, lookup will likely return the substituted package name like oracle.apps.requisition.LineItem without converting it to a URL path name as part of the lookup implementation. You can plan ahead now by either:

If your getMetaDataStream implementation already wants the component to be translated into an URL name (or can make use of it just the same in this format as a primary key into some runtime dictionary) then you can provide a simple implementation of getMetaDataStream like:

import oracle.jbo.server.xml.XMLContextImpl;
import java.util.Hashtable;
import java.net.*;
import java.io.*;
public class HTTPXMLContextImpl extends XMLContextImpl {
  public HTTPXMLContextImpl(Hashtable env) {
  super(env);
  }
  public InputStream getMetaDataStream(String name) {
  String urlBase = "http://metadataserver.company.com";
  InputStream iStr = null;
  try {
  iStr = (new URL( urlBase + name )).openStream();
  }
  catch (MalformedURLException m) { return null; }
  catch (IOException i) { return null; }
  return iStr;
  }
}

This is a very simple implementation of a custom XMLContext. It overrides the default behavior to fetch the metadata for a component like:

oracle.apps.requisition.LineItem

whose name will be passed to getMetaDataStream as:

/oracle/apps/requisition/LineItem.xml

from a webserver at URL

http://metadataserver.company.com/oracle/apps/requisition/LineItem.xml

Of course the implementation could be more sophisticated, requesting metadata from an arbitrary service. This service could even dynamically materialize Business Components XML metadata based on querying database-driven, runtime dictionary information.

Once you have created your custom implementation class, you need to tell the Business Components runtime to use your implementation instead of the default. This is accomplished by setting the value of the MetaObjectContext property in the ./oracle/jbo/server/jboserver.properties file. By default that file resides in the jbomt.zip archive in the .\lib subdirectory of the JDeveloper install home.

The example below shows the jboserver.properties file which has been edited to have the MetaObjectContext property set to use the sample HTTPXMLContextImpl class above, and the Factory-Substitution-List property set to use the mypackage.SomeProject project file to find the factory substitution list.

# ------------------------------------------------------------------------
# File: oracle.jbo.server.jboserver.properties
# Cont: JBO Runtime Property Definitions
# Desc:
# ------------------------------------------------------------------------
# XML Context Factory and context for Meta Object lookup.
MetaObjectContextFactory = oracle.jbo.server.xml.DefaultMomContextFactory
# MetaObjectContext = oracle.jbo.server.xml.XMLContextImpl
# XML Context Customized by user : For test only
MetaObjectContext = HTTPXMLContextImpl
# Is lazy loading property for MOM: Recommended value = true
IsLazyLoadingTrue = true
# User Substitution List through "Substitute Mechanism"
Factory-Substitution-List = mypackage.SomeProject
#SessionClass = oracle.jbo.server.SessionImpl
# Type of SQLBuilder interface to load
jbo.SQLBuilder = Oracle
#jbo.SQLBuilder = OLite
# ------------------------------------------------------------------------
# end of file
# ------------------------------------------------------------------------