[Opensource] dbobject.getTargetTable() deprecation [REALLY
LONG WINDED :)]
Michael Rimov
rimovm at centercomp.com
Sun Jul 27 03:39:17 PDT 2003
At 03:48 PM 7/25/2003 -0700, you wrote:
>Okay, thanks for the clarification.
>
>so DBObject subclasses JDBCDataObject, and thereby has the inherited method
>
> public final JDBCObjectMetaData getJDBCMetaData() {
> return (JDBCObjectMetaData)getMetaData();
> }
>
>Will this break for DBobjects which are not using JDBC?
DBObjects that aren't using JDBC will only implement DataObject and not
JDBCDataObject. So at that point, getTargetTable() will be unavailable
since it wouldn't necessarily make sense.
Let me clarify why I keep saying this :) Time for a Expresso 5.1
development history lesson:
There's much need for DBObjects to be able to expand to beyond the straight
JDBC realm. An example is hooking into IBMs MessageQueue system. Entity
EJBs would be another. But I won't continue beating a dead horse on
whether we need it or not.
So the obvious thing was that we needed an Interface to define DBObjects
and use implementation of interfaces to allow for interaction with the
various sources. But what to include?? I must have sat down on what to
include in this interface maybe 10 times. But I kept hitting a
wall: DBObject has, at my last count, about 125 Methods(!!) Talk about
superclass anti-pattern!! That sure didn't allow me to easily figure out
what was important. [I should add that I was not the first developer to
attempt an interface extraction, but previous attempts had all failed. ]
So a couple of months ago, an idea hit me and I took a different tact. I
reimplemented DBMaint and it's classes to accept DataObjects instead of
DBObjects. I figured that since DBMaint allows you to do basically what
any 'outside' client of DBObjects would want to do in a generic way, this
would give me a good idea of what was important for the Interface. My goal
was to provide a series of functions that would still give me the same
functionality as before, even if it was called slightly differently.
That was the primary effort that bore the current DataObject API as you see
today.
The second step to test the API was to create a new type of DataObject that
DBMaint could use. So I created the class:
com.jcorporate.expresso.core.dataobjects.jdbc.JoinedDataObject
This was a rewrite of MultiDBObject that was XML configurable and more
importantly, implemented the DataObject API in such a way that you could
see database joins through the DataObject right smack dab in DBMaint.
Although it wasn't a trivial task, it took me about 2 weeks working 1/2
days on it; the API basically stood as-is. I added a couple of more
'optional' interfaces such as Securable and Defineable that took care of
some specific issues such as how do you differentiate classes that are
defined differently through XML config files, but have the exact same
classname. It was here that I believe that the API had some legs to stand on.
So why am I telling all you guys (and gals!) this? Well I found out something:
- There seem to be two different 'views' to DBObject programming: (a)
Programming from within DBObjects [such as overriding add(), etc] and (b)
From 'outside' the DBObject, ie calling DBObject.add() from your controller.
The net result is that from 'outside'... I NEVER call getTargetTable(). On
the inside? I do it all the time. So by and large, the 'outside'
controller could give a rip whether the DataObject is JDBC based or not. [I
say, by and large] However, there are times when I have VERY JDBC specific
needs. So what do I do? I have in my parameters JDBCDataObject instead of
DataObject! Plain and simple. It may limit my options for non-JDBC
environments for the classes that use this, BUT the point is that if I'm
dropping to lower level JDBC-style objects, then I probably have a good
reason for it, and want to exploit a JDBC specific feature.
For example, JoinedDataObject HARDLY makes sense for anything outside of
the JDBC realm. So I feel free on its inner code to pass JDBCDataObjects
to and fro. But that's on the inside and it still doesn't break the
DataObject API contract, and thus DBMaint can still use it!
>Anyway, this is exactly the kind of convenience that I'm looking
>for. could we redefine getTargetTable() as
>
> public String getTargetTable()
> throws DBException {
> return getJDBCMetaData().getTargetTable();
> }
Sure... at this point, getDef and getJDBCMetaData() are essentially
synonyms with getDef eventually being removed. Of course I still want
DBObject.getTargetTable() as deprecated.
>Whatever protection is necessary to allow getJDBCMetaData() to be
>accessible from any DBobject could be reused for getTargetTable(),
>no? shall we introduce some NotImplemented exception, testing with instanceof?
Again, usually only the DataObject _implementation_ would ever need
getTargetTable() except for a few super minor cases. The way I see getting
the 80% case is to deal with JDBCDataObjects in your parameters where you
NEED it, use DataObject where you don't. You'll start finding entire
subsystems that don't NEED it and thus we slowly ween ourselves away from
API bloat.
After all, the DataObject API is going to ALWAYS be a case of sometimes
dealing with the base interface, sometimes dealing with lower level
implementations. It wouldn't be, as Raul so kindly put it, "lightening
fast", if we tried to apply the same API for all types of data sources. We
would loose power. After all, JDBC folks still want to specify "distinct
rows" and "custom where clauses" in their queries. Part of Expresso's power
and usability is the ability to drop down to lower level stuff when you
need it, use the higher abstractions when they work better.
So even in a full fledged API. DataObject will be the least common
denominator, JDBCDataObject will have JDBC-specific additions,
EJBDataObject will have Entity Bean-specific additions, and CSVDataObject
will have Flat File specific additions. If we tried to move all the 'cool
functions' to the base class, we suddenly have bloat in DataObject and it
becomes nearly impossible to implement a class based upon DataObject. So
that's why I don't believe getTargetTable() should be moved up to
DataObjectMetaData, I think it does very well in JDBCObjectMetaData, and I
provide the convenience for those that are working in the JDBC realm.
Make sense?
I'd also like to add something to those folks that have been astutely
watching (or even might not be! :) ) may have been wondering about. There
have been a LARGE number of functions @deprecated [I think about 30 at this
point in time]. If you look at the functions that were marked deprecated,
you'll see that by and large the implementation was something like:
getDef().getDescription(); or something like that.
Since the DataObject API provides a 'Metadata' interface, the underlying
class that represented all the metadata about the DBObject now exposes that
interface publicly. [Man, what kind of a list are we talking about public
exposure and all! :) .....(Hey, it's late! If you don't like the jokes
just skip 'em! ;) ) ]
So now you have to use: DataObject.getMetaData().getDescription() instead
of DBObject.getDescription(). Now that may sound like a typing pain in the
rear, but there's something specific I want to point out.
Remember the old implementation of DBObject.getDescription()? It called a
function called getDef(). Now that function performed a concurrent reader
HashMap lookup. Now hashmap lookups may be fast.... BUT! I've seen enough
abuse of things like getTargetTable() and getDescription(), that the
hashmap read to get the metadata is now showing up on the "profiling
radar", taking, perhaps 3-5% CPU time in the requests.
Now 3-5% CPU time may not be much. But if instead of just calling
getDescription() and getThis and getThat whenever you needed it you did:
JDBCObjectMetaData metaData = myObj.getJdbcMetaData();
metaData.getDescription();
metaData.getThis();
metaData.getThat();
.....
You've just saved yourself 2 synchronizing hashmap lookups! Now, this is
contrived, but I find many areas where the number of hashmap lookups was
much more serious than 2. And using this method is a quick and EASY way to
get the hashmap lookup to drop off the CPU chart once again.
[The good news is that Expresso is getting optimized enough in many areas
where multiple hashmap lookups ARE showing up on the radar now! I'm
getting happy ;)]
So there you have it, probably more about Expresso DataObjects than you
ever wanted to know. :) (Sure wish I had an editor to take these long
winded posts I do and put it into the doc set! <grin>) So I guess the next
question is, does this answer your concerns or should I write another 10 MB
post :)
-Mike
More information about the Opensource
mailing list