As part of the metamodel work, one of things I am working on is redesigning
the old notion of a "second pass" to be more efficient. For those not
familiar, this represents a piece of processing that needs to be delayed
until after another piece of processing is done. For example, processing a
composite identifier metadata for an entity might depend on the identifier
metadata for another entity being processed first.
"second pass" was essentially one big bucket. In the new design I am
trying to categorize or segment these things better, so we have different
buckets (one for identifier metadata completion, one for attribute Type
metadata completion, etc).
Not to get too involved, but essentially a bucket is a List of "watchers"
for specific "happenings" (I think of them as events, but am trying to
avoid that terminology for now). E.g., take the "identifier metadata
completion" bucket. As we complete the binding of the identifier metadata
for an entity, we fire off a notification of that happening. The watchers
can then react to that notification.
The implementation of this is a List of watchers, as I said, which is
iterated over for each notification. So here comes the trickiness. As
each watcher is finished it needs to be removed from the list of watchers.
And a watcher could in turn kick off a new notification (for it completing
whatever it represents). So in the initial impl I ran into
ConcurrentModificationException problems.
I went ahead and made it work just to move forward. But I wanted to circle
back and design this "right"; so I wanted to get others involved to see if
anyone had thoughts or better ideas.
Here is a simple example to use as a basis for discussion: consider the
entity Customer and Order. Customer has a simple identifier, whereas Order
has a composite identifier made up of (1) FK to Customer and (2) a order
number. We need the identifier metadata for Customer to be completely
bound before we can process the identifier metadata for Order. That is the
crux of the problem to be solved. Its an ordering concern. If the
metadata for the Customer entity is processed first, no big deal. But of
course we can't really control that (putting the onus back on the user here
is fugly). So we need to account for the case where metadata for the Order
entity is processed first. This kind of timing thing is the reason for
second passes and these new notifications. The idea in the new design is
that we would register a watcher for Order which waits for the notification
that Customer identifier metadata has been finished. As the identifier for
each entity is completed, that process fires off a notification of that
fact. So as the identifier metadata for Customer is finished, the process
fires off a notification which makes its way back to the watcher for Order.
Processing can now bind the identifier metadata for Order, and in turn
fire off its notification.
The trouble here, in the iteration impl, is that we are still iterating
over the "identifier metadata completion" notification, so there is an
active iterator over the list. When performing the Order-watcher
processing, since it no longer needs to watch, we would ideally remove it.
Initially I had simply exposed a deregistration method that removed the
watcher from the list, but that ran into the problems with CME. What I do
currently instead is to expose a method on the watcher contract for the
watcher to say whether its work is done, and if so use the Iterator to
remove it. That works, just not sure its the best option.
Another consideration is the iteration over non-interested watchers. This
may be a non-issue, not sure yet. Currently watchers simply register as
being interested in identifier metadata completion notifications, not
notifications for completion of identifier metadata for specific entity(s).
So on the con side, the List would become a Map and we'd need a key
object. On the plus side we'd avoid the iteration and CME problems
altogether.