STORE - Overview
STORE's Tivano's Object-Relational Engine.
It also is Not Java 2 Enterprise Edition
(the original name was dropped for obvious reasons).
Instead it is a simple package that implements some
of the nice parts of J2EE while trying to avoid the overhead that comes
with a full J2EE implementation.
In the past we have completed a couple of projects where J2EE was used quite
heavily, e. g. with Bea's Weblogic Commerce
Server. We have made the experience that in those projects the cost of
employing J2EE often outweighed the benefits. Cost, in particular, means
- Tutoring time for the developers
- Due to the fast pace at which J2EE has been evolving during the last few
years, our developers have spent a lot of time on keeping their knowledge
up to date. Therefore in this case tutoring time is not a one-time
investment but a continuous cost factor.
- Development time
- If you try to do things in the right way (in terms of J2EE), things are
more complicated. E. g. you have to get a JNDI context which you use to
look up the home interface for a bean, which you use to get a bean
instance, which you can finally use to invoke the method you were looking
for. So in some cases a simple method call can explode into four, not
counting any required try/catch clauses.
- Administrative overhead
- This may not be a big factor. A J2EE compliant application server usually
has an administration interface that makes some tasks easier (like
defining data sources etc.). Sometimes things have to be done by hand,
though, like setting up message queues for message driven beans. Sometimes
you want to be able to preserve configuration information in a simple form
but the only way to access it is some GUI.
- Resource usage
- CPU utilization can be significantly higher when using J2EE, especially
when beans are accessed via RMI. Also, database lookups can be
significantly slower (which may be an implementation detail, of course -
but sometimes you can't do anything about it). That means you have to
put more money into faster hardware to achieve the same application speed
compared to an implementation without J2EE. (One might speculate about
SUN's motivation for introducing J2EE here... ;-)
Of course, there are benefits, too:
- Entity beans provide a very convenient way to abstract the functionality
of a database. This is especially true for entity beans with container
- J2EE-based applications scale - in theory. I haven't seen an application
that actually uses beans deployed on multiple machines. In theory you
can load-balance a J2EE application quite nicely by distributing it among
several machines. In practice, for the vast majority of web applications
at least, this is simply not necessary.
So, the goal of this project is to create a simple infrastructure that
provides some of the benefits mentioned above.
At the time of writing the most important benefit is that of abstraction from
the database layer. In other words, we want a simple replacement for entity
beans. We will call these "entity peas" (because obviously they aren't beans).
Peas are designed with the following constraints in mind:
- An instance of a pea class represents a part of a datastore's contents,
e. g. a row in a database table. Let P mean a part of that
- For any P at any given point in time there must not exist more
than one instance of any pea class within an application representing
- Only if P is constant, i. e. it cannot be modified by any part
of the application (including any peas), P may be part of the
data represented by more than one pea.
- Usually nothing outside the application is allowed to modify any part of
the data represented by a given pea. This is application dependent, of
course - if the data will be modified the pea's implementation must handle
- Inside an application the only methods allowed to modify the P
represented by a given pea instance are the member methods of that pea.
- If a pea's implementation allows modification of the data represented by
it, the implementation must make sure that the modifications are
propagated into the datastore in a convenient way.
- Any pea instance may be in use by more than one thread at any given time.
If you don't like this, use synchronized methods.
- Any pea instance may be garbage collected at any given time, unless one
of its methods is currently being executed by a thread.
- Every pea instance is uniquely identified by its class and a primary
key. The primary key must never be modified.
- For every pea class B there must be a primary key class
K. B must define an instance method getPrimaryKey() that
returns an instance of K representing the primary key of the
instance. Instances of K must not contain references to instances
of B. For any two instances k1, k2 of K
returned by calls to getPrimaryKey() on the same instance b of
B the following equalities must hold:
It is encouraged that k1 == k2, i. e. b may contain a
reference to its primary key. However, it is not allowed that
k1 == b.
- k1.hashCode() == k2.hashCode()
- k1.hashCode() == b.hashCode()
- k1.getCache() == k2.getCache()
Peas will automatically be cached using weak references. A simple utility will
emulate container-managed persistence by automatically creating a pea class
with simple getter, setter, finder and creation methods.
How to employ generated peas
This section suggests an approach how to generate and handle pea classes that
represent database contents (usually individual rows in a single table) via
JDBC. This may not be the perfect method in all cases.
Employing a database-related pea encloses three things:
- managing database connectivity
- pea classes managing database content
- your application managing and using pea classes
These points are reflected in the approach described below. The goal of this
approach is to handle step 2 automatically, i. e. to use a tool for automatic
generation of java classes that handle most of the database interaction. In
this way you can simply re-run the tool whenever the database layout changes.
Database connectivity is something that is usually the same for many different
pea classes. This is a good reason to keep that part separate from the actual
pea implementations. Also, since you usually want to use connection caching,
or e. g. easily configurable connections, this is something that can hardly
be generated automatically.
On the other side you have the view of the application itself on the peas. You
usually want to have a stable interface for that application, that changes as
little as possible when the database layout changes. This is the third part
of the approach. In simple cases this part is not important and need not be
reflected in your class structure.
The suggestion is to create a tree of classes looking like this:
- At the top you have de.tivano.store.peas.Pea, of course. Below that you
create a Connector class (or several classes) that define a static method
getConnection(String) - these will provide your Pea classes with the
required JDBC connections.
- Then, use the de.tivano.store.util.DBPeaGenerator or
de.tivano.store.util.ParseDia tools to generate pea
classes for your database tables. Use the -x option to make these classes
extend your Connectors.
- Finally (and optionally) create classes that extend the generated classes.
Add your own methods for finding peas in the database or for creating new
ones here. (You should use the -impl switch of DBPeaGenerator or ParseDia
to make sure the generated Pea classes create instances of your classes!)
You can also override some of the getter or setter methods, e. g. to put
additional constraints on the values.
If at some later time the database layout changes, you can execute step 2
again and receive an updated representation of the database, while your own
additions and modifications (in the form of your manually created subclasses)
An example where this approach has been used can be found among the unit tests
for the project. Check test/de/tivano/store/util/DBPeaGeneratorTest.java .
[ t]ivano software gmbh
Sun, Java, JDBC, JNDI and J2EE are registered trademarks of SUN Microsystems, Inc.
BEA and BEA Weblogic are registered trademarks of BEA Systems, Inc. All other
products and services are trademarks of their respective owners.