Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreThe blog assumes that you have an install of SpringSource Tool Suite 1.1.1 (I'm using the Eclipse 3.4 version), dm Server 1.0.0 and GWT 1.5. It also assumes that you have a good understanding of Java programming and a basic understanding of Javascript and Ajax.
For the purposes of the paths used in the demo, I created a new Eclipse workspace at /Users/bcorrie/gwt/workspace. I have included zipped up projects you can download below, which contain a GWT_ROOT_INSTALL variable I have defined. To use my projects, when you import them navigate to "Preferences" -> "Java" -> "Build Path" -> "Classpath Variables" and define your own GWT_ROOT_INSTALL.
One limitation of these tools is that they are prescriptive about where your source code goes. Your source code must be in a project sub-directory called /src, your client code must be in a package ending in client and your server code in a package ending in server. The projectCreator and applicationCreator cannot be configured to do otherwise because this is typically where GWTShell and GWTCompiler expect your code to be. Later on, we'll look at some ways of reorganizing the source code and tuning the Run Configurations to make them more flexible.
Once you've created the project on the command-line, import it into STS.
Use "Import" -> "General" -> "Existing Projects into Workspace".
If you don't want to go through the process of developing the Sample code, you can download a zipped copy of my initial project here. To run with my project, you'll need to go through the following steps:
- Unzip and import the project ("Import" -> "Existing Projects Into Workspace") - Define a GWT_ROOT_INSTALL variable as described in Background above - Either modify the StockWatcher GWTShell.launch Run Configuration included, or create a new one with the following values:
- Right-click on the StockWatcher Project -> "Run As" -> "Run Configurations" - For the "Main class", enter com.google.gwt.dev.GWTShell - In "Program arguments", enter -out www com.google.gwt.sample.stockwatcher.StockWatcher/StockWatcher.html - On Mac OS X only, in "VM arguments", enter -XstartOnFirstThread - In "Classpath" -> "User Entries":
- add gwt-dev-<os>.jar (Eg. gwt-dev-mac.jar) - add the StockWatcher Project /src folder, using "Advanced" -> "Add Folders"
Note that adding the /src folder to the classpath is a requirement of the GWTShell because it needs to have the metadata, such as its .xml file, on the Java classpath.
Either click the "Run" button with the StockWatcher project selected, or choose the Run Configuration you created in Step 2.
Note also that when you run in hosted mode, GWTShell creates a /www output folder into your project as well as a /tomcat folder to configure the embedded Tomcat. You'll see these if you refresh your StockWatcher project after testing it.
So why not just copy everything over to the WAR project and run it all from there? Well, there are a number of reasons why I think it makes sense to maintain two separate projects:
Firstly, you don't want your hosted mode to generate its /www and /tomcat folders into your WAR project.
Secondly, generating javascript and html from the hosted mode project into the WAR project has the advantage of keeping both projects cleaner and separating concerns. It eliminates the duplication of generated code which can lead to versioning confusion, particularly given that the generated code is obfuscated.
Thirdly, as discussed in Step 1, GWTShell and GWTCompiler mandate that your source code is in a sub-directory called /src. This limits your WAR project's ease of integration with tools such as Maven and Ant.
Finally, it allows the Java code to also be separated so that you're not copying the redundant client code into the WAR file.
While it may seem like unnecessary extra effort, you'll see as we go forwards with the different approaches why breaking up the code early on makes it easier to deploy it as shared services later.
So let's create a new Dynamic Web project and at the same time, create a Server instance of the dm Server.
If you don't already have a dm Server instance in the workspace, you'll need to hit the "New" button next to the "Target Runtime" textfield and select "Create a new local server". Note that I've also chosen src/main/java and src/main/webapp for the "Java Source Directory" and "Content Directory" respectively. You can use the defaults, but these paths are recommended as they integrate well with build tools like Maven.
Next, we're going to split the Java code up between the two projects:
Note that this division of code is not essential if you are just going to export your GWT code as a vanilla WAR file. The simplest way to achieve that is to create your Java project as a Java EE Dependency of the WAR Project and Eclipse will turn your Java project into a JAR file which it adds to WEB-INF/lib in the WAR. However, the problems with that approach are that you package your redundant client code into the WAR and it makes it harder to split your application up into services later on.
So, we have 3 types of Java code in our project: code which is only ever compiled to javascript and html, code which is exclusively server-side and code which supports both purposes. It makes sense to move these last two types of code into our WAR project. It also makes sense to put our "common" classes (those used by the client and server) into a separate package (again, the need for this will become clearer in blog 3) which we'll call com...client.api. Finally, GWT requires that our Async interface is in the same package as the RemoteService interface, so refactor this into the com...client.api package. Once you're done, this is how it should look:
The last thing required in breaking up the code is to add the StockWatcherWar project to the build path of the StockWatcher project, so that it can access the classes in the com...client.api package (Properties -> Java Build Path -> Projects -> Add...).
If you prefer, you can skip all of this arduous work by download a zip of my two finished projects, plus the various Run Configurations here (see Step 2 and Background for instructions on importing and setting up). If you have a clean workspace, you'll need to create an instance of a dm Server runtime (New -> Server -> SpringSource ...) and you may need to select the server runtime for the WAR project in "Properties" -> "Targeted Runtimes" as it may not match mine.
- Right-click on the StockWatcher Project -> "Run As" -> "Run Configurations" and create a new configuration - For the "Main class", enter com.google.gwt.dev.GWTCompiler - In "Program arguments", enter -out <path to your workspace>/StockWatcherWar/src/main/webapp com.google.gwt.sample.stockwatcher.StockWatcher - On Mac OS X only, in "VM arguments", enter -XstartOnFirstThread - In "Classpath" -> "User Entries":
- add gwt-dev-<os>.jar (Eg. gwt-dev-mac.jar) - add the StockWatcher Project /src folder and the StockWatcherWar /src/main/java folder, using "Advanced" -> "Add Folders"
Note that adding the source folders to the classpath is a requirement of the Google compiler.
Now, run the compiler configuration you just created and refresh the StockWatcherWar project to see the generated files. You should see something like this:
Next, we need to add the required dependencies into our project.
- Add web module dependency gwt-servlet.jar ("Properties" -> "Java EE Module Dependencies" -> "Add External Jar"). Note that this module depends on the javax.servlet APIs. - Modify the web.xml file as per Google's instructions. It's worth also adding StockWatcher.html to a <welcome-file-list> so that it comes up automatically on deployment (although this doesn't always work when deploying in Eclipse as the browser window usually opens before the server is fully initialized).
If you're having problems, have a look at my zipped projects from Step 4.
Once you've got the WAR project running successfully, you can configure hosted mode to use dm Server as its server, rather than its embedded Tomcat. To do this, all you need to do is to modify the Run Configuration for GWTShell and change the Program Arguments to -noserver -out www http://localhost:8080/StockWatcherWar/. This allows you to quickly test client-side changes. Server-side changes are automatically re-deployed to the running server. Nice!
It's important to mention that if you want to run in the embedded Tomcat hosted mode with the setup I'm advocating, you need to temporarily unselect dm Server as the Targeted Runtime in the WAR project's properties. This is because adding StockWatcherWar to StockWatcher's build path also pulls in dm Server runtime packages (such as javax.servlet) which messes up the build path of GWTShell.
Assuming that this worked, let's now package up our WAR and deploy it outside of the tooling.
Once we've exported the WAR, we need to start up the dm Server outside of STS.
Firstly, make sure that the STS dm Server is stopped, otherwise they will clash over ports. Then, on the command-line, run the dm Server startup script. In my case, this is bin/startup.sh. You can add the -clean option to ensure that you're starting with a clean setup. You should see the message:
[2008-10-27 14:14:44.468] server-dm-10 <SPPM0002I> Server open for business with profile 'web'.
Once this has started successfully, open up the Admin console in a web browser, using the following URL:
http://localhost:8080/admin/web/applications/list.htm
The default username is admin and the password is springsource. For more detailed information on running and configuring dm Server, see the user guide.
You should now see the following:
Browse for your exported WAR file in the "Application Location" textfield and then click on upload. This will upload and deploy the WAR file which should then appear in "Deployed Applications":
In the terminal output, you should see the following messages:
[2008-10-27 14:07:44.380] server-tomcat-thread-5 <SPSC1000I> Creating web application '/StockWatcherWar'. [2008-10-27 14:07:44.396] async-delivery-thread-1 <SPSC1001I> Starting web application '/StockWatcherWar'. [2008-10-27 14:07:44.684] server-tomcat-thread-5 <SPDE0010I> Deployment of 'StockWatcherWar.war' version '0' completed.
Finally, all that remains to do is to click on the /StockWatcherWar link shown above and you are now using your GWT application!