Skip to content

GWT (Google Web Toolkit)

Gary edited this page Aug 8, 2022 · 16 revisions

GWT

This is a introductory/resource page for developers working on the RStudio GWT code.

  • GWT aka "Google Web Toolkit", pronounced "gwit"
  • A toolkit for writing web applications
    • A compiler to create optimized JavaScript from Java sources
    • A "dev-mode" watcher for "refresh the browser" incremental recompilation
    • Widget toolkit for creating desktop application-like user interfaces
    • RPC, internationalization, UI templates, code-generation, obfuscation, minification, resource bundling, etc.
  • Originally released by Google in 2006, open-sourced in 2013
  • Docs, tutorials: http://www.gwtproject.org/
  • Source code: https://github.com/gwtproject/gwt

In the early 2000s, building large-scale AJAX web applications in JavaScript was tough. The language was immature, and the tooling even more so. Google created GWT so developers could leverage existing Java tooling to build large scale applications.

Tools Needed

  • JDK 8, 11, or 14
    • javac -version to see version; set JAVA_HOME env variable if necessary to target a particular JDK
  • A Java editor such as Eclipse or VSCode
  • ant (https://ant.apache.org/)

Building

Build using ant from the src/gwt folder. Ant is configured with build.xml.

On Linux and Mac, recommend using the shell script src/gwt/ant rather than invoking ant directly. The script will attempt to locate and use a suitable already-installed JDK.

That is, use ./ant instead of just ant. On Windows, continue using ant directly.

  • ./ant (full optimized build, takes a long time)
  • ./ant draft (full build without most optimizations, significantly faster, though still slow)
  • ./ant devmode (RStudio Server dev mode <-- best way to work, only available on Mac and Linux)
  • ./ant desktop (RStudio Desktop dev mode)
  • ./ant unittest

Troubleshooting Builds

If you encounter errors while building GWT, try doing ./ant clean then running the build command again. There are sometimes issues switching between different types of builds, or if running builds with different versions of the JDK (for example, if you build with 8, then try to do an incremental build with 11, it will fail).

GWT Modules

  • A named set of instructions to the GWT compiler
  • Defined in files with .gwt.xml extension
  • Definitions corresponding to the ant targets found at rstudio/src/org/rstudio/studio:
    • RStudio.gwt.xml
    • RStudioDesktopSuperDevMode.gwt.xml
    • RStudioDraft.gwt.xml
    • RStudioSuperDevMove.gwt.xml
    • RStudioTests.gwt.xml

RStudio Startup

  • RStudio loads src/gwt/www/index.htm
  • This simple bootstrap page loads the GWT Javascript, invoking the entrypoint RStudio.onModuleLoad() in RStudio.java
  • From here it determines which type of window this is in RStudio.onDelayLoadApplication()
  • For the main window, this ends up creating an Application object and invoking Application.get()

Dependency Injection (GIN)

Dependency Injection Circular References

  • A circular dependency between injected objects will hang RStudio
  • When encountered, defer actual creation of dependency until needed using the Provider<> helper
  • Provides a proxy which which you can later invoke .get() to create/fetch the actual dependency, breaking the loop

Dependency Injection and Pro Features

  • RStudio Pro/Workbench-only GWT UI uses dependency injection to inject a stub for open-source, and an implementation for Pro. Files to watch out for are those ending in *Overlay.java and `*Pro.java
  • Compare RStudioGinModuleOverlay.java in the open-source and pro repos

EventBus Pattern

  • EventBus allows one part of code to fire strongly typed events, and other code to subscribe to receiving those events
  • The sender and receiver are unaware of each other's actual identity; the EventBus acts as an intermediary
  • The EventBus is a singleton available via dependency injector
  • To define an event, create a class that extends GwtEvent<>; lots of examples in the code

EventBus: sending

  • Given an event such as: public class ShowErrorMessageEvent extends GwtEvent<ShowErrorMessageEvent.Handler>
  • eventBus_.dispatchEvent(new ShowErrorMessageEvent(errorMessage));

EventBus: receiving

public class Foo implements ShowErrorMessageEvent.Handler {
   @Inject public Foo(GlobalDisplay globalDisplay) {
      this.disp_ = globalDisplay;
      eventBus.addHandler(ShowErrorMessageEvent.TYPE, this);
   }
   public void onShowErrorMessage(ShowErrorMessageEvent event) {
      ErrorMessage errorMessage = event.getErrorMessage();
      disp_.showErrorMessage(errorMessage.getTitle(), errorMessage.getMessage());
   }
   private final GlobalDisplay disp_;
}

Command Handling

  • Commands are events triggered by the user, typically by clicking on a button or menu item, or hitting a keyboard shortcut
  • Defined in Commands.cmd.xml, for example:
   <cmd id="showAboutDialog"
        label="About RStudio..."
        menuLabel="A_bout RStudio"
        rebindable="false"
        windowMode="main"/>
  • Must also create a corresponding entry in Commands.java: public abstract AppCommand showAboutDialog();

  • Handling a command is simple, add "on" to the command name and use @Handler:

@Handler
void onShowAboutDialog() { … }
  • Note, the class implementing the handler must contain: public interface Binder extends CommandBinder<Commands, SomeClass> {}

Making RPC Calls

  • The webpage can send messages to the rsession process, and receive an async response
  • Messages are defined in RemoteServer.java:
 private static final String LIST_GET = "list_get";
 @Override
 public void listGet(String listName,
       ServerRequestCallback<JsArrayString> requestCallback) {
    sendRequest(RPC_SCOPE, LIST_GET, listName, requestCallback);
 }
  • Inspect these messages via the "Show Internal Request Log" command and/or the browser devtools network tab
  • Search for the name (e.g. "list_get") in the rsession C++ code to find implementation on that side

Receiving Messages from RSession

  • The rsession can send messages to the page; this is done via long-polling by the page via the get_events RPC call
  • The list of client events is in: ClientEvent.java
  • Handlers and dispatching happen in: `ClientEventDispatcher.java; typically by emitting an event via the EventBus.

Desktop Specific

  • The web page and the desktop process (e.g. RStudio.exe) can communicate with each other
  • Discussed here

UI Templates

  • GWT UI can be constructed programmatically, by allocating and connecting various Widget subclasses
  • Alternatively, the .ui.xml template format can be used to declaratively construct UI
  • For example, see AskSecretDialog.ui.xml and AskSecretDialog.java
  • http://www.gwtproject.org/doc/latest/DevGuideUiBinder.html

Unit Tests

JavaScript Interop

RStudio GWT Patches

Clone this wiki locally