# 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:

> - Reimplementing all the methods in `XMLContext` yourself, so you can perform the substitution in your own `XMLContext` implementation (or ignore substitutions altogether)

>   or

> - Simply program your `getMetaDataStream` implementation today in a way that checks for the presence of slashes in the name and converts them to dots and removes `.xml` extension if the slashes are present.

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
    # ------------------------------------------------------------------------