synchronous user input: possible?

Hi,
We’re working on a proof of concept to convert an existing application, written in an old programming language for dumb terminals, to java + vaadin, with some nice results so far.
One of the major blockers right now is the “wait” instruction that essentially blocks the screen while showing a question (e.g. “Are You Sure”), waits for a character of input, and returns that character to the application.
Something like
char answer = wait(“are you sure”);
if (answer == ‘Y’) …
So the program logic is blocked until the wait returns, i.e. from the application point-of-view the wait is synchronous.
I always learned that synchronous communication from client to server is not possible, and the only way is to use callbacks.
But here we’re going server to client, and I’m not so sure.
Is there any possibility that this can work, perhaps a second thread doing some talking to the client over Ajax and a second connection. Is there perhaps something in the Vaadin framework that does something similar or that can give me a head start.
Note: it would be next to impossible to alter the logic in the existing application (which we’re converting to Java) to make it use callbacks.
Thanks for any information!
Regards
Geert

OK, found out something already here:
https://vaadin.com/wiki/-/wiki/Main/Enabling%20server%20push
I think this will get me started. Feel free to add any additional thoughts though :wink:
Thanks
Geert

You can still accomplish the same result with asynchronous applications without Push.

look at
ConfirmDialog addon
and its demo application for excample…

I followed the general approach explained in https://vaadin.com/wiki/-/wiki/Main/Enabling%20server%20push
by creating a new thread that pushes a Button to the client. The button is showing while the main thread is blocking. So that’s good.
Initial problem was that the button’s clickhandler would not trigger when clicking the button, causing the main thread to block forever.
Note the main thread is invoked from a RPC method in a custom widget, like this:

public class AutoCompletingTextField extends com.vaadin.ui.TextField {
  private AutoCompletingTextFieldServerRpc rpc = new AutoCompletingTextFieldServerRpc() {
    @Override
    public void controlKey(final int modifiers, final int charcode) {
       // invoke legacy program logic converted to java
       // doing screen updates and occasionally 
       // wait for synchronous user input...
    }
  }
}

I figured the click didn’t arrive on the server because the VaadinSession was still locked by the main thread.
I could work around this by moving everything in the above controlKey() method into a separate thread.
Now the button click does arrive and the main thread continues.
But this obviously circumvents the VaadinSession locking, resulting in all kinds of subtle threading issues, like
ConcurrentModificationExceptions and IllegalStateExceptions.

Is there a proper way to release the lock temporarily (i.e. during the time of the synchronous input) so that the button click can be received?
Or can I receive the click on another “channel” so to speak, so that the main thread’s lock doesn’t hinder?
Thanks for any advice.
Geert

If at all possible, please do not block any request handling threads for very long. Requests should be handled quickly and the thread released back to the server’s internal pool as soon as possible to wait for the next request to arrive. Instead, you should move the main application logic to a background thread that
can
block waiting for a request thread to signal that a user event occurred, for instance using a future or a condition variable.

99.99% of the “user code” is in fact perfectly reasonable to put in the event handler code (e.g. validating input, fetching from DB, updating screen fields…)
It’s only these blocking keyboard reads (style “are you sure”, or “error, (a)bort, (r)etry”) that interfere with this scheme and that assume totally sequential and synchronous processing.
I guess there is no way to solve this that would not block one of the request handling threads for (possibly) very long, so we will simply need to rewrite the generated user code at those places, to use a callback here.
Thanks for your help.

I would say that you should break that code into multiple parts…

Example synchronous:



  someMethod() {
       doStuff
       response =readkeyboard();
       if (response == responseA) {
           doStufA;
       } else if (response == responseB) {
           doStufB;
       } else {
           doStufC;
       }
  }

example asynchronous:




  Choice  choiceA = new Choice("are you sure");
  Choice  choiceB = new Choice("error, (a)bort");
  Choice  choiceC = new Choice("error, (r)etry");

  someMethod() {
       doStuff;
       final ChoiceDialogue dialogue = new ChoiceDialogue("Confirm ", "Some message", new ChoiceDialogue.Choice[]{choiceA, choiceB, choiceC});
       dialogue.addChoiceListener(this)
       UI.getCurrent().addWindow(dialogue);
  }
 
 @Override
  public void choiceSelected(final Choice choice) {    
       if (choice == choiceA) {
           doStufA;
       } else if (response == choiceB) {
           doStufB;
       } else {
           doStufC;
       }
  }


or even without splitting the code up into separate methods use



  Choice  choiceA = new Choice("are you sure");
  Choice  choiceB = new Choice("error, (a)bort");
  Choice  choiceC = new Choice("error, (r)etry");

  someMethod() {
       doStuff;
       final ChoiceDialogue dialogue = new ChoiceDialogue("Confirm ", "Some message", new ChoiceDialogue.Choice[]{choiceA, choiceB, choiceC});
       dialogue.addChoiceListener(new ChoiceDialogue.ChoiceListener() {
         @Override
         public void choiceSelected(final Choice choice) {    
            if (choice == choiceA) {
              doStufA;
            } else if (response == choiceB) {
              doStufB;
            } else {
              doStufC;
            }
         }
        });
       UI.getCurrent().addWindow(dialogue);
  }

13195.java (4.11 KB)