You are viewing a plain text version of this content. The canonical link for it is here.
Posted to torque-dev@db.apache.org by Alan Hodgkinson <al...@softxs.ch> on 2003/01/10 11:28:53 UTC
Suggestion: A change to Torque (populate & XML)
<cocoon-user-note>
To Cocoon users: Sorry for the off-topic post.
This is just a heads up to let you know what _may_
be coming and to solicit your lobbying efforts for
the Torque changes I am proposing below.
</cocoon-user-note>
Dear All,
I'd like to have some new functionality in Torque. My
ultimate goal is to implement the enhancements necessary
to make Torque a useful component when developing with
Cocoon.
<disclaimer>
I'm not hung up in implementing the changes exactly
as suggested here. I've written the following mainly
to clarify my ideas and solicit better suggestions
from those who know more. That said, I've tried to
keep things simple by separating my requirements from
the solution and suggesting a 'small-footprint' change
that I can quickly get up and running.
I just want a solution for my requirements and I'm
willing to write and test the code and DOCUMENT
whatever we collectively decide to do. But, barring
other suggestions, my analysis thus far shows that
I do require changes to Torque (and I'm not a Torque
commiter).
On the non-technical side, I'd like the community,
particularly the Cocoon users (who will get a new tool
for their toolbox), to share the benefits. After all,
the Torque-ers have already helped me.
</disclaimer>
1. REQUIREMENTS
===============
1.1 Populate Torque objects, e.g. objects which extend
BaseObject, automatically from a Map or Hashtable.
E.g.:
// users is an instance of a Users Torque object
// generated by Torque.
users.populate( myHashFromMyCgiInput );
if ( user.isValid() ) { // isValid is business logic
users.save();
} else {
throw new BadUserInputException(); // or whatever..
}
Ideally the populate() method would accept String
representations of fields and convert them to the
appropriate native types (as well as accepting native
types).
1.2 Allow Torque objects to emit SAX events to a
Content handler.
Note: most Cocoon processing is done via SAX events.
// myContentHandler is a Cocoon transformer that
// ultimately transforms it's input into fancy
// HTML suitable for web browser presentation.
// It has been opened and a document has already
// been started
myUser1.toXml( myContentHandler );
myUser2.toXml( myContentHandler );
myCompany1.toXml( myContentHandler );
// ..etc.. until done.. then close the document.
The toXml() method merely emits the tags and content
associated with to it's database record. E.g. the
table name '<user>' and the contained fields,
'<Userid>1</Userid><Username>joe</Username>' etc..
Note: If you accept this, then you'll get XML as
Strings more or less for free. (And you'll get free
Steak Knives too.. :)
2.0 POSSIBLE SOLUTION
=====================
<another-disclaimer>
Read the first disclaimer again: I'm open to other,
better solutions.
</another-disclaimer>
2.1 Populate()
With a bit of Java (and personal :) introspection and some
helpful suggestions from the list members, I feel I can
implement the populate method. The tricky part will be
getting all the type conversion working.
This task would be made MUCH easier if there were a
method getFieldNames(), that returns null (or throws an
exception) in BaseObject. It would be over-ridden by all
the Torque generated classes).
This would allow applications to use Torque objects in a
generic way. They could simply iterate over all the fields,
using BaseObject's (overridden) getByName method.
2.2 Sax events
Given the getFieldNames method in BaseObject, it becomes
a trivial exercise to implement the SAX event generation
directly in BaseObject. It is would also be trivial to
implement a toXml method, that returned the XML as a
String. (..and you'd get free Steak Knives too. :)
The only problem is to get the table name (for placing in
the top-level XML tag). The easiest solution would be to
add a null (or exception-throwing) method getTableName to
BaseObject, which would be overridden by the generated
Torque objects.
Note: since I pan to use Cocoon, I have no need of filtering
or forcing the XML to conform to any particular layout.
Cocoon allows me to easily use XSLT to perform any required
transformation(s).
3.0 SUMMARY OF CHANGES
======================
3.1 Add to BaseObject.java:
public List getFieldNames() { return null; }
public String getTableName() { return null; }
They could alternatively throw a 'not implemented'
exception the way getByName currently does.
void populate( Map or Hashtable ) { ... }
void toXml( ContentHandler ) { ... }
String toXml( ) { ... }
or toXml( Writer ) { ... }
I'll supply tested code with Javadoc for these methods.
3.2 Add to Object.vm:
public String getTableName() { return "$table.Name"; }
I'll need to test to ensure that the Torque/velocity variable
name is correct.
3.3 Collect the free Steak Knives :)
Sorry, but we're all out of Steak Knives :(.
..but I will write a few paragraphs of documentation for
the Torque web site and some Cocoon Wiki documentation when
I get this working with Cocoon. (That's BETTER than steak
knives, right? :)
4.0 AN APPEAL
=============
4.1 Is there a Torque committer willing to 'sponsor me'?
No, not to sponsor me to become a commiter, just to commit
the changes.
4.2 I'll supply the changes in whatever format is easiest.
Best wishes and thanks in advance (especially for reading
this far),
Alan.
P.S.
<thanks>
Nothing happens in a vacuum: Others have helped. In particular:
Michael Bain - For sharing your introspection based solution.
Gareth Boden - For sharing your Betwixt based solution and
giving me a bunch of insights.
Without your efforts, I would have been stuck. Thanks guys!
</thanks>
Re: Suggestion: A change to Torque (populate & XML)
Posted by Stephen Haberman <st...@beachead.com>.
On Mon, Jan 13, 2003 at 10:19:39AM +0000, Alan Hodgkinson wrote:
>
> > {Use] ..Intake.. [for populating your objects].
>
> Thanks. I hadn't seen that. Exactly how 'fragile' is it?
It is great once you have it set up (e.g. the XML file with the
rules you want and what not), but getting it that initial
point where everything clicks and works can be tedious. I had
problems with it anyway, and there have been several other people
posting with the same general problems, e.g. minor configuration
errors they couldn't debug, but once pointed out, it worked as
advertised.
- Stephen
Re: Suggestion: A change to Torque (populate & XML)
Posted by Gareth Boden <ga...@egsgroup.com>.
>> You can get field names by doing:
>> Torque.getDatabaseMap().getTable(XxxPeer.TABLE_NAME);
> <snip/>
>> ..if you just have Xxx, you can do Xxx.getPeer().TABLE_NAME.
>
> I just have Xxx, which in my case, is of type BaseObject.
> Unfortunately, BaseObject doesn't define a stub for getPeer, so
> my code won't even complile. Note that I use BaseObject
> because I need my code to be generic and can't be coding for
> a particular database table.
Simple reflection can sort that, something along the lines of (without
having the exact method names to hand) :
Method getPeer = Xxx.getClass().getMethod("getPeer", new Class[0]);
Object peer = getPeer.invoke(Xxx);
Field tableNameField = peer.getClass().getField("TABLE_NAME");
Object tableName = tableNameField.getValue();
However, I believe I'm right in thinking that the DatabaseMap does not
concern itself with the method names on the data objects - so although
you can find all the column names for a table, you still can't find
their values on an arbitrary object in order to turn it to XML. I could
be wrong... but if I'm not, something new still has to go into the
generated code.
G.
Re: Suggestion: A change to Torque (populate & XML)
Posted by Gareth Boden <ga...@egsgroup.com>.
>> You can get field names by doing:
>> Torque.getDatabaseMap().getTable(XxxPeer.TABLE_NAME);
> <snip/>
>> ..if you just have Xxx, you can do Xxx.getPeer().TABLE_NAME.
>
> I just have Xxx, which in my case, is of type BaseObject.
> Unfortunately, BaseObject doesn't define a stub for getPeer, so
> my code won't even complile. Note that I use BaseObject
> because I need my code to be generic and can't be coding for
> a particular database table.
Simple reflection can sort that, something along the lines of (without
having the exact method names to hand) :
Method getPeer = Xxx.getClass().getMethod("getPeer", new Class[0]);
Object peer = getPeer.invoke(Xxx);
Field tableNameField = peer.getClass().getField("TABLE_NAME");
Object tableName = tableNameField.getValue();
However, I believe I'm right in thinking that the DatabaseMap does not
concern itself with the method names on the data objects - so although
you can find all the column names for a table, you still can't find
their values on an arbitrary object in order to turn it to XML. I could
be wrong... but if I'm not, something new still has to go into the
generated code.
G.
Re: Suggestion: A change to Torque (populate & XML)
Posted by Alan Hodgkinson <al...@softxs.ch>.
Dear Stephen,
Thanks for your tips regarding the accessing of table and field
names. You suggestions were helpful and almost works in my case.
> {Use] ..Intake.. [for populating your objects].
Thanks. I hadn't seen that. Exactly how 'fragile' is it?
> You can get field names by doing:
> Torque.getDatabaseMap().getTable(XxxPeer.TABLE_NAME);
<snip/>
> ..if you just have Xxx, you can do Xxx.getPeer().TABLE_NAME.
I just have Xxx, which in my case, is of type BaseObject.
Unfortunately, BaseObject doesn't define a stub for getPeer, so
my code won't even complile. Note that I use BaseObject
because I need my code to be generic and can't be coding for
a particular database table.
Failing some other better idea, could we add a 'not-implemented
exception throwing' stub for getPeer to BaseObject.java?
[I can't help feeling that I'm going run into other problems
caused by BaseObject not defining a 'non-implemented' stub for
the methods that are generated in the XxxBase objects. ]
> As far as the toXml method, I'd rather not see the code go into
> Torque, especially the generation templates, as Torque is complex
> enough as it is.
Your choice. I'll work up a separate class, most likely using
some of your and the others suggestions (BeanUtils, Castor, etc.)
That aside, and having looked at the code, I am pleasently surprised
to see how simple it really is. This is not to take anything away
from Torque, just merely to say that the code seems reasonably
well organized and easy to read.
BEst wishes,
Alan.
P.S. The entire diff to implement the table name method and the
field name list is only:
Object.vm:
851c851
< public synchronized List getFieldNames()
---
> public static synchronized List getFieldNames()
1492,1501d1491
< }
<
< /**
< * Get the database table name associate with this
< * class: E.g.: $table.Name
< * @return the database table name.
< */
< public String getTableName()
< {
< return "$table.Name";
BaseObject.java
61d60
< import java.util.List;
339,385d336
< }
<
< /**
< * Retrieves a list of the field names from the object.
< * Must be overridden if called.
< * BaseObject's implementation will throw an Error.
< *
< * @return list of field names.
< *
< */
< public synchronized List getFieldNames() {
< throw new Error("BaseObject.getFieldNames: " +
NOT_IMPLEMENTED);
< }
<
< /**
< * Retrieves the object's database table.
< * Must be overridden if called.
< * BaseObject's implementation will throw an Error.
< *
< * @return list of field names.
< *
< */
< public String getTableName()
< { // We'd like this to be static, but then it cannot be
overridden.
< throw new Error("BaseObject.getTableName: " +
NOT_IMPLEMENTED);
< }
--end--
Re: Suggestion: A change to Torque (populate & XML)
Posted by Stephen Haberman <st...@beachead.com>.
On Fri, Jan 10, 2003 at 07:13:23PM +0200, Andreou Andreas wrote:
> How about letting an external tool handle the object->XML conversion
> (i.e. castor) ???
> We could then just have torque generate the Mapping File for the BaseXXX
> classes ...
I don't know much about Castor, but it sounds like a good solution.
- Stephen
Re: Suggestion: A change to Torque (populate & XML)
Posted by Andreou Andreas <an...@di.uoa.gr>.
How about letting an external tool handle the object->XML conversion
(i.e. castor) ???
We could then just have torque generate the Mapping File for the BaseXXX
classes ...
Re: Suggestion: A change to Torque (populate & XML)
Posted by Stephen Haberman <st...@beachead.com>.
On Fri, Jan 10, 2003 at 10:28:53AM +0000, Alan Hodgkinson wrote:
> 1.1 Populate Torque objects, e.g. objects which extend
> BaseObject, automatically from a Map or Hashtable.
We've already got a way to do this, plus it does validation and is
pretty darn spiff (though a bit fragile). Intake lives in both
Fulcrum (the fragile version I'm familiar with) and also in
Turbine-2 (with a recently refactored version by...Quinton, if I
remember right, that hopefully is a lot better than what is in
Fulcrum).
See:
http://jakarta.apache.org/turbine/fulcrum/howto/intake-service.html
> 1.2 Allow Torque objects to emit SAX events to a
> Content handler.
<snip/>
> This task would be made MUCH easier if there were a
> method getFieldNames(), that returns null (or throws an
> exception) in BaseObject. It would be over-ridden by all
> the Torque generated classes).
You can get field names by doing:
Torque.getDatabaseMap().getTable(XxxPeer.TABLE_NAME);
With the TableMap, you can get all of the columns and what not as
you were wanting to. (Although the
DatabaseMap/TableMap/ColumnMap...might only be available at runtime,
not compile/generation time, which might not be what you wanted).
> 2.2 Sax events
>
> Given the getFieldNames method in BaseObject, it becomes
> a trivial exercise to implement the SAX event generation
> directly in BaseObject. It is would also be trivial to
> implement a toXml method, that returned the XML as a
> String. (..and you'd get free Steak Knives too. :)
>
> The only problem is to get the table name (for placing in
> the top-level XML tag). The easiest solution would be to
> add a null (or exception-throwing) method getTableName to
> BaseObject, which would be overridden by the generated
> Torque objects.
Again, XxxPeer.TABLE_NAME should work. Also, if you just have Xxx,
you can do Xxx.getPeer().TABLE_NAME.
As far as the toXml method, I'd rather not see the code go into
Torque, especially the generation templates, as Torque is complex
enough as it is.
Unless you do something like XmlConverter which as a static
toXml(BaseObject obj) method to which uses the runtime-available
XxxMap stuff to spit out XML, either was a String or events or what
not, we could drop it in a util directory.
- Stephen