A good framework represents at least half of a project as it decomposes an application into manageable components with consistent and well-established methodology. After kicking off a J2EE development effort, you need a framework to make it succeed. E++ is a pattern language for developing a MREPICS framework on the J2EE platform. In Part 1 of this series, I explained E++'s applicability, design principles, and architecture patterns.
Read the whole "E++: A pattern language for J2EE applications" series:
- Part 1: Build better J2EE applications with a high-level pattern language
- Part 2: Weave the design patterns together
In this article, the second of two, I continue the progress made in Part 1 by detailing the patterns most important for a successful E++ implementation. As outlined in Part 1, to design the application as a whole, you should follow the E++ tree (Figure 1), from root to branches to leaves. As such, you'll find it useful to refer to the E++ tree as you work through the design patterns detailed below.
Due to space considerations, it is impossible to detail all of the E++ implementation patterns here; I'll stick to the major patterns and their uses. For more complete information and the related patterns, see the Resources section below. Continuing the practice from Part 1, for each major pattern I will detail:
- The pattern name
- The context in which the pattern applies
- The design problem raised by the context
- The conflicting forces that must be resolved
- The solution offered by the pattern
So, let's get to the patterns!
Pattern name: Application Mediator
The E++ tree starts with Application Mediator, an object that sits between the client and the application to handle all human or nonhuman inputs. As such, it is the single entry point to the application. Such an arrangement is suggested by the Layered Architecture pattern described in Part 1 of this series. On real-world application servers, you achieve this with the
configuring<servlet-name>webTierEntryPoint</servlet-name> attribute of a
What functionality should the Application Mediator possess so that it mediates reusable pieces together?
You should construct the E++ generic J2EE application framework such that it does not depend on any specific user requirements or actions. As a framework for large-scale enterprise applications, the Application Mediator should address every aspect of the application, such as JSP presentation layout, application models, security, and internationalization.
The Application Mediator should function like an organization's front desk: it should comprehensively refer to a specific manager to handle a specific set of tasks. As such, the mediator object encapsulates all interconnections, acts as the communications hub, and controls and coordinates its clients' interactions. Further, it delegates suitable user requirements to specific manager objects.
The E++ Application Mediator interacts with the following manager objects:
- The ComponentManager loads the component module information at runtime through an XML interface. It helps decouple the framework from domain-specific programming. The ModelManager manager uses the supplied information.
- The JSP Layout manager selects application presentations; it comprises JSP Template, JSP Page, and JSP Tag.
- The Event Processor, a help object, changes application models at all tiers according user requests.
- The Locale Manager handles language localization.
- The Security Manager operates the application's security realm.
- The ModelManager handles model synchronization of different tiers and serves as a gateway of the model retrieval from the Web tier.
Each of these manager objects works with general human or nonhuman clients (XML inputs). Each is cached in
ServletContext as soon as it instantiates at startup time, with the exception of ModelManager. Since
ModelManager keeps a specific session's EJB registry for fast access, it is cached in
In a simple example, let's examine the characteristics of an Application Mediator pattern:
- It's designed as a
- All client inputs (
HttpRequests) go through the servlet's
- It creates or retrieves a ComponentManager JavaBean that loads and caches customized module information.
- It creates or retrieves a JSP Layout Manager JavaBean that gets the next screen, if required
- It creates or retrieves an Event Processor JavaBean that passes the requests. The processor will process all user requests to change application EJBs and other related functionality
- It creates or retrieves a ModelManager JavaBean that handles synchronization of different tiers and serves as a gateway of model retrieval from the Web tier.
- It creates or retrieves a LocaleManager JavaBean that determines the specific language locale for the request. Remember, 2-byte Java character encoding just provides internationalization and localization potential.
- It creates or retrieves a SecurityManager JavaBean that handles the security realm.
Figure 2 shows the Application Mediator pattern's UML diagram. A general reminder: all the managers should implement a serializable interface that can be replicated in a failover or cluster environment.
Pattern name: Component Manager
You need to design the Component Manager.
The Component Manager should not hardcode application-specific Java objects and EJBs; if it does, the E++ framework will not be directly reusable for any other applications. With this in mind, how do you decouple the Component Manager from the customized module information, and, at the same time, be able to use them?
The Component Manager must load application-specific information, such as an EJB URL, at runtime; it should not compromise application performance.
Use an XML file to describe your module information. The Component Manager has an XML parser to load the file at startup time; as it will be cached in
ServletContext for general use, you will not experience any performance degradation. This design allows E++ to work with any import module -- but not depend on them. Figure 3 shows the Component Manager pattern's UML diagram.
Pattern name: JSP Layout Manager
You like the layout managers found in the Java Foundation Classes (JFC), as they help assemble visual components together. Based on the JSP Page and Tag, you want to construct a JSP Layout Manager for your Web application to conduct similar tasks.
For a browser-based application, you do not have generic GUI components. How do you come up with a mechanism to consistently present your application layout?
Because an application's layout will change over time, it's not smart to quickly glue parts together on the fly. Rather, design the layout handling codes to be understandable, maintainable, and reusable.
The solution stems from the Template Method design pattern, which sets up an outline of a composition object, leaving details to a specific implementation. This approach proves particularly useful for separating the variant and the invariant context, thus minimizing the code size. Each page consists of four or more portions: banner, index, body, and footer. Of the four, in general, only the body changes page by page.
The variant is placed in the abstract class (template), allowing any subclasses that inherit it to override the abstract methods and implement the specifics needed in that context. (Many ways exist for you to implement this design concept. Indeed, you'll find a detailed JSP template implementation in Resources.)
Pattern name: Event
You need to design the Event Processor to handle incoming
HttpRequests to establish a generic request-control infrastructure.
For synchronized communication, in Java you can wire components through either general method invocations or events. How do you choose a discipline for the interactions so that the design and implementation will be structured, understood, and reused?
So far, there are two Java event models:
- The Java 1.0.2 event model, known as the inheritance model, allows an event to be handled only by the component that originated the event, or by one of the containers that contained the originating component. Many consider the inheritance model one of Java's early design flaws.
- The Java 1.1 delegation event model (extended in Java 2) follows a publish-and-subscribe metaphor; events are received by subscription only. If a component shows no interest in an event type, then events of that type will not be propagated to it.
The Java delegation event model is our solution here. This model not only allows users to connect and manipulate JavaBeans programmatically or visually using a bean builder; it also proves powerful for the sort of nonvisual object wiring that our case requires. Objects communicate with each other via event
notifier(Model Manager). The event notification is type safe, instance based, synchronous, and multicasting. Further, it is restricted to a single process. For every event generated from
HttpRequest, you define one corresponding
EventListener interface so that
Web Model JavaBeans can be associated with the listener by implementing the interface. The
Event notifier(Model Manager), an event service, notifies the listeners. The delegation model is ideal for large application design, since it provides flexibility and consistent coordination. The UML diagram of the Event pattern is shown in Figure 4, in which the
Pattern name: Web Model JavaBean
With Event as your basic processing infrastructure, you need to design your listener objects -- a Java Bean representing the application model at the Web tier.
Given the J2EE n-tier architecture's benefits, because any EJB call goes through the RMI protocol, performance could be an issue. If you use only JSPs or servlets without EJBs -- a so-called Web-centric application, in other words -- you have Web-tier JavaBeans encapsulating your business model. In a n-tier architecture, your real application models are EJBs instead, so any model change or update information has to be forwarded to the Web tier. So you need to design application model JavaBeans at the Web tier. If you do not have these peers, you have to access the EJBs whenever you need model information -- a performance overkill.
The Web Model JavaBean design must:
- Contain application model information
- Be updated following user inputs
As our solution, we turn to the Event pattern. Design these Web-tier JavaBeans to implement the same model interface as the EJB. Moreover, depending on your business logic, let these JavaBeans associate with one or more interested events by implementing their listeners. Each time EJBs are created or updated, the event
notifier(Model Manager) automatically updates the JavaBeans. That way you can directly retrieve model information from these JavaBeans. Figure 5 shows the UML diagram. (It is not necessary to have such a notification mechanism for a Web-centric application.)
Pattern name: Event Processor
You need to process incoming requests to change or update the application model based on the Event and Web Model JavaBean patterns, leading you into the Event Processor design.
The processor, in principle, merely changes related application models and updates their Web peers. With that in mind, how do you fine-grain the processor so that it will be more robust and reusable?
Because the Event Processor pattern proves crucial to the whole architecture's reusability, it must be designed in a generic fashion such that all individual functions easily plug in. On the other hand, it should carry
a so-called smart caching mechanism to improve performance -- rather important for n-tier distributed systems.
To forward requests to the EJB tier, you may process the users' requests to if-else statements. However, it's problematic to create an ever-increasing list of if-else statements to dispatch requests to individual handlers. As indicated in Part 1, one of the desired MREPLICS features is inversion of control, which allows the framework (rather than developers) to determine which set of application-specific methods to invoke in response to external events.
Whenever we speak of a generic processor, we usually mean the Command pattern, as is our case here. The Event Processor uses the Event pattern and Web-tier model JavaBeans as its processing foundation, while the Model Manager employs the Command pattern to serve the notification. Within the Event pattern, the whole event processing proceeds as follows:
- Generates Event based on the incoming
- Sends the Event to EJB Facade (detailed next) for EJB model processing
- Creates the Web Model JavaBean to mirror the EJB Model; it registers interested event listeners for update notification
- Uses the Model Manager object to perform the notification process while the manager executes command processing
You'll find the Event Processor's UML diagram in Figure 4. For information about the Model Manager or other patterns, please refer to Resources.
Pattern name: EJB Facade
According the Layered Architecture, you need an unified entry point to the EJB tier.
Since you have an EJB controller as single entry point for the EJB tier, is it really necessary to have this layer?
If you support a user-intensive J2EE production system, you may have encountered unrepeatable exceptions from the EJB tier. The problem could stem from concurrent access to EJBs. EJB 1.1 spec handles EJB concurrent access by asking EJBs to throw an
EJBException to their container when they are accessed concurrently. This might result in exceptions for legitimate access requests at user-intensive time.
As our solution, we turn to the EJB Facade pattern, shown in Figure 4. I've called it a facade because, as the unified interface to access the EJB tier, it performs an important synchronization task. Since each cross-tier EJB access-method is synchronized, it guarantees that the event-based control mechanism works well in any user-intensive and concurrent-access situation.
The EJB Facade also simplifies cluster deployment in a production environment, since it is the only linkage between the Web tier and the EJB tier. When you deploy the EJB tier on a machine other than the one on which the Web tier runs, you need to make minimal changes on the EJB Facade. Indeed, often you need to change only its JNDI lookup.
Pattern name: EJB Controller
At the EJB tier, you need a unique stateful object to act on a specific user's behavior to coordinate the user's application models.
What type of EJB should we use as an EJB controller?
There has been some debate as to whether or not we should keep application state information on the EJB tier. I believe, given an n-tier architecture, that it's not sufficient to keep a user's state exclusively on the Web tier. Indeed, placing a user's state on the EJB tier enhances application performance and EJB accessibility because a stateful session EJB's instance variables serve as an ideal means for nonpersistent caching.
With the EJB Controller, the EJB accepts all event handling tasks and provides model information to the client side or other EJBs. As a stateful session EJB, it represents the user on the EJB tier and manages the model EJBs' lifecycles. Although stateful EJBs prove expensive in performance terms, EJB Controller represents the classic case for when to employ them. Each EJB Controller possesses a State Machine object to delegate all processing commands. Moreover, it keeps an EJB registration so that clients can quickly access EJB models. When the session ends, it should invalidate all the cached objects by marking them for garbage collection. Keep in mind that vendors implement EJB containers differently in setting
EJBContex, a fact that may influence your EJB Controller. You'll find the EJB Controller's UML diagram in Figure 6.
Pattern name: State Machine
You need a pattern to change any or all application models in a generic, reusable fashion.
How do you change or update application state in a reusable way?
Given that the state machine is a generic state-processing object, you need to keep the machine from directly referring to application-specific components. With that in mind, the State Machine pattern takes client requests, then changes or updates the application models. Further, it keeps a state map to track down a user's specific application state. It typically manipulates the cached application states via help objects.
To process individual events, E++ employs the Command pattern. The machine keeps a model
HashMap to accommodate all possible model changes. The State Machine's UML diagram is shown in Figure 6. State Machine leverages the JNDI directory server to discover specific handlers, provided by application programmers. Moreover, it keeps a Handler
HashMap to achieve better performance by caching used handlers.
The State Machine keeps the machine instance in the EJB Controller. When the EJB Controller is being moved, the controller should, by assigning it to
null, make the State Machine eligible for garbage collection.
Pattern name: Scheduler
Under the REAI architecture pattern, your components need to start or schedule B2B tasks.
How do you design the B2B scheduler such that it provides a generic mechanism to start your B2B tasks, and implements specific handlers without changing codes?
You can start B2B tasks in two ways: directly initiated from B2C method invocations, or from a B2B scheduler. If the B2B-related query requires a realtime response and the B2B connectivity is efficient, go with the former approach. With that approach, the entire interactive process holds off while it awaits responses from the backends.
In most B2B integration cases it is not necessary or possible to have a realtime response. Keep in mind that holding backend connectivity for a response increases network traffic, possibly sparking user frustration.
As an alternate, more flexible solution, you can employ the Scheduler pattern to start your B2B tasks. As shown in Figure 7, the Scheduler instantiates with knowledge of the Dispatcher and RuleEngine patterns. The Scheduler, a Java thread, executes the B2B tasks. When running, it loads the available B2B Events into the B2BEvent
Each event possesses an associated
B2BTaskHandler to take information from the event. The handlers implement the
Runable interface to associate them with threads. They can also be executed independently from each other. To improve application performance, you should also prioritize each task.
If a task fails, the main thread and other tasks will execute continuously. One advantage over other solutions: with the Scheduler pattern, you can start B2B tasks systematically in a well-organized fashion, as well as decouple one task from another. I'm not suggesting that you bypass problems; rather, if a handler cannot fulfill its tasks, it should notify the B2B administrator by resetting the
B2Bevent task status. You can discover
B2BTaskHandler through JNDI lookup and cache it for further use.
As for application security, the client, which starts the scheduler, should first obtain authorization, implemented through either declarative or programmatic authorization. It is worthwhile to mention that you're starting a multithreaded process here; however, you're not creating a concurrent threads situation because of the thread scheduler's algorithm.
Pattern name: Integration Rule Engine
You want to automate your integration process and the integration business rule described in a text script, so that each
B2BTaskHandler can consult with the Integration Rule Engine about how to conduct the actual tasks, and nonprogrammers can modify the rules.
When and how do you use a rule engine to help develop a more flexible integration solution?
Although rule engines can be difficult to use, many frequently changing and sometimes poorly structured B2B tasks can benefit from a rule engine.Consider a billing module for the TSP company from
. Pricing for the call is based on combined rules derived from marketing concerns, local regulations, various subcarriers, and special arrangements with large customers -- all on top of the expected rules based on time-of-day, the call's physical distance, its duration, and whether it was a prepaid or postpaid.
You can pick from several options for embedding a rule engine in J2EE-based systems. JESS (Java Expert System Shell) allows rules to access any JavaBean's
set methods as simple property values (see Resources).
In E++, I suggest you load a rule engine with
RuleEngineController, which provides you with a
RuleEngine instance, rule parser, and fact-assert functionality. The
RuleEngine can be implemented as a stateless session EJB so that the container can handle any security issues. You define specific business rules in
clp script. Each
B2Bhandler uses one rule engine instance to fulfill its task. Therefore, you can define your working memory element (WME) to resolve conflict set (CS). The UML diagram is also shown in Figure 7.
Pattern name: Dispatcher
You want to design a remote service dispatcher so that
B2BTaskHandler can get services from it without being bound in any specific service implementation.
How do you design a dispatcher that dynamically loads or removes available remote services?
Even if the
RuleEngine want specific remote services, they shouldn't need to know the services' locations. In case of any service failure or network problem, you could change the services dynamically.
The Dispatcher component acts as an intermediate layer between
B2BTaskHandler and services. The Dispatcher implements a unique service name so the handlers can refer to services by a simple string name instead of their implementation details. The handlers rely on the Dispatcher to locate a particular service; the Dispatcher's registration maintains all the available services. As another benefit, Dispatcher provides methods so the administrator can add or remove services dynamically. One could think of having a daemon process running against the Dispatcher to update the list of available services.
The Dispatcher's UML diagram is shown in Figure 7.
Pattern name: XML DTD
According to your business requirements, to communicate with backend services you need to use an XML schema to define your messaging.
Should you define your own XML schema?
XML's real strength will become apparent as more industries agree on standard schemas. However, due to competition concerns, numerous companies continue to define proprietary XML schemas. Moreover, XML does not define how information content should be structured. As a result, you'll face difficulties when dealing with business integration.
Because DTD schema design requires effort, in an ideal world you could adopt a well-accepted schema as your own. (I've provided links to preconstructed e-commerce schemas in Resources.)
If you cannot find a predefined schema to fit your needs, you'll have to develop one yourself. In that case, consider these points:
- How do you represent information for integration? Take as an example an
order.xmlin the TSP case from Part 1. To me, designing a good XML DTD is similar to designing a Java object. An
order.xmlattribute acts just like a private attribute in an
Order.javaobject, such as
Order.javaobject contains several objects, such as credit card, billing address, order date -- these should be elements.
- In a serious integration application, XML transformation proves essential. As such, you shouldn't deal directly with any incoming XML responses from the backend systems. In that way, you carry your partner's specifications to your problem. You do want to transfer the schemas into your XML schema so your application handles only one DOM structure converted from the schema. As such, in case you need to integrate with new partners in the future, you won't have to change much. The Java API for XML Parsing (JAXP) 1.1 provides a standard way for an application to access any XML-conformant parser and XSLT-conformant processor.
Pattern name: Security
You understand that to secure your communications with your business partners, you must address security.
TCP connections are subject to eavesdropping, spoofing, masquerading, false packet insertion, and packet modification. What level of security do you need to build trusted relationship with your business partners?
Your potential integration partners will be either within the same large organization or over the Internet, so you must address all possible scenarios to secure the remote method invocations or messaging communication.
Recent cryptography technologies can make your Internet communication acceptably secure. You can choose from several well-accepted security standards:
IP security: The Internet Engineering Task Force's standard IP extensions provide security services at the IP level. IP security adds authentication, encryption, and data integrity services to the
IP layer. This new standard is based on Virtual Private Networks (VPN), primarily used to secure a large organization with multiple Internet sites. Within a large organization, a VPN could provide acceptable communication security, provided repudiation is not an issue.
- Secure Socket Layer (SSL): SSL has becomes a de facto standard to secure HTTP connections. SSL uses X.509 certificates for authentication. Based on your X.509 certificate and your communication servers' certificates, you resolve three of the four security requirements for Internet-based communications: confidentiality, integrity and authentication. (The fourth requirement is nonrepudiation, is addressed next.)
- Digital signatures: The last security issue is nonrepudiation. A digital signature resembles a hand signature -- it is undeniable evidence of a document's origin because only the entity who has the private key can create the signature bit. To digitally sign an XML document, one has to first calculate the hash value of the document, and then use, for example, the Java Cryptography Architecture (JCA) API to sign or verify it. Any change (except whitespace) to a signed XML document will invalidate the digital signature. However, digital signatures usually require extra steps to prepare the document. Remember, different XML processors may produce different surface strings for the same XML document because of, for example, differences in character encoding.
Pattern name: Remote Wrapper Facade
The dispatcher needs to register the related remote services, which have nonobject-oriented APIs.
How do you deal with a large number of nonobject-oriented applications?
You don't want nonobject-oriented applications to ripple through your carefully constructed distributed architecture, especially if that architecture must change and evolve over time.
You should avoid directly converting nonobject-oriented functionality. Instead, for each set of related functions and data, create one or more wrapper facade classes to encapsulate these functions in more concise, robust, and maintainable methods. Let the dispatcher register these wrapper facade classes. Examine the Remote Wrapper Facade's UML diagram in Figure 8.
Pattern name: Proxy Adapter
The dispatcher must register all the related remote services, which have object-oriented APIs.
It is inappropriate to register the remote services directly; you do not want to hardcode their physical locations and protocols. To the dispatcher, the remote services should be simple and transparent.
The remote access implementations should be runtime-efficient, cost-effective, and smart.
By leveraging your business domain knowledge and rule engine, your proxies can provide some intelligence to improve your application performance, load balancing, and cache information to improve access performance. In other words, you may put some business domain knowledge through
ruleEngineController to turn the Proxy Adapter into smart adapters. In general, it's here where developers can improve application performance or security.
Pattern name: Prototype and Reality Bridge
Your integrated business entities reside on remote computers. You need a strategy to connect them. You want to lower the integration surprise as much as possible.
How can you ensure a seamless evolution from prototype to real implementation?
When integrating remote business entities, you must ensure that:
- The distributed communication protocols are verified with real network traffic situations
- The integration time to real production systems is as short as possible
If you want to guarantee a seamless evolution from prototype to reality, you'll benefit from maintaining two coexisting implementations for any remote entity. Your prototype simulations provide required integration functionalities at the development phase without interrupting the existing operations, but provide you with real distributed communications. Any protocol or traffic-related nonacceptances should be resolved at this time with your prototype application. As for functionality, we need to leverage the Bridge pattern or common interface so that the swap will be easier.
Formula for success
I believe in the following formula:
a successful project = domain-specific business modules + a well-designed framework
A framework should be based on standard components; otherwise, your business-module development will be largely overwhelmed by learning adopted standard technology platforms as well as proprietary technology. The E++ framework moves us towards reusability, extensibility, portability, and customizability. Since the E++ framework is based on standard J2EE components, to integrate or leverage it you'll need only the J2EE developer guide. By leveraging design patterns and a rule engine, E++ builds an efficient, intelligent J2EE application framework. It improves an application's performance, network traffic, and object caching.
The major patterns presented here should serve as a starting point for your development efforts in E++. To reference all of E++ 1.0 beta's patterns, visit http://www.organizeknowledge.com.
Learn more about this topic
- "E++A pattern language for J2EE applications," Bin Yang (JavaWorld):
- More E++ information
- Read A Pattern Language, Christopher Alexander, Sara Ishikawa, and Murray Silverstein (Oxford University Press, 1977; ISBN 0195019199)
- The famous Gang of Four bookDesign Patterns, Eric Gamma, Richard Helm, Ralph Johnson, John Vlissides (Addison-Wesley, 1995; ISBN 0201633612)
- "Java 2 Platform, Enterprise Edition Blueprints" from java.sun.com -- many of the B2C design patterns are inspired or refined by the sample application
- Pattern-Oriented Software Architecture, Volumes 1 & 2, Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal (John Wiley & Sons, 1996; ISBN 0471958697) contains many interesting architecture and design patterns
- For more J2EE stories, visit the Server-Side Java section of JavaWorld's Topical Index
- One detailed JSP template design and implementation can be found here"JSP Templates," David Geary (JavaWorld, September 2000)
- JESS rule engine homepage