XWiki Development Zone » Draft Documents » Writing GWT applications in XWiki

Writing GWT applications in XWiki

Last modified by Jue Wang on 2010/01/17 21:32

Running and Debugging GWT code in hosted mode

The purpose is to create a clean (as much as possible) GWT module and then integrate it into an existing web application. The existing web application can serve as a demo for the GWT module. Testing and debugging must be done using GWT's hosted browser. Throughout this tutorial the Wysiwyg project will be used as an example.

Part 1: The GWT module

Step 0: follow Claus's Up and running with GWT and Maven 2 tutorial if you don't have already a module.

Step 1: src/main/resources/com/xpn/xwiki/wysiwyg/Wysiwyg.gwt.xml

Make sure the module descriptor contains at least the entry point and a servlet mapping.

<module>
  ...
  <servlet path="/WysiwygService" class="com.xpn.xwiki.wysiwyg.server.WysiwygServiceImpl" />
  <entry-point class="com.xpn.xwiki.wysiwyg.client.Wysiwyg" />
  ...
</module>

Step 2: src/main/resources/com/xpn/xwiki/wysiwyg/public/Wysiwyg.html

Make sure you include the right JavaScript file in the module's HTML file.

<body>
  <script language="javascript" src="com.xpn.xwiki.wysiwyg.Wysiwyg.nocache.js"></script>
  <iframe src="javascript:''" id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
  ...
</body>

Step 3: src/main/webapp/WEB-INF/web.xml

Copy the deployment descriptor of your web application and add a servlet mapping matching the one you have in the module descriptor discussed above. This is definitely not the best solution. Instead, the deployment descriptor could be retrieved using the maven-remote-resources-plugin and be modified in the pom file, provided it is available as a remote resource. Ideally, this deployment descriptor should contain only the servlet mapping for the GWT services, but unfortunately I couldn't find a maven plugin to merge this descriptor with the one from my web application, during the integration stage.

<web-app>
  ...
  <servlet>
    <servlet-name>WysiwygService</servlet-name>
    <servlet-class>com.xpn.xwiki.wysiwyg.server.WysiwygServiceImpl</servlet-class>
  </servlet>
  ...
  <servlet-mapping>
    <servlet-name>WysiwygService</servlet-name>
    <url-pattern>/WysiwygService</url-pattern>
  </servlet-mapping>
  ...
</web-app>

Step 4: pom.xml

In your pom file you should at least add the GWT specific dependencies and configure the maven-googlewebtoolkit2-plugin and maven-war-plugin. In the case of maven-googlewebtoolkit2-plugin make sure you add the mergewebxml goal, which adds to the deployment descriptor discussed above the servlet mappings needed in hosted mode. The maven-war-plugin should include in the final war the deployment descriptor, updated by the mergewebxml goal, and the java sources from the client package. You'll not be able to run in hosted mode without the client sources!

<project>
  ...
  <packaging>war</packaging>
  ...
  <properties>
    <gwtVersion>1.4.62</gwtVersion>
    <!-- update gwtHome or use the setup profile -->
    <gwtHome>/home/marius/apps/${gwtArtifactId}-${gwtVersion}</gwtHome>
  </properties>
  ...
  <dependencies>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <version>${gwtVersion}</version>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
      <version>${gwtVersion}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-dev</artifactId>
      <version>${gwtVersion}</version>
      <classifier>${os}</classifier>
      <scope>provided</scope>
    </dependency>
    ...
  </dependencies>
  <build>
    <plugins>
      ...
      <plugin>
        <groupId>com.totsp.gwt</groupId>
        <artifactId>maven-googlewebtoolkit2-plugin</artifactId>
        <version>1.5.3-SNAPSHOT</version>
        <configuration>
          <runTarget>com.xpn.xwiki.wysiwyg.Wysiwyg/Wysiwyg.html</runTarget>
          <gwtHome>${gwtHome}</gwtHome>
          <compileTarget>
            <value>com.xpn.xwiki.wysiwyg.Wysiwyg</value>
          </compileTarget>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>mergewebxml</goal><!-- needed by GWT hosted browser -->
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <webResources>
            <resource>
              <directory>target</directory>
              <targetPath>WEB-INF</targetPath>
              <includes>
                <!-- generated by mergewebxml goal -->
                <include>web.xml</include>
              </includes>
            </resource>
            <resource>
              <!-- needed by GWT hosted browser -->
              <directory>src/main/java</directory>
              <targetPath>WEB-INF/sources</targetPath>
              <includes>
                <!-- we need only client java sources -->
                <include>com/xpn/xwiki/wysiwyg/client/**/*</include>
              </includes>
            </resource>
          </webResources>
        </configuration>
      </plugin>
      ...
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>linux</id>
      <activation>
        <os>
          <name>linux</name>
        </os>
      </activation>
      <properties>
        <gwtArtifactId>gwt-linux</gwtArtifactId>
        <os>linux</os>
      </properties>
    </profile>
    ...
  </profiles>
  <repositories>
    <repository>
      <id>gwt-maven</id>
      <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</url>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>gwt-maven</id>
      <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</url>
    </pluginRepository>
  </pluginRepositories>
</project>

Step 5: target/xwiki-web-wysiwyg-0.1-SNAPSHOT.war

In the end you must install the war file in the local repository.

$ mvn clean install

Part 2: The web application

Step 0: Create a maven web project if you don't have one already.

This web project will integrate the GWT module discussed above.

Step 1: pom.xml

In the project descriptor you have to add a dependency on the GWT module you made and specify how your web application should be assembled, using the maven-assembly-plugin.

<project>
  ...
  <packaging>pom</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>com.xpn.xwiki.platform</groupId>
      <artifactId>xwiki-web-wysiwyg</artifactId>
      <version>${pom.version}</version>
      <type>war</type>
    </dependency>
    ...
  </dependencies>
  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>src/assemble/application-no-database.xml</descriptor>
          </descriptors>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Step 2: src/assemble/application-no-database.xml

Create an assembly descriptor to integrate the GWT module in the final web application. I've also added two scripts for running and debugging the (integrated) GWT module in hosted mode.

<assembly>
  <formats>
    <format>dir</format>
  </formats>
  ...
  <dependencySets>
    ...
    <dependencySet>
      <!-- This shouldn't be required but there's a bug in version 2.2-beta-1 of the Assembly
        plugin where the artifact name will be used instead of / if outputFileNameMapping is
        not specified -->
      <outputFileNameMapping></outputFileNameMapping>
      <includes>
        <include>com.xpn.xwiki.platform:xwiki-web-wysiwyg</include>
      </includes>
      <outputDirectory>webapps/xwiki</outputDirectory>
      <unpack>true</unpack>
    </dependencySet>
    ...
  </dependencySets>
  <files>
    ...
    <file>
      <source>${basedir}/src/main/resources/start_gwt_noserver_debug.sh</source>
      <fileMode>755</fileMode>
    </file>
    <file>
      <source>${basedir}/src/main/resources/start_gwt_noserver.sh</source>
      <fileMode>755</fileMode>
    </file>
  </files>
  ...
</assembly>

Step 3: src/main/resources/start_gwt_noserver.sh

Create a shell script similar to the following one to run the GWT module in hosted mode. Make sure that you use a 32-bit JRE. Also, the noserver option is needed in order to bind the GWT hosted browser to an external application server where your web application will be deployed.

#!/bin/bash
APP_DIR=`dirname $0`/webapps/xwiki;
JAVA32_HOME=/usr/lib/jvm/ia32-java-1.5.0-sun-1.5.0.13/bin;
GWT_HOME=/home/marius/apps/gwt-linux-1.4.62;
$JAVA32_HOME/java \
-Xmx1024m \
-cp $APP_DIR/WEB-INF/classes:\
$APP_DIR/WEB-INF/sources:\
$APP_DIR/WEB-INF/lib/xwiki-web-gwt-1.5-SNAPSHOT-sources.jar:\
$GWT_HOME/gwt-dev-linux.jar:\
$GWT_HOME/gwt-user.jar \
com.google.gwt.dev.GWTShell \
-logLevel WARN \
-style DETAILED \
-noserver \
-port 8080 \
-out $APP_DIR/com.xpn.xwiki.wysiwyg.Wysiwyg \
xwiki/com.xpn.xwiki.wysiwyg.Wysiwyg/Wysiwyg.html

Step 4: src/main/resources/start_gwt_noserver_debug.sh

Create a shell script similar to the following one to debug the GWT module in hosted mode.

#!/bin/bash
APP_DIR=`dirname $0`/webapps/xwiki;
JAVA32_HOME=/usr/lib/jvm/ia32-java-1.5.0-sun-1.5.0.13/bin;
GWT_HOME=/home/marius/apps/gwt-linux-1.4.62;
$JAVA32_HOME/java \
-Xmx1024m \
-Xdebug \
-Xnoagent \
-Djava.compiler=NONE \
-Xrunjdwp:transport=dt_socket,server=y,address=5006,suspend=y \
-cp $APP_DIR/WEB-INF/classes:\
$APP_DIR/WEB-INF/sources:\
$APP_DIR/WEB-INF/lib/xwiki-web-gwt-1.5-SNAPSHOT-sources.jar:\
$GWT_HOME/gwt-dev-linux.jar:\
$GWT_HOME/gwt-user.jar \
com.google.gwt.dev.GWTShell \
-logLevel WARN \
-style DETAILED \
-noserver \
-port 8080 \
-out $APP_DIR/com.xpn.xwiki.wysiwyg.Wysiwyg \
xwiki/com.xpn.xwiki.wysiwyg.Wysiwyg/Wysiwyg.html

Step 5: target/xwiki-web-wysiwyg-demo-0.1-SNAPSHOT.dir

In the end assemble you web application from the command line. Here I use the mysql profile so that my final application is configured to work with this database.

$ mvn clean install -Pmysql

Part 3: Run & Debug

Run

To run the GWT module in hosted mode you need to open two consoles. In the first one you have to start the web server where you deployed the web application. In the second one execute the shell script from the third step. Make sure the application server and the hosted browser listen to the same port (8080 for instance).

$1 ./start_xwiki.sh
$2 ./start_gwt_noserver.sh

Debug

To debug the GWT module in hosted mode you need to open two consoles. In the first one you have to start in debug mode the web server where you deployed the web application. In the second one execute the shell script from the forth step. Make sure the application server and the hosted browser listen to different ports for debugging (5005 and 5006 for instance).

$1 ./start_xwiki_debug.sh
$2 ./start_gwt_noserver_debug.sh

To debug using XWiki in the backend you have to first start the server (normal or debug, depending if you wish to debug server side code also) and then run the start_wysiwyg_noserver_debug.sh script from the same directory as start_xwiki.sh (copy it there first). The "noserver" part in the script name means that this script doesn't run a server (like gwt maven plugin does) but connects to an existing server.

Tags: gwt hosted
Created by Marius Dumitru Florea on 2008/05/13 18:42

Get Connected