Just a little whine about Eclipse :)

July 12th, 2010 Alex Moffat

I’m not a regular Eclipse user, I prefer IntelliJ IDEA, but I’ve been using Eclipse a bit lately while doing some GWT work (exploring MVP actually) to find out how the experience has changed since I last used it. Obviously it takes a while to get used to any new IDE and become familiar with all the keystrokes and ways of doing things. Even so, there are some things about Eclipse that are a bit odd. For example, say you want to create a new Java class. This is going to be a reasonably common operation, certainly more common than creating a new project. As the video shows the most discoverable method of doing this in Eclipse makes you go through many more steps than the equivalent IDEA operation, it’s just weird.

Posted in Uncategorized | 7 Comments »

Secure cookies with apache and jetty.

June 15th, 2010 Alex Moffat

When you’re using SSL to secure browser – server communications it’s a good idea to also mark all the cookies you exchange as secure. This tells the browser to only sent the cookies back to the server over an SSL connection, protecting them against sniffing. In addition secure cookies can only be accessed by JavaScript loaded from a secure connection giving you additional protection against client side attacks. The best general overview of cookies I’ve found is HTTP cookies explained. Let’s look at typical production and development deployments using apache and jetty and see how to configure things. In production I want secure cookies but in development I want regular cookies and I don’t want to have to recompile the code going from development to production.

apache_jetty

In production apache handles the SSL decoding and encoding for the https connection and serves any static content. It passes requests for dynamically generated content to jetty over http using mod_proxy. In development the browser connects directly to jetty over http which serves both static and dynamic content.

My first concern turned out to be rather silly, will the secure cookies actually pass through the apache proxy and make it to jetty? A simple look at the cookie spec shows that information about cookie expiry, path, domain and the secure flag is only present in the set-cookie header sent from the server to the browser. The information sent from browser to server is only the cookie name and value. The server knows nothing more about the cookie and so apache’s mod_proxy just passes all cookies along with the request when it proxies it.

There are three sets of cookies to consider, those set on the client, those set on the server by code you write and those set on the server by jetty on your behalf, in particular the session cookie. The first set is the easiest, all of the client side cookies are going to be set by code you wrote. Using the Cookies.setCookie(….) method you can set the secure flag for any cookie you create. To detect whether a secure connection is present for the current page, and therefore whether the flag should be set you can use “https:”.equals(Window.Location.getProtocol()). This will set the flag in production but not in development.

On the server the first difficulty comes in detecting that there is an https connection. By the time the request reaches jetty it’s over http. How do you distinguish then between the development and production cases? The solution is in two parts, first using apache to add a header to identify requests originally coming over https, and second using this information in jetty.

Part one is accomplished using the apache RequestHeader direction from the mod_headers module. In the https configuration for apache add


 RequestHeader set X-Forwarded-Ssl true

Now each request arriving at jetty that has come through apache on an https connection will have the X-Forwarded-Ssl header set. This means that in the development situation the header will not be present, so no special configuration is needed to distinguish between development and production. In production the jetty instance is only available through the apache proxy so it’s not possible to set the header on a direct http connection to jetty and so attempt to access secure cookies over http.

In your code it would be possible to check the X-Forwarded-Ssl header directly, however, when we get to cookies set by jetty, which includes the JESSSIONID session cookie, you need a different solution.

The interesting bit here is how you actually find the information you need. I approached this from a few different angles, starting with searching. I found this page about configuring mod_proxy and jetty which pointed to extending SelectChannelConnector and overriding the customize method to set the scheme for an incoming request. While this doesn’t work it did get me thinking about the methods available on SelectChannelConnector. Then I went looking for the code that sets the session cookie. You can find this in the org.mortbay.jetty.servlet.AbstractSessionManager class in the getSessionCookie method. The line that sets whether or not the cookie is secure is


cookie.setSecure(requestIsSecure && getSecureCookies());

The getSecureCookies() method returns the value of a property of the session manager that can be set via configuration and requestIsSecure is a parameter to the getSessionCookie method.

The configuration changes needed to set the secureCookies property can be added to the jetty-web.xml file.


  <Get name="sessionHandler">
        <Get name="sessionManager">
            <Set name="secureCookies">true</Set>
        </Get>
    </Get>

Tracing back through the code the requestIsSecure parameter originates from the isSecure() method on the javax.servlet.ServletRequest class.

So the remaining step is to have isSecure() return true when the X-Forwarded-Ssl header is set on the request. Some more investigation shows that isSecure() is implemented as a call to isConfidential(…) on AbstractConnector and this is where it ties back into the page about configuring mod_proxy and jetty which shows using a subclass of SelectChannelConnector. The solution I chose was to subclass SelectChannelConnector and override the isConfidential method


    public boolean isConfidential(Request request) {
        if (request.getHeader("X-Forwarded-Ssl") != null) {
            return true;
        } else {
            return super.isConfidential(request);
        }
    }

With these two changes the JSESSIONID cookie produced by jetty is marked as secure in production and not in development with no additional configuration or flags needed to distinguish the two environments. For cookies created by code you write you can now check the isSecure() method on the request when creating the cookie.

Posted in GWT, Java, Web | No Comments »

XSRF/CSRF and GWT RPC- Cross site request forgery and Google web toolkit

May 30th, 2010 Alex Moffat

This is a minimal set of changes to protect existing GWT 2.0.3 RPC methods from CSRF (aka XSRF) attacks. GWT 2.0.3 has two different RPC mechanisms, the orignal one, and the new direct-eval RPC implementation. I’m going to talk mostly about the orignal RPC mechanism.

There are two parts to the protection. The first relies on the difficulty of setting a header on an HTTP request made from the browser. The only way to add a header to a request via JavaScript is to use an XMLHttpRequest. If you make a simple GET or POST request from a form element or a GET request using an img element or similar you can not modify the headers sent with the request. Access to the XMLHttpRequest is protected by the same origin policy. This means that simply setting a non standard header on the request and then checking on the server that it is present protects against CSRF done via JavaScript because the code setting the header must have been loaded from the server receiving the request. In GWT 2 custom headers are already set on the client for all RPC requests and are checked by the direct-eval RPC RpcServlet, so this protection already exists for direct-eval RPC calls. The only change needed is to add the check to the RemoteServiceServlet. If you look at the source for the doFinish method in the RpcRequestBuilder class you’ll see that two headers, X-GWT-Permutation and X-GWT-Module-Base are added to all XMLHttpRequest RPC calls.


  protected void doFinish(RequestBuilder rb) {
    rb.setHeader(STRONG_NAME_HEADER, GWT.getPermutationStrongName());
    rb.setHeader(MODULE_BASE_HEADER, GWT.getModuleBaseURL());
  }

RpcRequestBuilder is used on the client by both the original and direct-eval RPC mechanisms. The servlet for the server side of the direct-eval RPC is called RpcServlet and if you look at the source for the getClientOracle method you can see


    String permutationStrongName = getPermutationStrongName();
    if (permutationStrongName == null) {
      throw new SecurityException(
          "Blocked request without GWT permutation header (CSRF attack?)");
    }

To add the same protection to the original RPC mechanism you need to add a similar check to the subclasses of RemoteServiceServlet you implement. I use a common subclass of RemoteServiceServlet as a superclass for all my remote service implementations so in that class I overrode the onBeforeRequestDeserialized method to add a check.


@Override
    protected void onBeforeRequestDeserialized(String serializedRequest) {
        String permutationStrongName = getPermutationStrongName();
        if (permutationStrongName == null) {
            throw new SecurityException(
                 "Blocked request without GWT permutation header (CSRF attack?)");
        }
    }

This change will protect against CSRF attacks made from JavaScript. However, there are apparently ways to set headers from Flash that open a window of vulnerability. There’s more information available about other non JavaScript request mechanisms in part two of the Browser Security Handbook. To protect against this I add another header to the request, this one containing the value of the JSESSIONID cookie, which is accessible on the server as the session id. A cookie value is only accessible to code loaded from the server that set the cookie so checking on the server that the value passed from the client is correct protects against attack by non-javascript mechanisms, provided of course they, and the browser they are using, obey the same origin policy for cookies.

Implementing this second protection requires more work. On the server the principle is the same, retrieve the header value and check it, though you have to handle missing sessions and sessions that have just been created and the client isn’t aware of yet. The example code below would work in the onBeforeRequestDeserialize method.


        HttpServletRequest servletRequest = getThreadLocalRequest();
        HttpSession session = servletRequest.getSession(false);
        // If there is currently no session or if the client doesn't know about it yet then don't check.
        // Otherwise the client must provide the id of the session in a header.
        if (session != null && !session.isNew()) {
            String sessionId = servletRequest.getHeader(SESSION_HEADER);
            if (sessionId == null || !sessionId.equals(servletRequest.getSession().getId())) {
                throw new SecurityException(
                    "Blocked request without session header (CSRF attack?)"));
            }
        }

On the client you have to go to more effort to be able to set an additional header, specifically you need to subclass RpcRequestBuilder and then use your subclass when creating your remote service implementation. For example if the subclass is SubRpcRequestBuilder then the code below creates and configures SomeService correctly.


  SomeServiceAsync svc = (SomeServiceAsync)GWT.create(SomeService.class);
  ((ServiceDefTarget) svc).setRpcRequestBuilder(new SubRpcRequestBuilder());

In SubRpcRequestBuilder you can access the JSESSION id cookie and set the session header in an override of the doFinish method


     String sessionId = Cookies.getCookie("JSESSIONID");
     if (sessionId != null) {
         rb.setHeader(SESSION_HEADER, sessionId);
     }

I’m interested if anyone has any suggestions for further security enhancements or holes I’ve overlooked.

Posted in EffectiveGWT, GWT | 8 Comments »

Expanded multi-touch example

May 10th, 2010 Alex Moffat

I’ve done some more work on my multi-touch example hosted at touchexample.appspot.com. As well as working with the fingers on the iPad/Pod/Phone it also works on Safari, Chrome and Firefox with the mouse. There is little code difference between the different implementations, it’s mostly hidden behind some GWT.create calls so that the majority of the code works with drag events. You can drag and drop the squares into various locations. As you drag a square the others nudge slightly horizontally or vertically to indicate where the dragged square will go if you drop it.

A few things I found interesting, or problems I ran into.

1. Knowing what to do with multi-touch is harder than writing the code to support it and multi-touch drag and drop is going to be hard to do well. When you have only one object moving around it’s fairly simple to work out how to move the rest of the objects on the screen in response. Multiple moving objects make this much more difficult. At the moment though you can drag multiple things at once in touchexample the rest of the animation really only works for one. It is likely the case that just because you can support multiple drags at once you probably shouldn’t in many cases. Of course the importance of user experience design isn’t really a surprise but it does bear thinking about.

2. On the iPad etc., and even on the iPad simulator, if you rapidly start a drag you’ll see that the dragged square moves correctly but the other squares don’t move out of the way as they should. As far as I can tell the events are being delivered to my code as they should be and the correct dom manipulations are being performed but things just aren’t moving. Move investigation is needed here.

3. Debugging problems like 2. are difficult. For most of the work I was able to use the mouse driven code and GWT dev mode. When you’re debugging on the iPad though I needed to use a logging based approach and stream the data to the server for examination.

4. The extra support for CSS3 that Chrome/Safari provides over Firefox 3.6.n lets you achieve some nice effects very simply. Just compare the way touchexample behaves. The animated motion of the non-dragged objects and the fade in and out of the grid is all done with -webkit-transition CSS properties. It’s very easy to get nice animation with no JavaScript/GWT coding at all.

5. No support for IE yet. I’ve not looked very hard but it’s probably just the canvas I’m using to draw the grid when an item is being dragged.

6. Weird focus artifact on Chrome. A small square to the right of the selected square appears when you put the press the mouse button.

Posted in GWT, Multi-touch | 1 Comment »

Inline GWT serialized data with direct-eval RPC

May 1st, 2010 Alex Moffat

Earlier in the year I wrote about my experiences with using Inline GWT serialized data for reduced page load time. I recently tried out the GWT 2.0 direct-eval RPC implementation to see what impact it had in the same situation. First the numbers and then some information on the implementation. I recorded average deserialization timings and payload size using IE6, IE8, Chrome and Firefox 3.6 for one of the largest example processes I have in Blueprint.

RPC

  IE6     391ms 170kb
  IE8     198ms 170kb
  Chrome   31ms 170kb
  Firefox  80ms 170kb

Direct-eval RPC

  IE6     142ms 301kb
  IE8      95ms 301kb
  Chrome  159ms 301kb
  Firefox  76ms 301kb

As you can see the best saving is about 2 tenths of a second, for IE6, while Chrome is actually about 1 tenth of a second slower, which I was not expecting. The payload size just about doubles, as expected from the GWT documentation. Based on this and the advice in the documentation not to use this experimental code in production yet I decided to stick with our current SerializationPolicy based system.

The code on the client side is the same as when you’re using the previous serialization implementation. GWT.create can create the correct sort of serialization factory because ClientDataService implements the RpcService marker interface instead of RemoteService. In the example code below a ClientDate object is deserialized from a string embedded in the HTML page. The calls to Doings.mark and Doings.measure are to record the time take to do the deserializaton.


    public void loadRepository(String serializedData) {
        SerializationStreamFactory factory = GWT.create(ClientDataService.class);
        try {
            // Decode the data
            Doings.mark("deserialize");
            SerializationStreamReader reader = factory.createStreamReader(serializedData);
            clientData = (ClientData) reader.readObject();
            Doings.measure("deserialize");
        } catch (SerializationException e) {
            ClientRepositoryManager.logError("Error loading the repository!", e);
        }
    }

On the server the code is more complex. The basic idea is the same as I described before in the earlier post, you need to create an instance of some class using information produced at compile time and use that as a parameter to a method to serialize the data. When you’re using direct-eval RPC the class you need an instance of is ClientOracle. Once you’ve got that you can call streamResponseForSuccess on RPC. The example code below serializes a ClientData object.


        ClientData data = /* build data */

        // Encode the data to send to the client
        ClientOracle oracle =
            serviceManager.clientOracleProvider(request).getClientOracleFor(request, page);

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        RPC.streamResponseForSuccess(oracle, os, data);

        String payload = "";
        try {
            payload = os.toString("UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException converting json.");
        }

The tricky bit is constructing the ClientOracle and it’s tricky for the same reasons constructing a SerializationPolicy is, you need to use information created at compile time that is normally accessed at run time, and when it’s normally accessed it uses information passed from the client to the server. For direct-eval RPC what you need is the strong name for the permutation that you are going to generate the data for. You can see how this is done if you look at the code for RpcServlet. The data for the ClientOracle is in a file named <strong name>.gwt.rpc. This is in contrast to the SerializationPolicy case where you have a file per RemoteService interface instead of a file per permutation. Unfortunately the permutation is chosen on the client, not on the server, so there is no ready made code to pick the permutation that can be used on the server. You can’t, of course, wait for the client to determine the value because that defeats the whole purpose of this work, avoiding a roundtrip.

My solution uses the symbol maps produced when you pass the -extras flag to the GWT compile. There is one symbol map for each permutation and the name of the symbol map file is <strong name>.symbolMap. The useful thing about the symbol map for my purposes is that at the top of it is information about which values of which deferred binding properties apply to that map. So, by reading the top of the map you can work out which strong name goes with which deferred binding property values. Here’s the first 4 lines from one of the symbol map files. This one is for the permutation used by ie6.

  # { 0 }
  # { 'user.agent' : 'ie6' }
  # jsName, jsniIdent, className, memberName, sourceUri, sourceLine
  KMf,,boolean[],,Unknown,0

As part of the build process I create a mapping from property values to strong name and record this in a file. Then, if you can calculate the values of the binding properties on the server for a particular request, you can choose the correct strong name value and therefore pick the correct .gwt.rpc file. As part of the application initialization a client oracle provider object is configured with the information from the file. When a ClientOracle is requested at runtime the correct property values are calculated from the incoming HTTP request and the appropriate ClientOracle is returned. Caching is used as a single oracle can serve multiple threads.

Posted in EffectiveGWT, GWT | 1 Comment »

iDevelop : Building raps about quests on sand beaches

April 15th, 2010 Alex Moffat

Google automatic closed captioning is a great idea but still has a few problems.

Based on what it thought we were saying in our session proposal a better title than iDevelop : Building web apps for mobile devices is apparently iDevelop : Building raps about quests on sand beaches.

4-14-2010 11-31-42 PM

4-14-2010 11-34-11 PM

4-14-2010 11-34-59 PM

4-14-2010 11-36-24 PM

Posted in GWT, Web | No Comments »

Web 2.0 Expo New York 2010

April 14th, 2010 Alex Moffat

I know I said I’d quickly do a follow up post on my multi-touch work but I used up all my time working on a proposal for a presentation at Web 2.0 Expo in New York in October with Allison, who’s a user experience expert I work with. This year a video is required as part of your submission. I didn’t want to point to any of my Google I/O efforts and Allison didn’t have anything recent so we knocked up the following effort.

The submission guidelines said that the quality of the video wasn’t important and we sort of took them at their word.

The topic though, now that is interesting. Web apps on mobile devices are going to be important, for the same reasons they became important on desktops. The Apple App Store provides users with a way to find apps, and an easy way to install and get upgrades for apps. For developers it provides a distribution channel and, possibly more important, a way to get paid. If you have an existing product, or a product that’s going to have a web interface on the desktop then an App is less compelling in contrast to a web app on a mobile device. You’re already handling the finding and upgrading to support desktop browsers and you’re dealing with payments, if necessary, already. Unless there is some functionality you can’t deliver via the browser, which for the majority of Apps is pretty unlikely, a web app is a great choice. Especially when you consider it let’s you serve users with Android or Palm (as long as they are around) devices with no native code development work.

You can support multi-touch in Safari on iPhones, iPod touches and iPads and single touch on Android. You can remove the browser chrome. You can cache resources on the device. You can provide a custom image for the home screen on iDevices. Really, you can get very close to a native code experience, certainly close enough for a wide range of applications, and in lots of cases native code just isn’t needed.

Posted in Uncategorized | No Comments »

Multi-touch web apps on the iPad with GWT

April 4th, 2010 Alex Moffat

This post builds on my two previous ones about the right way to add support for a new browser to GWT and supporting multi-touch events with GWT on mobile Safari. I have created a very simple demonstration multi-touch app running on Google App Engine. It works on the iPod touch, iPhone and iPad, go to touchexample.appspot.com. You can also try it out using the iPhone/iPad simulator that comes with the iPhone SDK but simulating multi-touch is difficult on that device. When I said very simple I meant it, there are two squares you can drag around the screen at the same time. The video below, though poor, gives you an idea of the interaction involved.

As well as multi-touch this uses a canvas element to create the grid and some webkit CSS to fade it in and out as well as animate the final positioning of the dragged square when it is released.

I’ll explain in more detail how I converted the multi-touch events into drag actions tomorrow. For now I’ll just say that there was only one problem. Consider the following sequence of touches.

  • Finger one down
  • Finger one move
  • Finger two down
  • Finger two move
  • Finger two up
  • Finger one move
  • Finger one up

I expected to see the following sequence of touch events.

  • Touch start (Finger one)
  • Touch move (Finger one)
  • Touch start (Finger two)
  • Touch move (Finger two)
  • Touch end (Finger two)
  • Touch move (Finger one)
  • Touch end (Finger one)

However, when finger two was lifted touch end events were sent for finger two and finger one and then a touch start for finger one. The actual sequence of touch events was

  • Touch start (Finger one)
  • Touch move (Finger one)
  • Touch start (Finger two)
  • Touch move (Finger two)
  • Touch end (Finger two)
  • Touch end (Finger one)
  • Touch start (Finger one)
  • Touch move (Finger one)
  • Touch end (Finger one)

I resorted to a Timer with a 200ms delay so that in a multi-touch situation a touch end would only generate a drag end if it was not followed immediately by a touch start for the same element, and a touch start would not generate a drag start if it immediately followed a touch end for the same element.

Posted in GWT | 1 Comment »

Supporting multi-touch events with GWT on mobile Safari

March 28th, 2010 Alex Moffat

The goal is to be able to handle the touchstart, touchmove, touchend and touchcancel events provided by mobile Safari by writing standard GWT code like the example below for touchstart.


        touchable.addTouchStartHandler(new TouchStartHandler() {
            public void onTouchStart(TouchStartEvent event) {
                event.preventDefault();
                addStyleDependentName("touched");
                Touch t = event.touches().get(0);
                offsetX = t.pageX() - getAbsoluteLeft();
                offsetY = t.pageY() - getAbsoluteTop();
            }
        });

I’ll walk through the steps needed to get this working, concentrating on the implementation needed for the touchstart event.

The easiest place to start is by building the EventHandler and Event subclasses. The code below is the TouchStartHandler. It’s just extends EventHandler.


public interface TouchStartHandler extends EventHandler {

    void onTouchStart(TouchStartEvent event);
}

The TouchStartEvent class is also simple. It implements the abstract methods getAssociatedType and dispatch defined by GWTEvent. I chose to implement a TouchEvent abstract superclass for the TouchStart, TouchMove, TouchEnd and TouchCancel classes following the pattern of the MouseDown, MouseUp etc events provided by GWT. The start of the TouchStartEvent class looks like


public class TouchStartEvent extends TouchEvent<TouchStartHandler> {

    private static final Type<TouchStartHandler> TYPE =
        new Type<TouchStartHandler>("touchstart", new TouchStartEvent());

    public static Type<TouchStartHandler> getType() {
        return TYPE;
    }

    // getAssociatedType and dispatch
}

Notice the value “touchstart” provided as the value of the eventName parameter to the DomEvent.Type constructor. This is used when hooking up the handlers so that they are called when touchstart events are fired by the browser. It does not have to be the native event name but things are less confusing if you follow the convention that it is.

A basic implementation of the TouchEvent superclass just provides access to the touches array of touch objects provided by the native JavaScript.


public abstract class TouchEvent<H extends EventHandler> extends DomEvent<H> {

    public JsArray<Touch> touches() {
        return touches(getNativeEvent());
    }

    private native JsArray<Touch> touches(NativeEvent nativeEvent) /*-{
      return nativeEvent.touches;
    }-*/;
}

I used overlay types to implement Touch so there’s no overhead. The fragment below just shows access to the pageX value.


public class Touch extends JavaScriptObject {

    protected Touch() {
    }

    public final native int pageX() /*-{
      return this.pageX;
    }-*/;

Now all these pieces are in place it possible to write the code that will add support for touch events to a GWT widget. For example you would be able to extend SimplePanel to create TouchPanel and add this method.


    public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
        return addDomHandler(handler, TouchStartEvent.getType());
    }

As you probably expect this doesn’t work. To see why we need to take a look at the implementation of addDomHandler in the Widget class and understand a little about how GWT handles events. The critical line in addDomHandler is


  sinkEvents(Event.getTypeInt(type.getName()));

This is what eventually sets the ontouchstart property of the widget’s element.

Each different type of event supported by GWT has a corresponding integer code returned by Event.getTypeInt. Each code is a single bit so that the codes can be combined with an or operation as a bit field. The bit field is used when event handlers are added or removed to know which handlers are currently set on an element. Adding a new type of event requires that Event.getTypeInt return a new unique value for that type which works with the bit field mechanism and the values used for all the existing types. If you trace through Event.getTypeInt you end up at the implementation in eventGetTypeInt in DOMImpl. It’s just a large switch statement with case statements for each type value. For example


    case "load": return 0x08000;
    case "losecapture": return 0x02000;
    case "mousedown": return 0x00004;

The correct subclass of DOMImpl is chosen at compile time using deferred binding so to support these new events you need a subclass appropriate for mobile Safari. My post “The right way to add support for a new browser to GWT” explains how to do this.

I copied the code for eventGetTypeInt from DOMImpl into my DOMImplMobileSafari class and added new case statements for the new touch* event type values.


    case "touchstart": return 0x100000;
    case "touchmove": return 0x200000;
    case "touchcancel": return 0x400000;
    case "touchend": return 0x800000;

An alternative I experimented with was to override eventGetTypeInt with a non-native method, detect whether the native method returned an undefined value, which indicates no case statement matched, and use an extra switch statement to deal with the touch events. In my opinion the extra complexity wasn’t worth it, if GWT adds extra event types the overridden code will have to be investigated anyway to ensure the int values I’m using are still unique.

Next you need to look at the call to sinkEvents in Widget.addDomHandler. This is where the bit pattern returned from Event.getTypeInt is combined with the patterns from other events already being listened for by the widget to determine which event dispatch handlers should be registered. Tracing through the code leads to sinkEventsImpl in DOMImplStandard. This is the method that needs to be overridden in DOMImplMobileSafari. Each separate event has a corresponding if statement that checks whether the current call to sinkEventsImpl is targeting that event and if it is whether the dispatcher function should be added or removed.


    if (chMask & 0x00020) elem.onmouseout    = (bits & 0x00020) ?
        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;

As with the eventGetTypeInt method I just copied the existing code and added new statements to the end for the touch* bit patterns, for instance


    if (chMask & 0x100000) elem.ontouchstart = (bits & 0x100000) ?
        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;

With this change the solution is complete and the addTouchStartHandler presented earlier works correctly.

Posted in GWT | 13 Comments »

The right way to add support for a new browser to GWT

March 22nd, 2010 Alex Moffat

Well, at least if what you’re doing is supporting something that’s a variation of an existing case. As Thomas Broyer pointed out in a comment on my previous post I should have used the new conditional deferred-binding properties feature added in GWT 2.0. With this approach you define a new property that you use to detect the variation you’re interested in. Here I define a mobile.user.agent property, with values of mobilesafari and none, and a property provider that at runtime chooses between mobilesafari and none.


    <define-property name="mobile.user.agent" values="mobilesafari, none"/>

    <property-provider name="mobile.user.agent"><![CDATA[
      var ua = navigator.userAgent.toLowerCase();
      if (ua.indexOf("webkit") != -1 && ua.indexOf("mobile") != -1) {
        return "mobilesafari";
      }
      return "none";
  ]]></property-provider>

In the absence of any other information this will double the number of permutations because as far as the compiler is concerned the mobile.user.agent property can have either the mobilesafari or the none value for any user.agent value. The neat trick with conditional deferred-binding properties is that you can provide the GWT compiler with information to restrict the number of combinations. By using conditionals inside the set-property you can clamp the compile time value for mobile.user.agent to none for user.agent values other than safari.


    <set-property name="mobile.user.agent" value="none" >
        <none>
            <when-property-is name="user.agent" value="safari" />
        </none>
    </set-property>

This means that instead of having two values of mobile.user.agent for each value of user.agent you have one value for all user.agent values apart from safari. So, instead of doubling the number of permutations you just add one (in the case where you have a single locale). If you are supporting more locales the savings are even greater. With three locales you’d normally have 6 (user.agents) * 3 (locales) = 18 permutations. Add two values for mobile.user.agent and you have 6 (user.agents) * 3 (locales) * 2 (mobile.user.agents) = 36 permutations. Using condition deferred-binding you have (5 (user.agents != safari) + 1 (safari + none) + 1 (safari + mobilesafari)) * 3 (locales) = 21 permutations, saving 15 compilations to create JavaScript that would never be used at runtime because ie6 and mobilesafari is a permutation the property providers will never select.

Using mobile.user.agent also makes the overriding of behavior with deferred binding easier because you no longer have to re-implement the safari case for the mobilesafari browser, instead you can use the separate mobile.user.agent property to select the override where it’s needed.


    <replace-with class="com.google.gwt.user.client.impl.DOMImplMobileSafari">
        <when-type-is class="com.google.gwt.user.client.impl.DOMImpl"/>
        <all>
            <when-property-is name="user.agent" value="safari"/>
            <when-property-is name="mobile.user.agent" value="mobilesafari"/>
        </all>
    </replace-with>

So, until someone points out another better way that’s my solution for tweaking safari to support mobile safari.

Posted in EffectiveGWT, GWT | 3 Comments »