Arch4J: Open Source Model Framework for J2EE Applications
The purpose of this document is to briefly describe Arch4J. It doesn't go into a lot of detail, nor do we have an extensive user manual written yet. But if you are looking for a serious model-side pattern set and framework, we bet you can figure out the details pretty quickly by looking at the code. Good luck on your engagements. We hope that you find at least some of the ideas in Arch4J to be useful.
What is it?
Arch4J is to the Model in Model-View-Controller (MVC) as Struts is to the View-Controller. Arch4J is an open source Model framework that provides services and infrastructure to any type of J2EE client. Arch4J-based models can support Swing clients, console applications, other model logic, or web-based apps. In fact, we've wired into Struts to show the complete path from browser to model and back.
Arch4J adopts the notion of a business service. A business service is defined as an atomic, valid, transactional state change in the business, like adding a customer, placing an order, etc. No changes to the business state are allowed except through business service calls. Essentially extending the object-oriented notion of data hiding to the entire data state of the organization, Arch4J ensures that Model changes are hidden behind business method calls.
Arch4J specifies a business service pattern, but does not dictate the specifics of the implementation. A business service may run locally or remotely, determined at runtime. The service implementation's specifics are hidden from the consumer. Remote invocations may be through EJBs or some other mechanism.
If EJBs are selected as a remote implementation mechanism, Arch4J provides a pattern that maximizes EJB performance without building EJB-dependence into your application. Arch4J even comes with a code generator to assist in applying the pattern to your project.
Arch4J provides standard, stable facades to required, non-application- specific facilities such as logging, property file management, exception handling, data access, messaging and more. Behind these interfaces, designers may implement specific solutions (such as Log4J) without impacting the application code. This has the added benefit of protecting application logic from evolving specifications. Wiring in a specific implementation is straightforward: look at our Adapters in the org.arch4j.providers packages for examples on how you can wire in your favorite implementations.
What Does Arch4J cover?
Many Arch4J pieces are standalone, so you can cherry pick the parts you need. You can select from the following menu:
For web-app clients we wired into Struts, and you are welcome to do the same, or wire in your own view/controller solution. Use our Struts adapter as an example. We've also used Arch4J with Swing-based clients by accessing the Model through service factories in Swing code.
Our long-term objective is to have a solid controller class that ensures valid state changes automatically and acts as a buffer between the view and the model. This controller should not care about specific view implementations, such as Web vs. Swing.
Data objects are business-relevant data objects, like entity beans, with one serious difference: entity beans can't be sent to the client. Data objects can be. Data objects can also be nested, representing large, complex entities. They can be (at your option) initialized lazily to address performance. Through use of Data Domains (see below) they provide consistent field validation from the Model all the way into the View and back.
Copy and paste JDBC no more: prone to connection leaks, JDBC code should reside in only one place in your application. Consider yourself warned. We separate SQL from the code. This layer can be used to support a sophisticated persistence layer of your own making, or provide the makings of a simple persistence model for more straightforward applications. Or, if you are buying a persistence capability, you can use this to create fast read-only capabilities, or ditch it altogether.
Field validation is needed on the client and in the model. Don't duplicate; reuse code in data domains by defining business object attributes as data domains. Since these travel within the data object from the model to the view, the validation rules are always available and applied consistently whenever the mutator methods are called, whether inside the servlet VM or the EJB container or somewhere else.
Stateful v. stateless session beans. Entity beans. Message beans. Now there are local and remote interfaces. We've got a scaleable solution that works well, is clean, and, to bait an argument, doesn't get sucked into the entity bean trap. See below for more details. But in a nutshell - code your business logic in an implementation-independent way, and use factories to provide access to the implementation via an interface. That way, you aren't wedded to a particular deployment option (RMI, EJB, CORBA, etc.)
Adapters provide vendor independence for logging, JMS implementations, and even the EJB container itself. We use adapters around all key services that shield the development team from implementation specifics, thereby providing stability and protection from API changes in the underlying implementations.
Logging, file parsing, property/XML file manipulation, and code generation.
Target Coverage and Progress To Date
Arch4J was driven by a simple goal: confine each design decision to a single place in the code for very high levels of reuse, vendor independence and deployment flexibility. This also results in a lot of layers, as you can see. It is important not to be deterred from this goal by the number of classes that result. The fact is, each class is a highly focused and fairly small piece of code that is easy to maintain and easy to reuse. Each piece of code has a particular role to play. Focused roles = high reuse.
Business Service Model
Business services are methods through which an application can change the state of the business' enterprise information systems. These services are accessed via a factory, so that implementation specifics are hidden from the client application.
Arch4J presumes these services can be transactional, and are stateless. The need for transactions should be clear; the adoption of stateless services may seem to some to be counter to the trend in J2EE. We leave the detailed defense of this position to another forum; it has been our experience that scalability and development ease are supported best by stateless services. We eschew the use of entity beans because:
Assume a stateless model; write an interface that expresses the methods of the service. Write the implementation in a Java class that implements the interface. Create a service factory that returns implementation class as the service interface. When the logic is debugged, create the EJB wrappers: the Home, the Remote (which only has to extend the Service Interface in addition to EJBObject), and the Bean, that wraps the Implementation class. To help with all this trivial code, use the code generator to deliver flexibility, ease of testing and scalability.