Return to Joppa

 

The Road to Joppa - FAQ

 

 

Table of Contents

 

·         What is Joppa?

·         What is the “Adaptation Pattern”?

·         What is the application design goal of “Substitutability”?

·         What are the high-level Joppa “platform abstraction” characteristics?

·         Which technologies were initially abstracted as a “Proof of Concept”?

·         When a Joppa plugin abstracts a technology, is all functionality supported?

·         Hey, what’s the BO, LO, MO, RO deal?

·         What is “Joppa CRUD”?

·         What Common layer patterned objects does Joppa promote?

·         What Presentation layer patterned objects does Joppa promote?

·         What Service layer patterned objects does Joppa promote?

·         What Integration layer patterned objects does Joppa promote?

·         What Test patterned objects does Joppa promote?

·         Can an application use Joppa “al á carte”?

·         What about exception handling?

·         What development tools are used?

·         How are JARs organized?

·         How are the Joppa projects organized?

·         What is the genesis of the Joppa protocol?

 

 

What is Joppa?

Joppa is the open source "J2EE Objects: Pluggable Platform Abstraction" enabling OO transactional application development and automated method testing by abstracting existing best-in-class technologies.

 

Joppa delivers a consistent plugin module interface and base class extension (inheritance) style of API.  Joppa pursues the illusive write-once and run-with-a-choice-of-technologies goal.  As a platform abstraction - Joppa seeks to sustain loose coupling (between underlying frameworks or technologies).

 

Joppa serves as a reference implementation for the “Adaptation Pattern”.

 

Top of Page

 

 

What is the “Adaptation Pattern”?

 

Problem

 

You want to implement, sustain and extend application functionality in a cost-effective manner while underlying technologies are deprecated or mature-beyond-recognition over time.

 

Effective technologies are frequently transformed to remain relevant; others have a formal termination date or informally fade from usage and memory.  The “Adaptation Pattern” represents an alternative to hard-wiring an application by decoupling technologies from their API.  The fundamental notion of authoring general-usage applications to independently conceived APIs leads to several representative challenges:

 

·         Velocity - A temptation to slow progress in order to make “good” technology/API choices having long-term consequences.

·         Staffing - The need to obtain/train/retrain resources fluent in selected technology APIs.

·         Cost - The need to “glue” disparate technology/API choices together into a deliverable system.

·         Agility – An inherent “brittle” relationship between application and dependent technology.

·         Modularity – A lack of “architectural cohesion” when business and technology functions (inadvertently) merge.

 

 

Forces

 

·         You want to author general purpose applications to a consistent technology independent API.

·         You want to establish an Object Oriented stratification for organizing technology functions.

 

 

Solution

 

Use the “Adaptation Pattern” to segregate general-purpose applications from their dependent technology functions.

 

The strategy encourages a minimum of three (3) levels of contextual abstraction between a substitutable technology and application code.  Each abstraction level is independently testable.  Abstraction level artifacts consist primarily of plugin module implementations and/or extensions, base class implementations and/or extensions, and automated method (unit) tests.

 

 

 

Consequences (side-effects)

 

·         Reduces the unique lines of business function code required (to deliver a use case).

·         Reduces the number of test objects and unique lines of test code required.

·         Enables consistency of style and convention within the abstraction level.

o        No need to learn/reference multiple APIs.

o        Opportunity for optimized use of code completion.

o        Multiple entry points for (continuous) maturation of convenience methods.

·         Enables establishment (and verification) of level performance criteria.

·         Encourages design cohesion – particularly separation of technology and business functions.

·         Increases the need for a shared understanding of design approach within a level community.

 

 

Related Patterns

 

Adapter Pattern (or wrapper pattern):  The adaptation pattern is to an application what the adapter pattern is to a single object or class.  In addition to this conceptual relationship, the adapter pattern is a useful technique for translating methods from a technology specific API to a multi-technology consistent API.

 

Top of Page

 

 

What is the application design goal of “Substitutability”?

“Substitutability” as a design goal may be defined as:

 

The extent a technology change causes an expenditure of effort.

 

Some technologies are more prone to a substitution then others; “substitutability” is typically realized thru loose-coupling between an application and its dependent technologies.  Joppa (fundamentally) concedes tight-coupling to the JDK – although not necessarily all technologies contained therein.  In addition, Joppa promotes a balanced view of “substitutability”; a preferred target might be 80% “substitutability” achieved with a 20% expenditure of effort contrasted with 100% “substitutability” achieved with a 100% expenditure of effort.  (See “Pareto Principle” or “80-20 Rule” at http://en.wikipedia.org/wiki/Pareto_principle .)

 

Inherit in the pursuit is the pretext that technology substitutability is a characteristic of effective modular design.  In somewhat the same manner that the pursuit of “testability” can improve design as a side-effect; the intentional pursuit of “substitutability” can lead one to additional rigor in design pattern usage.

 

In any case, effect “substitutability” contributes towards reducing the unique lines of code required during the complete (multi-year) life-cycle of the application.

 

Top of Page

 

 

What are the high-level Joppa platform abstraction characteristics?

Joppa, as a platform abstraction, normally seeks to assist teams deploying proven technology.  Since design is a compromise, Joppa typically compromises in favor of Object Orientation (and testability).  Joppa stands opposed to design (and deployment) patterns explicitly or implicitly encouraging separating attributes (variables) and their associated behavior (methods).

 

At no time, in any way, should Joppa hinder application development not using a Joppa-related plugin module or base class.  This is a significant distinction between a framework and the Joppa notion of a “platform abstraction”.  Many frameworks attempt to provide 100% functionality in a problem space.  Joppa seeks to support typical web application capabilities – primarily those associated with request/response processing and reading/writing (transparent persistence) with an object store (a.k.a. database).  It has been said that Joppa (potentially) enables 80% of transactional web applications for 80% of their functionality.

 

Another Joppa distinctive is the enthusiastic use of plugins for abstracted programming logic.  Many base class methods are a façade for application invoked and call back methods; they simply invoke the complementary plugin method.  Typically plugins have defined Interfaces; base classes do not (excepting when Java single-class inheritance forces use of a “marker”).  The strategy enables base class maturation (without breaking existing applications) and use of “protected” methods.  The plugin strategy may be more readily apparent in the following class diagrams for two substitutable unit testing technologies – JUnit and TestNG.

 

JUnit Plugin

 

 

TestNG Plugin

 

The following abridged listing demonstrates invocation of plugin logic from base class (JjBaseOutsideContainerJunit/JjBaseOutsideContainerTestng) methods:

 

      /**

       * This method unloads the originally specified descriptor document and

       * loads an alternate. It is typically used in the context of testing

       * declarative plugin values. The corresponding "unload" method is invoked

       * after completion of test logic.

       *

       * @param documentName

       *            Descriptor document name.

       */

      protected void loadAlternateDescriptorDocumentBeforeTesting(String documentName) {

 

            JjUtilPluginFactory.returnTestOutsideContainerPlugin()

                        .loadAlternateDescriptorDocumentBeforeTest(documentName);

 

      }

 

      /**

       * This method unloads the alternate and reloads the originally specified

       * descriptor document.

       */

      protected void unloadAlternateDescriptorDocumentAfterTesting() {

            JjUtilPluginFactory.returnTestOutsideContainerPlugin()

                        .unloadAlternateDescriptorDocumentAfterTest();

 

      }

 

Somewhat uncharacteristically in the Java world, Joppa artifacts are intentionally named to leverage code completion.  For instance, all Joppa classes begin with “Jj” in these representative examples:

 

·         JjBase

·         JjException

·         JjFactory

·         JjInterface

·         JjTo

·         JjUtil

 

The Joppa Reference Implementations are integral for validating and demonstrating the application development protocol.  Not unlike Equinox, AppFuse and Honeycomb – Joppa presumes application projects begin with a working implementation and then launch into a test driven refactoring style of development.

 

Top of Page

 

 

Which technologies were initially abstracted as a “Proof of Concept”?

The “real” Proof of Concept, in production at a Fortune Five company, is not available to the open source community.  That said, the pre-work completed to communicate the strategic intent and tactical approach includes the following technology substitutions.

 

·         Logging

o        J2SE logging (packaged in joppa-core.jar).

o        Log4j logging (packed in joppa-log4j.jar).

 

·         Outside Container Testing

o        JUnit (packaged in joppa-core.jar).

o        TestNG (packed in joppa-testng.jar) for JDK v. 5.0

 

Top of Page

 

 

When a Joppa plugin abstracts a technology, is all functionality supported?

It would normally be a violation of the intent of Joppa (and the “Pareto Principle”) to support 100% of a technology’s capability.  Using logging as an example; J2SE logging has seven (7) predefined levels and Log4j has six (6).  Joppa asserts (in principle) that 80% of the time five (5) levels are enough.  The mapping between J2SE/Log4j with Joppa is represented in the following table:

 

          J2SE / LOG4J   VALUE   JOPPA METHOD

          ====   =====   =====   ============

          SEVERE/FATAL  = 1000 = logThrowable()

          WARNING/ERROR =  900 = Not explicitly supported

          INFO/WARN     =  800 = Not explicitly supported

          CONFIG        =  700 = Not explicitly supported

          [custom]      =  600 = logLayer() [refined by architectural layer]

          FINE/INFO     =  500 = logInformation()

          FINER/DEBUG   =  400 = logEntering()/logExiting()

          FINEST/TRACE  =  300 = logDebug()

 

However, an additional nuance is introduced beyond hierarchical log levels.  Level 600 can be further designated by “Common”, “Presentation”, “Service” and “Integration” architectural layer; so that one may log Integration layer transparent persistence information without logging the same detail for the Presentation layer.  (See JjInterfaceLoggingHandlerPlugin Javadoc for details.)

 

Joppa asserts that 80% of applications can benefit from layer-sensitive logging in addition to standard hierarchical logging.  The good news is that if one disagrees with a Joppa plugin implementation, there are several options:

 

·         Override an existing plugin

·         Extend an existing plugin

·         Author a new (competing) plugin

 

And of course, there is no project velocity penalty to simply ignore a particular Joppa capability and hard-wire a portion of an application to a native API.

 

Top of Page

 

 

Hey, what’s the BO, LO, MO and RO deal?

Business Object (BO): The J2EE Core Patterns 2nd Edition identifies a Business Object as (minimally) encapsulating business data and behavior.  The BO instances collectively represent the domain model or object graph.  A BO is typically coded with an immutable primary key and may also contain a no-argument constructor.

 

Note: Care should be exercised before adding unmapped attributes to a BO.  Attribute state may be lost when (shared) cached instances are refreshed.

 

A BO is typically configured to be refreshed in shared cache based on a change to the last updated date – the same attribute used for optimistic locking for update operations.  When a BO is used in a read-only context it is referenced as a RO, when a BO is being used in a modifiable context it is notated as a MO.

 

Lookup Object (LO): A LO is a specialized BO.  So, why have the distinction?

 

A LO is typically configured to not be refreshed in shared cache.  When a LO is used in a read-only context it is referenced as an RO.  A LO would never be in a modifiable state and may be declaratively configured as read only.  The only transactional operation performed on a LO is similar to:

 

          registerCountryLoAsRelated()

 

A list of countries provides an excellent example of LO usage.  Historically, country names have been reasonably static.  An application may have country names preloaded into a database table for subsequent use with a drop-down list box on a web page.  There is no reason to continuously determine if a country name should be refreshed in shared cache – the presumption is that once loaded, the country name is static and will not change.

 

When global upheaval is endured and a country name change required, the table must be updated outside of the application and the shared cache refreshed – perhaps by restarting the application server.

 

Modifiable Object (MO): Unlike a BO or LO, the MO designation is a naming convention to clarifying the instance is a private copy – not a reference (to shared cache).  It indicates a BO has (already) been registered for either create or update.  An example declaration might look as follows:

 

          private PersonBO personMO;

 

Read-only Object (RO): A RO is a wrapper object protecting a BO instance in shared cache from a state change.  Typically, only (accessor) “getters” are exposed on an RO.

 

Wait – how about Transfer Objects (TOs)?  Joppa redefines the Core J2EE Patterns problem (2nd ed. p. 415) as – “You want to transfer multiple data elements and be able to refactor the elements without breaking method signatures.”  Simply stated, many Joppa method signatures require (immutable) TOs as a deliberate platform abstraction sustaining strategy.  TOs are often the messenger from an application to a Joppa method.

 

Top of Page

 

 

What is “Joppa CRUD”?

The “Joppa CRUD” constitutes the template method naming conventions providing object graph management.  Eight (8) conventions support read-only operations, four (4) are transactional and two (2) are used on an exception basis.  The read-only conventions consist of two sets beginning with the verbs “exists” and “read”.  The transactional conventions begin with the verb “register” and use the overloaded acronym CRUD (for Create, Relate, Update and Delete).  The “Joppa CRUD” may be referenced generically by their JjBaseDAO method names:

 

·         existsRoBy()

o        executes a parameterized named query

o        determines if a persisted (RO) instance exists

o        example = existsCountryRoByCode()

·         existsRoWith()

o        executes a hard-coded named query

o        determines if a persisted (RO) instance exists

o        example = existsCountryRoWithUS()

·         existsRoListBy()

o        executes a parameterized named query

o        determines if any persisted (RO) instances exist

o        example = existsCountryRoListByContinent()

·         existsRoListWith()

o        executes a hard-coded named query

o        determines if any persisted (RO) instances exist

o        example = existsCountryRoListWithNA()

·         readRoBy()

o        executes a parameterized named query

o        retrieves a reference to persisted (RO) instance

o        example = readCountryRoByCode()

·         readRoWith()

o        executes a hard-coded named query

o        retrieves a reference to persisted (RO) instance

o        example = readCountryRoWithUS()

·         readRoListBy()

o        executes a parameterized named query

o        retrieves a list of persisted (RO) instance references

o        example = readCountryRoListByContinent()

·         readRoListWith()

o        executes a hard-coded named query

o        retrieves a list of persisted (RO) instance references

o        example = readCountryRoListWithNA()

·         registerBoForCreate()

o        typically utilizes an instantiated BO with immutable primary key

o        returns a modifiable instance (MO) bound to a transaction

o        example = registerPersonBoForCreate()

·         registerBoAsRelated()

o        typically utilizes an instantiated BO with immutable primary key

o        returns a modifiable instance (MO) bound to a transaction

o        example = registerCountryLoAsRelated()

·         registerBoForUpdate()

o        typically utilizes an instantiated BO with immutable primary key

o        returns a modifiable instance (MO) bound to a transaction

<