[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