Skip to content

Latest commit

 

History

History
376 lines (326 loc) · 17.9 KB

Introduction.md

File metadata and controls

376 lines (326 loc) · 17.9 KB

Introduction to openMDX

openMDX is a model-driven application framework which helps you in writing service-oriented, MDA-based applications. Standards such as JDO, MDA, REST and JCA build the corner stones of openMDX. openMDX implements, combines and integrates these standards resulting in a fully working, lightweight application framework.

Overview

At the heart of openMDX is the JDO-compliant openMDX persistence manager. But other than most JDO persistence managers, the openMDX persistence manager does not store objects on the database. Instead, it acts as a proxy which is capable of delegating to one or more (local or remote) persistence managers. The most important features of the openMDX persistence manager are:

  • Pluggable: Plug-Ins implementing business-logic can be registered with the persistence manager. If an application invokes a method on a persistence capable object, the openMDX persistence manager intercepts this invocation and dispatches the call to the appropriate plug-in.
  • Distributable: The openMDX persistence manager can either delegate to local or remote persistence managers. The protocol used for the local communication is REST/JCA and for the remote communication REST/HTTP. openMDX provides the necessary REST infrastructure. The persistence manager is configured with a jdoconfig.xml configuration file. Whether local or remote transports are used is completely transparent to the application.

The openMDX persistence manager allows to write simple, distributable and portable applications. For example a hello world client which invokes a sayHello() service looks as follows:

:::java
import org.openmdx.example.helloworld1.*;
  
javax.jdo.PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("EntityManagerFactory");
javax.jdo.PersistenceManager pm = pmf.getPersistenceManager("guest", "guest");
HelloWorld helloWorld = (HelloWorld)pm.getObjectById(HELLOWORLD_XRI);
HelloWorldPackage helloWorldPkg = 
  (HelloWorldPackage)helloWorld.refOutermostPackage().refPackage(Helloworld1Package.class.getName());
pm.currentTransaction().begin();
org.openmdx.example.helloworld1.SayHelloResult hResult = helloWorld.sayHello(
  helloWorldPkg.createHelloWorldSayHelloParams("en")
);
pm.currentTransaction().commit();
System.out.println("Client: sayHello[en]=" + hResult.getMessage());

NOTE:

  • The openMDX persistence manager factory is looked up with the configuration-id EntityManagerFactory which is configured in the jdoconfig.xml.
  • The application client does not know whether the sayHello() service is deployed locally or remote.
  • The transaction (or unit of work) handling is either optimistic or non-optimistic according to the configuration of the persistence manager.
  • Java interfaces such as HelloWorldPackage, HelloWorld, SayHelloParams, SayHelloResult are generated from the HelloWorld UML model.
  • Each openMDX-based application is automatically a service, or more precisely a RESTful service. In case the HelloWorld service is deployed as remote service, the operation sayHello() can be invoked with a POST request and the resource with the XRI HELLOWORLD_XRI can be retrieved with a GET request by any REST client.

In addition, openMDX provides tools which are used at development time such as the model mappers. They are responsible to map a MOF-compliant class diagram to corresponding Java interfaces, XML schemas, JPA classes and ORM mapping files.

Key concepts

JDO

The Java Data Objects (JDO) API is a standard interface-based Java model abstraction of persistence, developed under the auspices of the Java Community Process. The original JDO 1.0 is Java Specification Request 12 (JSR 12), and the current JDO 2.0 is Java Specification Request 243 (JSR 243). The benefits of using JDO for application programming are:

  • Ease of use: Application programmers can focus on their domain object model and leave the details of persistence (field-by-field storage of objects) to the JDO implementation.
  • Portability: Applications written with the JDO API can be run on multiple implementations without recompiling or changing source code. Metadata, which describes persistence behavior external to the Java source code including most commonly used features of O/R mapping, is highly portable.
  • Database independence: Applications written with the JDO API are independent of the underlying database. JDO implementations support many different kinds of transactional data stores, including relational and object databases, XML, flat files, and others.
  • High performance: Application programmers delegate the details of persistence to the JDO implementation, which can optimize data access patterns for optimal performance.

However, the JDO and JPA (Java Persistence Architecture) leaves an important question unanswered: where comes the business logic? One can put all or part of the business logic into the persistence capable (or entity) classes (or into a library which is invoked by the persistence capable class). Or one can put an application-layer on top of the persistence layer. However, all these approaches have drawbacks:

  • There is no clean separation between business and persistence logic
  • The business logic is located in the persistence tier instead of in the application tier
  • Introducing an application layer also introduces a different style of architecture and programming. Code which delegates to the application layer looks different than code which delegates to the persistence layer. This way code is layer-specific and hence not as portable and reusable as should be.

The openMDX persistence manager addresses these issues as follows:

  • The openMDX persistence manager is a JDO-compliant implementation which acts as a proxy to one or more (local or remote) persistence managers. By default all invocations are delegated to one of the configured proxies (routing is configurable).
  • The business logic is isolated into separate classes, called aspect oriented plug-ins (AOP). Persistence capable classes do not contain any business logic. Their only responsibility is to make an object persistent. As a consequence, the persistence capable classes can be generated, so no programming is required at this level. AOPs are registered with the openMDX persistence manager. If an application invokes a method of a persistence capable, the openMDX persistence manager intercepts the invocation and dispatches the call to the registered AOPs. In case no AOP intercepts the invocation, the call is forwarded to one of the configured delegation persistence mangers.
  • The openMDX persistence manager is stackable. This allows to split the business logic into layers, i.e. different aspects (business logic, generic functions such as auditing or access control) of the application logic can be completely separated.

REST and JCA

The openMDX persistence manager acts as a proxy persistence manager and allows to delegate to one or more (local or remote) persistence managers. The protocol used for communication between persistence managers is REST:

  • Object retrievals are mapped to a GET
  • Queries are mapped to a GET <reference xri, query>
  • Object modifications are mapped to PUT
  • Object creations are mapped to POST
  • Method invocations are mapped to POST <object xri, method, parameters>
  • Object removals are mapped to DELETE

    REST/HTTP is used for remote (inter-process) and REST/JCA for local communication between persistence mangers. What is REST/JCA? REST was initially described in the context of HTTP, but is not limited to that protocol. RESTful architectures can be based on other application layer protocols if they already provide a rich and uniform vocabulary for applications based on the transfer of meaningful representational state.

    The Java EE Connector Architecture (JCA) ([http://jcp.org/aboutJava/communityprocess/final/jsr322/index.html JCA]) provides a suitable application layer protocol. The REST methods GET, PUT, POST and DELETE are mapped to corresponding REST interaction specifications. The remote persistence manager is treated as a JCA resource. Using REST/JCA an object retrieval looks as follows:

    :::java
    javax.resource.cci.Connection conn = connectionFactory.getConnection(
      new RestConnectionSpec(user, password)
    );
    javax.resource.cci.RecordFactory rf = connectionFactory.getRecordFactory();
    javax.resource.cci.Interaction interaction = conn.createInteraction();
    InteractionSpec ispec = InteractionSpecs.getRestInteractionSpecs(true).GET;
    javax.resource.cci.IndexedRecord input = factory.createIndexedRecord(Multiplicities.LIST);
    input.add(object_xri);
    javax.resource.cci.Record output = interaction.execute(ispec, input);
    

    Output contains the retrieved object in a JCA record.

    Using REST as unified communication protocol has the following advantages:

    • Independent deployment of components: an application using the openMDX persistence manager can either be deployed in-process or fully distributed.
    • Integration: A persistence manager configured for REST/HTTP can be accessed by any 3rd party REST client. This allows easy integration of openMDX-based applications with non-openMDX applications and even with non-Java applications.
    • Lightweight: The implementation of REST/HTTP and REST/JCA is lightweight. All that is required on client-side is a HttpUrlConnection and on server-side a WebApp container such as Tomcat.
    • Scalability: An application using the openMDX persistence manager is scalable out-of-the box. A persistence manager deployed under Tomcat can handle multiple sessions and concurrent requests (such as all HTTP servlets can).

    MDA

    Based on OMGs established standards such as

    • Unified Modeling Language (UML)
    • MetaObject Facility (MOF )
    • XML Metadata Interchange (XMI)
    • Common Warehouse Metamodel (CWM)

    the OMG's Model Driven Architecture ([http://www.omg.org/mda MDA]) standards separate business and application logic from the underlying platform technology. Platform-independent models (PIMs) of an application or integrated systems's business functionality and behaviour, built using UML and the other associated OMG modeling standards, can be realized through the MDA on virtually any platform, open or proprietary, including WebServices, .NET, CORBA, J2EE, and others. These platform-independent models document the business functionality and behaviour of an application separate from the technology-specific code that implements it, insulating the core of the application from technology.

    The domain object model of an openMDX-based application is specified by a platform-independent model (PIM). The model does not contain any platform-specific (J2EE, WSDL, CORBA, RPC, etc.) information. Using the MDA/PIM-approach has the following advantages:

    • Automation: the PIM can be mapped by generators to any platform-specific artifact by applying the mappings specified by the MDA standards. E.g. the PIM can be mapped to a Java API by applying the JMI mapping (specified by the [http://java.sun.com/products/jmi/index.jsp Java metadata interface (JMI)] standard).
    • Single-source: the domain model has to be specified exactly once even if the application must support several platforms, e.g. expose the application logic as Java library, REST or RPC service.
    • Model-driven algorithms: According to the MDA standards, PIMs are stored in a MOF (Meta Object Facility) repository which is accessible to the application at runtime. This allows an application to inspect the model and perform generic, model-driven algorithms on application data.

    The development process is rather straight-forward: first the business objects (BOs) are specified by platform-independent, MOF-compliant class diagrams. These are then mapped by openMDX-generators to Java interfaces by applying the MOF to Java mapping (specified by the [http://java.sun.com/products/jmi/index.jsp Java metadata interface (JMI)] standard). These interfaces define the API of the the application's domain object model.

    img

    The corresponding JMI interface is shown below:

    :::java
    package org.openmdx.example.helloworld1.jmi1;
    
    public interface HelloWorld
      extends org.openmdx.example.helloworld1.cci2.HelloWorld,
        org.openmdx.base.jmi1.Segment{
    
      public org.openmdx.example.helloworld1.jmi1.SayHelloResult sayHello(
          org.openmdx.example.helloworld1.jmi1.HelloWorldSayHelloParams in
      );
    
    }
    

    A sample hello world client:

    :::java
    import org.openmdx.example.helloworld1.*;
      
    javax.jdo.PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("EntityManagerFactory");
    javax.jdo.PersistenceManager pm = pmf.getPersistenceManager("guest", "guest");
    HelloWorld helloWorld = (HelloWorld)pm.getObjectById(HELLOWORLD_XRI);
    HelloWorldPackage helloWorldPkg = (HelloWorldPackage)helloWorld.refOutermostPackage().refPackage(Helloworld1Package.class.getName());
    pm.currentTransaction().begin();
    org.openmdx.example.helloworld1.SayHelloResult hResult = helloWorld.sayHello(
      helloWorldPkg.createHelloWorldSayHelloParams("en")
    );
    pm.currentTransaction().commit();
    System.out.println("Client: sayHello[en]=" + hResult.getMessage());
    

    The hello world implementation:

    :::java
    package org.openmdx.example.helloworld1.aop2;
    
    import javax.jmi.reflect.RefException;
    
    import org.openmdx.base.aop2.AbstractObject;
    import org.openmdx.example.helloworld1.jmi1.HelloWorldSayHelloParams;
    import org.openmdx.example.helloworld1.jmi1.Helloworld1Package;
    import org.openmdx.example.helloworld1.jmi1.SayHelloResult;
    
    public class HelloWorldImpl
        <S extends org.openmdx.example.helloworld1.jmi1.HelloWorld,N extends org.openmdx.example.helloworld1.cci2.HelloWorld,C extends Void>
        extends AbstractObject<S,N,C> {
    
        public HelloWorldImpl(
            S same,
            N next
        ) {
        	super(same, next);
            System.out.println("Plugin: instantiating HelloWorldImpl");
        }
                  
        public SayHelloResult sayHello(
    	    HelloWorldSayHelloParams params
        ) throws RefException {
            System.out.println("Plugin: invoking sayHello(language=" + params.getLanguage() + ")");
            String language = params.getLanguage();
            String message = null;
            if("de".equals(language)) {
                message = "hallo welt";
            }
            else if("fr".equals(language)) {
                message = "bonjour monde";
            }
            else {
                message = "hello world";
            }       
            return ((Helloworld1Package)this.sameObject().refOutermostPackage().refPackage(
                Helloworld1Package.class.getName())
            ).createSayHelloResult(message);
        }
        
    }
    

    The openMDX persistence manager

    In detail, the openMDX persistence manager works as follows:

    • At the top level there are one or more entity managers. Their responsibility is to dispatch API method invocations issued by the client application and dispatch them to the configured AOPs. The last entity manager in the stack delegates to the object view manager which manages service data objects (SDOs). SDOs implement a generic interface which allows to manage the object's state in a generic way, e.g. objSetValue(feature, value) or objGetValue(feature). For more information about SDOs see [http://www.ibm.com/developerworks/java/library/j-sdo/ Introduction to Service Data Objects]. (NOTE: openMDX SDOs implement the interface DataObject_1_0 which is a much simpler and more JDO- and JPA-aligned than originally specified by IBM). Typed JMI method invocations are mapped to the SDO interface. E.g. if the client application invokes the method Person.setName(String name), the JMI persistence manager first checks if any AOP implements the method. If an implementation is found, the call is dispatched to this AOP. If none is found, the call is forwarded to the corresponding SDO and mapped to the method objSetValue("name", value).
    • The object view manager manages SDOs. It does it more or less the same way as the JMI entity manager, however it allows to implement low-level, generic plug-ins. It also allows to register AOPs and dispatches method invocations. In order to be able to distinguish plug-ins at the different levels, plug-ins at JMI level are called AOP2, whereas plug-ins at object view level are called AOP1. The object view manager delegates to the next entity manager in the stack which is the data object manager.
    • The data object manager manages transactions (also called unit of work), the state and the life-cycle of SDOs. The data object manager is either delegates to a local or remote JCA connection. All object operations are mapped to REST interactions.

    Summary

    openMDX helps you in writing platform-independent applications. The application's interface is specified with a platform independent model (PIM) and the business logic is implemented as POJOs (plain old Java objects) which are platform-, distribution- and persistence-technology independent. The application can be deployed locally or distributed by using the RESTful, JDO-compliant openMDX persistence manager. The resulting applications are lightweight and can be deployed on any J2SE or J2EE platform such as Tomcat/OpenEJB.