Bug 237857 - [DataBinding] Extend the MultiValidator class to support asynchronous validations
Summary: [DataBinding] Extend the MultiValidator class to support asynchronous validat...
Status: CLOSED WONTFIX
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.4   Edit
Hardware: All All
: P3 enhancement (vote)
Target Milestone: ---   Edit
Assignee: Platform UI Triaged CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on: 251559
Blocks: 248868
  Show dependency tree
 
Reported: 2008-06-19 18:08 EDT by Ovidio Mallo CLA
Modified: 2019-11-27 07:39 EST (History)
4 users (show)

See Also:


Attachments
proposed patch along with some unit tests and a snippet (17.76 KB, patch)
2008-06-20 12:55 EDT, Ovidio Mallo CLA
no flags Details | Diff
updated patch with tests and a snippet (17.91 KB, patch)
2008-07-03 15:55 EDT, Ovidio Mallo CLA
no flags Details | Diff
Latest patch using status callback interface (27.97 KB, patch)
2008-07-04 00:18 EDT, Matthew Hall CLA
no flags Details | Diff
Latest patch using status callback interface (27.97 KB, patch)
2008-07-04 00:21 EDT, Matthew Hall CLA
no flags Details | Diff
extension of Matthew's patch to support cancellation along with unit tests (18.07 KB, patch)
2008-10-12 10:10 EDT, Ovidio Mallo CLA
no flags Details | Diff
extension of Matthew's patch to support cancellation along with unit tests (18.07 KB, patch)
2008-10-12 10:12 EDT, Ovidio Mallo CLA
no flags Details | Diff
Patch merging my last patch with HEAD (26.32 KB, patch)
2008-10-14 13:13 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (24.26 KB, application/octet-stream)
2008-10-14 13:13 EDT, Matthew Hall CLA
no flags Details
Fixed validated observable taking invalid values (63.39 KB, patch)
2008-10-14 20:13 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (179.37 KB, application/octet-stream)
2008-10-14 20:13 EDT, Matthew Hall CLA
no flags Details
Update (57.52 KB, patch)
2008-10-16 14:34 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (21.46 KB, application/octet-stream)
2008-10-16 14:34 EDT, Matthew Hall CLA
no flags Details
Update (76.36 KB, patch)
2008-10-16 16:56 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (101.32 KB, application/octet-stream)
2008-10-16 16:56 EDT, Matthew Hall CLA
no flags Details
Merged with Ovidio's patch (85.92 KB, patch)
2008-10-16 17:16 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (113.47 KB, application/octet-stream)
2008-10-16 17:16 EDT, Matthew Hall CLA
no flags Details
Update (88.92 KB, patch)
2008-10-17 12:19 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (52.70 KB, application/octet-stream)
2008-10-17 12:19 EDT, Matthew Hall CLA
no flags Details
Update (87.60 KB, patch)
2008-10-17 14:11 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (18.47 KB, application/octet-stream)
2008-10-17 14:11 EDT, Matthew Hall CLA
no flags Details
Update (88.70 KB, patch)
2008-10-20 17:26 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (20.88 KB, application/octet-stream)
2008-10-20 17:26 EDT, Matthew Hall CLA
no flags Details
Experiment (87.92 KB, patch)
2008-10-21 13:20 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (41.42 KB, application/octet-stream)
2008-10-21 13:21 EDT, Matthew Hall CLA
no flags Details
Experimental: automatic progress bars (113.88 KB, patch)
2008-10-22 14:08 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (210.68 KB, application/octet-stream)
2008-10-22 14:08 EDT, Matthew Hall CLA
no flags Details
Experiment (109.04 KB, patch)
2008-10-22 16:16 EDT, Matthew Hall CLA
no flags Details | Diff
mylyn/context/zip (275.98 KB, application/octet-stream)
2008-10-22 16:16 EDT, Matthew Hall CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ovidio Mallo CLA 2008-06-19 18:08:48 EDT
It would be nice if the MultiValidator class would support asynchronous validations. To that end, an adequate API should be added to allow for subclasses to notify the MultiValidator about a validation being executed asynchronously. Ideally, whenever an asynchronous validation is pending, the MultiValidator should set the validation status observable to be stale.
Comment 1 Ovidio Mallo CLA 2008-06-20 12:55:19 EDT
Created attachment 105515 [details]
proposed patch along with some unit tests and a snippet

The proposed patch introduces the pair of methods enterStale()/exitStale(IStatus) on the MultiValidator class.

enterStale() should be called by subclasses whenever an asynchronous validation is initiated and leads to the validation status observable of the MultiValidator to become stale.

As soon as the asynchronous validation terminates, subclasses should call exitStale(IStatus) and pass the result of the validation to the MultiValidator which in turn sets the validation status observable to be not stale anymore.

For synchronous validations, there is no need to use the above methods.

When starting an asynchronous validation, the result of the already existing validate method can be used as a temporary validation result which is used while performing the actual validation.

Note: The patch also includes the trivial fix for bug #237163 which is required to get the staleness state right. If wanting to move this fix out of the patch, please just remove the single tiny change in the UnmodifiableObservableValue class.
Comment 2 Ovidio Mallo CLA 2008-06-25 17:22:45 EDT
By the way, the proposed patch only contains adaptations to the MultiValidator class. Of course, the ValidatedObservable(Value|Set|List|Map)s should also be adapted to track the staleness of the validation status observable. Matthew Hall has already done so in a patch contributed to the predecessor of this bug, bug #233191, where he is providing an alternative patch to the one posted here.
Comment 3 Ovidio Mallo CLA 2008-07-03 15:55:58 EDT
Created attachment 106506 [details]
updated patch with tests and a snippet

The original patch did not apply anymore due to some recent commits so I have merged the code and I'm providing an updated version of the patch. I've also dropped the fix for bug #237163 which was contained in the previous patch since that fix has already been released to HEAD in the meanwhile.
Comment 4 Matthew Hall CLA 2008-07-04 00:18:49 EDT
Created attachment 106541 [details]
Latest patch using status callback interface

I am still of the mind that a callback is preferable to an enterStale() / exitStale() structure, for the following reasons:
* The validate() method as it exists currently is expected to return the current validation status.  In the enterStale() / exitStale() paradigm the returned result may or may not be relevant depending on whether the status is calculated asynchronously.  In the callback paradigm, the user is expected to either override the validate() method for synchronous validation or validate(Callback) for asynchronous validation.  I am very uncomfortable with diluting the contract of existing API, and the change I have advocated avoids this.
* The revalidate() routine, as of this patch, makes the validation status observable stale only if the callback hasn't been called by the time the validate method returns.  So the client doesn't have to worry about staleness.
* The callback implementation executes the status update on the correct realm, so clients don't have to worry about realms either.
* Using a separate callback object allows us to introduce a cancel option on the callback, in the case where a dependency observable changes while validation is still pending.  The enterStale() / exitStale() procedure has no context attached from validation to validation--it is even conceivable, without a cancel option, that the current validation process could complete before an obsolete validation process, and that the obsolete process wipes out the correct validation status.
Comment 5 Matthew Hall CLA 2008-07-04 00:21:46 EDT
Created attachment 106542 [details]
Latest patch using status callback interface

I am still of the mind that a callback is preferable to an enterStale() / exitStale() structure, for the following reasons:
* The validate() method as it exists currently is expected to return the current validation status.  In the enterStale() / exitStale() paradigm the returned result may or may not be relevant depending on whether the status is calculated asynchronously.  In the callback paradigm, the user is expected to either override the validate() method for synchronous validation or validate(Callback) for asynchronous validation.  I am very uncomfortable with diluting the contract of existing API, and the change I have advocated avoids this.
* The revalidate() routine, as of this patch, makes the validation status observable stale only if the callback hasn't been called by the time the validate method returns.  So the client doesn't have to worry about staleness.
* The callback implementation executes the status update on the correct realm, so clients don't have to worry about realms either.
* Using a separate callback object allows us to introduce a cancel option on the callback, in the case where a dependency observable changes while validation is still pending.  The enterStale() / exitStale() procedure has no context attached from validation to validation--it is even conceivable, without a cancel option, that the current validation process could complete before an obsolete validation process, and that the obsolete process wipes out the correct validation status.
Comment 6 Ovidio Mallo CLA 2008-07-04 01:31:26 EDT
(In reply to comment #5)
> Created an attachment (id=106542) [details]
> Latest patch using status callback interface
> 
> I am still of the mind that a callback is preferable to an enterStale() /
> exitStale() structure, for the following reasons:
> * The validate() method as it exists currently is expected to return the
> current validation status.  In the enterStale() / exitStale() paradigm the
> returned result may or may not be relevant depending on whether the status is
> calculated asynchronously.  In the callback paradigm, the user is expected to
> either override the validate() method for synchronous validation or
> validate(Callback) for asynchronous validation.  I am very uncomfortable with
> diluting the contract of existing API, and the change I have advocated avoids
> this.
You're right here regarding the validation status returned by validate() while a validation is pending since in practice you will probably to keep the last validation status while performing a validation asynchronously. This could also be done with my implementation by checking the stale flag and not setting the validation if the flag is true but this is obviously not so nice.

> * The revalidate() routine, as of this patch, makes the validation status
> observable stale only if the callback hasn't been called by the time the
> validate method returns.  So the client doesn't have to worry about staleness.
That's great as I that was my main concern about the callback implementation!

> * Using a separate callback object allows us to introduce a cancel option on
> the callback, in the case where a dependency observable changes while
> validation is still pending.  The enterStale() / exitStale() procedure has no
> context attached from validation to validation--it is even conceivable, without
> a cancel option, that the current validation process could complete before an
> obsolete validation process, and that the obsolete process wipes out the
> correct validation status.
The canceling in my implementation was implicit in the sense that whenever you trigger the validate() method any potentially pending validation was canceled which is illustrated in the snippet but with the callback approach you may be able to do this in the MultiValidator which is good.

So, all in all, you seem to have convinced me of the callback approach :-).
Comment 7 Ovidio Mallo CLA 2008-08-31 13:27:44 EDT
Matthew, I would suggest to move the part of your patch related to the staleness of the ValidatedObservable(Value|Set|List|Map) to a separate bug as this is a different issue. What do you think?

BTW, if you want me to contribute something to your patch like e.g. some unit tests for the staleness of the validated observables or the like, just let me know.
Comment 8 Matthew Hall CLA 2008-09-02 11:43:00 EDT
(In reply to comment #7)
> BTW, if you want me to contribute something to your patch like e.g. some unit
> tests for the staleness of the validated observables or the like, just let me
> know.

Consider this a standing invitation to submit any patches for any bug, which you think may be useful.  Unit tests are most definitely welcome.
Comment 9 Matthew Hall CLA 2008-09-02 13:58:02 EDT
Planned for 3.5M2
Comment 10 Ovidio Mallo CLA 2008-09-28 12:08:45 EDT
Matthew, sorry for my rather long absence but I have been a bit busy in the last few weeks. In any case, I have written some unit tests for the validated observables to track the staleness of the validation status observable. I've found some minor issues which prevented the validated observables from becoming non-stale. This should be fixed in the new patch and captured by the unit tests. I've attached the patch to a new bug: bug #248868.
Comment 11 Ovidio Mallo CLA 2008-10-12 10:10:42 EDT
Created attachment 114899 [details]
extension of Matthew's patch to support cancellation along with unit tests

Matthew, I have extended your patch for the asynchronous validation in order to make it support the cancellation of obsolete validations. I had also to adapt a few things due to bug #238909 which requires that the dependencies are up-to-date before setting a new validation status. Please see the code documentation for more details. The patch also includes some unit tests.
Comment 12 Ovidio Mallo CLA 2008-10-12 10:12:41 EDT
Created attachment 114900 [details]
extension of Matthew's patch to support cancellation along with unit tests

Matthew, I have extended your patch for the asynchronous validation in order to make it support the cancellation of obsolete validations. I had also to adapt a few things due to bug #238909 which requires that the dependencies are up-to-date before setting a new validation status. Please see the code documentation for more details. The patch also includes some unit tests.
Comment 13 Matthew Hall CLA 2008-10-13 01:03:32 EDT
Taking ownership, retargeting for 3.5M3
Comment 14 Matthew Hall CLA 2008-10-13 13:11:54 EDT
Ovidio: All your improvements are great and I would commit them as is, however the patch is now over the LOC threshold so unless we can determine how many lines of code are yours and how many are mine, we will have to submit this to IPZilla for review first.  I took a stab at this but got lost quickly :-/
Comment 15 Ovidio Mallo CLA 2008-10-13 15:26:57 EDT
Matthew, if I simply remove the IStatusCallback interface and your new validate(IStatusCallback) method (along with its extensive JavaDoc) from the patch, Eclipse already reports 253 added and 21 removed lines, including all the unit tests (these alone make up 158 lines). So here I'd say that the patch as a whole (including tests) would definitely fall below the 250 LOC threshold if also removing other code I've taken over from your patch.
Comment 16 Matthew Hall CLA 2008-10-13 16:04:49 EDT
(In reply to comment #15)
> Matthew, if I simply remove the IStatusCallback interface and your new
> validate(IStatusCallback) method (along with its extensive JavaDoc) from the
> patch, Eclipse already reports 253 added and 21 removed lines, including all
> the unit tests (these alone make up 158 lines). So here I'd say that the patch
> as a whole (including tests) would definitely fall below the 250 LOC threshold
> if also removing other code I've taken over from your patch.

Okay, I see that you renamed StatusCallback in my patch to IStatusCallback (a good change, but it still accounts for at least a few LOC).  To be safe I'm going to have to do my diligence on this and scrutinize each line to determine who owns what.  If we come in below the threshold then I'll commit the patch as is (but will add attribution comments to the patch).  If we're above the threshold then I'll submit a contribution review to IPZilla and we'll go from there.

Matthew
Comment 17 Matthew Hall CLA 2008-10-14 11:26:11 EDT
I've been thinking that IStatusCallback should have an isCanceled() method so that long-running validators can abort on their own, instead of just having MultiValidator ignore the status when they complete.
Comment 18 Matthew Hall CLA 2008-10-14 12:41:05 EDT
I had to merge my patch with recent changes to HEAD before I could run a comparison.  Here is my tally:

Lines of code tally:
* MultiValidator - 85 lines different from my merged version (determined this renaming my version to MultiValidator2 and side by side with MultiValidator from Ovidio's patch).
* MultiValidatorTest - 158 new lines
* IStatusCallback - 3 lines

For a total of 246 lines--just under the wire.  :)

I will submit my post-merge patch just for good measure.

I've also been thinking that we might want to allow a validator to call handleStatus multiple times.  This would allow an asynchronous validator to inform the user show the current status of the validator as it is running:

public void validate(final IStatusCallback callback) {
  new Thread(new Runnable() {
    public void run() {
      callback.handleStatus(ValidationStatus.cancel("Reticulating splines"));
      Spline[] reticulated = reticulateSplines();
      IStatus status = validateSplines(reticulated);
      callback.handleStatus(status);
    }
  }).start();
}

Perhaps there should be a boolean parameter indicating whether validation is complete, or a separate method for intermediate "progress" statuses.

Thoughts?
Comment 19 Matthew Hall CLA 2008-10-14 13:13:10 EDT
Created attachment 115064 [details]
Patch merging my last patch with HEAD
Comment 20 Matthew Hall CLA 2008-10-14 13:13:14 EDT
Created attachment 115065 [details]
mylyn/context/zip
Comment 21 Matthew Hall CLA 2008-10-14 17:27:37 EDT
There's a problem with the validated observables when you use asynchronous validators.  Run Snippet021MultiFieldValidation and do the following:

1. Edit the fields on the left so they are both even
2. Add some addends on the right so they equal 5 (the default sum)
3. Note that the status is ok.  Note also that all model fields are now equal to their respective target fields
4. Type a large number into the sum field.
5. After the 1-second delay the status line changes to an error message, as expected.
6. Note that the bad data from the sum field has been copied to model.  This is because the validation status is still OK by the time ValidatedObservableValue receives the change event.

The problem is that the ValidatedObservableValue listeners are getting notified before MultiValidator about the change.  So we do not have a chance to stale the validation status before the validated observables update themselves.

The fix I'm attempting is to trigger a revalidation any time the observeValidated* observable observable a change in its target, and to use asyncExec() to avoid redundant revalidations.
Comment 22 Matthew Hall CLA 2008-10-14 20:13:45 EDT
Created attachment 115099 [details]
Fixed validated observable taking invalid values

This patch does not yet incorporate Ovidio's changes
Comment 23 Matthew Hall CLA 2008-10-14 20:13:50 EDT
Created attachment 115100 [details]
mylyn/context/zip
Comment 24 Ovidio Mallo CLA 2008-10-15 16:58:23 EDT
(In reply to comment #17)
> I've been thinking that IStatusCallback should have an isCanceled() method so
> that long-running validators can abort on their own, instead of just having
> MultiValidator ignore the status when they complete.
That's definitely a good idea.

(In reply to comment #18)
> I had to merge my patch with recent changes to HEAD before I could run a
> comparison.  Here is my tally:
> [...]
> For a total of 246 lines--just under the wire.  :)
:-)

> I've also been thinking that we might want to allow a validator to call
> handleStatus multiple times.  This would allow an asynchronous validator to
> inform the user show the current status of the validator as it is running:
> [...]
> Perhaps there should be a boolean parameter indicating whether validation is
> complete, or a separate method for intermediate "progress" statuses.
I think that it would be good to be able to at least (optionally) provide one temporary validation status which is used while the validation is being performed asynchronously. This simpler use case could e.g. be supported by letting the new MultiValidator#validate(IStatusCallback) method return an IStatus which, if non-null, could be used as a temporary validation status for asynchronous validations:

  public abstract class MultiValidator {
    protected IStatus validate(IStatusCallback);
  }

What you're proposing is even more flexible since then you would even be able to pass back multiple temporary validation statuses which might also be useful in practice. In that case, I think I would introduce a subinterface of IStatusCallback declaring an additional method for that purpose since the IStatusCallback interface might be usable for other things in future in which having intermediate statuses does not make sense. So, I would do something like:

  public interface IProgressStatusCallback extends IStatusCallback {
    public void handleProgressStatus(IStatus);
  }

  public abstract class MultiValidator {
    public void validate(IProgressStatusCallback);
  }

However, I think that both APIs above have the weakness that clients may mis-use them by e.g. returning a temporary validation status even though the validation is not asynchronous (case 1) or by calling the different callback methods in the wrong order (case 2).
Comment 25 Matthew Hall CLA 2008-10-16 14:34:31 EDT
Created attachment 115289 [details]
Update

In the previous patch, MultiValidator was doing revalidation in a Realm.asyncExec().  This had the side effect that you had to pump the event loop to get the validator to run.  This patch fixes the problem mentioned in comment #21 without doing an asyncExec().
Comment 26 Matthew Hall CLA 2008-10-16 14:34:34 EDT
Created attachment 115290 [details]
mylyn/context/zip
Comment 27 Ovidio Mallo CLA 2008-10-16 16:29:56 EDT
(In reply to comment #21)
> [...]
> The problem is that the ValidatedObservableValue listeners are getting notified
> before MultiValidator about the change.  So we do not have a chance to stale
> the validation status before the validated observables update themselves.
It seems to me as if this problem is not limited to the new staleness feature but it could also happen with the normal change events. The reason why the problem didn't arise so far probably is that the MultiValidator registers itself as a plain change listener to its dependencies. Since the validated observables attach themselves as more specific value/list/set/map change listeners and those listeners are always notified about changes after the normal change listeners, nothing bad ever happened. Actually, it was interesting to debug this through. In any case, it's good that you have noticed this, Matthew.
Comment 28 Matthew Hall CLA 2008-10-16 16:56:10 EDT
Created attachment 115313 [details]
Update

Added IStatusCallback.isCanceled().  The snippet has been overhauled and split into two pages: the first for synchronous validation, and the second for asynchronous validation
Comment 29 Matthew Hall CLA 2008-10-16 16:56:17 EDT
Created attachment 115314 [details]
mylyn/context/zip
Comment 30 Matthew Hall CLA 2008-10-16 17:16:39 EDT
Created attachment 115315 [details]
Merged with Ovidio's patch

Merged included 30-40 lines of Ovidio's code in MultiValidator (mostly comments), and 158 lines of code from MultiValidatorTest.

Boris, +1?
Comment 31 Matthew Hall CLA 2008-10-16 17:16:44 EDT
Created attachment 115316 [details]
mylyn/context/zip
Comment 32 Matthew Hall CLA 2008-10-16 18:57:54 EDT
I have a p(In reply to comment #27)
> (In reply to comment #21)
> > [...]
> > The problem is that the ValidatedObservableValue listeners are getting notified
> > before MultiValidator about the change.  So we do not have a chance to stale
> > the validation status before the validated observables update themselves.
> It seems to me as if this problem is not limited to the new staleness feature
> but it could also happen with the normal change events.

The way I got around this was to trigger a revalidation on the multivalidator when the validated observable detects a change to its target observable.  If the validation status is stale by the time revalidation returns then an asynchronous validation is taking place and the validated observable is made dirty.
Comment 33 Matthew Hall CLA 2008-10-16 18:58:19 EDT
Boris, +1 for latest patch?
Comment 34 Ovidio Mallo CLA 2008-10-17 11:14:41 EDT
Matthew, I had a brief look at your patch an here are a few comments:

1. Just a detail: In the method ValidationCallback#handleStatus() (line 280) you should probably be using the "realmSnapshot" variable instead of "realm" in the expression "realm.isCurrent()".

2. Regarding the intermediate status' in your snippet, it seems as if after the first intermediate status returned to the callback, the MultiValidator's validation already becomes non-stale which should not happen. I guess there's really need for a second method or a flag to differentiate between intermediary and the final status.

3. Why do you -always- make the MultiValidator's validation stale inside the MultiValidator#revalidate() method?
Comment 35 Matthew Hall CLA 2008-10-17 11:25:26 EDT
(In reply to comment #34)
> 1. Just a detail: In the method ValidationCallback#handleStatus() (line 280)
> you should probably be using the "realmSnapshot" variable instead of "realm" in
> the expression "realm.isCurrent()".

I'll fix that, thanks for catching that.

> 2. Regarding the intermediate status' in your snippet, it seems as if after the
> first intermediate status returned to the callback, the MultiValidator's
> validation already becomes non-stale which should not happen. I guess there's
> really need for a second method or a flag to differentiate between intermediary
> and the final status.

My thought was that an intermediate status should always be of severity IStatus.CANCEL (I should probably document this in validate(IStatusCallback) javadocs).  This ensures that the validation status is not considered valid by the validated observables, and thus they will not update from their targets yet.  If you think this is not explicit enough then let's discuss what the API would look like.

> 3. Why do you -always- make the MultiValidator's validation stale inside the
> MultiValidator#revalidate() method?

Good point.  We could change it to be stale only if a status has not been received before returning.
Comment 36 Matthew Hall CLA 2008-10-17 12:19:28 EDT
Created attachment 115418 [details]
Update

Fixed problems mentioned in points 1 and 3 of comment #34.  Also added fix to avoid duplicate revalidations when a dependency is also the target of a validated observable
Comment 37 Matthew Hall CLA 2008-10-17 12:19:33 EDT
Created attachment 115419 [details]
mylyn/context/zip
Comment 38 Boris Bokowski CLA 2008-10-17 12:48:19 EDT
Running the snippet causes a NPE on the first page:

Exception in thread "Thread-0" java.lang.NullPointerException
        at
org.eclipse.jface.examples.databinding.snippets.Snippet021MultiFieldValidation$6.run(Snippet021MultiFieldValidation.java:320)
        at java.lang.Thread.run(Thread.java:619)

Also, I am not happy with isCanceled() on IStatusCallback, and the fact that
you use callback.handleStatus(ValidationStatus.cancel("Revalidating in " +
count)) to report progress. It looks like validate() should take an
IProgressMonitor and an IStatusCallback (without the isCanceled), or a subclass
of IProgressMonitor that adds the handleStatus() method.
Comment 39 Matthew Hall CLA 2008-10-17 14:11:26 EDT
Created attachment 115438 [details]
Update

Fixed NPE in snippet--it was actually being thrown from the asynchronous validator's thread.
Comment 40 Matthew Hall CLA 2008-10-17 14:11:30 EDT
Created attachment 115439 [details]
mylyn/context/zip
Comment 41 Matthew Hall CLA 2008-10-20 17:26:43 EDT
Created attachment 115630 [details]
Update

Modified snippet to use wizardPage.getContainer().exec(true, false, runnable) to spawn async validation instead of new Thread(runnable).start().  I've also changed the timings to make the progress bar more fluid.

One major drawback is that WizardDialog automatically disables all controls on the page while the forked task is running.  The behavior we'd like to see is for the next and finish buttons to disable and to show the progress bar, but otherwise leave the UI intact so the user can continue to interact with the form.  Any changes to the UI while asynchronous validation is running should cancel the current validation request and spawn a new one.

The goal with all this is to let *PageSupport users to get free progress monitor updates when the using asynchronous validation in MultiValidator.
Comment 42 Matthew Hall CLA 2008-10-20 17:26:54 EDT
Created attachment 115631 [details]
mylyn/context/zip
Comment 43 Matthew Hall CLA 2008-10-21 13:20:56 EDT
Created attachment 115720 [details]
Experiment

Reverted to using WizardDialog.run().  Adding IStatusCallback.handleMessage(String)
Comment 44 Matthew Hall CLA 2008-10-21 13:21:03 EDT
Created attachment 115721 [details]
mylyn/context/zip
Comment 45 Ovidio Mallo CLA 2008-10-21 17:40:23 EDT
(In reply to comment #38)
> [...]
> Also, I am not happy with isCanceled() on IStatusCallback, and the fact that
> you use callback.handleStatus(ValidationStatus.cancel("Revalidating in " +
> count)) to report progress. It looks like validate() should take an
> IProgressMonitor and an IStatusCallback (without the isCanceled), or a subclass
> of IProgressMonitor that adds the handleStatus() method.
Boris, how did you intend letting clients report progress during validation? Would you use the task methods on the IProgressMonitor or simply allow clients to call IStatusCallback#handleStatus(IStatus) multiple times until IProgressMonitor#done() is finally called to terminate the validation?

I personally think that the IProgressMonitor interface has a few methods which do not naturally apply to the MultiValidator context which might be a bit confusing so I think I would rather try to define some subinterface of IStatusCallback which introduces an isCanceled() method as well as a second method for explicitly reporting intermediary validation statuses.

What seems important to me is:
* If introducing an IStatusCallback interface, I would try to only give it a handleStatus(IStatus) method. Other things like progress statuses should be placed in a subinterface since a plain IStatusCallback interface may be used at other points in future where such "special features" do not make sense.
* If supporting intermediary statuses in the MultiValidator during an asynchronous validation, the MultiValidator should remain stale as long as the final status is not received, even if the intermediary status is of type CANCEL/ERROR since I think that the distinction between "invalid" and "stale" is important. This implies that we need an explicit distinction between some intermediary status and the final one.
Comment 46 Matthew Hall CLA 2008-10-22 10:47:16 EDT
(In reply to comment #45)
> Boris, how did you intend letting clients report progress during validation?
> Would you use the task methods on the IProgressMonitor or simply allow clients
> to call IStatusCallback#handleStatus(IStatus) multiple times until
> IProgressMonitor#done() is finally called to terminate the validation?

The client would be expected to pass progress messages to the IProgressMonitor, and pass the final result to the IStatusCallback.  The idea is to translate status messages in the IProgressMonitor into stale events (with the progress information embedded) on the validation status observable.  With progress information integrated into StaleEvents, we could then change WizardPageSupport so that stale events on the validation status observables translate into automatic management of the wizard's progress bar.

> I personally think that the IProgressMonitor interface has a few methods which
> do not naturally apply to the MultiValidator context which might be a bit
> confusing so I think I would rather try to define some subinterface of
> IStatusCallback which introduces an isCanceled() method as well as a second
> method for explicitly reporting intermediary validation statuses.

I can see it both ways.  However the possibility to get progress bars for free in the wizard dialog is very encouraging, and one that would benefit many Eclipse projects.  So we're investigating to see how well it would work.

> What seems important to me is:
> * If introducing an IStatusCallback interface, I would try to only give it a
> handleStatus(IStatus) method. Other things like progress statuses should be
> placed in a subinterface since a plain IStatusCallback interface may be used at
> other points in future where such "special features" do not make sense.

I'm actually looking at two possibilities:
* Pass both an IStatusCallback (with a single handleStatus method) and an IProgressMonitor to the validate() method
* Make IStatusCallback a subinterface of IProgressMonitor (IStatusMonitor?) and just pass that one object in.

> * If supporting intermediary statuses in the MultiValidator during an
> asynchronous validation, the MultiValidator should remain stale as long as the
> final status is not received, even if the intermediary status is of type
> CANCEL/ERROR since I think that the distinction between "invalid" and "stale" is
> important. This implies that we need an explicit distinction between some
> intermediary status and the final one.

We are planning to put intermediate status in the StaleEvent, so intermediate status messages would implicitly stale the validation status observable.
Comment 47 Matthew Hall CLA 2008-10-22 14:08:14 EDT
Created attachment 115840 [details]
Experimental: automatic progress bars

The recent changes in this page are somewhat sloppy, but they work.  Boris, I need a critical eye on everything in this patch related to IProgressMonitor, particularly in WizardPageSupport.  I had to do a lot of weird stuff to compensate for the fact that WizardDialog.run() doesn't give you an IProgressMonitor to send updates to until the forked thread calls my run() method.

A few hiccups with the current state of this patch:
* The first time asynchronous validation runs, only the subtask label of the progress monitor part is visible.  On all subsequent validations the part is fully visible as expected.
* Still no way to keep the UI enabled while asynchronous validation is running.
Comment 48 Matthew Hall CLA 2008-10-22 14:08:24 EDT
Created attachment 115841 [details]
mylyn/context/zip
Comment 49 Matthew Hall CLA 2008-10-22 16:16:48 EDT
Created attachment 115861 [details]
Experiment

Removed observable-to-progress monitor mapping.  This is simpler but has its own set of problems (i.e. what if there are two multivalidators running concurrently)
Comment 50 Matthew Hall CLA 2008-10-22 16:16:55 EDT
Created attachment 115862 [details]
mylyn/context/zip
Comment 51 Matthew Hall CLA 2008-12-09 15:42:49 EST
Moving to M5
Comment 52 Matthew Hall CLA 2009-01-20 19:23:28 EST
Retargeting to 3.5M6
Comment 53 Matthew Hall CLA 2009-03-06 19:15:24 EST
We are out of time for 3.5.  Sorry.
Comment 54 Lars Vogel CLA 2019-11-27 07:39:36 EST
This bug hasn't had any activity in quite some time. Maybe the problem got
resolved, was a duplicate of something else, or became less pressing for some
reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it.
The information can be, for example, that the problem still occurs, that you
still want the feature, that more information is needed, or that the bug is
(for whatever reason) no longer relevant.

If the bug is still relevant, please remove the stalebug whiteboard tag.