| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This chapter has two goals. First, it explains the architecture of the library itself, and then it shows a few architectures in which the library can be used, ranging from simple applications to enterprise front-end applications.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following image is a general overview of the BeanKeeper framework:
As a caller, one can access the Store class, and it's methods (save(),remove(),find()).
If there are multiple datasources in an application, each can have it's own Store object, but usually there is only one
datasource (or database) in an application, so usually there is only one Store instance. All methods invokable
through this class are thread-safe, so a single instance is enough for the whole runtime (for a single data source).
It is possible to instantiate many instances of a Store class for the same datasource (same database), for example
in a load-balanced environment, or failover architectures (see diagrams below).
The TransactionTracker object can be accessed through the Store object. The tracker manages Transaction
objects, which themselves contain the Connection to the physical database. Transactions have the usual methods
for transaction demarcation, but also, they implement the Map interface. This is useful if you want to
add data to the transaction itself, for example the user who is manipulating data. If a locking exception
occurs, the exception will contain the Transaction which accesses the object currently, so by getting for
example the user object from the Transaction itself, you can create a meaningful message, or tell the other
user to hurry up with her work.
The LockTracker object is also published through the Store. This tracker can be used to
lock objects, so other threads or other nodes can not modify the object. The save() and remove()
operations of the Store all lock an object before it is processed, so if an object is locked by some
code, no operations can take place on that object except query.
There are a few internal modules which are not directly accessible:
Store, the Class Tracker determines whether
to create the appropriate table, or whether to alter an existing table.
The lowest layer of the library is the Database access layer itself. The task of this layer is to offer an abstraction over sql, to use by the above layers. All database manipulations are categorized into a few operations:
Before these abstract operations delegate the work to the appropriate, database specific implementation, some basic transformations take place. All table and attribute names are checked, that they do not exceed the maximum length supported by the database implementation, and that they do not match some database reserved word. If they do, they are abbreviated or renamed, and the new name will be noted, so all subsequent references to the specific identifier is always renamed the same way.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section describes some example architectures of different applications, and the library's place in them. Of course, you are free to create your own model, these are just the most common ones.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In this case, the most straightforward way to use the library is to let it persist the beans of your object/data model, and use those same beans (queried from the library, and saved by the library) on the user interface. Even if you employ a strict MVC (Model-View-Controller) model, the beans can traverse the whole stack without re-packaging and without affecting the separation.
The best way to guarantee, that only a single instance of the
Store will be used, you should use the singleton programming pattern.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is very similar to the standalone application case. The difference is, that the Controller and View roles are now replaced by different technology (Servlet/JSP, or other web framework). The usage is the same though, the preferred way is to use the simple beans to communicate between each layer. The persistence library does not care, if an object leaves or re-enters the controller layer, or if it returns at all. If an object is read from the database, that object is tracked throughout it's lifetime, regardless, whether it stays in the same transaction, or goes out to be rendered on a webpage. The same is true for result lists. Result lists can leave the transaction they were created in, or re-enter into a different transaction, it does not matter, so no special care needs to be taken when handling data received from or sent to the persistence library.
As before, the Store object should be a singleton though.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Most web applications do not handle their JDBC driver directly, but the web container (application server)
handles and pools connections for them, and it publishes a DataSource object through JNDI.
You can construct the Store object with a DataSource object, in which case the architecture
of the web application will be something like this:
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Commonly, webapplications are deployed on a cluster, or are load-balanced, using multiple application
servers, and a single database server (or a database server cluster, but with a single entry point).
In this case, there needs to be multiple Store objects instantiated in different JVMs to support this
architecture (one in each application server). BeanKeeper will in this case
automatically detect, that more than one Store objects (also called Nodes in this case) are connected
to the database, and will connect to these Nodes to coordinate the work.
| [ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Robert Brautigam on November, 21 2009 using texi2html 1.78.