Create Object Models Using Extensible Abstract Model (XAM)

Overview

XAM is an extensible framework for building logical domain-specific object models on top of any base models. XAM has built-in support for XML W3 standard DOM syntax tree and is well-integrated with the underlying XML Document Model (XDM). This integration give XAM-based models the capabilities of efficient mutation with smart limitless undo-redo, lazy-loading all model components, automatic synchronization with source changes, document fidelity... Other capabilities include internal and external reference resolving based on namespaces, as well as a framework to add schema-based and semantic validations.

XAM based model could be used for any domain modeling, however, for the capabilities listed above, it is well-suited for document authoring tool such as an designer in an IDE.

XAM-based Modeling Concepts

A XAM-based logical domain model consists of a single model as container of all the domain components. Domain components could reference other domain components in the same model or even components defined in totally different domain.

  1. Domain Model:

    1. Typically the domain model should extends DocumentModel. Minimally the model interface should have access to a component factory allowing client to create new domain components.

    2. The implementation of the interface should extend AbstractDocumentModel, which require further services to be implemented: creation of and access to the model root component, a synchronization update helper ComponentUpdater.

  2. Domain Components:

The shaping of the domain model components could be start from the schema describe the domain components. In general, there should be a domain component corresponding to each schema element of complex type or global elements. Currently there is no automate tool for initial generation of the Java interfaces and implementation classes. The best way to work at this time is to use NetBeans Enterprise Pack Schema Tool to view the model in Design view. This help decide the interfaces and its attributes as well as its associated components. Each domain component interface should have the following patterns:

  • For each attribute create a setter/getter method. Note that attribute that refer to an element (through QName or not) should be represented as Reference or NamedComponentReference. The referenced component interface should extends Referenceable or NamedReferenceable.

  • For each child element with multiplicity 1 create set/get methods. The set method would have remove semantic for null argument.

  • For each child element with multiplicity n, create get/add/remove methods. The get method could return List or Collection of child component. If the attribute is ordered and List is returned, the add method needs to have argument for indexing.

  • Each attribute or child element needs have declared property change event name.

Define an common base class that all your domain component implementation would share. The base class should extends AbstractDocumentComponent. The base class should implement abstract method populateChildren() which should add to the component children list using its component factory generic create method.

  1. Component Factory:

    Component factory should have both methods to create domain components generically from a given DOM node and one specific create method for each of the defined component interfaces. The generic create method is used during reading in from document. The multiple specific create methods are for specific UI client code.

  2. Visitor Pattern Support:

    There should be a visitor pattern support both deep or shallow traversing of the model components. Typically this support consist of a domain visitor interface and a method to accept this visitor on each of the implementation class of all domain components. The built-in support will be used by UI client code as well as implementation of ComponentUpdater or validation support.

  3. Model Source:

    Model source is an interface encapsulate the concrete source from which model could be loaded from. The encapsulation is provided by means of a lookup services. Typically in the IDE environment, a model source should provide at list the data object of the source file. An important note is that an writable model source file does not means that the model source is editable. For example, some model sources with temporary file created by the retrieved are not supposed to be editable. Domain model author does not have to provide for model source.

  4. Domain Model Factory:

    Each domain model implementation should provide a public model factory class which extends AbstractModelFactory. This abstract class provides services such as caching of model instances, automatic background synchronization of all cached model instances. Domain model factory implementation need to provide method to create a domain model given a model source.

Model Client Usage

  1. Dependencies:

    Aside the specific domain model, in-IDE client code should minimally depend on the following NetBeans IDE modules:

    org.netbeans.modules.xml.xam

    org.netbeans.modules.xml.xdm

    org.netbeans.modules.xml.retriever

    Note that client code that execute out of NetBeans IDE environment, who typically do not mutate the model, might wish to not to have dependencies on XDM and Retriever modules because they entail many other NetBeans text editor and UI modules.

  2. Loading Model:

In-IDE client code just simply create model source using Retriever module method on class Utilities:

    
ModelSource source = createModelSource(FileObject sourceFile, boolean editable);

then use the spcific domain model factory to load the module source:

    
factory.getModel(source);

Note that client code executed outside IDE environment, who does not depend on Retriever module should have an implementation of CatalogModel and provide ModelSource instances with proper content for lookup: java.io.File, javax.swing.text.Document and org.netbeans.modules.xml.xam.CatalogModel.

  1. Listening to Model Events:

    Having the desired model instance, typical UI client code could add listeners to handle changes happened in the model.

  • Model Property Change Event: to listen to these accurate fine-grained events on model status or component properties add an instance of PropertyChangeListener to the model. Typically UI code that are common to all components does not need this kind of listener. This listener is mostly used for model status change event. Other than that it just provide a flexibility that might be needed for some special handling of component changes. For this fine granularity usage, each domain component interface declares a event property name for listener client to identify each specific change on the component.

    During sync with source, XAM will fire the following property change events: (1) change in DOM attribute of each domain element (attribute name as event name), (2) DocumentModel.TEXT_CONTENT, for non-blank change in text node within each domain element, (3) change within each top non-domain model element (local name as event name). Note that each domain model implementation could always provide additional level of details by defining deeper domain components or by overriding event processing methods on AbstractDocumentModel

  • Component Event: these are coarse-grained events with information about the source of change, type of change (some components attribute value changed or a child component is added or removed). To listen, client should add an instance of ComponentListener to the model. If you don't really need the fine-grained details, these events are more efficient to process because they are consolidated by source component to reduce event count.

  • Undo-Redo Event: To take advantage of model efficient undo-redo capabilities, client code need to add UndoableEditListener instance of the model. If UI client also expose source editor in addition to graphical design view, coordination between different kind of UndoableEditEvent (from source editing or from model mutation needs to be handled. XAM UI module in the NetBeans Enterprise Pack provide a framework for such implementation. For more detail on multiview Undo-Redo technique refer to XAM UI Undo support Framework.

  1. Accessing Components:

    Client start with obtaining the root component by generic method DocumentModel.getRootComponent() or domain specific method such as SchemaModel.getSchema().

    Typical UI client code would access specific child component with specific domain model child component access methods such as: Definitions.getPortType() in WSDL model. Generic client code could call various versions of getChildren() methods to access child components of a certain interface or class type.

  2. Model Mutation:

    To add new component, client code would first get the domain specific component factory from the model. For example on SchemaModel there is method getFactory(). Client then call specific method to create the required component, e.g., SchemaComponentFactory.createGlobalElement(). Client then populate the new component with all appropriate children and attributes. Note that all mutation to component in the model need to be enclosed inside an atomic transaction. For example, following is client code that adds a new global element to a Schema component:

           model.startTransaction();
           try {
               model.getSchema().addElement(newGlobalElement);
               // 
               // the transaction will be ended here if there isn't any exception.
               model.endTransaction();
           } finally {
               //
               // the transaction will be rolled back here if it isn't ended.
               model.rollbackTransaction();
           }
  1. Source Synchronization

There is a background automatic synchronization that run every 2 seconds. In some use cases, such as user starts a validation command or switches between source editor to graphical editor, client code needs to do an immediate synchronization by calling method Model.sync().

A Small Model Implementation: Sample Registry Model.

There is no automate generation of XAM model at this time. You can copy the xml/xam/kitmodel (including unit test) and use refactoring to start your XAM model. If, large number of components needed, you could use Java class template to ease manual class creation.









Project Features

About this Project

XML was started in November 2009, is owned by dstrupl, and has 56 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20160708.bf2ac18). © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close