Skip to main content

JGoodies Binding Framework

78 replies [Last post]
scottr
Offline
Joined: 2004-09-05

Hi Guys,

Have you seen this project https://binding.dev.java.net/ also underway on JavaDesktop? It seems to overlap a lot of what JDNC covers, at least as far as the binding part goes.

It would be nice if this stuff could make it into JDNC, rather than having so many different incompatible projects trying to achieve the same purpose.

Scott

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Kleopatra

Amy Fowler wrote:

+1! Looks like we tend to agree more often than not :-)

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rbair
Offline
Joined: 2003-07-08

Hey Patrick,

> I agree with the equals() method...although we might
> have a
> key()implementation which returns a Key() which can
> have overridden
> equals() for special cases, just another option.

Following this line of thought, another approach would be to have a method in the DataModel interface for comparing one record with another. For example, it could be called 'compareRecords(int index, DataModel dm, int otherIndex)' or something. The default implementation in the AbstractDataModel would be to use the 'keyFields' in the MetaData to figure out how to equate the two different records. In addition, somebody could easily override this method in a child class and perform their own 'equals' operation.

> I believe that in strict relational work, queries are
> used to identify
> sets, so duplicates should in principle not "be
> allowed". If the
> developer allows duplicates in their results, then
> they have other
> problems we can't help them with.

I agree. This brings up a really good question -- how far should the API go? We need to strike a balance. The easy stuff should stay easy and the hard stuff should be made as easy as possible. Trying to solve some of the rare/impossible stuff would only complicate the API, IMHO. It might be a good idea to document what some of these rare/impossible situations are. Just something to keep in mind as we go.

> What I like about a key() method is that it lets us
> move towards a
> DataModel/RowSet for which we can construct a SQL
> output for
> auto-generation of insert/update/delete operations
> back to the database.

I agree completely that the auto-generation of insert/update/delete operations is important, IMO, because they are *almost* always simple queries like 'delete from blah where pk = ?'. Of course, the programmer should be able to override these default queries with a custom one.

However, I'm not sure if a key() method or even the 'keyFields' property would be much benefit because the RowSetMetaData already has a 'keyFields' type property and should therefore have enough information to autogenerate the insert/update/delete queries.

Rich

Kleopatra

Hi Richard,

jdnc-interest@javadesktop.org wrote:
>
> Another thing to consider when designing this binding architecture: currently a single component can only be bound to a single field, or as altered in my incubator code a single component could be bound to an entire DataModel.

Now even I got your example running (thanks for polishing :-) - and at
last I understand why you wanted a getValue(String, int)! Interesting,
your approach to bind a complete DataModel. Though I'm a bit weary with
it (seems like my stomach rarely stops grumbling ).

A minor issue is that a form cannot bind automatically to that
DataModel: the type of component is chosen by metaData or elementClass
and then the binding by type of component. Hmm, maybe we could come out
of this by a new type of MetaData...

A slightly less minor (read major :-) issue is that it tends to smear
the responsibility for "adapting". Currently the responsibilities in the
chain from converting domain type into something swallowable by a
component are fairly well defined and bounded (at least as I read the
code, not so much doc around ): the DataModel adapts whatever is
thrown in into something accessible uniformly by fieldName. A Binding
takes that value and converts it to any type/format expected by the
component. The formal route to do so is to use the converter. Hmm, now I
have to start thinking about clarifying the difference between
"adapting" and "converting" ... will let you know the outcome :-)

> But what about a single component being bound to many fields, but not necessarily all?
>
> A second approach could be to have a new AbstractBinding constructor take a List or Array of fieldNames and register with each of them. The push/pull semantics might have to change in order to handle multiple fields, but then a custom LabelBinding would be able to set the text of the label just like all other bindings do. This seems the better approach to me, but that's just me :)
>

yet another approach could be to let a DataModel handle it :-) Let it
listen to an arbitrary number of properties of an input dataModel,
transform them into a new value and output the latter (for the sake of
the binding). Just a thought, though, did not do it.

Okay, 'nough fun for now

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rbair
Offline
Joined: 2003-07-08

Hey Jeanette,

> A minor issue is that a form cannot bind
> automatically to that
> DataModel: the type of component is chosen by
> metaData or elementClass
> and then the binding by type of component. Hmm, maybe
> we could come out
> of this by a new type of MetaData...
>
> A slightly less minor (read major :-) issue is that
> it tends to smear
> the responsibility for "adapting". Currently the
> responsibilities in the
> chain from converting domain type into something
> swallowable by a
> component are fairly well defined and bounded (at
> least as I read the
> code, not so much doc around ): the DataModel
> adapts whatever is
> thrown in into something accessible uniformly by
> fieldName. A Binding
> takes that value and converts it to any type/format
> expected by the
> component. The formal route to do so is to use the
> converter. Hmm, now I
> have to start thinking about clarifying the
> difference between
> "adapting" and "converting" ... will let you know the
> outcome :-)

Ya, I have to be honest, I've been totally ignoring the Form binding situation so far. I guess I've been somewhat skeptical of how far form binding can take us. I've never used a 4GL language (VB doesn't count, right?) or any kind of form binding architecture before, so I've been focusing on the DataModel architecture and binding by hand because that's what I'm familiar with.

From what I've seen I'd tend to think that Form binding will be great for generating simple layouts (like the detail panel in my demo), but the developer might have to manually set up the more complicated things such as "navigational" components like the JList in the demo. At some point it may become easier to say "add a bound JList to the JTitledPanel and put it in a split pane" than to try to describe the same behavior in MetaData. Especially with a good GUI builder helping with the layout.

> yet another approach could be to let a DataModel
> handle it :-) Let it
> listen to an arbitrary number of properties of an
> input dataModel,
> transform them into a new value and output the latter
> (for the sake of
> the binding). Just a thought, though, did not do it.

This is a really interesting idea. It moves the complexity out of the Binding and into the DataModel. It would have to be a special kind of DataModel (WrappingDataModel, or something). We'd still need some kind of language for describing how to construct the composite field value, and the WrappingDataModel would have to act as a binding by being notified by the root DataModel when one of the fields change. Hmmmm.... I'm not sure whether this is simpler or not, but I really like the idea of leaving the Bindings as simple as possible (for all those folks out there who will end up writing their own bindings for custom components). Perhaps we could "chain" bindings together in a sort of pipeline, or perhaps the job should be left up to a chain of converters....

Richard

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

> then it will call label.setText("Hello, " +
> dm.getValue("firstName") + " " + dm.getValue("lastName"));

Would the combination be specified programmatically or
would you come up with some mini-syntax for specifying what
got combined in what order with what seperator characters etc?

Or maybe some type of placeholder/format syntax with ? - like JDBC or
isn't there something like a format statement in Tiger that might help?

C

rbair
Offline
Joined: 2003-07-08

Charles,

> Rich,
>
> > then it will call label.setText("Hello, " +
> > dm.getValue("firstName") + " " +
> dm.getValue("lastName"));
>
> Would the combination be specified programmatically
> or
> would you come up with some mini-syntax for
> specifying what
> got combined in what order with what seperator
> characters etc?
>
> Or maybe some type of placeholder/format syntax with
> ? - like JDBC or
> isn't there something like a format statement in
> n Tiger that might help?
>
> C

That's a great idea! Personally I like control so I'd have leaned towards doing the work manually, but obviously your suggestion would work much better for the "JN" layer components and for people new to Swing. I like using renderers, but it would be great to allow people to specify this kind advanced functionality without having to know how renderers work.

Which approach would you favor?

Rich

Kleopatra

Hi all

(sorry for being so late, currently the Empire needed/needs some
building :-)

>
> > In JDNC the listeners are added at the Datamodel
> > level -
> > but how do you keep the various Datamodels in
> > sync? Different Datamodels may specify different
> > views
> > on the same or related data (e.g. data related by
> > inverse mappings) - so keeping them in sync will be
> > more complex than a like-to-like mapping...
>
> I'm not sure if this is what you're saying, but I think I see the problem you're pointing out. Basically, say we have an object of type Person p, and two DataModels -- lets call them A and B. If both of those DataModels are bound to the same Person (in JavaBeanDataModel speak, A.setJavaBean(p), B.setJavaBean(p)), then what happens if A.setValue("firstName", "Richard") is called? Well, the components bound to A will be updated, but the components bound to B won't know that the change has happened. In fact, B won't know the change has happened either.

As I see it we have to _guarantee_ that the changes are propagated to
all interested parties. If the adapted properties are bound properties,
we get the behaviour for free (currently JavaBeanDataModel is broken in
that respect because it does not even try to listen for
propertyChangeEvents). If they are arbitrary values a possible way out
is to wrap the original Person by a DataModel and chain A and B to this
wrapping DataModel instead to the Person directly.

>
> However, this puts the burden of adding bound properties for beans on the shoulders of the poor Application developer.

It's no burden - at least not from the (my :-) domain object perspective
- because there need to be change notifications anyway "somehow". The
bean-way of handling those is well specified and lightweight (in that it
does introduce only very "light" inter-object coupling).

> But, I'd still favor adding this functionality to JavaBeanDataModel and let the developer decide whether it is important or not. I think :)

Agreed - though I would view that functionally as an absolute "must
have".

>
> For RowSets it is not nearly that clear. I had an inhouse RowSet heiarchy that I wrote that didn't have the problem because each Row in the RowSet was stored in a global cache identified by its key fields (which are noted in the RowSetMetaData). So whenever another record with those key fields showed up, I just reused the same Row object, so a change to one Row's field would propogate throughout the program. It only works if the developer doesn't do anything crazy and sticks to more simple select statements, so it falls short of a general solution.

Again I would try to wrap it into a DataModel right from the start (easy
to say without much experience in the RowSet world :-)

Greetings
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

> Overall, a complicated looking caveat. Any ideas?

Yup. That is the issue I was highlighting. If you can solve
the problem then it means developers are freed from worrying
about the interdependencies between components. In a complex
application not having to think through the interdependencies
between dozens of components becomes the biggest benefit of binding.

Charles.

rbair
Offline
Joined: 2003-07-08

Hey Charles,

Here are my thoughts. The problem here is really two problems:

1) How do DataModels communicate with each other when a change has been made?

There are myriad ways that this can be accomplished. Both you and I had worked out a way to do it over the network. I used a registration/notification mechanism over HTTP. You did yours over JXTA. From within the same VM notification is trivial. There could be a single VM repository that tracks what objects/rows are in what DataModels in a "client-server" sort of relationship and when a DataModel updates a field value it could notify the repository which then notifies the other DataModels. Or the DataModels could register as listeners of each other in a more "peer-to-peer" arrangement. In any case, notification between DataModels within the same VM isn't a showstopper.

Notifying DataModels between VM's, like over the network, is a little more complicated but I contend out of the realm of JDNC. JDNC just needs to provide a hook (perhaps in the DataSource) for a way to communicate a change over the network, and then let specific implementations (yours and mine, for instance) to work out the details of network communication. The point is that if a distributed transaction like this is taking place, then the rules for that distributed transaction - including notification - is already accounted for in each respective architecture. Therefore, JDNC shouldn't reinvent the wheel but leverage it.

2) How does a DataModel know whether it contains the same object that has been changed in another DataModel?

This, in my mind, is the harder question. First let us observe that there *must* be some way for an Object or a Row to be identified as unique. For instance, say I had 3 tables -- Person, Order, LineItem -- and I had a DataModel heirarchy set up for it (personDM, orderDM, lineItemDM). Now say I also have an InvoiceView which was built on an sql join between these tables, and was represented by an object in the invoiceDM. If my invoiceDM did NOT contain the primary key fields from the 3 tables, then it would be impossible for the invoiceDM to be automatically refreshed when a change was made in one of the 3 DataModels. We can look at the arrangement and see that it should be, but there is no generic algorithm that the computer could use to determine that the "firstName" field in invoiceDM is the same as the "firstName" field in the personDM. Hence the reason that updateable views are not automatic in relational database management systems.

It is my opinion, therefore, that there must be some sort of "primary key" or "key field" on each record in a DataModel in order to have this automatic update/notification facility. I see it as impossible to implement automatic updates without it. Essentially, I'm suggesting that we need a way to implement a generic "equals()" method where a row in one DataModel can be compared to a row in another DataModel -- yes, even between a row (aka an Object) in a JavaBeanDataModel and a row (aka RowSet row) in a RowSetDataModel.

My proposed method for doing this would be to add "keyFields" to the MetaData. The keyFields would be some data structure containing the names of the fields that together form a unique key for the Object. In an Object that might be its address in memory (just like the default equals() method), or it might be a combination of the first and last name. For a RowSet row it would simply be the primary key field(s) on the table from which the RowSet was queried. With this information, we can easily construct a HashMap mapping keys to DataModel rows. Automatic updates become trivial at this point.

But the question is raised "that's a burden on the application developer. What if he doesn't WANT to specify a key field for each object?". In that case, automatic updates don't happen. He can still use POJOs with the DataModels, but he'll have to manually call refresh on the DataModel according to some application specific set of rules instead of relying on the automatic notification mechanism.

I'm just exploring the idea in this post not proposing any solid solutions. You'll notice that what I've outlined doesn't cover the example scenario of specifying interest in 3 *different* keys for example, but it shouldn't be hard to get there from here.

What do you think?

Richard

Patrick Wright

>
> It is my opinion, therefore, that there must be some sort of "primary key" or "key field" on each record in a DataModel in order to have this automatic update/notification facility. I see it as impossible to implement automatic updates without it. Essentially, I'm suggesting that we need a way to implement a generic "equals()" method where a row in one DataModel can be compared to a row in another DataModel -- yes, even between a row (aka an Object) in a JavaBeanDataModel and a row (aka RowSet row) in a RowSetDataModel.
>
> My proposed method for doing this would be to add "keyFields" to the MetaData. The keyFields would be some data structure containing the names of the fields that together form a unique key for the Object. In an Object that might be its address in memory (just like the default equals() method), or it might be a combination of the first and last name. For a RowSet row it would simply be the primary key field(s) on the table from which the RowSet was queried. With this information, we can easily construct a HashMap mapping keys to DataModel rows. Automatic updates become trivial at this point.
>
> But the question is raised "that's a burden on the application developer. What if he doesn't WANT to specify a key field for each object?". In that case, automatic updates don't happen. He can still use POJOs with the DataModels, but he'll have to manually call refresh on the DataModel according to some application specific set of rules instead of relying on the automatic notification mechanism.
>
> I'm just exploring the idea in this post not proposing any solid solutions. You'll notice that what I've outlined doesn't cover the example scenario of specifying interest in 3 *different* keys for example, but it shouldn't be hard to get there from here.
>
> What do you think?

Rich

I agree with the equals() method...although we might have a
key()implementation which returns a Key() which can have overridden
equals() for special cases, just another option.

I believe that in strict relational work, queries are used to identify
sets, so duplicates should in principle not "be allowed". If the
developer allows duplicates in their results, then they have other
problems we can't help them with.

There is the special case of a DataModel shared between two views, in
which case the indexing can be on the item/row index.

What I like about a key() method is that it lets us move towards a
DataModel/RowSet for which we can construct a SQL output for
auto-generation of insert/update/delete operations back to the database.

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

> there *must* be some way for an Object or a Row to be
> identified as unique

I use the ObjectID pattern i.e. every object has
a globally unique ID Field. This also makes lazy loading and
caching trivial - as you just lookup the Objects across the network
using their Object ID when you need them.

However this isn't a general solution as it makes assumptions about the 'data structures'.
So you'll have to find a way of doing it that fits
the JDNC mould. Metadata as you suggest may be an option.

Charles.

rbair
Offline
Joined: 2003-07-08

Hi Charles,

> I use the ObjectID pattern i.e. every object has
> a globally unique ID Field. This also makes lazy
> loading and
> caching trivial - as you just lookup the Objects
> across the network
> using their Object ID when you need them.
>
> However this isn't a general solution as it makes
> assumptions about the 'data structures'.
> So you'll have to find a way of doing it that fits
> the JDNC mould. Metadata as you suggest may be an
> option.

I agree 100%. You point out two important things to keep in mind. First, if somebody has globally unique id's for their objects then we should leverage that. Second, if they don't, we shouldn't impose it on them. But the programmer needs to understand that without some kind of unique id (whether that be a long, integer, String, whatever) some functionality within JDNC such as automatic query generation (for sql) or automatic update notification/propogation is not possible. As long as they understand that limitation, they shouldn't be forced to include a key field.

Oh, and as Patrick and I discussed we could also provide some kind of method to determine equality instead of just relying on key fields, giving the programmer a lot of additional flexibility. Relying on key fields would be our default implementation, but the programmer could override this default functionality if desired.

Rich

charles.armstrong
Offline
Joined: 2006-02-17

Rich, Patrick

> Oh, and as Patrick and I discussed we could also provide
> some kind of method to determine equality

All good stuff. When you go down this route you'll also
have to override hashCode and compareTo (the latter only
being the case if you choose to implement Comparable)...

In six months you guys will either say 'OK OK we give in,
persistence is not orthogonal' or you'll have a general
and very interesting solution :)

C

Kleopatra

Charles,

> In JGoodies they are bound to the ValueModel (the
> ValueModel interface contains addListener methods) -
> and the consistency between components is done by
> using BeanChannels between the ValueModels.
>
> In JDNC the listeners are added at the Datamodel level -
> but how do you keep the various Datamodels in
> sync?

Analogous way as in JGoodies: wrap DataModels around ("DataModel
channels) and work with those. But the similarity breaks up if we start
introducing more "collectionness" into the DataModel - which I would not
do, but looks like that's a minority opinion

When it comes to modifying collection structures it's really tricky to
get the synch correct. JGoodies Binding does not help much in this
respect.

Greetings
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Jeanette,

> When it comes to modifying collection structures it's
> really tricky to get the synch correct. JGoodies Binding
> does not help much in this respect.

Its manageable for Sets. The only thing you have to
manage is if you receive a delete request for an element
you have not yet added. You store these in a 'hanging removals'
subset, so that when the addition arrives you
delete it straight away.

There may be some approach for Lists, but I decided it was
simpler to do without and use Comparable to order the
elements of a Set.

Charles.

Kleopatra

Charles,

> Its manageable for Sets. The only thing you have to
> manage is if you receive a delete request for an element
> you have not yet added. You store these in a 'hanging removals'
> subset, so that when the addition arrives you
> delete it straight away.
>
> There may be some approach for Lists, but I decided it was
> simpler to do without and use Comparable to order the
> elements of a Set.
>

Good idea, never thought of it this way, thinks :-)

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Amy Fowler

This has been an exciting thread and I was glad to see that
the ruffled feathers smoothed themselves out without moderation :-)

I wish jsr227 would come to the rescue, but it's not gone anywhere,
so here we are.

Let me try to summarize some of the key elements of this discussion,
with a bit of my own jdnc bias sprinkled in:

0) "Data-binding" in jdnc means tie-ing GUI components to elements
in a local data-model such that *typed* values in the model are easily
displayed, edited, validated, and stored back to the local data model
without the developer having to write all the error-prone glue code
to make this happen.

1) "Data-binding" in this context has nothing to do with fetching data
into client-local data models, nor persisting changes in the model
back to the data source; that is an orthogonal issue that relates more
directly to the type of data model and its relationship to its source.
I would see such functionality hidden either behind the data model's
api or possibly provided as independent 'actions' on the datamodel.

2) However! the api must accommodate possible lazy fetching of values.
For simplicity I would like to keep the binding get/set apis synchronous,
however what should happen if a textfield binding tries to pull a value
which requires a possibly delayed query response to the server??? humm.

3) A data-binding framework at jdnc's *swing extensions* level should
be flexible enough to allow GUI components to be bound to a
variety of data model flavors:

a) rowset, for sql/database applications
b) simple javabeans, for JAX-RPC clients, etc
c) domain objects (suped-up javabeans containing business
logic, possibly local vs. remote execution concerns, etc)

I don't think this means either "make all rowsets look like javabeans"
or "respresent ALL data, sql or not, as a rowset". If I'm building an
sql application, I *want* to deal with the rowset and all its transactional
capabilities directly. If I'm getting my data from a WebService, then
I've got a collection of JavaBeans that I want to manipulate. If I've
painstakingly developed a suite of app domain classes, then of course I
want to work with those. [note: I came up with "DataModel" originally
as a simple abstraction for dealing with the common binding tasks ONLY;
I never intended for apps to embrace it as the be-all data-model API to
usurp RowSet or objects - in fact, for many cases I envisioned it would
be a hidden binding detail and completely invisible to the developer].

Personally, I think a common low-level data-binding mechanism should
be able to work for all three of these flavors, albeit many of the
binding *implementation* details would differ (I think this was Scott's
point). I'll confess that in jdnc we have to-date only thought about
the first 2, however, at the gui-to-datamodel binding level, I just don't
see a huge difference between b & c. Charles' vehement disagreement with
this assumption is duely noted :-), and if such complex domain objects
really do reak havoc for binding, then I'd opt to focus jdnc on a & b.

4) The base-level data-binding api should support dealing with strongly
typed values. Note: RowSet supports a finite set of typed values, but
that set remains strongly typed. Glory-be, we are out of the
"nothing-but-string" world of browser clients!

5) In addition to a flexible base-level data-binding framework, JDNC should
layer higher-level API (particularly in the JN* components) which
hides the glorious OO details from those who don't care ("I just want
to bind this textfield to the "lastname" property on this javabean").
This means RAD does NOT have to be at the exclusion of more sophisticated
layers underneath.

6) The binding API must support binding to nested elements within a datamodel
(combobox binds to the "street" property on an bean which is the "address"
property on "customer", or textfield binds to a "itemnumber" column in
a rowset which is the "orders" column in the customer rowset, ...)

I think reflection could be a very powerful mechanism here, however I
agree that we should make a note that performance/scalability needs to
be evaluated. Let's not jump the gun and discount reflection based on
performance concerns without concrete evidence to back it up.

7) The JGoodies binding framework provides very strong, flexible, OO support
for dealing with 'object' data models, but does not include direct
binding support for RowSet/sql. [With Jeanette's help :] we can investigate
how the JGoodies framework might provide the low-level data-binding mechanism
that meets these requirements and then jdnc can build some higher level
api on top to meet RAD and toolability requirements. Or maybe there's a
way to combine the best concepts from both worlds?

In the end, the best way to illustrate the goodness of an API is to show
code examples....

Aim

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rbair
Offline
Joined: 2003-07-08

Hey Aim,

Both humorous and concise :).

>2) However! the api must accommodate possible lazy fetching of values. For simplicity I would like to keep the binding get/set apis synchronous, however what should happen if a textfield binding tries to pull a value which requires a possibly delayed query response to the server??? humm

Just expanding on the idea, lazy fetching comes in two styles -- when fetching data for a field or when fetching data to populate a child DataModel. The later case is handled simply enough. The code responsible for handling the master/detail relationship (in incubator code that isn't yet submitted its called the MasterDetailHandler, in the architecture.jpg I linked to earlier it was just called "binding" in the picture) would start an asynchronous load call and the detail DataModel would be updated when the data was available, etc.

The former is more troublesome. In JDO, for instance, it is possible that a field has not been loaded from the database, and won't be until the accessor method for that field is called. Or if rowsets are used with a fetch count of 300-500 like Patrick suggested, then on nextRecord() or previousRecord() or setRecordIndex() method calls the DataModel might block. Both of these situations are obviously undesireable because we won't be able to properly display in the GUI why the application has hung. On the other hand, designing for the getValue() and related methods to be asynchronous seems onerous.

Lazy loading is definately necessary, but how to handle some of it is still not clear to me.

>4) The base-level data-binding api should support dealing with strongly typed values. Note: RowSet supports a finite set of typed values, but that set remains strongly typed. Glory-be, we are out of the "nothing-but-string" world of browser clients!

I'm still hazy about what is meant by "strongly typed" support in the binding api. Are we talking about having an "IntegerBinding", "StringBinding", "LongBinding", etc? I don't mind this as long as the higher level api exists. Would the Converter part of the API be irrelevant at that point? If everybody else gets this terminology but me, don't worry too much about explaining it, I'm sure it'll be obvious when I look at the code :).

I think your post is right on the money, Aim.

Rich

Message was edited by: rbair

Patrick Wright

> My Company Object has an Employees Field. Employee has
> at least two subtypes Manager and Graduate Trainee. If I
> only want to display a Table of Managers how do I do
> it? I have a reference to the Company Object.
>

Charles

I have been following these threads with interest...

What I want to know at this point is what you are trying to accomplish,
that is, what you want the (JDNC or JGoodies) toolkit to provide you with
as regards domain objects.

1) Simplified or "managed" binding to forms: Allows the developer to avoid
tedious, verbose, and error prone mapping between domain object and form
elements. Should be usable to tabular or single-instance display (e.g. one
or many domain objects). Should handle both read and write for elements,
with notification.

2) Persistence of domain elements: could be a higher-level persistence API
than Hibernate, so that when the user hits "save", all "mapped" domain
instances receive a "save message". Would need to be tied to transaction
boundaries.

3) Graph-based "managed" linking, (1-1, 1-M) between multiple forms

4) Graph-based "managed" navigation, (1-1, 1-M) e.g. drill-down between
multiple forms

In the example you gave is the issue
- a binding problem: how do I bind an Employee list to a table, where I
may actually have Employee subtypes?
- a persistence problem: how does the toolkit know what to retrieve from
Company?
- a linking/navigation problem: should the toolkit provide an easy way to
drill down from Company to Employee (or Manager)?

and so on...

Even if we have a mapping from a DataModel to a List of domain objects,
there will be some operations where we need to extract the domain object
associated with a "row" and perform some operations on it directly--which
means we need to cast from an Object associated with the row to the type
we know the row to be mapping, which will unfortunately involve a
cast...for example, for specific validation routines.

Where I start from is that we can't treat domain objects in an abstract
way unless they share common characteristics we can abstract from. If all
the domain objects implement a Saveable interface, then we can have
methods to work with any Saveable element. The JavaBeans spec specifies
one simple type of abstraction that lets us treat bean "properties" in a
standard way for reading and writing, regardless of the domain object in
question. But I think this discussion should be oriented towards the
specific goals re: JDNC and domain objects, and then see how much of the
developer's life we can simplify.

For my part, I'm a bit suspicious about frameworks that try to help me
with domain objects, because there may be performance problems with, for
example, "walking" a domain model graph and loading the graph in
pieces...if the API makes it look like this is easy, you can easily write
yourself into a performance (or memory) swamp. There is an ideal use case
where we have a lot of memory and we can navigate without any performance
problems, because all domain objects an in memory...for example, if mapped
to an XML DOM. But that, in my experience, is the rare case. I think
developing well with a serious domain model is difficult, and the API
shouldn't hide that. Or, the API should make the task as easy as possible
for the developer, and no easier. :)

So--can we clarify where you would like the API to make your life easier?

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Patrick,

To answer the quick question - the problem I gave was
really a configuration one. When presented with an Object
containing lots of Employee subtypes, but being required
only to display, edit and add one of these subtypes - how
would the filtering out of the other subtypes be handled.

As for the future:

(1) On the desktop - you ideas about many to many navigation and Object graphs are very much where I would
hope to see things go. Some completely new components
using Java 3D would be allow you to view many to many
relationships a lot more easily.

(2) On the architecture side. I'd like not only all
components, but also all business logic to bind to
Fields of an Object model (i.e. fire when there is a
change in the value of a Field). I would like this
state to be consistently distributed across the
network so that you have an event driven,
asynchronous, high performance distributed architecture -
where any changes anywhere on the network automatically
cause anyone's components or business logic to update
in near real time.

As you can see this would all lead JDNC far away from
its stated purpose - which is why I would like
another framework to do it (unless JDNC can get
permission to abandon the RAD goal).

rgds,
Charles.

Patrick Wright

Charles

Thanks for the reply.

> To answer the quick question - the problem I gave was
> really a configuration one. When presented with an Object
> containing lots of Employee subtypes, but being required
> only to display, edit and add one of these subtypes - how
> would the filtering out of the other subtypes be handled.

I like the filtering idea that appeared on the list for this problem a few
days ago. After the community plays around with it, we might be able to
make the filter fairly small and generic for straightforward cases like
Employee/Manager. The thing I worry about with client-side filtering (and
sorting) is that it can perform poorly with large datasets--the developer
thinks it is an easy solution to implement, where it might perform much
better to filter at the datasource (e.g. company.listManagers()) if there
are many items to filter (lots of Employees). It can also be a waste to
load the entire pre-filter set if most of the items are filtered out
anyway and never accessed.

I don't know how to get around this, though. The RAD tools for client-side
development can make it very quick to develop for small datasets. But
there are scaling problems...the trick will be to provide both the
client-side filtering option as well as a more sophisticated solution (and
guidelines in documentation) for developers. One goal should be to develop
some (rough) heuristics. When I started developing client-server apps, the
rule of thumb was to return no more than 300-500 rows in a query, even if
you were planning to filter on the client side. Sorting on the client side
was discouraged for large datasets as well.

> (1) On the desktop - you ideas about many to many navigation and Object
> graphs are very much where I would
> hope to see things go. Some completely new components
> using Java 3D would be allow you to view many to many
> relationships a lot more easily.

My guess is we can facilitate this but it will be difficult to have it
perform well in the general case, as above. We'll see.

> (2) On the architecture side. I'd like not only all
> components, but also all business logic to bind to
> Fields of an Object model (i.e. fire when there is a
> change in the value of a Field). I would like this
> state to be consistently distributed across the
> network so that you have an event driven,
> asynchronous, high performance distributed architecture -
> where any changes anywhere on the network automatically
> cause anyone's components or business logic to update
> in near real time.

Yikes! Way complicated stuff. I would think one would want to piggyback on
top of a push or a pull technology where the messaging is already worked
out (JMS, JXTA, Jini)...there are also issues depending on the backing
datasource. The solution would be different for J2EE and for a relational
database as the backing storage. The trick (as with having object caches
in a cluster) is how to make changes transactional across the network (so
that local 'copies' of the data are always consistent), as well as
high-performing. A tough goal!

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rbair
Offline
Joined: 2003-07-08

Mornin' folks,

> > (2) On the architecture side. I'd like not only all
> > components, but also all business logic to bind to
> > Fields of an Object model (i.e. fire when there is
> a
> > change in the value of a Field). I would like this
> > state to be consistently distributed across the
> > network so that you have an event driven,
> > asynchronous, high performance distributed
> architecture -
> > where any changes anywhere on the network
> automatically
> > cause anyone's components or business logic to
> update
> > in near real time.
>
> Yikes! Way complicated stuff. I would think one would
> want to piggyback on
> top of a push or a pull technology where the
> messaging is already worked
> out (JMS, JXTA, Jini)...there are also issues
> depending on the backing
> datasource. The solution would be different for J2EE
> and for a relational
> database as the backing storage. The trick (as with
> having object caches
> in a cluster) is how to make changes transactional
> across the network (so
> that local 'copies' of the data are always
> consistent), as well as
> high-performing. A tough goal!

Charles, I actually have roughly the same desire. At each site I have a small cluster of users (between 1-10) -- I mention this so that the scale of the application in the ensuing discussion is understood to be small, although the latencies between nodes could be quite long.

First, in my mind JDNC is a GUI framework only. That's why in previous discussions I said persistence is orthogonal to JDNC. In my mind, JDNC should sit on top of persistence, network architecture, and application architecture. It needs to provide a means to interact with those things, but doesn't need to provide an API for OR-mapping, for instance.

If we all agree that JDNC is fundementally a GUI framework, then for this discussion we can leave out the details of how the various clients notify each other of changes in shared objects. As Patrick noted, you'd probably want to piggyback on some distributed network technology that handles the transactional and communication anyway. Also, we can consider this network communication to be happening on a separate thread since it is (or should be) asynchronous.

Ok, if we are still all in agreement, then what we have, in essence, are a bunch of objects that are being manipulated in two or more different threads -- the event dispatch thread and a 'network' thread, and as many other threads as you care to use. For this discussion lets call these threads the EDT and NT. Lets also assume that all of the manipulation is happening in a single distributed transaction.

Now, what we need is for changes to an object in the NT to be pushed onto the EDT. If we were using conventional swing with Charles' use case, then we would tell our table model to fireTableDataChanged (using a table model that is adapted to our filtered list) and it would refresh the gui with the changes that the NT made to the object. If we didn't call this method, then on the next repaint the job would get done -- but it is certainly undesireable to have the user resize the window and *then* notice the change, so we really have to call the fireTableDataChanged method.

Now, its my opinion that even this approach is lacking, because the user doesn't do anything and now their table is changed (perhaps they notice, perhaps they don't). If this is the way that makes the most sense for your app, then you're done. For my apps, however, I really want to also notify the user that something has changed. If the change occurred outside of this transaction, then I'd still want to notify the user that a change has occurred, but then let them decide whether to override the change or refresh their data. In either case, the GlassBox concept in swingx fits perfectly.

So, I'd like to see an API change in JDNC that allows for not just push/pull, but also notify. The notify methods would notify the gui that something has changed in the background, and ask them to notify the user of this change. The user can then refresh (if in the same transaction as the change then the refresh is simply push the change from the DataModel to the gui. If its in a different transaction, then it would ask the DataSource (or whatever we call it) to refresh the data from over the network), or ignore the changes and make the GlassBox go away.

Obviously, the notify methods should not be invoked in some situations (such as the initial load) and should be in others, so this API would need to spell out when and under what circumstances notification of "collisions" occur. The semantics are probably different for a single field as opposed to a collection, as well.

With all of this background we can discuss what would happen with your use case, as well as the bigger question of asynchronous background changes to your data objects, or in other words to the DataModel (since the DataModel wrapping the domain object would in essence be changed when the underlying domain object's field is changed).

Charles, in your use case I would have actually copied the objects out of the list and into the JavaBeanDataModel. The reason for this is that traversing a list that is being altered by two or more threads is difficult if not just plain dangerous. Besides, even with traditional swing programming your TableModel doesn't know when the list has been altered, so you must have code in place somewhere to notify the TableModel of the change so it can cause a repaint of the JTable. At least, that's the way I would have approached it.

Ok, back to the distributed use case. In our gui we have a single JTable displaying only the managers. The form is to be bound to the Company, and the table is to be bound to the 'managers' property (or alternately, the 'employees' property with a managers filter attached -- it all works out the same in the end).

When the Company object is passed to the form's main DataModel, it notifies the child DataModel that the JTable is bound to that it needs to reload itself. It then (being a JavaBean aware data model) calls the 'getManagers' method on the Company (which the child has access to by calling the parent DataModel's getJavaBean() method). The resulting objects are copied into the child data model, the TableModel is notified of the change (the TableModel being adapted to reference the child DataModel, of course) which in turn notifies the JTable which finally refreshes the gui.

Now, lets say that on another node in your distributed architecture somebody adds a new manager. Whatever you are using for your network architecture passes that information on to our node announcing the new manager. Whatever data store specific code needs to execute to get the new manager is executed (all on the NT). In my proposed changes to the DataModel architecture (https://jdnc-incubator.dev.java.net/source/browse/jdnc-incubator/src/jav...) all of this would be coded in the DataSource. The DataSource then updated the Company object and notifies the parent DataModel that the Company object has changed. This notification automatically causes the child DataModel to refresh itself, recalling the 'getManagers' method and copying all of the managers into the child DataModel (after having previously flushed the existing references in the child DataModel).

If the notification mechanism for collisions (or background updates) is in place then a notification would occur without actually updating the Company object until the user indicated whether they wanted to accept the changes and refresh or not.

In summary, I think that the basic problem of notifying the gui of updates or changes to the underlying data model is common with both domain objects and simple RAD applications. Regardless of the underlying technology used, the gui framework needs to be able to handle asynchronous changes to the underlying data in a user friendly manner. If the gui framework (aka JDNC) supports asynchronous updates and handles these updates gracefully, and if you have a good network architecture for handling distributed transactions etc, then I think you can accomplish what you want. Or, at least, I hope you can because I'm trying to accomplish the same basic thing :)

Richard

PS> I hope it made sense :)

charles.armstrong
Offline
Joined: 2006-02-17

Rich, Patrick

Rich - I agree with a lot of what you say. Interested that
you had been thinking about what happens when a List is
changed by two people at once. I have worked out ways
of making it manageable for Sets, but think that
as you say Lists might be almost insoluble.

My approach on persistence is ortogonal to yours!

I want to get rid of transactions and replace back end storage
with a Data Event History store. If you have a
programming model where everyone agrees in what order things
happened and who did what when, then you can do
a lot without transactions. ie. what I am saying is
back end storage has to be made to fit the programming
model - and the programming model needs to make a lot
of assumptions about the behaviour of the back end
storage.

On a purely human level - if a change appears on your
screen and you can click a history button and see who
caused the change - then if you don't like it you
can telephone them - this prevents the need for locking.
An analagous negotiation process can also be done at
the software level.

Transactions in distributed computing will destroy
scalability, as Patrick notes, so you have to look at
new programming models.

Patrick - I have been experimenting with Jxta and
getting reasonable results for this type of thing.

So in conclusion - your layered approach Rich where
persistence, network communication and GUI are orthogonal
would be a more general solution, possibly even a
better one. However I think things will soon become
unmanageably complicated, and hit scaleability
problems.

I favour a streamlined approach and want a simplified
programming model where the layers can make a lot
of assumptions about each other, and there is
agreed upon standard Object model for state
representation.

Charles.

rbair
Offline
Joined: 2003-07-08

Hey Charles,

[snip]
> My approach on persistence is ortogonal to yours!

:)

> I want to get rid of transactions and replace back
> end storage
> with a Data Event History store. If you have a
> programming model where everyone agrees in what order
> things
> happened and who did what when, then you can do
> a lot without transactions. ie. what I am saying is
> back end storage has to be made to fit the
> programming
> model - and the programming model needs to make a
> lot
> of assumptions about the behaviour of the back end
> storage.
>
> On a purely human level - if a change appears on
> your
> screen and you can click a history button and see
> who
> caused the change - then if you don't like it you
> can telephone them - this prevents the need for
> locking.
> An analagous negotiation process can also be done at
> the software level.
>
> Transactions in distributed computing will destroy
> scalability, as Patrick notes, so you have to look
> at
> new programming models.

(offtopic)
Funny, that's *almost* the direction I was heading :). The basic problem of distributed notification of changes is complicated, and really suffers scalability problems, like you said. I brought up the subject on the JDOGenie forums a while ago, and they had a lot of good insight into the problem as well. You obviously can't broadcast to the world every time you make a change, so somehow each node has to be able to communicate changes only to other nodes that need to know a change has occured.

The way I was going to go about it was to have a table in my database that would keep track of "registrations". When a client wants to be notified of changes in something it will register itself with the database. When somebody updates/inserts/deletes a table a trigger is fired and will place a record in a "notifications" table for every client that is interested in the event. Interest in events would be signified by the primary key of the table of interest, or a range of primary keys if a range of rows in a table are of interest. Then, since most databases don't seem to support push notification (and since I don't form a physical connection to the database from the clients anyway, they use xml-rpc to communicate with the server which then manages the database connections), I'd have a background thread in each client app that would check for updates every 5 min or so, and notify the user in the gui of changes. Like you say, I'd not use distributed transactions at all but let each client be in its own transaction. Most (if not all!) database locking schemes require user interaction to resolve conflicts, hence my desire to have a signal in the gui for the user to see that a conflict is going to happen on commit, and be able to resolve it!

[snip]
> So in conclusion - your layered approach Rich where
> persistence, network communication and GUI are
> orthogonal
> would be a more general solution, possibly even a
> better one. However I think things will soon become
> unmanageably complicated, and hit scaleability
> problems.
>
> I favour a streamlined approach and want a
> simplified
> programming model where the layers can make a lot
> of assumptions about each other, and there is
> agreed upon standard Object model for state
> representation.

Ya, I see what you mean. I don't know if the general approach would *have* to scale poorly for most(?) architectures, but I can definately see how it could. I have to admit -- I don't have any experience in distributed transactions (where a single transaction spans multiple nodes) or peer-to-peer, so I don't know how things will shake out for those. If anybody with a good background in those technologies is around, I'd love to hear the gory details. I'd hate for JDNC to have to narrow its focus to only one or another architecture, and I'd equally hate to see it not be useable by a distributed transactional OO architecture.

Rich

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

I think what you have described there is an example of
why the layers should know about each other.

The 'database' should know who has registered a change
listener of the Field of the Object - only they get
notified. It all then happens transparently. The code
or component just adds the listener to the Field of the
Object model - the programming model can hide the
issues of distributing the notification to the right
places.

rgds,
Charles.

rbair
Offline
Joined: 2003-07-08

Charles,

> I think what you have described there is an example of why the layers should know about each other.

Do you mean that each layer should know about all of the other layers, or just about the layers next to them? I mean, the gui layer needs to know how to ask for stuff from the data store (in a generic way), and how to initiate a save, and maybe a transaction, etc. But the gui layer shouldn't know how its done. Likewise, the DataSource layer should know how to actually get the data and save the data and handle transactions, but shouldn't know whats going on in the gui, really (especially since they are on separate threads).

In other words, the gui layer definately needs to know how to participate in the larger world, but doesn't need to know the implementation details. I would think that concepts such as transactions and persistence have enough commonality among their respective implementations that a general interface could be developed for the gui to utilize these services.

Of course, with a network involved somebody somewhere has to be concerned about what methods are called when and where, and some of that logic may find its way in gui code. However, the framework (hopefully) would still be common from one implementation to another.

> The 'database' should know who has registered a change listener of the Field of the Object - only they get notified. It all then happens transparently. The code or component just adds the listener to the Field of the Object model - the programming model can hide the issues of distributing the notification to the right places.

Exactly. I'd have my DataSource (again, not javax.sql.DataSource but the one in the incubator -- man I wish I had a different name for it) implementation be the one that registers with the database, and hence the one that handles communication with the database. My gui would just know that a collision has occured.

It'll be interesting to see how this works out when it moves from concept to working demo. Wish me luck :)

Rich

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

I have a working demo - which works across the network.

At the moment you have to do the JXTA configuration manually - but if you don't mind that I can point you to it.

Charles.

rbair
Offline
Joined: 2003-07-08

> Rich,
>
> I have a working demo - which works across the
> network.
>
> At the moment you have to do the JXTA configuration
> manually - but if you don't mind that I can point you
> to it.
>
> Charles.

Ya, that'd be way cool.

Thanks,
Rich

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

To get hold of it either right click

http://www.kanabos.com/incubator/Hire.jar

or click

http://www.kanabos.com/incubator/Hire.zip and unzip it

[The jar contains software from jxta.org and jacorb.org]

then from a command line run

java -jar Hire.jar

The jxta configuration should start - the only non-obvious
bit is the rendezvous configuration click 'download
rendezvous and relay list' - the essential parts are

(1) use the same I.P. addresses for the rendezvous and
relay on all nodes you run it on - best to use
192.18.37.36 in all four boxes

(2) it is ESSENTIAL that you check the use only
configured rendezvous box, and you also need to
check the 'use a relay box'

After that the thing should start up and an ugly GUI
should appear - click 'View Hire' in the project menu

Then the fun starts - if you have got this far on two
PCs connected to the internet then any changes you make
in tables etc on one machine should cause the components
on the other machine to update pretty much
instantaneously...

let me know how you get on... I hope to get round to
doing the Jxta config programmatically next month...

Charles.

rbair
Offline
Joined: 2003-07-08

Charles,

> Rich,
>
> To get hold of it either right click
>
> http://www.kanabos.com/incubator/Hire.jar
>
> or click
>
> http://www.kanabos.com/incubator/Hire.zip and unzip
> it
>
> [The jar contains software from jxta.org and
> jacorb.org]
>
> then from a command line run
>
> java -jar Hire.jar
>
> The jxta configuration should start - the only
> non-obvious
> bit is the rendezvous configuration click 'download
> rendezvous and relay list' - the essential parts are
>
> (1) use the same I.P. addresses for the rendezvous
> and
> relay on all nodes you run it on - best to use
> 192.18.37.36 in all four boxes
>
> (2) it is ESSENTIAL that you check the use only
> configured rendezvous box, and you also need to
> check the 'use a relay box'
>
> After that the thing should start up and an ugly GUI
>
> should appear - click 'View Hire' in the project
> menu
>
> Then the fun starts - if you have got this far on
> two
> PCs connected to the internet then any changes you
> make
> in tables etc on one machine should cause the
> components
> on the other machine to update pretty much
> instantaneously...
>
> let me know how you get on... I hope to get round to
> doing the Jxta config programmatically next month...
>
> Charles.

Sorry it took me so long to get to the demo, but it was no problem getting it to run at all. Very cool. Is it all proprietary code? I'd love to write a DataSource for it and see if it would work with the jdnc code in the incubator. If it is proprietary I'd love to see you write a DataSource for it and see if it works with the architecture :).

Rich

charles.armstrong
Offline
Joined: 2006-02-17

Rich,

Glad it worked.

> Is it all proprietary code?

Nope. Its split between two java.net projects

https://kanabos.dev.java.net/

and

https://distributor.dev.java.net/

I haven't been publicising it as the documentation
is currently inadequate.

If you want to know how anything works and the question
is too specific to be of interest to JDNC readers then
you can post your thoughts to:

https://kanabos.dev.java.net/servlets/SummarizeList?listName=users

The list is pretty desolate :( and could sure use
some traffic.

Charles.

scottr
Offline
Joined: 2004-09-05

Hi Charles,

>
> I still think with parent-child etc you are going to
> end
> up with something that looks like a relational data
> model.
> So to make an Object graph mappable to DataModel you
> wouldn't be able to use anything that
> distinguished OO from relational models.
>

Well, yes and no. Ultimately that's going to be a problem with any data that is persisted to a RDBMS, rich domain or not. ORM tools like Hibernate can allow some amount of translation between RDBMS and OO, but you are still going to design your object model to be compatible with the natural structure of the database.

> Do you and I more or less agree that for simple cases
> it
> might work - but for rich domain models you need the
> precision tools of a JGoodies type approach?
>
> In which case trying to unify them wouldn't ge a good
> idea as they are tools for different jobs?
>

Well, I don't know really. I think that the simple cases - RowSets and value objects (ie. no logic) are in themselves simplified versions of the rich domain model anyway. A RowSet acts, as you have pointed out, as a plain vanilla Object with limited types available for fields. I think the JGoodies style could be used for these simple cases also, albeit with standard adapter classes to support RAD development.

I guess the question of whether to take a unified approach or not depends on JDNC's roadmap for future development. If JDNC's only purpose was to support RAD development for simple data models like RowSets, CSV files, and so on, then its already on that track. But if JDNC intends to support rich domain models (and if it intends to support JSR 227 it would need to), then consideration will need to be given to how that will be done.

But don't take it that I am saying dump either approach in favour of wholesale adoption of the other. I think that the sort of complexity that JGoodies supports can be intoduced into the JDNC without sacrificing the RAD simplicity desired for simple data models. In other threads I have listed some of the functionality I would like to see supported in JDNC, like complex object graphs, lazy loading, caching and transactional demarcation. But at the same time I'd want to see the API support simple use cases when that was desired. Whether that can be done and how is a question for discussion and experimentation.

Scott

charles.armstrong
Offline
Joined: 2006-02-17

Rich

>Also, I don't see how you can have one unified API for both >RowSets and Objects that doesn't use the tabular data model >as the base abstraction

Ah hah!

That is exactly my point. You can't. So you can't have a
unified model without being stuck with the tabular format.
So then you lose inheritance, inverse mappings etc. etc.

What I was saying in earlier posts is you can't have a
unified model, that would work for rich Domain Models.
i.e. trying to unify JDNC and JGoodies approaches
wouldn't work.

Can we start there? And deal with one issue at a time?

Charles.

scottr
Offline
Joined: 2004-09-05

Hi Charles,

>
> >Also, I don't see how you can have one unified API
> for both >RowSets and Objects that doesn't use the
> tabular data model >as the base abstraction
>
> Ah hah!
>
> That is exactly my point. You can't. So you can't
> have a
> unified model without being stuck with the tabular
> format.
> So then you lose inheritance, inverse mappings etc.
> etc.
>

We've some discussions in other threads about what would be needed to be modified in the DataModel API to support data relationships, ie. parent-child or header-detail relationships. Whether you are dealing with object models or RowSets, there is often a requirement to have a form display and modify hader-detail style data. I don't think a pure tabular approach serves either model, because you then need to re-code each time the logic to keep the detail in synch with the header. What is needed is actually a modification of the DataModel abstraction itself.

Scott

charles.armstrong
Offline
Joined: 2006-02-17

Scott,

I still think with parent-child etc you are going to end
up with something that looks like a relational data model.
So to make an Object graph mappable to DataModel you wouldn't be able to use anything that
distinguished OO from relational models.

Do you and I more or less agree that for simple cases it
might work - but for rich domain models you need the
precision tools of a JGoodies type approach?

In which case trying to unify them wouldn't ge a good idea as they are tools for different jobs?

rgds,
Charles.

charles.armstrong
Offline
Joined: 2006-02-17

OK Rich.

Seeing as you prefer specifics lets go through some use
cases, one at a time. I am not saying any of these can't
be done. I just want to try and establish common ground, so I know how your thinking is working on this.

First:

My Company Object has an Employees Field. Employee has
at least two subtypes Manager and Graduate Trainee. If I
only want to display a Table of Managers how do I do
it? I have a reference to the Company Object.

Charles.

gphilipp
Offline
Joined: 2003-06-10

> My Company Object has an Employees Field. Employee
> has
> at least two subtypes Manager and Graduate Trainee.
> If I
> only want to display a Table of Managers how do I do
> it? I have a reference to the Company Object.
>
> Charles.

Hi Charles,

That's not difficult, I do it all the time in my own framework (which has a TableModelAdapter that acts on a collection of POJOs). You just have to restrict yourself the list of employees to the Manager types and pass it to some JDNC own TableModelAdapter-like implementation. I've coded a simple one in Richard's own sandbox area (JavaBeanTableModelAdapter)... It's still in the sandbox though...

Gilles Philippart

charles.armstrong
Offline
Joined: 2006-02-17

Giles,

>You just have to restrict yourself the list of employees to >the Manager types

Thats the bit I was interested in. How do you do the
restriction? How do you filter on type? Do you copy
the Managers into a seperate List Object, in which case
the binding will break down as additions or removals will
not be synchronized with the Original Employees List.

Or do you pass the Employees List Object in with a
filter attached - but how does the filter work?

Charles.

gphilipp
Offline
Joined: 2003-06-10

> Giles,
>
> >You just have to restrict yourself the list of
> employees to >the Manager types
>
> Thats the bit I was interested in. How do you do the
> restriction? How do you filter on type? Do you copy
> the Managers into a seperate List Object, in which
> case
> the binding will break down as additions or removals
> will
> not be synchronized with the Original Employees
> List.
>
> Or do you pass the Employees List Object in with a
> filter attached - but how does the filter work?
>
> Charles.

I think I would use a filter. I've coded something very similar to the iTunes "smart playlist" function, but applied to javabeans. The user can create its own filter by combining predefined predicates on the object graph.
I use the predicate package from jakarta-commons. The filter then acts transparently on the source collection (the Employees list). You create it when you bind the collection to the UI component because as Karsten specified in some other thread (http://www.javalobby.org/thread.jspa?forumID=17&threadID=14486&start=0&m...), you don't necessarily have to use reflection to do the mapping.

Gilles Philippart

charles.armstrong
Offline
Joined: 2006-02-17

Gilles,

That's the kind of solution I was thinking of.

But its much more along Karstens field by field approach
than the drill down through a globular Typeless Datamodel with reflection approach.

Maybe the approaches can be unified. My instincts say it
will get harder and harder as the OO enthusiasts push
for the features they need.

However its always far more educational to have your
instincts proved wrong. So good luck.

Charles.

charles.armstrong
Offline
Joined: 2006-02-17

And finally,

Just in case Rich has managed to confuse anyone.

The current Datamodel API is just a Rowset/Table structure with a few methods renamed and the Interface renamed to 'Datamodel' ... see Amy's comparison table in this
thread.

http://javadesktop.org/forums/thread.jspa?threadID=4613

Its structure eg record index etc is row/table orientated.

Just changing the word 'Row' or 'Table' doesn't change its structure.

Unless you change its structure then it can't be used for anything else without gymnastics. Renaming 'Meat' to 'Food' doesn't make it more useful to vegetarians.

I hope pointing this out doesn't offend anyone - Amy
was very open about her thought process and goals.

Charles.

Kleopatra

>
> Yes - I am sure you could write an OO system where
> everything extends Object or String - and do all method
> calls by reflection - but your code would be
> horrendous.
>
> Maybe you should post your reflection code - and then
> compare it to the typed examples Karsten gives in
> the binding paper at:
>
> http://www.jgoodies.com/articles/
>
> I hope its obvious business logic is far easier with
> types. If not obvious any gentle OO introduction
> will help.
>

Don't know much about persistence or OO-relational mapping and obviously
a nice domain layer needs to be good in typing - but I'm quite confused
about your statement that the JGoodies Binding is strongly typed. The
very essence of it is a port from Smalltalk ValueModel Framework - every
value passed along is an Object, no typing at all along the chain. And
the (mighty for bean-like objects) "convenience" layer
(PropertyAdapter/BeanAdapter/PresentationModel) does use reflection as
its only means, String based...

Maybe we should try to agree on a common and verified starting point
before balking around.

Greetings
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Jeanette,

>but I'm quite confused
>about your statement that the JGoodies Binding is strongly
>typed. The
>very essence of it is a port from Smalltalk ValueModel >Framework

There is one ValueModel per Field. So ValueModel is different to JDNC DataModel
which is a much bigger
structure. ValueModels operate at the Field level
not Type level. So generic Value Models do not
cause loss of Type Information.

In Karstens code examples he always knows what Type he is
dealing with. He then binds the specific Fields of the
Type to a Component using a ValueModel. (See pp 50-55 of
the Binding paper - shall we take that as our starting
point).

Putting a generic wrapper round something on a Field
by Field basis when dealing within the
context of a known type is how he gets generic binding within the context of Typed business logic.

so his code goes something like:

Book aBook = getEditedBook(); [strong typing]

ValueModel aValueModel = new PropertyAdaptor(aBook,"available");
[generic bit at Field/property level]

So he is dealing with a Typed Book Object rather
than a Typeless DataModel.

He can then add listeners to the Fields of his
Book - knowing his logic refers to a Book.

Is that common ground?

rgds,
Charles.

Kleopatra

jdnc-interest@javadesktop.org wrote:

okay, I think I'm starting to understand where we differ..

> There is one ValueModel per Field. So ValueModel is different to JDNC DataModel
> which is a much bigger
> structure. ValueModels operate at the Field level
> not Type level. So generic Value Models do not
> cause loss of Type Information.
>

just a minor comment here: I would compare a DataModel to a BeanAdapter
- both handling collections of fields/properties. Another possibility
(for the sake of finding similarities) would be to compare a degenerated
DataModel (one field only) to a ValueModel.

>
> Putting a generic wrapper round something on a Field
> by Field basis when dealing within the
> context of a known type is how he gets generic binding within the context of Typed business logic.
>
> so his code goes something like:
>
> Book aBook = getEditedBook(); [strong typing]
>
> ValueModel aValueModel = new PropertyAdaptor(aBook,"available");
> [generic bit at Field/property level]
>
> So he is dealing with a Typed Book Object rather
> than a Typeless DataModel.
>
> He can then add listeners to the Fields of his
> Book - knowing his logic refers to a Book.
>

agreed - that's in the part of the code which needs to know about the
"Bookishness". My perspective is a bit more on the side of the generics
- once the Book is handed over the fence to the binding area there is
nothing (? maybe that's arguable) that needs to know about the concrete
type.

Expanding on your example: typically we would use a BeanAdapter to get
"appropriate" ValueModels for binding to components in some form.

// Note that the adapter doesn't know anything about
// the type of the adaptee
BeanAdapter adapter = new BeanAdapter(null, true);
// for all properties we want to bind
someComponent = BasicComponentFactory.createComponent(
adapter.getValueModel()

At this point in time, we have to know (from the perspective of binding)

a) some relevant names - they should relate to getters/setters of the
object to bind
b) some type information about the properties so we can choose fitting
components

Only later in code a adapter.setBean(myBook) does the binding to a
concrete object. And then it's possible to call adapter.setBean(myCD)
provided both Book and CD share the set of properties that are bound in
the form - note that Book and CD need _not_ be compatible Types.

So there is (as least as I see it :) much similarity between "binding"
the goodies and the jdnc way: both minimally need a per-field
"name"/"type" pair to prepare a form. Both basically leave it to the
calling code to guarantee that the passed-in type somehow can be mapped
between domain data and component.

Greetings
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Jeanette,

So what you are saying is Datamodel should be replaced
with BeanAdaptor and then everyone should use
SwingEmpire Formbuilder? Just teasing :)

Agree with your line of thought. Where you put the
event listeners in Datamodel/BeanAdaptor or on the
ValueModels?

How confident are you BeanAdaptor would map to
Rowsets?

Charles.

Kleopatra

Charles,

>
> So what you are saying is Datamodel should be replaced
> with BeanAdaptor and then everyone should use
> SwingEmpire Formbuilder? Just teasing :)
>

Certainly I would love everybody to use SwingEmpire FormBuilder - would
increase the probability to pay my rent longer the next two months
But FormBuilder is not about a particular binding, it's about decoupling
different roles in ui-building.

> Agree with your line of thought. Where you put the
> event listeners in Datamodel/BeanAdaptor or on the
> ValueModels?
>

Hmm, seems to evolve as a pattern - don't quite understand what exactly
you mean in the first round :-) Listeners for what?

> How confident are you BeanAdaptor would map to
> Rowsets?

Not to the BeanAdapter as such (it's targeted to objects as of the bean
spec) - but the concept of managing a collection of adapters should map
well enough. For a raw example, there's GTabularDataModelAdapter in my
incubator data package - it adapts ValueModels to the fields of a row in
TabularData.

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

charles.armstrong
Offline
Joined: 2006-02-17

Jeanette,

> Hmm, seems to evolve as a pattern - don't quite
> understand what exactly you mean in the first
> round Listeners for what?

Listeners for changes to the Field values.

In JGoodies they are bound to the ValueModel (the
ValueModel interface contains addListener methods) -
and the consistency between components is done by
using BeanChannels between the ValueModels.

In JDNC the listeners are added at the Datamodel level -
but how do you keep the various Datamodels in
sync? Different Datamodels may specify different views
on the same or related data (e.g. data related by
inverse mappings) - so keeping them in sync will be
more complex than a like-to-like mapping...

Charles.

rbair
Offline
Joined: 2003-07-08

Hi Charles,

> In JDNC the listeners are added at the Datamodel
> level -
> but how do you keep the various Datamodels in
> sync? Different Datamodels may specify different
> views
> on the same or related data (e.g. data related by
> inverse mappings) - so keeping them in sync will be
> more complex than a like-to-like mapping...

I'm not sure if this is what you're saying, but I think I see the problem you're pointing out. Basically, say we have an object of type Person p, and two DataModels -- lets call them A and B. If both of those DataModels are bound to the same Person (in JavaBeanDataModel speak, A.setJavaBean(p), B.setJavaBean(p)), then what happens if A.setValue("firstName", "Richard") is called? Well, the components bound to A will be updated, but the components bound to B won't know that the change has happened. In fact, B won't know the change has happened either.

Ok, this looks like a Bad Thing. What can be done about it? Note that the same issue can exist (quite readily) with RowSets, and its a bit more complicated there since a RowSet could be an actual view from the database, and not contain any kind of information for linking one RowSet's record to another. If JavaBeans had each field set up as a bound property, the JavaBeanDataModel could easily register a listener for each bean it contains, and thus B would be notified of the change that A made.

However, this puts the burden of adding bound properties for beans on the shoulders of the poor Application developer. But, I'd still favor adding this functionality to JavaBeanDataModel and let the developer decide whether it is important or not. I think :)

For RowSets it is not nearly that clear. I had an inhouse RowSet heiarchy that I wrote that didn't have the problem because each Row in the RowSet was stored in a global cache identified by its key fields (which are noted in the RowSetMetaData). So whenever another record with those key fields showed up, I just reused the same Row object, so a change to one Row's field would propogate throughout the program. It only works if the developer doesn't do anything crazy and sticks to more simple select statements, so it falls short of a general solution.

Overall, a complicated looking caveat. Any ideas?

Richard

rbair
Offline
Joined: 2003-07-08

Another thing to consider when designing this binding architecture: currently a single component can only be bound to a single field, or as altered in my incubator code a single component could be bound to an entire DataModel. But what about a single component being bound to many fields, but not necessarily all?

For instance, consider a JLabel that would contain the text "Hello, " where and are both fields in a DataModel. One way to accomplish this would be to have the window/frame/dialog/panel/whatever add a listener to the DataModel for the firstName and lastName fields, so that if either one of them changes then it will call label.setText("Hello, " + dm.getValue("firstName") + " " + dm.getValue("lastName"));

A second approach could be to have a new AbstractBinding constructor take a List or Array of fieldNames and register with each of them. The push/pull semantics might have to change in order to handle multiple fields, but then a custom LabelBinding would be able to set the text of the label just like all other bindings do. This seems the better approach to me, but that's just me :)

Thoughts?

Richard

Amy Fowler

jdnc-interest@javadesktop.org wrote:

> A second approach could be to have a new AbstractBinding constructor take a List or Array of fieldNames and register with each of them. The push/pull semantics might have to change in order to handle multiple fields, but then a custom LabelBinding would be able to set the text of the label just like all other bindings do. This seems the better approach to me, but that's just me :)
>
> Thoughts?

Ooh - I'm intrigued by this. One feature we'd like to support in table
(but it's obviously applicable to the general form case) is in representing
multiple field values in a single column. I like the idea and think we should
experiment with it further!

Aim

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net