Tuesday, May 17, 2011

Writing GWT Linker for offline applications – part 1

 
NOTE: You can read part 2 of this article HERE and the issues fixes HERE!
 
I was looking after the latest GWT 2.3 and I wanted to experiment with the local storage HTML5 features. It looks good but what would be more interesting if you can make your GWT application to work offline. Looking in internet for some documentation I realized that to make my GWT runs offline I may need to write a custom linker. So why actually linker? Basically first you do need to understand how offline web applications really work. I would propose you first to take a look after this documentation here: http://dev.w3.org/html5/spec/offline.html#offline.
 
As you can see to make your application works offline you would need an application cache manifest file, which describes you application files and requests. Basically you know all that, since you write your application, so you can also do it manually but this means that on every change you did in your GWT application you have to check and see if your application manifest file is up to date, so you run in the chancy, that something could be forgotten at some point.
 
If GWT there is also another issue. GWT compiles and optimize your code for every browser platform and save the compiled code to corresponding folder.  All this files are generated based on the checksum of there content, so you get a lot of files looking like this:
 
image
 
The issue here is that every time you make some correction and recompile, you will need also to change the name of the file into your manifest application cache file.
 
One of the solutions of the problem is to go for GWT linkers and write custom one. Of course you can do also your own script which goes through the files and generated you manifest file after every compilation but I decided to use custom GWT linker, which for me looks let’s say more interesting and more propriety for a lot of reasons.
 
Of course the question first would be, how to write GWT linkers? I was looking some examples in internet, so let me share my experience on it. Here the basic steps to be able to write linkers:
  • Define namespace where you want to create your linker. You do not need to use the client namespace, for example I use com.gwt2go.dev.linker to create my linker example.
  • Create a class which implements AbstractLinker or just Linker from the namespace com.google.gwt.core.ext.linker. Personally after some investigations, I prefer to use the AbstractLinker class. It gives you access to methods to like the emit functions, which you can use into your code, we will see how later.
  • Set up the order using LinkerOrder. With this annotation you set up the execution priority. For example LinkerOrder.Order.Post means execute after the primary linker. You can also select the options Pre or Primary. Primary means that your linker will be executed instead of the primary linker.
  • Create new module file <module>.gwt.xml inside the namespace where you create your linker class. You can use also another namespace but for me was more easier to use the same. You have to define your linker inside, I will show you later how to do it.
After you finish with the creation of the linker you should do the following to use the linker into your project:
  • Inherits the linker inside your main <module>.gwt.xml file
  • Add the linker using the “<add-linker name="<linker_name>" />
Let’s see how all this works in practice. I checked in all my examples into the Google Code project Gwt2Go here.
The first step was to create a namespace where you will develop your custom linker. I create the namespace com.gwt2go.dev.linker.
 
image
 
Inside the namespace I create a class which calls ManifestLinker.java. My custom GWT Linker extends from AbstractLinker and the order will be LinkerOrder.Order.Port, here is the code for it:
 
1 @LinkerOrder(LinkerOrder.Order.POST)
2 public class ManifestLinker extends AbstractLinker {
3
4 @Override
5 public String getDescription() {
6 return "Personal simple linker";
7 }
8
9 public ArtifactSet link(TreeLogger logger, LinkerContext context,
10 ArtifactSet artifacts) throws UnableToCompleteException {
11
12 // Create a new set of artifacts that we can modify and return.
13 ArtifactSet toReturn = new ArtifactSet(artifacts);
14
15 // Add a new artifact to the set that we're returning.
16 toReturn.add(emitString(logger, "Some simple text here",
17 "gwt2go.appcache"));
18
19 return toReturn;
20 }
21
22 }
23


Very simple linker but it is perfect just to start and see how it works. This simple linker just creates a file with the name “gwt2go.appcache” and puts inside the text “Some simple text here”.




The next step will be to create linker module file, into which you will register the linker. As shown in the screenshot above, I created a module with the name ManifestLinker.gwt.xml in the same folder where the linker class was created. Inside the module file you have to register the linker:



1 <module>
2
3 <define-linker name="manifest" class="com.gwt2go.dev.linker.ManifestLinker" />
4
5 </module>


This is a very important step, without this registration if you try to use the linker you will always get exception that the linker could not be compiled.



We finish with the registration we can try use the custom linker. To do so, open your application main module file and inherit it. In my case I had to inherit the linker my Gwt2Go.gwt.xml file following:



1 <inherits name="com.gwt2go.dev.linker.ManifestLinker" />


After you inherited from the linker you have to add the linker again in the same main module file like this:



1 <add-linker name="manifest" />
Now your linker is ready to use. Compile your code and you should see the file generated into the folder where your client side code is generated:


image



We have now everything we need to start with something more complicated. In the next article I will try to show you how to use this linker to generated the offline manifest cache file.



cheers

8 comments:

  1. Hi,

    I'm very interested in that matter and wanted to ask if there will be a sequel to this post, soon?
    Or has this approach turned out to be a dead end?

    Regards, Roman

    ReplyDelete
  2. Yes, I plan a new one and start to make some examples, unfortunately due to my too much travelings in the last weeks, I wasn't able to finish it. I will try to post the next one this week.

    ReplyDelete
  3. OK, Part 2 is release you can read it now here:
    http://webcentersuite.blogspot.com/2011/06/writing-gwt-linker-for-offline.html

    ReplyDelete
  4. AnonymousJuly 18, 2011

    hiiii....it's very intresting.

    ReplyDelete
  5. Really interesting
    but i can't use it... i'm using grails + gwt (via gwt plugin)
    and for this example to work i have to use the gwt-dev.jar (usually i use the gwt-user.jar) in my lib path...
    and this have some conflict with other library

    java.lang.LinkageError: loader constraint violation: loader (instance of ) previously initiated loading for a different type with name "org/xml/sax/SAXParseException"

    and I can't solve it :-(

    ReplyDelete
  6. Hi Gabriele, unfortunately I never used this approach, I afraid I would not be able to help you with it.

    ReplyDelete
  7. Very good artical!
    Does code splitting work well with appcache?
    Yu

    ReplyDelete
  8. should not be a problem, I think

    ReplyDelete