Need a few details about optimizing a widgetset for a touchkit app

I am attempting to optimize a widgetset for a Vaadin Touchkit application.

The application works, but takes too long on its somewhat slow server to load
the first page on mobile devices. I used an http logger program (called
Fiddler) to see the traffic while the app was run, and it showed many messages
loading JavaScript onto the first page – makes sense given the way vaadin
works. By adding up the sizes of mostly .js files downloaded before the first
page was displayed, it was shipping 2-3M. One JS file alone was over 1M.

I have read about optimizing the widgetset; as I understand it, I write code
that informs the system at runtime which connectors are necessary, so that
others can be loaded later, and this limits the amount of information that must
be loaded at application start.

I have read instructions about getting a list of the necessary connectors: run
the application with “?debug” appended to the end of the URL, visit each page
of the application, and then use the little debug window, third tab from the
left, to see instructions. (And yes, I remembered to visit each page of the
application.)

That tab lists the purpose of each of its four tabs, and the third one is for
optimizing widget sets. Unfortunately, though it has all the instructions and
code to be put in the application, it is missing the list of connector names.

Here is what that tab has in it:

    import java.util.HashSet;
    import java.util.Set;
    import com.google.gwt.core.ext.typeinfo.JClassType;
    import com.vaadin.client.ui.ui.UIConnector;
    import com.vaadin.server.widgetsetutils.ConnectorBundleLoaderFactory;
    import com.vaadin.shared.ui.Connect.LoadStyle;
    
    public class OptimizedConnectorBundleLoaderFactory extends
                ConnectorBundleLoaderFactory {
        private Set<String> eagerConnectors = new HashSet<String>();
        {
        }
    
        @Override
        protected LoadStyle getLoadStyle(JClassType connectorType) {
                if (eagerConnectors.contains(connectorType.getQualifiedBinaryName())) {
                        return LoadStyle.EAGER;
                } else {
                        // Loads all other connectors immediately after the initial view has
                        // been rendered
                        return LoadStyle.DEFERRED;
                }
        }
    }

I figure the empty set of braces below the declaration of eagerConnectors
is supposed to have code in it to add names to the set. I figure that without
any names in that set, getLoadStyle will return DEFERRED for all connectors.

The first tab in the debug window shows the component hierarchy, and it has the
names of many connectors in it. I loaded all those into the set by modifying the
above code to this:

        // ... without repeating code above this line
        private Set<String> eagerConnectors = new HashSet<String>();
        {
          eagerConnectors.add("UIConnector");
          eagerConnectors.add("NavigationManagerConnector");
          eagerConnectors.add("NavigationViewConnector");
          eagerConnectors.add("NavigationBarConnector");
          // ... continuing through all Connector names found in the 
          // hierarchy tab...
        }

When I attempt to run the application this way, it first puts up the little
page saying that I’m evidently running on a desktop browser (which I am), then
it fails to load. Once it just displayed its rotating image without end,
the next time it produced the following stacktrace:

    39ms    Dispatching: null -> APP_STARTING flags=false true false
    208ms    Starting application wedding-1225735508
    209ms    Using theme: wedding
    210ms    Vaadin application servlet version: 7.3.10
    213ms    Default implementation of createWidget() does not work for UIConnector. This might be caused by explicitely using super.createWidget() or some unspecified problem with the widgetset compilation.java.lang.IllegalStateException: Default implementation of createWidget() does not work for UIConnector. This might be caused by explicitely using super.createWidget() or some unspecified problem with the widgetset compilation.
       at Unknown.Fg(rc.wedding.gwt.jwWidgetSet-0.js@41)
       at Unknown.Mg(rc.wedding.gwt.jwWidgetSet-0.js@21)
       at Unknown.Qsd(rc.wedding.gwt.jwWidgetSet-0.js@22)
       at Unknown.uPb(rc.wedding.gwt.jwWidgetSet-0.js@2331)
       at Unknown.kPb(rc.wedding.gwt.jwWidgetSet-0.js@43)
       at Unknown.xkd(rc.wedding.gwt.jwWidgetSet-0.js@182)
       at Unknown.KWb(rc.wedding.gwt.jwWidgetSet-0.js@430)
       at Unknown.ZVb(rc.wedding.gwt.jwWidgetSet-0.js@4411)
       at Unknown.Zi(rc.wedding.gwt.jwWidgetSet-0.js@102)
       at Unknown.Ri(rc.wedding.gwt.jwWidgetSet-0.js@60)
       at Unknown.bj(rc.wedding.gwt.jwWidgetSet-0.js@4623)
       at Unknown.Xi(rc.wedding.gwt.jwWidgetSet-0.js@25)
       at Unknown.qi(rc.wedding.gwt.jwWidgetSet-0.js@29)
       at Unknown.vi(rc.wedding.gwt.jwWidgetSet-0.js@57)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@53)
    Caused by: com.vaadin.client.metadata.NoDataException: There is no return type for com.vaadin.client.ui.ui.UIConnector.getWidget
       at Unknown.Eg(rc.wedding.gwt.jwWidgetSet-0.js@30)
       at Unknown.Jg(rc.wedding.gwt.jwWidgetSet-0.js@19)
       at Unknown.dtc(rc.wedding.gwt.jwWidgetSet-0.js@20)
       at Unknown.Ttc(rc.wedding.gwt.jwWidgetSet-0.js@89)
       at Unknown.uPb(rc.wedding.gwt.jwWidgetSet-0.js@2245)
       at Unknown.kPb(rc.wedding.gwt.jwWidgetSet-0.js@43)
       at Unknown.xkd(rc.wedding.gwt.jwWidgetSet-0.js@182)
       at Unknown.KWb(rc.wedding.gwt.jwWidgetSet-0.js@430)
       at Unknown.ZVb(rc.wedding.gwt.jwWidgetSet-0.js@4411)
       at Unknown.Zi(rc.wedding.gwt.jwWidgetSet-0.js@102)
       at Unknown.Ri(rc.wedding.gwt.jwWidgetSet-0.js@60)
       at Unknown.bj(rc.wedding.gwt.jwWidgetSet-0.js@4623)
       at Unknown.Xi(rc.wedding.gwt.jwWidgetSet-0.js@25)
       at Unknown.qi(rc.wedding.gwt.jwWidgetSet-0.js@29)
       at Unknown.vi(rc.wedding.gwt.jwWidgetSet-0.js@57)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@53)
    216ms    Could not determine ApplicationConnection for Overlay. Overlay will be attached directly to the root panel
    2045ms    Ping URL ./PING
    2046ms    Sending a ping request to the server.
    2053ms    Dispatching: APP_STARTING -> SERVER_AVAILABLE flags=false true false
    2053ms    Network Back ONLINE (SERVER_AVAILABLE)
    2385ms    Starting application wedding-1225735508
    2385ms    Using theme: wedding
    2385ms    Vaadin application servlet version: 7.3.10
    2387ms    Default implementation of createWidget() does not work for UIConnector. This might be caused by explicitely using super.createWidget() or some unspecified problem with the widgetset compilation.java.lang.IllegalStateException: Default implementation of createWidget() does not work for UIConnector. This might be caused by explicitely using super.createWidget() or some unspecified problem with the widgetset compilation.
       at Unknown.Fg(rc.wedding.gwt.jwWidgetSet-0.js@41)
       at Unknown.Mg(rc.wedding.gwt.jwWidgetSet-0.js@21)
       at Unknown.Qsd(rc.wedding.gwt.jwWidgetSet-0.js@22)
       at Unknown.uPb(rc.wedding.gwt.jwWidgetSet-0.js@2331)
       at Unknown.kPb(rc.wedding.gwt.jwWidgetSet-0.js@43)
       at Unknown.xkd(rc.wedding.gwt.jwWidgetSet-0.js@182)
       at Unknown.KWb(rc.wedding.gwt.jwWidgetSet-0.js@430)
       at Unknown.ZVb(rc.wedding.gwt.jwWidgetSet-0.js@4411)
       at Unknown.Zi(rc.wedding.gwt.jwWidgetSet-0.js@102)
       at Unknown.Ri(rc.wedding.gwt.jwWidgetSet-0.js@60)
       at Unknown.bj(rc.wedding.gwt.jwWidgetSet-0.js@4623)
       at Unknown.Xi(rc.wedding.gwt.jwWidgetSet-0.js@25)
       at Unknown.qi(rc.wedding.gwt.jwWidgetSet-0.js@29)
       at Unknown.vi(rc.wedding.gwt.jwWidgetSet-0.js@57)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@53)
    Caused by: com.vaadin.client.metadata.NoDataException: There is no return type for com.vaadin.client.ui.ui.UIConnector.getWidget
       at Unknown.Eg(rc.wedding.gwt.jwWidgetSet-0.js@30)
       at Unknown.Jg(rc.wedding.gwt.jwWidgetSet-0.js@19)
       at Unknown.dtc(rc.wedding.gwt.jwWidgetSet-0.js@20)
       at Unknown.Ttc(rc.wedding.gwt.jwWidgetSet-0.js@89)
       at Unknown.uPb(rc.wedding.gwt.jwWidgetSet-0.js@2245)
       at Unknown.kPb(rc.wedding.gwt.jwWidgetSet-0.js@43)
       at Unknown.xkd(rc.wedding.gwt.jwWidgetSet-0.js@182)
       at Unknown.KWb(rc.wedding.gwt.jwWidgetSet-0.js@430)
       at Unknown.ZVb(rc.wedding.gwt.jwWidgetSet-0.js@4411)
       at Unknown.Zi(rc.wedding.gwt.jwWidgetSet-0.js@102)
       at Unknown.Ri(rc.wedding.gwt.jwWidgetSet-0.js@60)
       at Unknown.bj(rc.wedding.gwt.jwWidgetSet-0.js@4623)
       at Unknown.Xi(rc.wedding.gwt.jwWidgetSet-0.js@25)
       at Unknown.qi(rc.wedding.gwt.jwWidgetSet-0.js@29)
       at Unknown.vi(rc.wedding.gwt.jwWidgetSet-0.js@57)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@50)
       at Unknown.eval(rc.wedding.gwt.jwWidgetSet-0.js@53)
    2389ms    Could not determine ApplicationConnection for Overlay. Overlay will be attached directly to the root panel

So now I’m stuck again.

Am I right that the instructions in the debug tab are supposed to have the
names of connectors included in their code?

I don’t know another way to get a complete list of connectors, or perhaps
there’s some other problem that I don’t see because this technology is new to
me.

Any help anyone can offer is appreciated.

I’ve not managed to make this work. Searches provided a few ways that had worked for other people, or suggestions that I cannot verify did work:

  1. someone suggested adding “widgetset=com.example.MyWidgetSet” (no .gwt.xml) to the @VaadinServletConfiguration annotation. I had a bit of trouble figuring out where this should be, but eventually put it in the UI class that extends TouchKitUI. However, it gave me an error message saying it could not find “VAADIN/widgetsets/jwWidgetSet/jwWidgetSet.nocache.js”, so I went back and put in the package name. The application then gave me a pair of rotating progress icons, a small square in the middle of the screen, with the rotating circle icon rotating around that, as if it were on the end of a second hand on an analog clock.

  2. “You must clean up the gwt-unitCache directory (at the same level as the compilation destination) before/after doing a GWT Compile.” I am assuming they do NOT mean to delete all files in this directory after compilation, though it is hard to tell. All of mine had create date/time stamps indicating they were created during my previous compilation.

  3. I went and looked in the source code for AbstractComponentConnector – it is the class that outputs the “Default implementation of createWidget()” error message – and found the following

/**
     * Creates and returns the widget for this VPaintableWidget. This method
     * should only be called once when initializing the paintable.
     * 

     * You should typically not override this method since the framework by
     * default generates an implementation that uses {@link GWT#create(Class)}
     * to create a widget of the same type as returned by the most specific
     * override of {@link #getWidget()}. If you do override the method, you
     * can't call super.createWidget() since the metadata needed
     * for that implementation is not generated if there's an override of the
     * method.
     * 
     * @return a new widget instance to use for this component connector
     */
    protected Widget createWidget() {
        Type type = TypeData.getType(getClass());
        try {
            Type widgetType = type.getMethod("getWidget").getReturnType();
            Object instance = widgetType.createInstance();
            return (Widget) instance;
        } catch (NoDataException e) {
            throw new IllegalStateException(
                    "Default implementation of createWidget() does not work for "
                            + getClass().getSimpleName()
                            + ". This might be caused by explicitely using "
                            + "super.createWidget() or some unspecified "
                            + "problem with the widgetset compilation.", e);
        }
    }

I guess I’m in the “unspecified problem with the widgetset compilation” category, since I have no custom widgets. It does not appear that looking at the source gives me any great insight at this time.

  1. I did one other thing on my own that certainly gives a surprising result, but I don’t know why. I set a breakpoint in the OptimizedConnectorBundleLoaderFactory where I started with all this; set two of them, in fact, one in the initializer and one in the only public method. NEITHER OF THEM WERE HIT. I was expecting them to cause a break during the loading of the application, either before anything happened in the browser or after the initial screen but before the first page was rendered.

So I’m stuck again. Can someone tell me why this code didn’t execute, or at least didn’t cause a breakpoint to be hit? Perhaps the reason it doesn’t seem to make any difference is that there is some other piece of configuration I do not have.