There are two aspects to deploying a GWT application: client side deployment, and server side packaging and deployment. In this tutorial, I will cover the different sets of issues that are tied to each aspect of deployment and packaging.
Here are things you have to keep in mind for client side deployment:
- are you going to embed the GWT app in an inframe?
- are you going to embed the GWT app in a div?
- are you going to use cross site scripting?
- are you going to use services on a different host/port than the one you are deploying your app into?
- are you going to embed the GWT app into an existing web app or webpage?
- are you going to create a new app from scratch, without having to deal with legacy integration and deployment issues?
Here are things that you have to keep in mind for server side packaging and deployment:
- are you going to host the WAR file in an HTTP or HTTPS server?
- are you going to serve up the client app on a different host than the service host?
Depending on what answers you provided to these questions, you will find that there are constraints to doing what you really want to do with GWT apps. I will try and paint a clear picture of what is possible, and what is not, with GWT apps and services using some deployment scenario use cases that are outlined below.
Client side deployment
You might want to deploy your app so that it controls the full content of a web browser window, or you may want to deploy it as a widget that runs inside an existing web app, web page, or portal. Or you might want to deploy an app that doesn’t use any services, but operates on content that’s available in a web browser’s DOM (eg, you might have some widgets that control the display of content on an existing div on a webpage). If these scenarios are what you have in mind as deployment options for your app, then read on.
Taking up the full browser window
The simplest client side deployment scenario involves your app adding a widget to the bottom of the browser’s DOM with the following call –
If you don’t have any existing <div> sections in the browser’s DOM that you would like to replace, then this is the easiest thing to do. If you are in complete control over the HTML host page that’s rendered in the browser, then you don’t have to worry about much else. You can even reference an external CSS stylesheet in the HTML HEAD tag –
<link href=”Style.css” rel=”stylesheet” type=”text/css” />
Alternatively, if you don’t have control over the HTML head tag, eg, if you are embedding your app in an empty blog page that you don’t host yourself, then you can add a directive to include the CSS style sheet in the XML deployment descriptor for your app –
The “Style.css” page in both cases above would have to be in the public folder of your GWT project.
Splash screen while your app loads
In the case you want to provide a loading screen, you can simply insert a <div> section in your HTML host page that shows a message with an animated gif –
<div id=”loading”><img src=”loading.gif”>Loading app…</div>
You can then remove this message in the onModuleLoad method of your entry point class –
Once the loading div is removed, you can add your widget to the DOM.
Replacing existing div sections
A slightly more complex deployment scenario is when you want to insert your GWT app into an existing page, and your plan is to replace an existing <div id=”yourapp”> section with your own widget. In this scenario, you would have to hard code the div-id into the pre-existing HTML host page. Depending on how complex you want this to get, you might just assume that there is only one instance of this div-id in the browser’s DOM, or there may be multiple instances for you to swap with multiple instances of your widget. Here’s the code that you might have to put in the onModuleLoad() method of your entry point class –
Keep in mind that when you add your widget to this existing div with id=”yourapp”, the page might resize, depending on the styling that you apply to your widgets. So if your div is constrained by bounds (height/width) then you have to keep this in mind when designing the app itself. So if you are going to embed an app into a web page which only has 700 px wide area for your div to expand into, and your app takes up 1024 px, then there will be a problem. You also have to test your app running on Firefox, IE, WebKit/Safari, etc. to make sure that everything works as you expect it to. There are lots of differences in how different browsers implement CSS functionality, so don’t assume that just because something works in hosted mode, that it will work in production once deployed in it’s intended hosting environment.
When modifying an existing web page, to embed your app, you can insert the script tag in the BODY tag of your HTML page –
You just have to make sure that the .nocache.js file is accessible from your HTML page.
Cross site scripting
Browsers impose a restriction on JS code. You can only connect to XMLRPC services on the originating host, ie, the host that served up the web page to begin with. If the script tries to load itself from a host:port which is different than the enclosing HTML page then the browser won’t load it. There are 2 sets of issues that stem from this restriction:
- If you have a GWT app that does not use RPC services, but is hosted on a different server than the one that you’re planning to embed it in, then you will have an issue referencing the .nocache.js file in your <script> tag. The solution here is to use the <yourmodule>-xs.nocache.js script file, which GWT 1.4.x generates for you along with the .nocache.js file. For example, I host an app I wrote in GWT on developerlife.com, but I want to use this app in a page on screamingtoaster.com. Without using the .xs-nocache.js file, I would be out of luck trying to attempt.
- If you have a GWT app that uses RPC services, but is hosted on a different server than the one you’re planning to embed it in, then you are going to have issues. Even the cross site script (<yourmodule>-xs.nocache.js) is not going to be of use to you in this scenario. Using the screamingtoaster and developerlife example from above, even though the app will load in the page in screamingtoaster, the browser will not be able to connect to an RPC service running on developerlife, since this violates the originating host security policy. How do you handle situations like these? By using iframes, more on this next.
Integration with existing portals, web apps, or web pages
When you have GWT apps that consume RPC services, and you want to package them as widgets to be deployed in existing portals or web pages or web apps, the simplest way to accomplish this is to use iframes. By loading your GWT HTML Host page inside of an inframe, you can bypass the issues with being restricted to accessing URIs on the originating host. The only issue with using an iframe is passing parameters to your apps, but this can be accomplished by dynamically generating the HTML host page itself using a servlet, and using URI or parameter passing by using meta-tags in the generated page. You can pass parameters by encoding it in the URL (via key/value pairs) and then you can have your servlet take these key/value pairs and encode them in the URI used to reference your GWT HTML host page, or use meta tags to encode these key/value pairs, which you can then access in your code.
Here’s the syntax for using an iframe:
<iframe scrolling=”no” frameborder=”0″ width=”50%” height=”500pt” src=http://host:port/Module/HostPage.html#token>
The example above specifies the following things:
- your app is bound to 50% of the width of the container of the iframe
- your app is bound to 500 pt height
- your app will be loaded from http://host:port/Module/Hostpage.html. Since this is an iframe, you don’t have to worry about originating host, and put whatever host:port you wish, and it doesn’t matter if this is different than the host:port of the page that loads this iframe. Note that you can pass parameters to the app itself. In this example I’m passing a “token” in the URI… this can be retrieved using the GWT History mechanism. You can alternatively dynamically generate this HTML host page, and pass whatever key/value pairs you want to it.
Why is it necessary to pass some kind of token or key/value pair to your GWT app? In case you want to package your app as a widget that can be deployed to existing portals, web apps, etc. then it will become necessary for you to reference a unique id inside of your app… for example, if you have a widget that displays weather, then the zip code maybe passed via the URI, to that the user doesn’t have to be typed in. Think of a Youtube video, the unique id of a video is passed to the youtube.com URI that loads up the video player. Here’s an example of a Youtube embed URI:
Note that this Youtube “name” param tag references a value of “/v/Xg39kY0muv8” as the unique id of a video. So you might have some similar scheme to reference an object that you can initialize your GWT app with.
Limitations with iframe
When using inframes to load your app, you have a lot of flexibility in creating your HTML host page. You don’t have to worry about not having access to the HTML HEAD tag, to insert meta tags, script tags, and style tags. However, keep in mind that because you are running in an iframe, you won’t have access to the DOM element of the containing element of your iframe. That means the root of your DOM is your iframe itself. If you need access to the DOM elements in the enclosing/parent container of your iframe then don’t use iframes. If you need access to the iframe’s parent DOM element, and you need to make RPC calls on an originating host that’s different from the enclosing page, then you are in in trouble .
Server side deployment
Your GWT app can easily be packaged into a WAR file and then deployed to a servlet container. Depending on how you want your client app to be accessed, you might have to be careful of a few things.
If you deployed the WAR file to a servlet container, and you’re not using iframes to load the GWT app on the browser, then you are limited to accessing the GWT app only on webpages served up by the servlet container bound to a specific port. You can’t run Tomcat on port 8080, then deploy your WAR file to this instance, and then access the app from an HTML host page that’s running on an Apache web server on port 80. There is going to be an issue with the originating host problem, and the browser won’t load the page.
MOD JK for Apache and Tomcat
How do you resolve this situation? In case you are using Tomcat and Apache, there’s an MOD JK connector that allows Apache to redirect HTTP requests to a Tomcat instance, without the client browser being aware of any of this. Here are some links to help you setup MOD JK for Apache, so that you can simply re-use the same URI that you do for apache to connect to Tomcat:
HTTPS and HTTP
If you host your GWT apps and services in an HTTPS server, then you will run into the originating host problem if you don’t use an iframe, and try to access your GWT HTML Host page from HTTP. This is assuming that you can even access the same URI from HTTPS and HTTP. There are some limitations that SSL/HTTPS puts on virtual domains… Long story short, you can only have 1 IP address tied to a digital certificate, and an HTTPS server. So if you have Apache that’s hosting multiple domains, then you can only secure one of these domains using HTTPS. So, if you have a GWT app that needs to be accessed by lots of your own domains, but it’s hosted in an HTTPS server, then you have to take the iframe approach described in this tutorial.
Depending on your constraints and requirements, you might be able to use MOD JK to come up with creative solutions around the originating host problem, but iframes give you some breathing room to be able to bypass a lot of the problems that you might face.