Moving from ZK event thread to the recommended servlet thread. Part I.

Blog
26/7/15
Lluís Turró Cutiller
303
0
zk

As you already imagined, migrating code to the recommended servlet thread is a nightmare. Anyway, since ZK deprecated the event thread, I thought reasonable to start the migration now. Here are some issues I encountered while doing so.

This is not a replacement to ZK migration guide (ZK Event Threads), but an extension taken from a real-world application.

Close without saving?

Are you capturing the onClose event of a container to prevent user from exiting without saving its content?

This piece of code does capture the event, ask user if really want to exit loosing modifications. If user says no, the event method stopPropagation() is called and the tab remains open.

Tab tab = container.getLinkedTab();
tab.addEventListener(9000, Events.ON_CLOSE, new EventListener() {
  @Override
  public void onEvent(Event event) throws Exception {
    if(modified) {
      if(!ZkossUtils.confirmMessage(ElLabel.getLabel("lCloseWithoutSaving"))) {
         event.stopPropagation();
      }
    }
  }
});

...

public static boolean confirmMessage(String message) {
  if(Messagebox.show(message, ElLabel.getLabel("lQuestion"),
           Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION) == Messagebox.OK) {
    return true;
  }
  return false;
}

With servlet thread this code no longer works. The method stopPropagation() gets never called. Messagebox.show() returns immediately and there is no chance that confirmMessage() returns true.

We need to make some changes. In the example I choose commons-chain, but Runnable is also a choice.

final Tab tab = container.getLinkedTab();
tab.addEventListener(9000, Events.ON_CLOSE, new EventListener() {
  @Override
  public void onEvent(final Event event) throws Exception {
    if(modified) { // check whether tab content has been changed
      event.stopPropagation();
      ZkossUtils.confirmMessage(ElLabel.getLabel("lCloseWithoutSaving"), new Command() {
        @Override
        public boolean execute(Context context) throws Exception {
          tab.close();
          return Command.PROCESSING_COMPLETE;
        }
      });
    }
  }
});

...

public static void confirmMessage(String message, final Command command) {
  Messagebox.show(message, ElLabel.getLabel("lQuestion"),
            Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION,
            new EventListener() {
    @Override
    public void onEvent(Event event) throws Exception {
      Context ctx = new ContextBase();
      switch ((Integer) event.getData()) {
        case Messagebox.OK: command.execute(ctx); break;
      }
    }
  });
}

First modification is to use Messagebox's EventListener. There we put the code we want to execute when the OK button gets clicked.

The onClose event has changed some more. Fist, we call stopPropagation() when modified is true. This ensures the tab will remain open. Then, we close the tab. Doing so programmatically prevents from entering an endless loop. Notice that in real-world applications, the tab may have its own listeners and perform some stuff.

Before you get mad with modal windows

Setting the modal state. With the event thread enabled you could do setMode("modal") before attaching the window to the page. With the servlet thread that's no longer true. It will throw a not attached exception. So, if you set the window mode somewhere before setPage(page), simply remove the call to setMode() and use doModal() once the page has been set.

Comentaris