A Thinner/Slimmer Java
In my current project, there are several new solutions to some old patterns and there are also several new patterns, which were created to provide better performance and efficiency for the system. In this blog, I will attempt to provide you with information regarding each of the following patterns. Later blogs may include the details of why they were chosen, how they were put together, any problems that were encountered, and how those problems were solved.
First of all, most systems in the last few years have been built using an MVC pattern. Furthermore, those with foresight have also chosen to build hooks that can later be exposed as Web Services, building systems that lend themselves to Service-Oriented Architecture (or Integration). When building MVC based systems the current trend is to keep it light and provide the frontend implementation on a light-weight "Rendering" framework. As an action is received from the end-user (the browser), a series of steps must be completed in order to run full-spin to the backend services, retrieve data (perhaps based on some criteria) and return that data to the end-user (through the rendering framework).
In most cases, the development team chooses to implement heavy architectures (not because they want to, but because they feel that they have to...no other alternative exist...until now). The answer to simplifying the architecture is to use XML to describe what the application needs to do at runtime. The XML can later be used to modify the application, without having to cold-deploy the system. The following patterns were used, implemented, and connected to produce a framework that uses XML to accomplish a light-framework that packs a heavy punch.
1. The Business Delegate - implemented as a singleton object that receives the name of the "action" to be performed, along with the session and request object used to retrieve content from. The action tells the business delegate which XML object to retrieve. The XML objects tell the business delegate which data elements from the passed in objects to retrieve and where to retrieve them from. This object then fetches Transfer objects to stored and pass the needed content to the next layer, which could be a Session Facade or a POJO with the knowledge of processing requests and passing them to backend services.
2. The Session Facade - receives requests, breaks them apart and calls Business Objects. The biggest change to my implementation is that the objects are always retrieved using factories and the factories always use pools. The fascinating challenge is in hiding the setter methods from clients, while still making them available to factories. I solved this problem with an old hidden treasure that is seldom used and often overlooked. I'll save the details for the article.
3. The Business Object - processes a portion of a request, calls out to backend services utilizing data access objects or object stores and receives results. The results are collected as responses, collected together into a response collection (by the facade) and then returned to the business delegate.
4. Data Access Object utilizes more XML to determine how to call out to the database based on what's needed. The information is conveyed at runtime (not design time). Thus, all of the objects operate in a generate fashion, producing one object for each layer (rather than several for each layer).
5. There are several other objects including Pools, Factories, and Caches which help to provide for a very efficient and performance oriented system. One of the important patterns utilized in the pools for example is a pattern I like to call the Bus-Stop pattern. It is basically used to signal which objects have expired and need to be collected from the pool. I call it the bus-stop pattern cause the objects essentially jump onto a bus, which allows them to travel as long as their expiration hasn't expired. When the expiration is reached, the objects are thrown off the bus and then next set of passengers are collected. All objects currently on the bus have the same (or as close to) lifetime. This pattern is much more efficient than checking through a list of objects' expiration date each time a timer fires off.
6. Also heavily used was Service Locator. The major challenge here is in supporting both Local and Remote services and hiding the details of registration. In order to accomplish this, I used callbacks and other tricks to hide the details and provide an elegant solution that can be hooked in to other services as the need grows. Currently, my solution will work with JMS, DataSources, EJBs, and POJOs.
Again, what makes these patterns different than their usual implementation is the fact that they're implemented in a generic manner with XML describing the specifics. The specifics can then be changed and reread at runtime to change the system without having to stop, deploy, and restart the system. Utilizing other technologies such as JMX, the system can be controlled and instrumented at runtime.