SourceForge.net Logo

Chapter 3. JMI Mapping Overview

The JMI accessor is an implementation of the [17] specification. The JMI accessor is layered on top of the openMDX generic accessor as shown in Figure 3-1. The JMI externalizer of the MOF repository supports the generation of JMI interfaces and implementations as defined by the JMI specification. The JMI externalizer supports two different flavors of JMI: a) JDK compliant, b) .NET compliant which uses the .NET interfaces and classes for collections and primitive types instead of the JDK classes.

Figure 3-1. JMI Mapping Overview

The JMI specification defines the purpose and scope of JMI:

"The JavaT Metadata Interface (JMI) Specification defines a dynamic, platform-neutral infrastructure that enables the creation, storage, access, discovery, and exchange of metadata. JMI is based on the Meta Object Facility (MOF) specification from the Object Management Group (OMG), an industry-endorsed standard for metadata management.

The MOF standard provides an open-ended information modeling capability, and consists of a base set of metamodeling constructs used to describe technologies and application domains, and a mapping of those constructs to CORBA IDL (Interface Definition Language) for automatically generating model-specific APIs. The MOF also defines a reflective programming capability that allows for applications to query a model at run time to determine the structure and semantics of the modeled system. JMI defines a Java mapping for the MOF.

As the Java language mapping to MOF, JMI provides a common Java programming model for metadata access for the Java platform. JMI provides a natural and easy-to-use mapping from a MOF-compliant data abstraction (usually defined in UML) to the Java programming language. Using JMI, applications and tools which specify their metamodels using MOF-compliant Unified Modeling Language (UML) can have the Java interfaces to the models automatically generated.

Further, metamodel and metadata interchange via XML is enabled by JMI's use of the XML Metadata Interchange (XMI) specification, an XML-based mechanism for interchanging metamodel information among applications. Java applications can create, update, delete, and retrieve information contained in a JMI compliant metadata service. The flexibility and extensibility of the MOF allows JMI to be used in a wide range of usage scenarios."

As described the scope of JMI is metadata interfaces. However, as described in [], application-models (Level M1) modeled in UML are mapped according to the 'UML Profile for MOF' to MOF-compliant models. Having a MOF-compliant application-level model allows to apply the MOF-to-JMI mapping.

The MOF-to-JMI mapping has been extended by the following features:

  • Support for filters. MOF allows navigation between instances of classes using references. References are mapped in JMI as get-operations returning a Collection object. This allows the application to iterate on the object set and retrieve all referenced objects. However, in many cases it is desirable to retrieve only a filtered subset of referenced objects. All collections returned by the JMI classes implement the interface org.openmdx.compatibility.base.collection.Container interface which supports filtering of an object collection. NOTE: This mapping will be replaced in the next versions of openMDX by methods on the instance-level interfaces which allow to pass filters as parameters.

  • Support for qualifiers. The standard JMI mapping does not allow to retrieve objects by application-defined unique identifiers. Objects can only be retrieved by an opaque MOF identifier which is not usable for application-level programming. However, application-level unique identifiers are supported with UML qualifiers. openMDX extends the 'UML Profile for MOF' by 'UML qualifiers' and adds a new model element to MOF. The qualifier is supported in the JMI mapping and allows to get and create objects using their qualifiers. The JMI mapping is extended by void add{feature}(qualifier, object), void remove{feature}(qualifier), RefObject get{feature}(qualifier) operations.

  • Support for object lifecycle. As already mentioned the JMI accessor is mapped to the openMDX generic accessor which offers JDO-like distributed object management and defines an object lifecycle. In order to support this object lifecyle all JMI objects returned by the JMI accessor implement the org.openmdx.base.accessor.jmi.RefObject_1_0 interface which in turn extends the javax.jmi.reflect.RefObject interface. This way all openMDX JMI objects are JMI compliant but still offers object lifecycle management functionality offered by openMDX.

The extension of JMI by these features allows to use JMI not only for metamodel management but also for simple to medium up to enterprise-level applications. The JMI accessors are a thin layer on top of the openMDX generic accessor classes and imply only little performance impact compared to the generic accessor or to platform-specific, native EJB or CORBA programming.

The JMI APIs has a three-layered approach to manage objects:

  • Packages play the role of a class directory, i.e. Packages are class-level object factories.

  • Class objects are the factories (or homes) of instance-level objects.

  • Instance objects are the application-level objects.

Package Objects and Package Creation

A package object is little more than a 'directory' of operations that give access to the classes described by the model. The outer most package extent (a.k.a. outer most extent) represents the "root" package. All other objects (i.e., instance objects, class proxies, associations, and (nested) package objects) are contained within some outer most extent.

Class Proxy Objects

A class proxy object serves a number of purposes:

  • It is a factory object for producing instance objects within the Package extent.

  • It is the intrinsic container for instance objects.

  • It holds the state of any classifier-scoped attributes for the class.

  • It provides operations corresponding to classifier-scoped operations.

The interface of a class proxy object provides operations for accessing and updating the classifier scoped attribute state. The interface also provides factory operations that allows the client to create instance objects.

Instance Objects

An instance object holds the state corresponding to the instance-scoped attributes, and any other "hidden" state implied by the class specification. Generally speaking, many instance objects can exist within a given package object.

Instance objects are always tied to a class proxy object. The class proxy provides a factory operation for creating instance objects. When an instance object is created, it is automatically added to the class proxy container. An instance is removed from the container when it is destroyed.

The interface for an instance object provides:

  • Operations to access and update the instance-scoped and classifier-scoped attributes.

  • Operations corresponding to instance-scoped and classifier-scoped operations.

  • Operations to access and update associations via reference.

Association Objects

An association object holds a collection of links (i.e. the link set) corresponding to an association defined in the metamodel. The association object is a 'static' container object (similar to a class proxy object) that is contained by a package object. Its interface provides:

  • Operations for querying the link set.

  • Operations for adding, modifying and removing links from the set.

  • An operation that returns the entire link set.

NOTE: Association objects are NOT supported by the openMDX JMI mapping. All assocations between objects must be managed through references.

Figure 3-2 shows the mapping of a UML model to Java files.

  • The model package {M}is mapped to a Java class called {M}Package.java

  • Each class {C} in the model is mapped to a class-level file called {C}Class.java and an instance-level file called {C}.java

Figure 3-2. Mapping a model to Java files.

JMI Mapping - Package

Each model is mapped to a package file as shown in Figure 3-3. For each class a corresponding getter is created. The returned class is associated with the package and therefore knows the accessor.

Figure 3-3. Mapping of a model to a JMI package.

A package is created an initialized as shown below:

Example 3-1. Initializing the JMI package.

    RefPackage rootPkg = new RefRootPackage_1(
          manager, // manager used for object management (get, create, modify)
          null, // impls
          null // context
    );
    lab1Package lab1Pkg = (lab1Package)rootPkg.refPackage("org:openmdx:example:lab1");

The root package has to be initialized only once. Based on the provided manager, the root package creates a basic accessor which is used for all object management (get, create, modify). The root package serves as factory for retrieving model-specific packages which are retrieved by refPackage(). All objects managed by the JMI package (class-level and instance-level objects) delegate to the basic accessor of the root package. This allows a consistent unit of work policy even if multiple accessors delegate to the same manager. As shown in the figure each instance-level JMI object wraps a RefObject which is managed by the basic accessor. Generic objects retrieved from the generic accessor are marshalled (by the root package) to JMI objects, JMI objects forwarded to the generic accessor are marshalled to generic objects.. Units of work and transactions are controlled by the manager.

Figure 3-4. Package-, class- and instance-level JMI objects and their dependencies.