This section is maintained by the qooxdoo community. Here is how you can contribute.

Client-Server Programming

QWT applications have a client part and a server part. The client part is a translated to JavaScript and executes in the browser, the server part executes in the servlet container on the server.

QWT provides remote method invocation for client-server communication: client objects can invoke methods on server objects and vice versa, passing objects between client and server.

Client-server programming with QWT was heavily inspired by Java RMI: applications use 'normal' Java objects, and the system handles networking and Java/JavaScript issues transparently.

Example

The grep example demonstrates client-server programming with QWT. It defines a grep service to search for files on the server and the corresponding user interface to call grep with an arbitrary browser. Hitting the grep button in your browser invokes the grep method on the server.

This example is used throughout the following sections to explain the respective feature

Value Objects

RMI passes objects (method arguments and results) between client and server. Normally, objects are passed by value. If you send an object to the server, the JavaScript object in the browser is serialized, sent to the server, and de-serialized into a Java object on the server. If you send an object to the client, the Java object on the server is serialized, sent to the client, and de-serialized into a JavaScript object in the browser.

Build-in Java objects like String and Date are value objects. Primitive types like int and boolean are also value objects.

Value Objects should be defined in the common package of your application because they are used on both client and server.

Example

The Match class defines a value object passed from the grep service back to the browser. It is defined in a common package.

Service Objects

If passing objects by value is not suitable, you can use service objects to pass objects by reference: QWT passes all objects by value - unless it's a service object. Passing a service object from server to client creates a proxy object in the browser. The proxy has the same interface as the service object, but a method called on the client is forwarded to the server for execution. Similarly, passing a service object from client to server, creates a proxy on the server which forwards method calls back to the client.

To define a service object Foo:

  1. write an interface FooService defining the methods you wish to call from remote
  2. write a class Foo that implements "FooService"
  3. create an instance of "Foo" and pass it to the remote side
  4. from remote: invoke your methods

QWT uses the interface name to distinguish between service objects and normal objects. When passing an object, QWT checks all interfaces implemented directly or indirectly. If any of them has a name the ends with Service, the object is a service object and passed by reference. Otherwise, it's a normal object and passed by value.

Note: the service class (Foo) should be defined in a server or a client package, depending on where the services executes. The service interface (FooService) should be define in a common package because the interface has to be known on both client and server.

Note 2: make sure to synchronize service objects running on the server, they can be accessed concurrently.

Example

The Grep class defines a service object because it implements the GrepService interface.

Application startup

QWT applications have two main classes, a server main class and a client main class.

The server main class is instantiated when the application starts. It has to extends QWT's Server class and may override various methods. In particular, you can override createClient, which is called whenever a new client starts. The object returned by this method is passed to constructor of the client main class.

The client main class is normal qooxdoo application main class, except that it's written in Java. If the server passes an argument to clients, it's passed to the client main constructor.

Example

The Server Main class overrides createClient to pass a Grep object to every client. Since Grep is a service object, it's passed by reference, thus, clients receive a proxy object. Note that every client has gets a new Grep instance, so there's no need for synchronizing Grep. Alternatively, you could create a single synchronized Grep instance in the constructor and pass this very instance to all clients.

The Client main class has a one-argument constructor receiving the proxy sent by the server. The proxy is stored in the grep field an used in the notify method to call grep on the server.

Configuration

To run client-server applications, QWT needs to know the server main class, the client main class, and the client classes. All this is specified the pom file of your application, by the lines marked here with '-':

   <plugin>
     <groupId>org.qooxdoo.toolkit</groupId>
     <artifactId>plugin</artifactId>
     <version>${toolkit.version}</version>
-   <configuration>
-      <client>com.foo.bar.client.Main</client>
-      <includes>**/*.java</includes>
-      <excludes>**/server/**/*.java</excludes>
-      <server>com.foo.bar.server.Main</server>
-   </configuration>
     <executions>
       <execution>
         <goals>
           <goal>war</goal>
         </goals>
       </execution>
     </executions>
   </plugin>
  • client specifies the client main class. This field is optional, if not specified, QWT uses the applications group- and artifact id and appends client.Main. (Or more precisely: the default value is ${project.groupId}.${project.artifactId}.client.Main)
  • server specifies the server main class. This field is optional, if not specified, QWT uses the applications group- and artifact id and appends server.Main. (Or more precisely: the default value is ${project.groupId}.${project.artifactId}.server.Main)
  • includes and excludes specify the client classes which will be translated to JavaScript. These fields are optional, if not specified, QWT translates all classes except * */server/* */*.java.

Example

The above default values are fine for the Grep example, there's no need to specify the above fields. That works because the application is structured into a client, a server, and a common package, all of them under org.qooxdoo.grep, which is the application's group- and artifact id.