QxWT explained Part 4


In the last 3 blog entries (part 1, part 2, part 3) we concentrated on generating JavaScript code using the GWT-Compiler integration and Java-Annotations. In this blog post we’ll concentrate on something completely different.

One of the major problems of JSNI-Wrappers for JavaScript libraries is that you always have to deliver the complete JavaScript-framework though you probably don’t need vast parts (e.g. your application doesn’t use a Tree-control so why still sending out the JS-Code for tree creation?).

A nice feature of the qooxdoo-library is that it comes with a toolchain which analyzes your code dependencies and creates an optimized js-Files for you only holding the code and classes you really need (please note this is still not as good as GWT because GWT even strips out methods you are not calling).

The task now is that we need to teach QxWT to spit out informations about which Java-Classes are used in your application and collect somewhere which JavaScript-class(es) those are related to.

Step 1: Is once to define an annotation:

/**
 * This holds meta informations about JS-Resource-Files required by this class
 */
public @interface QxJsResource {
  /**
   * @return list of qooxdoo javascript resource files
   */
  String[] jsResourceFiles();
}

Step 2: make the GWT-Generator regonize those meta information

Well the GWT-Generator only steps in when creating a Class-Instance using GWT.create() which is a bit of a problem for us because this would required that people create widget-classes like this:

QxLabel l = GWT.create(QxLabel.class);

instead of

QxLabel l = new QxLabel();

beside that inconvenience the second problem is that this concept assumes that there’s a no-arg constructor which is not available always in QxWT and there are even static classes which are not instantiated at all. This means we need to find some other way to make the GWT-Generator to kick in.

The only solution I came up with was to create an inner class, call GWT.create() in an static-init block like this:

public class QxAtom extends QxWidget {
  @QxJsResource(jsResourceFiles={ "qx.ui.basic.Atom" })
  private static class I extends QxJsResourceBuilder {
		
  }
	
  static {
    GWT.create(I.class);
  }
}

Step 3: Collect informations in a GWT-Generator

The information we provide through the annonations have to be collected by a generator which and passed on to the GWT-Linking chain where we can access them and spit out a bootstrap class we can feed into the qooxdoo-Toolchain.

The Generator looks like this:

public class QxToolchainGenerator extends Generator {
  /**
   * {@inheritDoc}
   */
  @Override
  public String generate(TreeLogger logger, GeneratorContext context,
    String typeName) throws UnableToCompleteException {

    try {
      QxJsResource resource = context.getTypeOracle().getType(typeName).getAnnotation(QxJsResource.class);
      for( String jsFile : resource.jsResourceFiles() ) {
        QxToolchainArtifact art = new QxToolchainArtifact(jsFile);
        context.commitArtifact(logger, art);
      }
    } catch (NotFoundException e) {
      throw new UnableToCompleteException();
    }
    return null;
  }
}

The trick here is to generate a so called linker artifact we can pass on to the linker chain and plug in ourselves there with a class like this:

@LinkerOrder(Order.PRE)
public class QxToolchainLinker extends AbstractLinker {
  /**
   * {@inheritDoc}
   */
  @Override
  public String getDescription() {
    return "QooxdooToolChain";
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public ArtifactSet link(TreeLogger logger, LinkerContext context,
    ArtifactSet artifacts) throws UnableToCompleteException {

    ArtifactSet toReturn = new ArtifactSet(artifacts);

    StringBuffer buf = new StringBuffer(template_1);

    for (QxToolchainArtifact e : toReturn.find(QxToolchainArtifact.class)) {
      buf.append("#require(" + e.getQxClassName() + ")\n");
    }
		
    buf.append(template_2);

    // Add a new artifact to the set that we're returning.
    toReturn.add(emitString(logger, buf.toString(), "class/qooxdoogwt/Application.js"));

    return toReturn;
  }
}

This generates the main-Application file used by qooxdoo as the start of an application (similar to class with the main-Method on your Java-Application). We add all collected information to this class using a special meta-data tag “#require” recognized by the qooxdoo toolchain.

Step 4: Call the qooxdoo tool chain

Calling the qooxdoo toolchain is not a very hard task but it still involves some steps you need to follow to use it with our QxWT-Project. That’s why QxWT 1.0.0.2 will come with an extra build-project which provides you with an ant-file to create an deployable QxWT-Application.

One only have to define in 2 parameters:

  • qxproject.name: the project name
  • qxproject.source: the project source directory

For my QxDemo-Project the call looks like this:

ant build.xml -Dqxproject.name=QxDemo -Dqxproject.source=/Users/tomschindl/ws/ufacekit/QxDemo
Advertisement
This entry was posted in QxWT. Bookmark the permalink.

4 Responses to QxWT explained Part 4

  1. Pingback: QxViewers – The first steps towards a UFaceKit-Webport « Tomsondev Blog

  2. Markus says:

    Hi Tom,

    I followed your interesting explanations about Qxwt and its integration into the GWT tool chain. After taking a look into the sources I was wondering if there’s a way to use the classes within an exisiting GWT app?

    Thank you,
    Markus

    • tomeclipsedev says:

      Hi Markus,

      Do you talk about QxWT itself or only the stuff that leverages the code generation facilities? I already thought about extracting the common stuff so that people can easily extend and use it in their own GWT-applications or other JSNI-Wrappers but didn’t had time to do so far because I’m busy working on the 1.0.1.0 release and a show case for QxWT showing it in a real life application.

      Could you specify in more detail what you need? You can also contact me offline on tom dot schindl (a) bestsolution dot at.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.