OpenEAI API Introduction

Version 1.0

 

January, 2003

 

by

 

Tod Jackson (tod@openeai.org)

Steve Wheat (steve@openeai.org)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Copyright ©  2002, 2003 OpenEAI Software Foundation.

 

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Section being the first section entitled “Introduction”, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "Appendix 1: GNU Free Documentation License".


Contents

 

Introduction

Helpful Definitions

Application

Scheduled Application

Message Gateway

Message Relay

Messaging Enterprise

Analysis Template

Deployment Descriptor

Enterprise Object Document

Integration Process Overview

Perform Analysis

Define Messages

Generate Java Message Objects

Develop, Document, and Test Messaging Applications

Update Enterprise Documentation Artifacts

Deploy in Production

OpenEAI Foundation Components

JMS Foundation

Enterprise Messages

Java Message Objects

Other Foundation Components

Java Message Object Details

XML Enterprise Objects

JMS Enterprise Objects

Performing Request Message Actions

Performing Synchronization Message Actions

Building Messages

Developing Messaging Applications

AppConfig

Scheduled Applications

Message Gateways

OpenEAI Deployment Descriptor

OpenEAI Enterprise Object Document

 

 

Introduction

 

Work on the OpenEAI API began in March 2001 at the University of Illinois.  The purpose of this work was to provide foundation components with which to implement integrations using the OpenEAI Message Protocol.  While the benefits of describing data using XML are widely understood and generally accepted today, the fact remains that building and manipulating XML documents is programmatically challenging for many developers, and gets really boring very fast for nearly all developers.  For these reasons, the work is highly prone to error.

 

It would be ideal if developers did not have to use their knowledge of XML to programmatically build or manipulate every XML message at the document level.  It would be ideal if developers did not have to use their knowledge of and the Java Message Service (or any other transport an organization may need to employ in interfacing specific applications) to send, receive, or consume messages.  If developers had a business-object-oriented API, with objects that looked like the enterprise data objects defined by an organization in its messages (such as BasicPerson, BasicEmployee, InstitutionalIdentity, DriversLicense, EmergencyContact, HonorAward,  LicenseCertification, WorkHistory, AdmissionApplication, TestScore, or whatever else), they could simply focus on implementing the business logic provided to them by analysts (or that they came up with by working with the design team, depending upon how the organization performs analysis and development).

 

At its heart, the OpenEAI API is this business-object-oriented API for building integrations.  Specifically, this business-object-oriented API is the OpenEAI Message Object API, referred to as the MOA.  OpenEAI Java Message Objects know how to build themselves from XML and serialize themselves to XML.  They know how to build all the messages specified by the OpenEAI Message Protocol and send them using a JMS provider.  They know how to translate the application-specific values for data fields for application X and translate them to enterprise values.  They know how to take enterprise values and translate them to appropriate application-specific values for application Y.  They know how to enforce the presence of required fields.  They know how to enforce formatting masks.  They know how to execute scrubbers on data to address complex transformation and formatting that may not be so easily generalized.  And they know how to do a lot more.

 

Since business objects are most often specific to an organization, each organization is going to have its own message object definitions and Java Message Objects or MOA.  Sure, some organizations and industries will standardize and agree to use common definitions for some business objects, and some already have.  However, for the vast majority of data that organizations need to pass between their own systems, there are no standard definitions, and organizations need to work quickly to meet their own requirements and internal deadlines.  It would be great if all the complex EAI and JMS capabilities of message objects could be inherited from OpenEAI foundation objects, making OpenEAI Java Message Objects easy to implement, matching each organization’s message object structures. 

 

Well, this is exactly how it works!  As it turns out, it’s even better.  All of the JMS and EAI behavior of Java Message Objects is implemented in ancestor classes provided in the OpenEAI foundation.  The Java Message Objects that must be developed for an organization’s own MOA are so straightforward that they can be programmatically generated from XML message definitions by an MOA generation application provided by the OpenEAI Project.  So, the development of a business-object-oriented API becomes a non-step in the integration project lifecycle.  It’s simply a byproduct of defining enterprise data objects in XML. 

 

The rest of the OpenEAI foundation components were developed over time to facilitate the use of these business objects in one way or another.  Layout managers were developed to implement serialization of these objects to and from various formats such as XML, flat files, and stored procedure calls.  Enterprise field foundation was implemented to allow analysts to specify enterprise values and application-specific values and to perform translations to and from these values.  Scheduled application and message consumer client foundation was implemented to provide generic, runnable applications that serve as containers for specialized commands.  These commands are where the business logic of integrations is implemented using the XML-, JMS-, and EAI-aware business objects.  Application configuration foundation and a common deployment descriptor were developed to allow developers and deployers to configure messaging applications systematically, and to enable contemporary deployment patterns, such as storing the configuration files for distributed applications that may run in many instances on many servers in a central directory server or web server and retrieving them via a secure protocol at runtime.

 

The OpenEAI API is an especially critical aspect of the OpenEAI Project.  The OpenEAI Message Protocol, Methodology, and Implementation Strategies could be used by themselves.  They are concepts that have proven useful in a number of ways for thinking about the dynamics of integration applications, for performing integration analysis, and for organizing an enterprise that is integrated using messaging.  However, the fact that the OpenEAI Project takes these ideas and provides a set of APIs to implement them makes the protocol, methodology, and implementation strategies so effective.  We can learn much from actually implementing these concepts and building real integrations to run our organizations, and what we learn can be used to refine and extend the underlying theory.

 

The OpenEAI API for implementing enterprise integrations is based on several other architectures, concepts, and foundation.  These include:

 

·         Java 2 Platform Enterprise Edition, specifically core Java itself and specifications within the J2EE platform such as the Java Naming and Directory Interface (JNDI) and the Java Message Service (JMS).

 

·         The Extensible Markup Language (XML) and specific XML parsing and manipulation foundation such as Xerces, Xalan, and JDOM.

 

Throughout this document, there are both code examples and XML examples.  The OpenEAI Project also maintains reference implementations of real-world messaging applications that are used by one or more organizations to integrate production enterprises, as well as a complete sample messaging enterprise.  The sample messaging enterprise is intended to serve as a leaning tool and pattern reference.  It is intended for use in conjunction with the Getting Started with OpenEAI document.  If you have not already read this document and followed through the example enterprise, you may want to peruse it quickly.  It will help you focus in on the area of OpenEAI you want to explore first, depending on your role in your organization.  The Getting Started document also serves as a guide to the OpenEAI Core Documentation Suite.  You probably need to have a general understanding of the OpenEAI Message Protocol and OpenEAI methodology to best understand OpenEAI API.

 

The OpenEAI API can be classified into ten general areas of foundation.  These are the areas and their corresponding package names.

 

  1. Application foundation (org.openeai.afa)
  2. Application configuration (org.openeai.config)
  3. Enterprise Message Object API foundation (org.openeai.moa)
  4. JMS Foundation (org.openeai.jms)
  5. Enterprise Layout Manager foundation (org.openeai.layouts)
  6. Enterprise Scrubber foundation (org.openeai.scrubbers)
  7. Enterprise Database Connection pool foundation (org.openeai.dbpool)
  8. ThreadPool foundation (org.openeai.threadpool)
  9. XML Utilities (org.openeai.xml)
  10. Reference implementations (org.openeai.implementations)

 

The official API documentation (javadoc) is available for download and online browsing. This document describes how components from these packages are used, and provides examples.

 

As we write, the current release of the OpenEAI API is 3.0 beta 2.  The precursor of the OpenEAI API, the University of Illinois EAI API, was released internally at the University of Illinois in December 2001 (release 1.0) and again in June 2002 (release 2.0), and is currently used in production at the University of Illinois. Both the University of Illinois and SCT Corp. are testing the 3.0 beta release of OpenEAI.  As soon as a site that practices OpenEAI uses the 3.0 release satisfactorily in production, the project will provide a final 3.0 release.  The OpenEAI Project promotes software from ‘beta’ to an official release only after it has both completed rigorous testing by the OpenEAI project and been successfully used in production by at least one site that practices OpenEAI. 

 

The OpenEAI API is maintained by the OpenEAI Project (info@OpenEAI.org).  This document was originally written by Tod Jackson (tod@openeai.org) and Steve Wheat (steve@openeai.org) in 2001 and 2002 and published in January 2003.

 

 

Helpful Definitions

 

This section provides brief definitions of some key terms that will be used throughout this document.  Each of these will be described in more detail later on.

Application

 

An application will be involved in the production and/or consumption of enterprise messages.  It will typically be the initiator of a messaging conversation.  For example, an employee self-service application that requests emergency contact information from the enterprise’s ERP system.

 

Scheduled Application

 

A scheduled application can start, execute some logic and exit, or can run as a daemon application that runs continuously and executes business logic on a configurable schedule.  This is a common requirement for integration applications.  For example, you may be familiar with requirements to check a directory for a URI for a file at a specified interval to see if a mainframe extract file has been dropped off.  You may need to check a database table for changes or pending transactions every so often.  When it comes to integration tasks, there are about a million things you could have to do on an interval-based schedule.  After doing quite a few, it becomes clear that some integrations become much more efficient (and less latent) if you do not have to rely upon scheduling things every minute or every second.  Optimally, you need the flexibility to schedule some things to happen within the bounds of a single second.  The OpenEAI Scheduled Application foundation provides the ability to encapsulate business logic in individual components (commands).  These commands can be executed according to a defined schedule associated with the application.  This serves several purposes:

 

·         Allows a generic “main” class for all applications that need to run in this fashion.  This generalizes some of the standard application startup code, but more importantly, it allows a generalized startup mechanism for all applications, such as a common start script, service deployer, or administration console.  This is an important consideration when deploying applications.  It can become very confusing to support a different startup mechanism for each application if they all have a unique way to be configured and started.

 

·         Execute immediately and exit (type=Application).  This means the application will execute just like any “normal” application one might think of.  The application will start, it will execute the business logic associated to it immediately, and it will exit.  This is similar to a normal Java class with a “main” routine.

 

·         Execute immediately and go back to sleep (type=Triggered).  This means the application will start, execute the business logic associated to it immediately, and then wait for a signal to tell it to stop.  This is useful if you want the business logic itself to have more control over the life of the application.

 

·         Execute on a given day(s) at a given time(s) (type=Daemon).  This means the application will start, then utilize a flexible scheduling facility (which is part of the OpenEAI API) to determine when business logic should be executed.  After it has executed that business logic, it will wait until the next scheduled initiation to execute the business logic again.  This is useful for long-running applications that need to execute the same, or different, business logic over and over again on a regular interval.

 

Message Gateway

 

A message gateway is a daemon application that consumes messages in the publish/subscribe model, point-to-point model, or both.  It is used to expose an existing application that is authoritative for some data to the rest of a messaging enterprise through request/reply messages or to consume synchronization messages from authoritative application to keep itself up to date.

 

Specifically, a message gateway may consume a request message, execute or invoke appropriate business logic to process the request message, and return the reply appropriate to the request it consumed.  It may also need to publish a sync message appropriate to the action of the request.  Alternately or in addition, it may consume synchronization messages, execute or invoke the appropriate business logic to process each sync message, and publish an Error-Sync message if it encounters errors processing a sync message it consumed.

 

See the section entitled “Implementing Message Support” in the OpenEAI Message Protocol Document for details on which messages a gateway may need to support, depending on whether it is or is not the application authoritative for one or more enterprise message objects.

 

Similar to the scheduled application foundation, the message gateway foundation provides the ability to encapsulate business logic, or the invocation of application business logic, in individual components (commands).  Then, when messages are consumed, the appropriate command is executed to process each message, and it replies in the case of requests or publishes a Sync-Error message if a sync message is unsuccessfully processed.

 

Message Relay

 

A message relay is a useful infrastructure component for making applications message-aware that are JMS-unaware and/or XML-unaware.  A message relay is typically a daemon application or servlet that serves as an intermediary between a JMS-unaware application and the rest of a JMS-aware messaging enterprise.  It can relay messages between applications that are JMS-aware and those that may only be able to send or receive messages with other, more traditional transport protocols such as TCP, HTTP, and HTTPS.  In addition to transport bridging, a relay can also be useful in bridging message protocols.  Some technologies that cannot easily be made JMS-aware also cannot easily be made XML-aware.  For more details on the concept and implementation of message relaying, see the OpenEAI Implementation Strategies Document.

 

Messaging Enterprise

 

The messaging enterprise is the combination of all messaging applications, gateways, relays, proxies, and other messaging infrastructure applications that are deployed to integrate and manage messaging within an organization.

 

Analysis Template

 

The analysis template is used to document integration analysis and define the enterprise messages needed for a particular integration.  Additionally, it defines the production and consumption logic for those messages.  This document must be completed before any serious development work can begin.  See the OpenEAI Methodology Document for more details on the OpenEAI analysis template.

 

Deployment Descriptor

 

This is an XML document structure used to configure all messaging applications and gateways that use OpenEAI foundation components.  This document is constrained according to the configuration options of the OpenEAI foundation components to provide a clear and uniform way to configure applications.

 

Enterprise Object Document

 

This is another XML document structure that OpenEAI Java Message Objects use to apply business rules to their data in their member fields.  The rules are specified in enterprise object documents and implemented by the message objects when data is put into the member fields via setter methods. 

 

Integration Process Overview

 

Details of the recommended OpenEAI integration process are covered in the OpenEAI Methodology Document.  The following brief overview is intended to help place the use of the OpenEAI foundation components in the context of the development, documentation, and testing phases of the integration process.

 

Perform Analysis

 

Once the systems that need to be integrated are identified, an analysis group or team comprised of business, functional and technical integration analysts complete the OpenEAI analysis template, or their organization’s customized version of the template, for each application that must be interfaced.  Among other things, the template documents general integration requirements, specifies which existing message objects will be used and which new message objects will be required, defines new message objects, specifies which message actions of the OpenEAI Message Protocol will be required for each message object, enumerates the messaging applications, gateways, and infrastructure that must be developed to implement the integrations, and enumerates detailed message production and consumption logic.

 

Define Messages

 

Once any new enterprise message objects and the message actions for them have been defined through the process of completing the OpenEAI analysis template, technical integration analysts create the XML message definitions for the new messages in the organization’s message hierarchy and provide one sample message for each definition.

 

Generate Java Message Objects

 

Next, the message definitions are implemented as Java objects.  A Java object must be created for every complex enterprise business object defined.  These Java objects are automatically generated using the OpenEAI MoaGenApplication; message definitions are prepared by integration analysts.

 

Develop, Document, and Test Messaging Applications

 

 

The details of this phase will vary from organization to organization: many organizations already have application development and testing practices established.  However an organization chooses to implement them, the following guidelines should be considered.

 

1.       Developers and analysts prepare detailed, technical stories for each messaging application and gateway listed in the completed analysis.  These stories will draw heavily on the message production and consumption logic prepared by the functional staff and analysts and included in the analysis template.

 

2.       Developers implement the appropriate messaging applications and gateways listed in the template using OpenEAI foundation components, the message object API that was generated for the organizations enterprise message objects, and the enterprise object documents completed by the functional staff and analysts.  When developing an OpenEAI based application or gateway, this means developing the commands needed to support the processes defined in the analysis.

 

 

3.       While steps one and two above are proceeding, integration analysis staff can prepare OpenEAI TestSuiteApplication test suite documents for testing the message gateways that are to be developed.  Test suite documents are XML documents comprised of messaging test cases.  The OpenEAI TestSuiteApplication can take a test suite document and execute all its test cases very rapidly: it sends test messages to a target application and compares the replies received and sync messages published by the target application with expected results, produces a detailed report, and can even tear-down any messaging artifacts or database entries created as a result of the TestSuite execution.  Functional staff and analysts are typically the best equipped to prepare these test suite documents, because they are the people who specified the integration requirements and message production and consumption logic to begin with.  Developers can perform this work, but if they do the functional staff and analysts should review and approve the test cases as being representative of the requirements. 

It’s useful for developers to have these test cases available to them during the development process: as they implement message support they can iteratively execute the test suite using the OpenEAI TestSuiteApplication to check their progress and to verify that changes they make do not break anything.

 

At this time, functional staff and analysts also prepare real-world online and batch scenarios to test the new messaging applications and gateways in integration with the rest of the messaging enterprise in a test environment.

 

4.       All messaging applications and gateways pass both informal developer testing and all of the formal test suites executed by the TestSuiteApplication.

 

5.       The new messaging applications and gateways are promoted from a development environment to a test environment for integration testing, and the real-world online and batch scenarios are executed until the functional staff and analysts are convinced the new applications are performing appropriately.  Note that although the practice of preparing test suites and unit testing messaging applications can be very effective at ensuring that messaging applications perform as designed, it may not help validate that the design is correct.  From time to time, integration testing with the rest of the messaging enterprise turns up new requirements, such as identifying additional applications that need to know about data from a new authoritative source.  For this reason, integration testing is a critical part of the process.  It is also the part of the testing process that gives management a tangible level of confidence that it is appropriate to proceed with a production implementation.

 

Update Enterprise Documentation Artifacts

 

Practicing the OpenEAI methodology produces a number of documentation artifacts, including an analysis template for each application that interfaces with other applications, enterprise data object definitions, message definitions, and javadoc for commands that implement support for each message object.  These artifacts should be posted in a web-accessible format.  For example, message definitions and enterprise object documents should be posted on a web server so that messages can be validated when necessary and so that field-level business rules and translations can be applied by Java Message Objects at runtime.  This practice allows you to build a web page to nicely document each messaging application or gateway, linking to and leveraging each of these artifacts that must be created anyway.

 

The OpenEAI Methodology Document recommends a format for these web pages.  Just as your organization may customize the analysis template or the OpenEAI methodology itself, you will likely choose to customize the web documentation template as well.  This web page can be posted on your organizational web site or intranet.  Posting this documentation helps managers, functional analysts, and technical analysts plan and prepare for new integrations.  Additionally, many organizations have auditing or best-practice requirements that mandate the preparation of some type of formal documentation for each integration.  Posting this documentation as a web page makes this information available to those who need it.  In some cases, it can even be helpful to complete and post most of this template prior to or during the development phase.

 

Deploy in Production

 

There’s not much to say about this step from an overview perspective, since if you get to this point, most of the work has already been done. If you follow the recommended OpenEAI practices for testing in pre-production environments, deploying in production should be anticlimactic.  The OpenEAI Deployment Patterns Document provides details on the minimum number of recommended environments you should set up for a messaging enterprise and how and when to promote messaging application and gateways from one environment to the next.

 

 

OpenEAI Foundation Components

 

JMS Foundation 

 

This includes four types of messaging components specifically designed for JMS messaging.  They include:

 

·         PointToPoint producers for producing requests to JMS queues and handling a reply

·         PubSub producers for publishing messages to JMS topics

·         PointToPoint consumers for consuming requests from JMS queues and returning a reply

·         PubSub consumers for consuming messages from JMS topics

 

These components will be used by applications and gateways to produce or publish to other applications in a messaging enterprise and to consume enterprise messages from other applications in a messaging enterprise.  These components simplify the process of making an application JMS-aware.  They can be used in Java and non-Java applications alike.  By using these objects, consistency and simplicity is ensured in the development of JMS-aware applications without requiring all developers become JMS experts.

 

Enterprise Messages

 

Enterprise messages are the definitions of enterprise business objects that will be used in integrations as well as the actions that will be performed on those objects.  These are defined during integration analysis and are implemented as constrained XML.  They constitute the "contract" with any application or gateway involved in an organization’s messaging enterprise.  Refer to the OpenEAI Message Definitions Document and the OpenEAI Message Protocol Document for more details regarding the definition of enterprise messages and the protocol.

 

Java Message Objects

 

These are Java objects that "wrap" the enterprise message objects defined using XML.  This exposes an API (the Message Object API, or “MOA”) to developers of messaging applications and gateways.  The MOA simplifies the implementation of these applications.  With an MOA, application developers can function effectively even without a great deal of knowledge of JMS and XML.  Instead, they just need to be familiar with the Java API.  This also opens the door for development languages like ColdFusion, PERL, and any other language that can instantiate and call methods on Java objects to use this same API without have to use a specialized set of XML libraries and more rudimentary communications protocols like TCP, HTTP, HTTPS, etc.  In essence, Java message objects summarize enterprise messages into a common, re-usable set of objects that can be used consistently in many different application development environments.

 

Other Foundation Components

 

The following are peripheral OpenEAI foundation components:

 

·         database connection pools (org.openeai.dbpool package)

·         thread pools (org.openeai.threadpool package)

·         producer pools (org.openeai.jms.producer package)

·         scheduled application foundation (org.openeai.afa package)

·         XML utilities (org.openeai.xml)

 

Additional information regarding these APIs may be included in this document at some point in the future.

 

 

Java Message Object Details

 

All examples listed in this section are for a fictitious system called the AnyERP system.  Its domain is any-erp-vendor.com.  The artifacts mentioned in the examples can be found in the OpenEAI CVS repository for additional reference information.  The official API documentation (javadoc) is also available for download and online browsing.

 

Important note: all of these objects can be automatically generated using the OpenEAI MoaGenerationApplication reference implementation application.  This application also takes care of generating the appropriate build…Message methods in the case of an object requiring a different buildQueryMessage or buildGenerateMessage implementation.  Additionally, if the object doesn’t support a particular action, it will add the code necessary to throw the appropriate exception.  It can do this because all of the information required to make these programming decisions is available in the message definitions and sample messages that an organization prepares during the analysis process.  If your organization follows the directory structure recommendations for organizing these artifacts included in the OpenEAI Message Definitions Document, the MoaGenerationApplication can read that structure and generate your entire MOA code for you.  The detailed descriptions provided in this section are solely provided to clarify what is going on under the covers.  They can be particularly helpful for developers and architects who are looking to build their own implementation of this functionality.  Users of the OpenEAI API can remain largely unaware of these mechanics if they desire. 

 

As mentioned above, message objects can be of two types:  XML-aware or both XML- and JMS-aware.

 

XML Enterprise Objects

 

Objects that are only XML-aware implement an interface called XmlEnterpriseObject and extend a class called XmlEnterpriseObjectImplXmlEnterpriseObjectImpl is the class that provides most of the implementation that makes the Java Message Objects XML-aware.  Examples of these objects include:  Address, Phone, and Name.  These are complex child elements within enterprise message objects like BasicPerson, EmergencyContact, and InstitutionalIdentity.  The definition of these enterprise message objects can be found in the appropriate segments file for the organization that defined them.  For more information on the segments file and the practice of defining enterprise message objects and maintaining enterprise message definitions, see the OpenEAI Message Definitions Document

 

The following hierarchy shows the relationship between these objects:

 

- org.openeai.moa.EnterpriseObject

   - org.openeai.moa.XmlEnterpriseObjectImpl

      - com.any_erp_vendor.moa.objects.resources.v1_0.Address

 

JMS Enterprise Objects

 

Objects that are both JMS- and XML-aware implement an interface called JmsEnterpriseObject and extend an abstract class called JmsEnterpriseObjectBase, which extends XmlEnterpriseObjectImpl and provides most of the implementation for JMS objects.  JmsEnterpriseObjectBase adds JMS awareness to an object in addition to the XML awareness it inherits from XmlEnterpriseObjectImpl.  Examples of these objects are BasicPerson, EmergencyContact, and InstitutionalIdentity.  These are objects that have enterprise messages defined for them and can perform actions such as com.any-erp-vendor.Person.BasicPerson.Query-Request.

 

The following hierarchy shows the relationship between these objects:

 

- org.openeai.moa.EnterpriseObject

   - org.openeai.moa.XmlEnterpriseObjectImpl

      - org.openeai.moa.jmsobjects.JmsEnterpriseObjectBase

         - com.any_erp_vendor.moa.jmsobjects.person.v1_0.BasicPerson

 

In their simplest form, these objects contain getter and setter methods that correspond to elements and attributes contained in the XML definition of the enterprise object.  For example, the Address Java object has a private instance variable called m_type that corresponds to the XML “type” attribute in the Address element, which is defined in the Segments.dtd file of the AnyERP Vendor.  Data is retrieved from this variable via the public getType() method and is set via the setType(String type) method.

 

Simple fields (elements that do not have child elements and attributes) are always specified in the Java object as variables of type String.  If the field is complex (an element with children) the variable specified in the Java object has a type corresponding to that object.  For example, the BasicPerson element includes a child element called Name, which is a complex element consisting of simple fields like FirstName, LastName and MiddleInitial.  Therefore, the BasicPerson Java object has a private instance variable called m_name that is an object of type Name, which is another Java object that implements XmlEnterpriseObject and extends XmlEnterpriseObjectImpl.  The BasicPerson object then contains a getName() method which returns a Name object associated to the BasicPerson object and a setName(Name aName) method that accepts a Name object in its signature, allowing a developer to set the Name object of the BasicPerson object.  This is true for all “exactly one” or “zero or one” complex fields that are children of other fields.

 

If the definition of a field specifies that it is “zero or more” or “one or more” (that is, it’s a repeating field) then the parent object contains a java.util.List of those types of fields.  If the repeating field is a simple field then this list will include a list of strings; otherwise, it will include a list of objects of the appropriate type.

 

For example, the BasicPerson message object in the org.any-erp-vendor.Person category is defined as having “zero or more” Address objects in it.  Therefore, the BasicPerson Java object includes a private instance variable called m_address which is of type java.util.List.  The contents of this List will be a list of Address Java objects when populated via the methods of the BasicPerson object.  Another example is the AdmissionsApplication message object in the com.sct.Student category.  This object has a repeating field called “Cohort”.  However, the definition of the Cohort element in the segments file says that the Cohort element is just a simple field (PCDATA).  Therefore, the private m_cohort instance variable in the AdmissionsApplication Java object is a List of String objects.  Each String object represents a Cohort associated with the AdmissionsApplication.

 

If the field is a simple field (PCDATA), the getter method returns a String and the setter method accepts a String as a parameter.  For example, the following six methods must be implemented for a repeating, simple field (using Cohort as an example):

 

public int getCohortLength()

public String getCohort(int index)

public java.util.List getCohort()

public void setCohort(int index, String cohort) throws EnterpriseFieldException

public void setCohort(Vector cohort)                                             

public void addCohort(String cohort) throws EnterpriseFieldException

 

If the field is a complex field, the getter method returns an object and the setter method accepts an object as a parameter.  For example, the following seven methods must be implemented for a “repeating, complex” field (using Address as an example):

 

public int getAddressLength()

public Address getAddress(int index)

public java.util.List getAddress()

public void setAddress(int index, Address anAddressObject) throws

  EnterpriseFieldException

public void setAddress(Vector addresses)

public void addAddress(Address anAddressObject) throws EnterpriseFieldException

public Address newAddress()

 

The reason for many of these methods is simply convenience.  However, they can become very important to an organization trying to integrate non-Java applications.  Many non-Java technologies can instantiate and call methods on Java objects (for example, ColdFusion and PERL).  Developers of applications using these technologies may not understand Java well enough to know exactly how a typical Java developer might use a java.util.List.  Additionally, depending on the language, it may be very cumbersome for them to do things that Java developers may take for granted, because of the style imposed upon them by the language they are using.

 

For all non-repeating fields, only the getter and setter methods need to be implemented.

If the field is a simple field (PCDATA), the getter method returns a String and the setter method accepts a String as a parameter.  Using Gender as an example:

 

public String getGender()

public void setGender(String theGenderValue) throws

  EnterpriseFieldException

 

Notice that the setGender method throws an EnterpriseFieldException.  When the setter method is called, the data being passed has to be validated against the Enterprise Object document, which defines the business rules associated with the Gender field such as length, translations, scrubbers, etc.

 

To accomplish this enterprise object validation, all setter methods for simple fields execute the getEnterpriseValue method, which is inherited by all Java message objects and is implemented in the XmlEnterpriseObjectImpl class.  This method takes the data being passed to the setter method and makes sure it is valid enterprise-quality data.  If it is not valid enterprise-quality data and if it cannot be scrubbed, translated, or otherwise converted into valid enterprise data by executing the business rules specified in the enterprise object document for that object, it throws the EnterpriseFieldException to indicate that the field value that has been passed to the setter method is invalid enterprise data.  The following is an example of how the setGender method is actually implemented in a com.any_erp_vendor.moa.jmsobjects.person.v1_0.BasicPerson object:

 

m_gender = getEnterpriseValue("Gender", theGenderValue);

 

This call uses the information found in the org/any-erp-vendor/Person/1.0/BasicPersonEO.xml document (BasicPersonEO stands for BasicPerson Enterprise Object) to validate the data for the BasicPerson/Gender element.  This is how consistent business rules can be applied to all enterprise objects at the field level.

 

If the field is a complex field, the getter method returns an object and the setter method accepts an object as a parameter.  Additionally, there is a convenience method that returns a newly initialized object of that type.  This is so the child objects don’t have to be listed in the Deployment Descriptor for the application.  Instead, the parent object has the information and ability to create an object of the desired type and initialize it with the appropriate configuration information so developers can use that child object and the rules that have been specified for that object in its EO document.  The OpenEAI Deployment Descriptor section of this document discusses how the parent object is made aware of the child object’s configuration information.  For example:

 

public Name getName()

public void setName(Name aNameObject)

public Name newName()

 

Performing Request Message Actions

 

When a message action, such as create, is called on a JmsEnterpriseObject, such as BasicPerson, the data contained in the BasicPerson object is used to build a com.an-erp-vendor.Person.BasicPerson.Create-Request XML message.  That message is sent to a destination (a JMS queue) by the PointToPointProducer passed to the BasicPerson object’s create method.  A gateway then consumes that message and executes the business logic associated with the create action specified in the com.any-erp-vendor.Person.BasicPerson.Create/ControlAreaRequest/@messageAction attribute of the message.  The com.any-erp-vendor.Person.BasicPerson.Create /DataArea/BasicPerson element supplied in the Create-Request message is the data with which to perform the action.

 

All of the logic needed to build the com.any-erp-vendor.Person.BasicPerson.Create-Request XML message, as well as sending that message to the destination and consuming the reply from the gateway, is implemented in either the JmsEnterpriseObjectBase class or in the Java message object itself, if necessary, which extends JmsEnterpriseObjectBase and implements JmsEnterpriseObject.  In this example, it is implemented specifically in the create method of the JmsEnterpriseObjectBase class.  If any errors occur during this process, the create method throws an exception indicating the nature of the problem.  Additionally, if the gateway that consumed the create message has problems actually creating a record in its repository with the data sent to it, the create method in the JmsEnterpriseObject class will inspect the result returned from the gateway, and if errors exist it will throw an exception containing the error that occurred in the gateway.  The calling application will catch this exception and either use the information provided in the exception or call the getLastErrors method of the JmsEnterpriseObjectBase class to get the actual Error objects that were created when the error occurred.  With these objects, the calling application will have more information at its disposal regarding the error(s) that occurred.  The error information will be retrieved from the reply document returned from the gateway and Error Java objects will be built from the contents of the reply document.  The message actions update and delete work the same way as the create action described here.

 

There are two other request actions that work a little differently, query and generate.  These actions differ in that they accept an additional parameter in their signature.  That parameter is the “key object” with which to query or generate.  For example, the com.any-erp-vendor.Person.BasicPerson.Query-Request.dtd specifies that a LightweightPerson element should be included in the DataArea of the query message.  Therefore, to perform a BasicPerson query action using the Message Object API, you call the query method of a BasicPerson object passing a LightwieghtPerson object that has been populated with values corresponding to the person you are querying for.  The query method will return a List of objects returned from the gateway that processed the request.  These will be Java objects of the type specified in the query; in this case they will be BasicPerson objects.  These objects will have been built from the contents of the reply document sent back from the gateway and are ready to be used by the developer as Java objects.

 

The generate method works much the same way except the key object being sent is generally some sort of seed or source data that the gateway’s generation algorithm uses to generate a composite object.  For example, the org.any-openeai-enterprise.CoreApplication.InstitutionalIdentity.Generate-Request.dtd specifies that an UnknownPerson object is required to generate an InstitutionalIdentity.  To implement this case, the application developer retrieves an UnknownPerson object from the application’s AppConfig or creates a new object via the newUnknownPerson() method in the InstitutionalIdentity object, populates it with the appropriate data, and passes it to the InstitutionalIdentity.generate method, which builds the org.any-openeai-enterprise.CoreApplication.Generate-Request message and sends it to the destination that will perform the generation and return the generated InstitutionalIdentity.  Again, if any errors occur in the process of building the outbound message or if errors are sent back from the gateway that performed the generation, it will throw an exception indicating the nature of the problem.

 

Performing Synchronization Message Actions

 

For every request action that causes data to be created, generated, updated, or deleted at an authoritative application, there is a corresponding synchronization message that must be published by that authoritative application, which indicates that the action has occurred.  Gateways that “gate” authoritative applications or message-aware applications that are authoritative sources can also use the Message Object API to publish these sync messages when these actions occur.  These sync methods are also specified in the JmsEnterpriseObject interface and implemented in JmsEnterpriseObjectBase.  They are createSync, updateSync, deleteSync and generateSync.  They behave similarly to the request action methods, except they accept a PubSubProducer object instead of a PointToPointProducer in their signatures, because a sync message does not expect a reply.

 

Building Messages

When an action is performed on a Java Message Object, the contents of that object and key object (in the case of query and generate actions) are used to build an XML document corresponding to the action being performed.  This is a two-part process.  The first part involves building the XML message corresponding to the action.  The second part of the process actually sends that message to a destination via a PointToPointProducer or a PubSubProducer.

 

This process is broken into two parts to provide flexible support for various actions of the protocol for each message object.  For example, many objects related to person information may use a LightweightPerson object as a key object for queries.  In other words, the DataArea element of their Query-Request message is defined to contain a LightweightPerson element.  However, other objects, such as InstitutionalIdentity, require a different key object, such as UnknownPerson, in the DataArea of their query document.  Still other message objects are totally unrelated to person data and require other objects in Query-Request messages.  One common case (for example, the building of Query-Requests with a LightweightPerson) can be implemented the JmsEnterpriseObjectBase class; this common case is implemented there.  However, if an individual Java Message Object requires different processing than this common case (and many will), it must override the method and build the appropriate document for the action being performed.

 

These methods all correspond to the action being performed.  For example, one of the first things the query method of a Java Message Object does is call the buildQueryMessage method to build the Query-Request document for the object.  If an object such as InstitutionalIdentity requires a different type of key object it must override the buildQueryMessage method it inherits from JmsEnterpriseObjectBase and build the document appropriately for itself, casting the XmlEnterpriseObject object to an UnknownPerson (or whatever is appropriate according to the message definition) instead of a LightweightPerson, which is what the buildQueryMessage method in JmsEnterpriseObjectBase does because it is a fairly common case.

 

For every action, there is a corresponding build…Message method.  Five actions specified by the OpenEAI Message Protocol can actually be performed on a message object: query, create, update, delete, and generate.  So the following build…Message methods are defined in JmsEnterpriseObjectBase: buildQueryMessage, buildCreateMessage, buildUpdateMessage, buildDeleteMessage and buildGenerateMessage.  Since the DataArea portion of the sync messages look exactly the same as their corresponding request messages, they use the same build…Message methods to build the XML document for the corresponding sync actions.

 

Additionally, if an object doesn’t support a certain type of message action, it should throw an exception in the build…Message method that it implements to inform users that they have attempted to use the object incorrectly—that it doesn’t support that method.  For example, relatively few objects will need to support the generate action.  Therefore, all objects that don’t support that action must implement a buildGenerateMessage method that simply throws an exception saying the action is not supported by that object.  In fact, the buildGenerateMessage method is defined as an abstract method in JmsEnterpriseObjectBase, meaning that all objects that extend JmsEnterpriseObjectBase must implement that method.  The reason for this design is that generation of an object is usually very specific to that object.  For example, the seed or key object is very specific to the object being generated.  Most objects, however, will simply throw an exception stating that they don’t support the buildGenerateMessage method.

 

Important note: As mentioned above, all of these objects can be automatically generated using the OpenEAI MoaGenerationApplication reference implementation application.  This application also takes care of generating the appropriate build…Message methods in the case of an object requiring a different buildQueryMessage or buildGenerateMessage implementation.  Additionally, if the object doesn’t support a particular action it will add the code necessary to throw the appropriate exception.  It can do this, because all of the information required to make these programming decisions is available in the message definitions and sample messages that an organization prepares.  If your organization follows the directory structure recommendations for organizing these artifacts included in the OpenEAI Message Definitions Document, the MoaGenrationApplication can read that structure and generate your entire MOA code for you.  The detailed descriptions provided in this section are solely provided to clarify what is going on under the covers.  They can be particularly helpful for developers and architects who are looking to build their own implementation of this functionality.  Users of the OpenEAI API can remain largely unaware of these mechanics if they desire. 

 

Developing Messaging Applications

 

When a message-aware application is developed using the OpenEAI foundation components, everything starts with a specialized object called an AppConfig object.  This object is an XML-aware object that knows how to configure itself from an XML file stored in a directory server, on a web server, or on the file system.  This object works in conjunction with an XML configuration document called the OpenEAI Deployment Descriptor.  These documents describe, in technical terms, the integrations that will be performed among applications in an organization by specifying all OpenEAI components that will be used by the messaging application or gateway.

AppConfig (org.openeai.config.AppConfig)

 

Simply put, the AppConfig object reads the deployment descriptor and loads itself with all the objects that will be needed for this application based on what it finds in that file.  The types of objects that it may load include:  message objects, producers, consumers, logging objects, thread pools, database connection pools and general application properties.  So, in essence, AppConfig is a container that holds pre-configured and, in some cases, started objects that can be retrieved by an application developer when the objects are needed.

 

It should be noted that all applications that use OpenEAI foundation components do this same thing one way or another.  If a developer chooses to develop a standalone application with a “main” method, it will configure an AppConfig.  Likewise, the org.openeai.afa.GenericAppRunner and the org.openeai.jms.consumer.MessageConsumerClient classes both instantiate and initialize an AppConfig in the same manner.

 

For example, let’s assume we’ve been given a completed analysis template, enterprise object documents, and a generated MOA for exposing a legacy mainframe system that runs in batch and is authoritative for person and employee information.  Let’s refer to this system affectionately as the BarneySystem, meaning the big purple dinosaur.  We prepare our technical stories, which basically outline what we need to develop a scheduled application.  Let’s call it the BarneyScheduledApplication.  The BarneyScheduledApplication will read the mainframe extract files that are created at the end of each batch run of the BarneySystem and build BasicPerson and BasicEmployee objects from the mainframe extract files.  The building of these message objects from the extract lines will be handled for us by the OpenEAI layout manager foundation and extract layout implementation.  It will use the extract file-to-object mappings and the BarneySystem values-to-enterprise-values translations provided by the analysis team in the enterprise object documents for BasicPerson and BasicEmployee.  The scheduled application will then publish messages to inform other applications in the messaging enterprise about new people and employees and changes in person and employee state.

 

There’s just one interesting twist, though.  The BarneySystem does not know about ID numbers.  Years ago when the BarneySystem was implemented, the organization did not issue ID numbers.  The BarneyApplication only knows about social security number.  So we see in the analysis that our scheduled application is going to have to perform some Query-Requests and Generate-Requests for InstitutionalIdentity with the organization’s ID card system to get ID numbers for known people and generate them for new people.  So our application needs to read extract file lines, build message objects from the extract lines, query for or generate ID numbers through messages, set the ID number (the InsitutionalId) on the BasicPerson and BasicEmployee objects that were either returned from the query or generated to complete these objects, and then publish sync messages for the appropriate actions.

 

So, this technical story helps us determine that the BarneyScheduledApplication is going to need the following configurations in its deployment descriptor:

 

1.       Message Objects

- BasicPerson

- BasicEmployee

           

2.       A PointToPointProducer to perform request/reply messaging with the ID card systems to get those ID numbers

 

3.       A  PubSubProducer to publish the sync messages for BasicPerson and BasicEmployee

 

Once these objects are loaded into the AppConfig object and initialized with information obtained from the deployment descriptor, the application can retrieve the objects out of the AppConfig object whenever they are needed.  This gives the developer the ability to configure these objects once, and then the application has them at its disposal for use while it’s running.  This is important because some of these objects require valuable resources that may be expensive to initialize.  It also allows us to specify in one place all the configuration information for an application in its entirety.

 

Very little information has to be stored in a deployment on the target hosts where the application will run.  The only information needed with the application jar files and a start script is information used to locate and read the deployment descriptor.  This will include some sort of URI specifying the location of the document and may include security credentials necessary to read the document from a directory server or secured web server.  Finally, it contains information that tells the AppConfig which messaging component it should configure (an application/gateway name).  This also gives us the opportunity to develop highly customizable applications using consistent methods.  Consistent methods improve an organization’s ability to quickly develop and deploy sophisticated applications and administer them efficiently.

 

There are three places in which deployment descriptors are typically stored: on a file system with the deployed application, on a web server, or in a directory server.  For security and deployment management reasons, many organizations are starting to experiment with storing configuration files such as these deployment descriptors in a directory server.  Access to all configurations can then be restricted to application administrators, these application administrators do not necessarily have to have access to the servers on which these applications are deployed to administer them, and configuration files do not have to be synchronized between servers when many instances of the same application are run on multiple servers in a clustered deployment.  The OpenEAI deployment patterns recommended that deployment descriptors be stored in a directory server.  However, that is an organizational choice.  Even if your organization does use a directory server for this purpose, during development phases you may find it convenient to use the local file system or a web server at times.

 

To switch between these storage locations, simply change the providerUrl property shown below to be the desired URI.  The AppConfig object takes care of the rest.

 

All applications, gateways, and servlets can be started with a simple properties file that contains the following properties (obviously, the values assigned to the properties will differ depending on the application, gateway, or servlet).  The following are examples of properties files that point the AppConfig object of a starting application to its deployment descriptor.  Note that in some cases, lines have been broken to fit them on this page in this document.

 

A properties file pointing to the deployment descriptor in a directory server:

 

providerUrl=ldaps://ldap.any-openeai-enterprise.org:636/ou=Development,

  ou=Configurations,ou=Messaging,dc=openerp,dc=org

initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory

securityPrincipal=uid=SampleApplication,ou=Development,ou=Users,

  ou=Messaging,dc=openerp,dc=org

securityCredentials=secretpassword

configDocName=configxmlname=SampleApplication

messageComponentName=SampleApplication

 

A properties file pointing to the deployment descriptor on a web server:

 

providerUrl= http://xml.openeai.org/xml/message/uillinois

  /xml/1.0/Configuration/SampleApplication.xml

messageComponentName=SampleApplication

 

A properties file pointing to the deployment descriptor on a local file system:

 

providerUrl= file://configs/SampleApplication.xml

messageComponentName=SampleApplication

 

The following is an example of how a standalone application can load the properties object:

 

String propFileName = args[0];

Properties props = new Properties();

InputStream in = new FileInputStream(propFileName);

props.load(in);

in.close();

 

aConfig = new AppConfig(props);

 

After the properties file is loaded it is passed to the AppConfig constructor, which will bind to the directory server (in this case), search for and read the deployment descriptor, and initialize itself with contents found in that file. This is the same processing that occurs when the document is stored on a web server or file system, except with a directory server, stricter access controls can be put in place regarding who has access to the deployment descriptor.  So, as it turns out, there is a very small set of external properties that must be stored with the application.  Once the application has this information, it can obtain the contents of the configuration document and initialize itself.

 

Scheduled applications and message gateways all use a common component to start themselves, called GenericAppRunner or MessageConsumerClient respectively, that use this same approach.  Therefore, it is unlikely that very many developers even need to code this AppConfig initialization.  The only time it would be necessary is if they are developing a standalone application that is not a scheduled application or a message gateway.  Decisions to do this should be weighed carefully, because foundation components are already in place to do this initialization and ensure that these applications and gateways can be started and stopped in a uniform fashion.

 

Once AppConfig has been loaded with pre-configured, instantiated, and initialized objects, developers can use a couple different methods of the AppConfig object to retrieve those objects from AppConfig and use them in the normal course of development.  These methods are:

 

getObject(String name)

getObjectByType(String fullyQualifiedClassName)

 

For example, the following example demonstrates getting a PubSubProducer from AppConfig named “SyncProducer,” which it instantiated and initialized based on information found in the application section of the deployment descriptor.

 

PubSubProducer pubSub1 = (PubSubProducer)aConfig  .getObject("SyncProducer");

 

The next example asks the AppConfig object to locate and return the first object it finds that has a class name equal to the class name of the PubSubProducer which it instantiated and initialized based on information found in the deployment descriptor.  Note that this will return the first object of this type.  If multiple PubSubProducers are listed in the d