Juzu is a web framework based on MVC concepts for developing applications. Juzu is an open source project developed on GitHub licensed under the Apache 2 License.

This chapter continues the exploration of the architecture of Juzu, it is an essential read if you want to understand how Juzu globally works and a recommanded read if you extend Juzu. Juzu philosophy is to provide a minimal core that is extended with plugins: this design allows to extend Juzu with no need to touch its core.

Plugins

Juzu plugins can be classified according several criterions. Let’s study the different kind of plugins possible.

Metamodel plugins

A metamodel plugin is executed at compilation time when the application is compiled. Usually it reacts to Java annotations in order to:

  • Validate the application : make checks depending on Java annotations

  • Read or write application resources : create new resources

  • Generate Java code : the generated code will be transparently compiled by the Java compiler

When a metamodel plugin is not happy, it can fail the current by reporting an error to the Java compiler.

Runtime plugins

A runtime plugin is executed during the execution of the web application. A runtime plugin can create objects that will be available for the application. Such objects are usually consumed by the application thanks to the IOC container.

Entity processors

Entity processors map the request and response stream to Java objects.

Value types

Value types map the controller request parameters to request parameters.

Provider factories

A provider factory provides plugability for integrating beans that are not managed natively by the IOC container but needs to be integrated inside the container.

Templating engine

Juzu can easily be extended with new templating engine. Templating engine integrates of course at runtime, however they can optionally be part of the compilation phase of the application for validating templates or for creating resources or classes to be used at runtime.

Value types

Value types is a Juzu plugin for dealing with controller parameters that can trivially be converted from and to strings. In this section we will explain how the juzu.impl.value.ValueType interface works.

Implementing the ValueType

The ValueType abstract class
public abstract class ValueType<T> {

  /**
   * The list of java classes this implementation can handle.
   *
   * @return the list of types.
   */
  public abstract Iterable<Class<?>> getTypes();

  /**
   * Parse a string and returns the corresponding value type.
   *
   * @param element the element annotations
   * @param s the string to parse
   * @return the corresponding value
   * @throws java.lang.Exception any exception preventing the parse to succeed
   */
  public abstract T parse(AnnotatedElement element, String s) throws Exception;

  /**
   * Format a value and returns the corresponding string.
   *
   * @param element the element annotations
   * @param value the value to format
   * @return the corresponding string
   */
  public abstract String format(AnnotatedElement element, T value);

}

The base implementation should extend the ValueType interface and provide a class type for the <T> generic parameter of the class:

The ValueType abstract class
public class DateValueType extends ValueType<java.util.Date> {
  ...
}

The getTypes() interface should return the class type the value type is converting:

The getTypes implementation
public Iterable<Class<?>> getTypes() {
  return Collections.singleton(java.util.Date.class);
}
several types can be returned by the method, this is used by the ValueType that handle primitive types such as int, boolean, etc…

Finally the parse and format methods need to be implemented too:

The parse and format implementations
public Date parse(AnnotatedElement element, String s) throws ParseException {
  return getSimpleDateFormat(element).parse(s);
}

public String format(AnnotatedElement element, Date value) {
  return getSimpleDateFormat(element).format(value);
}

The parse and format methods provides access to the element that is converted, the purpose of those objects is to provide access to optional annotation the element may have. Such annotations can be used by the value type for doing the conversion:

Using the annotated element for configuring the SimpleDateFormat object
private SimpleDateFormat getSimpleDateFormat(AnnotatedElement element) {
  Format format = element.getAnnotation(Format.class);
  return format != null ? new SimpleDateFormat(format.value()) : new SimpleDateFormat();
}

Declaring the ValueType

Value types are declared in the META-INF/services/juzu.impl.value.ValueType file, such plugins are loaded via the java.util.ServiceLoader interface.

Entity processing

Juzu allows the application to interact with request and response entities with the juzu.request.ClientContext and the juzu.Response.Body objects. Those objects are binary data (or character data) oriented and provide a low level interface for reading or writing request entities.

Juzu provides also a plugable higher level API for dealing with request entities such as File Upload or Json. In this section we will explain how to implement such plugins.

Entity unmarshallers

Entity unmarshallers are plugins that decodes a juzu.request.ClientContext into a set of arguments that will be used by Juzu when invoking the controller. The unmarshaller can manipulate those arguments, usually reading the request entity. The juzu.impl.request.EntityUnmarshaller abstract class has two methods to implement, let’s review them.

The EntityUnmarshaller abstract class
public abstract class EntityUnmarshaller {

  /**
   * Decide wether or not this reader accept to read the specified <code>mediaType</code> argument.
   *
   * @param mediaType the media type to test
   * @return true if the media type is accepted
   */
  public abstract boolean accept(String mediaType);

  /**
   * Unmarshall the entity from the {@link juzu.request.ClientContext}. This unmarshaller can modify the
   * request control arguments:
   * <ul>
   *   <li>the contextual arguments can be iterated and the value updated</li>
   *   <li>the parameter arguments map can be freely modified</li>
   * </ul>
   *
   * @param mediaType the request media type
   * @param context the client context for reading the entity
   * @param contextualArguments the contextual arguments
   * @param parameterArguments the contextual parameters
   * @throws IOException anything preventing the read operation to succeed
   */
  public abstract void unmarshall(
      String mediaType,
      ClientContext context,
      Iterable<Map.Entry<ContextualParameter, Object>> contextualArguments,
      Map<String, RequestParameter> parameterArguments) throws IOException;

}

Implementing an unmarshaller

The accept method is quite simple to implement, it should return true when the unmarshaller wants to unmarshall the incoming request, for instance:

@Override
public boolean accept(String mediaType) {
  return mediaType.equals("application/json");
}

The unmarshall method will be invoked when the accept method returns true. At this moment, the unmarshaller should read the entity data using the ClientContext interface and update the request arguments. There are two kinds of request arguments that can be modified:

  • parameter arguments using the parameterArguments method parameter

  • contextual arguments using the contextualArguments method parameter

Parameter arguments is a mutable map that provides string parameter values, those parameters are used by Juzu at a later stage when invoking the controller handler. Those parameters can be used as is, or can be transformed into other types via the ValueType extension or the @Mapped bean mapping. The File Upload unmarshaller will create parameter arguments when reading the file upload form.

Contextual arguments are any controller argument that are not parameter arguments (i.e any type that is not a ValueType or annotated with @Mapped). The unmarshall method can iterate over such arguments and modify them freely. The ContextualParameter object provides the name, class+ and _generic type+ of the argument. Those shall be used by the unmarshaller to properly modify the arguments. The _File Upload unmarshaller will look at the contextual arguments having the type org.apache.commons.fileupload.FileItem and the right argument name to do the match.

Declaring an unmarshaller

Unmarshallers are declared in the META-INF/services/juzu.impl.request.EntityUnmarshaller file, such plugins are loaded via the java.util.ServiceLoader interface.

Entity marshallers

Entity marshallers are plugins that encodes an object, usually returned by a controller handler into binary data sent with the response. The juzu.impl.request.EntityMarshaller abstract class has a single method marshall to implement, let’s review it.

Implementing a marshaller

The EntityMarshaller abstract class
public abstract class EntityMarshaller {

  /**
   * Marshall the object for the specified <code>mimeType</code> or return null.
   *
   * @param mimeType the mime type to test
   * @param annotations the contextual annotations
   * @param object the object to marshall  @return the corresponding streamable
   */
  public abstract Streamable marshall(String mimeType, AnnotatedElement annotations, Object object);

}

The marshall method will be invoked by Juzu, when a controller returns an unknown object response (i.e an object that does not inherit from the juzu.Response class). The marshall method can either return a null response to signal that it cannot handle it or a Streamable implementation that will be used to create a juzu.Response.

Declaring a marshaller

Unmarshallers are declared in the META-INF/services/juzu.impl.request.EntityMarshaller file, such plugins are loaded via the java.util.ServiceLoader interface.

Asset minifier

An asset minifier is simple interface providing the opportunity to transform the original source files into a new version that is a minified version of this source.

A minifier should implement the juzu.plugin.assetMinifier interface and provide a no argument constructor. Minification occurs at compilation time when the annotations are processed: Juzu instantiates a minifier to transform the physical asset and write the minified version on the disk. The minified asset name uses the original asset name with the -min suffix placed before the asset name extension, for instance jquery.js will be named as jquery-min.js, this is totally transparent for the user.

Let’s look at the implementation of the minifier:

public class NormalizeJSMinifier implements Minifier {

  @Override
  public InputStream minify(String name, String type, InputStream stream) throws IOException {
    if (type.equals("script")) {
      NormalizeJSReader reader = new NormalizeJSReader(new InputStreamReader(stream));
      String s = Tools.read(reader);
      return new ByteArrayInputStream(s.getBytes());
    } else {
      throw new IOException("Can only process scripts and not " + type + " asset");
    }
  }
}

The minify method provides three arguments: . the asset value, for instance jquery.js . the asset type with possible values of script and stylesheet . the asset stream

The implementation is quite simple it wraps, the InputStream argument and returns the minifying stream.

in this implementation the stream is buffered before returning the stream because Java does not provide an out of the box ReaderInputStream but if it would be the case, that could be done on the fly instead of buffering. In all case the implementation can chose between buffering the stream or transforming on the fly.

Provider factories

Provider factories provide plugability for integrating beans that are not managed by the IOC container. A provider factory is dynamic: it is a factory for javax.inject.Provider that returns a provider for a specificied class. Usually provider factories will lookup the service in a registry (like another IOC container) and returns a provider that return them lazily or not.

The provider factory defines the getProvider method:

  /**
   * Returns a provider for a specific type or null if it cannot be produced.
   *
   * @param implementationType the implementation class object
   * @param <T>                the implementation generic type
   * @return a provider for this class or null
   * @throws Exception any exception that would prevent to obtain the provider
   */
  <T> Provider<? extends T> getProvider(Class<T> implementationType)
    throws Exception;

The factory implementation must provide a public zero argument constructor and it will be instantiated during the application boostrap by Juzu to obtain the provider. The returned providers will then be bound into the IOC container.

The IOC container uses the java.util.ServiceLoader discovery mechanism for finding provider factories when injection occurs.

Let’s study a simple example with a provider for the current time:

Time provider factory
package my;

public class TimeProviderFactory implements java.inject.ProviderFactory {
  public <T> Provider<? extends T> getProvider(final Class<T> implementationType) throws Exception {
    if (implementationType == java.util.Date.class) {
      return new Provider<T>() {
        public T get() {
          return implementationType.cast(new java.util.Date());
        }
      };
    }
    else {
      return null;
    }
  }
}

This provider should be declared in the META-INF/services/juzu.inject.ProviderFactory file:

Time provider configuration
my.TimeProvider

Templating SPI

This chapter dives into the template life cycle from the compilation time to the run time. We will describe the template Service Provider Interface (SPI), the SPI is designed to make Juzu templating extensible and integrating template engines in Juzu. This chapter is optional is you are only writing ab application with Juzu, however it is a must read if you want to know more Juzu internals or if you want to understand how to integrate a template engine in Juzu.

When a Juzu application is compiled, the Juzu annotation processor detects the @Path annotations and triggers the compilation of the related templates. The template compilation can be split in two parts:

Compiling a Groovy template

Let’s study an example with the Groovy template at compilation time.

Life cycle
Figure 1. Compiling a Groovy template

When the Java compiler is invoked, the following steps are executed

  1. The Java compiler triggers the Juzu annotation processor when it finds the @Path annotation

  2. Juzu resolves the relative path to the templates package of the application

    1. When the template cannot be resolved a compilation error is triggered

    2. Otherwise the template is loaded

  3. The template provider is looked up according to the file name extension, it generates the index.groovy_ source file

  4. Juzu creates the index class that extends the juzu.template.Template class annotated by the @Path("index.gtmpl") annotation

After that the only remaining part is to compile the index.groovy_ source to a class. It can be achieved either at build time using the groovyc compiler or at load time when the index template is loaded using a GroovyClassLoader. The former approach makes the build a bit more complex (but not much as Groovy compilation is fairly well supported in build systems or IDEs) as it requires to run a Groovy compilation but it will perform additional validation of the template as well as reduce the load time of the template. The later approach will detect any compilation error (such as Groovy syntax error) at runtime and the index.groovy_ compilation will take a few milliseconds.

This flexibility allows to use the lazy approach during development and when the application is released then the Groovy compiler can be used to compile the index.groovy_.

Type safe URL resolution

Groovy templates provides the @{…} syntax for generating URL from the application controllers. This section gives an overview of the underlying resolution mechanism.

URL resolution
Figure 2. Template URL resolution during compilation
  • Parse: the template is parsed into its model representation

  • Resolve: the index link is resolved againt the controller meta model

  • Validate: the index link is validated

  • Emit: the corresponding index.groovy_ file is emitted and save on the class output

  • Compile: the Groovy source is compiled into a class by the groovyc compiler (this part is done after javac)

Template Service Provider Interface

Juzu provides a Service Provider Interface (SPI) for integrating thirdparty template engine. Actually all template system are integrated with the SPI. We will study briefly the integration points so you can integrate a template engine of your choice in Juzu.

Template providers

The juzu.impl.template.spi.TemplateProvider is the main entry point when a templating system is integrated. The provider is triggered during the compilation phase by the APT system built into the Java compiler.

public abstract class TemplateProvider<M extends Serializable> {
  ...
}

The provider must declare the template model <M> generic type, this type must be a serializable as Juzu will sometimes write template models on the disk during the compilation. This usually happens only in Eclipse due its incremental compiler architecture. The type specified by the provider is privately managed (i.e it is opaque for Juzu) and it symbolizes an internal representation of the parsed source (usually an Abstract Syntax Tree), it will be used in various methods of the provider.

Let’s have a review of the methods of this class to have a better understanding.

  /**
   * Returns the template source extension without the dot recognised by
   * this provider. For instance it should return <code>gtmpl</code>
   * for groovy templates.
   *
   * @return the source extension
   */
  public abstract String getSourceExtension();

The getSourceExtension() method is used to determine what file extension the provider can compile. The implementation should return a constant value, for instance the Groovy provide simply returns the gtmpl value.

  /**
   * Parse the provided char sequence and return the corresponding template model.
   *
   * @param context the parse context
   * @param source the source to parse
   * @return the corresponding template model
   * @throws TemplateException any template related exception
   */
  public abstract M parse(
      ParseContext context,
      CharSequence source) throws TemplateException;

  /**
   * Process the template.
   *
   * @param context the process context
   * @param templateModel  the template to process
   * @throws TemplateException any template related exception
   */
  public abstract void process(
      ProcessContext context,
      TemplateModel<M> templateModel) throws TemplateException;

  /**
   * Provide an opportunity for emitting a file on the disk.
   *
   * @param context the emit context
   * @param templateModel the template
   * @throws TemplateException any template related exception
   * @throws IOException any io exception
   */
  public abstract void emit(
      EmitContext context,
      TemplateModel<M> templateModel) throws TemplateException, IOException;

The parse, process and emit methods care about transforming the template source to its final representation: the compiled template.

  • The parse method is invoked with the content of the template and returns a template model. The representation returned by the parse method is a parsed representation of the template source. If a parsing error occurs the method can throw a TemplateException.

  • The process method is invoked after the template is parsed with the necessary context for performing further processing of the template, for instance the Groovy templating engine performs the resolution of type safe URLs or type safe parameters declaration at this moment. During the process:

    • The provider can resolve other templates using the ProcessContext, if the template to resolve is not yet loaded it will trigger the parse/process/emit lifecycle, it if was already processed the template is simply returned

    • The implementation can resolve controller methods and translate them into method invocation, this is used for checking type safe URL and translating them into controller companion invocation

    • The juzu.impl.template.spi.TemplateModel argument models the template, it has several fields such as the underlying model or the template path

    • The implementation can declare type safe parameters using the TemplateModel#addParameter(String) method. The declared parameters will be generated on the juzu.template.Template subclass

  • The emit method is invoked when the template processing is over. The EmitContext interface can be used to create resources during this round.

  /**
   * Return the template stub type.
   *
   * @return the template stub class
   */
  public abstract Class<? extends TemplateStub> getTemplateStubType();

Finally the getTemplateStubType() returns the type of a java class that will be used for creating a template stub. For each template, a stub is created, the stub is responsible for loading the template at runtime, i.e the original template or the compiled template that may have been generated during compilation during the emit callback.

Template stub

Template stubs are java classes created by Juzu for managing a template at runtime on behalf of the provider. Each provider provides its own stub implementation as a juzu.impl.template.spi.TemplateStub subclass.

A stub must provide a public constructor accepting a java.lang.String argument: the template id. The template id if the class name of the generated template. In addition, a stub must implement two abstract methods:

  /**
   * Init the template with the associated resource.
   *
   * @param loader   the class loader
   */
  protected abstract void doInit(ClassLoader loader);

  /**
   * Performs template rendering.
   *
   * @param renderContext the render context
   * @throws TemplateExecutionException any execution exception
   * @throws IOException any io exception
   */
  protected abstract void doRender(TemplateRenderContext renderContext)
      throws TemplateExecutionException, IOException;

The doInit method loads the template using the provided ClassLoader, it will be call only once before the template is rendered. Usually it uses the template id provided during the construction of the template to locate the template on the disk, in its original form or in its compiled form.

The doRender method renders the template using the provided TemplateRenderContext. The render context provides the necessary hooks such as:

  • Producing markup

  • Setting the title

  • Obtaining the locale

  • Accessing parameters or application beans for resolving expressions

Template at work

After having described the various pieces of the templating SPI, let’s look at how the template generated stubs are used by Juzu templating system at runtime.

When the controller declares the index.gtmpl template the compiler produces three artifacts * the index class template inherits juzu.template.Template: it is the only class visible from the controller and the whole application * the index.groovy_ Groovy template is the effective template code: it produces the markup, resolve expressions, etc…

At work
Figure 3. index groovy at work

When a controller is instantiated, the index template instance is injected into the controller, the @Path annotation plays an essential role because it’s a qualifier and that qualifier is used to distinguish the correct subclass to inject in the controller.

When the template is created, the corresponding template stub is instantiated. When the template needs to be rendered, the doInit(ClassLoader) method of the stub is invoked. At this moment the Groovy index_ class is loaded from the class loader, when the class is not found, the index.groovy_ is loaded and it is compiled on the fly.

Qualified template class

Controller can be injected with the juzu.template.Template class, however they can also be injected with the template subclass that was genereted by Juzu: instead of using the qualified template injection, the controller declares the template index subclass. This approach cab be used when type safe parameters are used as only the index type declares the fluent API.

For instance if the index.gtmpl declares the color parameter the index class will look like:

@Path("index.gtmpl")
public class index extends Template {

  ...

  public index with() {
    return new index.Builder();
  }

  public class Builder extends Template.Builder {

    public Builder color(String color) {
      // Generated code
    }
  }
}

The controller can then use the fluent API:

public class Controller {

  @Inject
  @Path("index.gtmpl")
  Template index;

  @View
  public Response.Content index() {
    return index.with().color("red").ok();
  }
}

Bundlegen plugin tutorial

The bundlegen plugin tutorial provides guidance for the implementation of a Juzu metamodel plugin.

Unbreakable resource bundles

The bundlegen plugin generates a typed Java class for a resource bundle:

@BundleGen("mybundle")
@Application
package my.app;

Le’t suppose we have this mybundle.properties file:

hello_world=Hello World

This will generate a bundlegen Java class, the application can then retrieve the entries via static methods:

String s = bundlegen.hello_world();

The bundle will be loaded using the current user locale, providing unbreakable resource bundles!

The implementation

We will provide now a detailled analysis of the plugin structure and code. This plugin is a metamodel plugin, it does all the work during the compilation: it processes @BundleGen annotations in order to generate a Java class source for this bundle. The generated source will be transparently compiled by the Java compiler in the same compilation phase than the application.

The plugin will be packaged under the examples.plugin.bundlegen package and provides three classes:

  • examples.plugin.bundlegen.BundleGen annotation is the plugin API : the application will use this annotation for describing its bundles

  • examples.plugin.bundlegen.impl.BundlResolver is an utility class used by the generated code at runtime for loading a bundle

  • examples.plugin.bundlegen.impl.BundleGenMetaModelPlugin is the metamodel plugin triggered during by the compilation phase by Juzu

The metamodel plugin structure

Let’s begin by describing the overral plugin structure. The metamodel plugin BundleGenMetaModelPlugin extends the juzu.impl.plugin.application.metamodel.ApplicationMetaModelPlugin base class. It must provide a no arguments public constructor

  public BundleGenMetaModelPlugin() {
    super("bundlegen");
  }

This plugin must be declared in the META-INF/services/juzu.impl.plugin.application.metamodel.ApplicationMetaModelPlugin file:

examples.plugin.bundlegen.impl.BundleGenMetaModelPlugin

To process the @BundleGen annotation the plugin needs to declare the annotations it has interest for, this is done in the init method.

  @Override
  public Set<Class<? extends Annotation>> init(ProcessingContext env) {
    return Collections.<Class<? extends Annotation>>singleton(BundleGen.class);
  }

Processing the @BundleGen annotation

During compilation our plugin will receive lifecycle callbacks for the BundleGen annotation:

  @Override
  public void processAnnotationAdded(ApplicationMetaModel application, AnnotationKey key, AnnotationState added) {
    Name type = key.getType();
    if (type.toString().equals(BundleGen.class.getName())) {
      ElementHandle.Package pkg = (ElementHandle.Package)key.getElement();
      bundles.put(pkg, (String)added.get("value"));
    }
  }

  @Override
  public void processAnnotationRemoved(ApplicationMetaModel application, AnnotationKey key, AnnotationState removed) {
    Name type = key.getType();
    if (type.toString().equals(BundleGen.class.getName())) {
      ElementHandle.Package pkg = (ElementHandle.Package)key.getElement();
      bundles.remove(pkg);
    }
  }

The two callbacks are used to maintain a map with all the known annotations by the plugin. Indeed code generation will not occur in those callbacks but in a later callback (prePassivate). The annotation key object provides access to:

  • the element declaring the annotation, in our case it is an ElementHandle.Package since our annotation can only target Java packages

  • the annotation type, we use it to check this is our annotation: in our case the check is here for educational purpose since we only register interest for the @BundleGen annotation

The annotation state is a map containing the various annotation members: we retrieve the value member that is the name of the resource bundle we will use later.

Generating the bundle source

Until now we focused on the plugin structure and the lifecycles of the framework. This part will show the implementation of the prePassivate callback we mentionned earlier:

The prePassivate callback
  @Override
  public void prePassivate(ApplicationMetaModel application) {
    for (Map.Entry<ElementHandle.Package, String> entry : bundles.entrySet()) {
      ElementHandle.Package pkg = entry.getKey();
      String bundleName = entry.getValue();
      processBundle(application, pkg, bundleName);
    }
  }

The prePassivate method has the application argument which is the current application being processed it can be used to access the overral application structure. The implementation simply iterates the bundles map of the plugin calling the processBundle method:

The processBundle method
  private void processBundle(ApplicationMetaModel application, ElementHandle.Package pkg, String bundleName) {
    ProcessingContext context = application.getProcessingContext();
    PackageElement pkgElt = context.get(pkg);
    Properties properties = loadBundle(context, pkg, bundleName);
    if (properties == null) {
      throw BUNDLE_NOT_FOUND.failure(pkgElt, bundleName);
    } else {
      try {
        generateBundleClass(context, properties, pkgElt, bundleName);
      }
      catch (IOException e) {
        throw CANNOT_CREATE_BUNDLE.failure(pkgElt, bundleName).initCause(e);
      }
    }
  }

The processBundle does three things:

  • it uses processing context to load the resource bundle via the loadBundle method

  • when the bundle is found, the class generation is delegated to the generateBundleClass method

  • error handling

    • when the bundle is not found, the plugin raises a BUNDLE_NOT_FOUND exception

    • when the generateBundleClass* method thows an +IOException the CANNOT_CREATE_BUNDLE exception is raised

Raising an error is done via the juzu.impl.compiler.ProcessingException. Providing the package element is important as it allows the compiler to do a precise error reporting when showing the error. Such exception can be created directly or via the juzu.impl.compiler.MessageCode class: it uses the ProcessingException to create the notion of message code:

  public static final MessageCode BUNDLE_NOT_FOUND = new MessageCode("BUNDLE_NOT_FOUND", "The bundle %1$s cannot be resolved");
  public static final MessageCode CANNOT_CREATE_BUNDLE = new MessageCode("CANNOT_CREATE_BUNDLE", "The bundle %1$s cannot be created");

The loadBundle implementation uses the current ProcessingContext to load the bundle property file the user will provide in the package containing the @BundleGen annotation:

The loadBundle method
  private Properties loadBundle(ProcessingContext context, ElementHandle.Package pkg, String bundleName) {
    Path.Absolute absolute = pkg.getPackageName().resolve(bundleName + ".properties");
    FileObject bundle = context.resolveResourceFromSourcePath(pkg, absolute);
    if (bundle != null) {
      try {
        InputStream in = bundle.openInputStream();
        Properties properties = new Properties();
        properties.load(in);
        return properties;
      }
      catch (IOException e) {
        context.log(Level.SEVERE, "Could not load resource bundle", e);
      }
    }
    return null;
  }

Finally let’s wrap up the bundle processing by looking at the generateBundleClass method which generates the Java class:

The generateBundleClass method
  private void generateBundleClass(ProcessingContext context, Properties properties, PackageElement pkgElt, String bundleName) throws IOException {
    String fqn = pkgElt.getQualifiedName() + "." + bundleName;
    JavaFileObject source = context.createSourceFile(fqn, pkgElt);
    PrintWriter writer = new PrintWriter(source.openWriter());
    writer.println("package " + pkgElt.getQualifiedName() + ";");
    writer.println("import examples.plugin.bundlegen.impl.BundleResolver;");
    writer.println("public class " + bundleName + " {");
    for (String key : properties.stringPropertyNames()) {
      writer.println("public static String " + key + "() {");
      writer.println("return BundleResolver.resolve(" + bundleName + ".class, \"" + key + "\");");
      writer.println("}");
    }
    writer.println("}");
    writer.close();
  }

The implementation is quite straightforward, it creates a source file that returns a JavaFileObject whose writer is used to to print the source code of the bundle. The generated bundle class contains one method for each property of resource bundle.

Testing the plugin

The last part of the bundlegen tutorial explains how to test a compilation plugin. We will use create a mock application from its sources, this way we will test the plugin works from the source files to the runtime.

We will study three tests each one focusing on a different aspect of the plugin usage:

  • successful generation of the bundle class

  • runtime resolving of the bundle via the bundle class

  • correct error reporting when the bundle properties file does not exist

Testing the bundle generation

For this part, we will only use the Juzu compiler interface which is a wrapper of the underlying Java compiler that can be used for writing unit tests. This wrapper allows us to compile an application from its sources. Our test application contains the following package declaration:

@BundleGen("mybundle")
@Application
package examples.app1;

The resource bundle properties contains a single property:

abc=def

The sources of the application are located in the resources of the project, the only thing needed for the compiler to resolve the source is the package of the application.

The testGenerateBundle test
  @Test
  public void testGenerateBundle() throws Exception {
    CompilerAssert<File, File> compilerAssert = compiler("examples.app1"); //1
    compilerAssert.assertCompile();                                        //2
    ReadWriteFileSystem<File> output = compilerAssert.getClassOutput();    //3
    ClassLoader loader = new URLClassLoader(new URL[]{ output.getURL() }); //4
    Class<?> bundleClass = loader.loadClass("examples.app1.mybundle");     //5
    Method m = bundleClass.getDeclaredMethod("abc");                       //6
    assertEquals(String.class, m.getReturnType());
  }
1 Create the compiler from the tested application package
2 Triggers compilation
3 Get the file system where the compiler created the compiled classes
4 Create a classloader for loading the bundle class
5 Load the bundle class
6 Assert the bundle class structure

Testing the plugin failure

In the previous section we tested the expected behavior of the plugin when it works, we also need to test the behavior of the plugin when the bundle does not exist. The absence of the bundle properties file will raise a compilation error with the BUNDLE_NOT_FOUND message code. By default the compiler will use the message defined in the constant, however we can set the compiler in the special formalErrorReporting mode that will use instead the message code value, making easier to write our test:

The testBundleNotFound test
  @Test
  public void testBundleNotFound() throws Exception {
    CompilerAssert<File, File> compilerAssert = compiler("examples.app2");
    compilerAssert.formalErrorReporting();                                     //1
    List<CompilationError> errors = compilerAssert.failCompile();              //2
    assertEquals(1, errors.size());                                            //3
    CompilationError error = errors.get(0);
    assertEquals(BundleGenMetaModelPlugin.BUNDLE_NOT_FOUND, error.getCode());  //4
    assertEquals(Collections.singletonList("mybundle"), error.getArguments());
    File source = error.getSourceFile();
    assertEquals("package-info.java", source.getName());
    assertEquals("app2", source.getParentFile().getName());
  }
1 Set the formalErrorReporting mode
2 We call now the failCompile that returns a list of compilation errors
3 We shall have a single error
4 Among other checks we assert that the BUNDLE_NOT_FOUND code was used

Testing the bundle resolution

Last but not last, we will test now the runtime behavior. A very simple controller will test the behavior at runtime:

public class Controller {
  @View
  public Response index() {
    return Response.ok("<abc>" + mybundle.abc() + "</abc>");
  }
}

The previous test only required a compiler, now we need to execute our application. Juzu provides a mocking framework that takes an application, compiles and then run it.

The testResolveBundle test
  @Test
  public void testResolveBundle() throws Exception {
    MockApplication<File> application = application(InjectorProvider.GUICE, "examples.app1"); //1
    application.init();                                                                       //2
    MockClient client = application.client();
    MockViewBridge view = client.render();                                                    //3
    String markup = view.assertStringResponse();
    assertEquals("<abc>def</abc>", markup);                                                   //4
  }
1 Create a mock application
2 The init step compiles and starts the application
3 Render the application, this invokes the index method of the application
4 Assert the returned application markup is correct

Metrics plugin tutorial

The Metrics plugin tutorial provides guidance for the implementation of a Juzu service. This plugin provides an integration of the Metrics library in Juzu. Metrics is an easy to use library for reporting and publishing metrics.

In this section we will study three Juzu runtime aspects:

Creating a Juzu service

A Juzu service is a class extending the juzu.impl.plugin.application.ApplicationService abstract class. The service must be declared in a +META-INF/services/juzu.impl.plugin.application.ApplicationService_ file:

The META-INF/services/juzu.impl.plugin.application.ApplicationService service declaration
examples.plugin.metrics.MetricsService

Our service constructor must be a public no argument constructor, it calls the super constructor with the service name metrics:

  public MetricsService() {
    super("metrics");
    registry = new MetricRegistry();
    responses = registry.timer("juzu.responses");
  }

The constructor initializes two fields:

  • the registry field, a Metrics registry that holds all the metrics, this registry will be bound in the IOC container so an application or another service can be injected with this registry for publishing custom metrics

  • the responses field, a Metrics timer, bound in registry that will accumulate request statistics

Service initialization

After the service is created, Juzu will call its init method to perform the initialization step. The init method can return a ServiceDescriptor that will instruct Juzu to load the service. The service can chose to return null instead of the descriptor, the null value tells Juzu to discard the service instead.

The service descriptor contains a list of BeanDescriptor classes: this is the list of the beans the service wants to register in the IOC container. In our case we want to expose the Metrics registry as a singleton bean so it can be injected in the whole application:

  @Override
  public ServiceDescriptor init(ServiceContext context) throws Exception {
    Provider<MetricRegistry> registryProvider = new Provider<MetricRegistry>() {
      @Override
      public MetricRegistry get() {
        return registry;
      }
    }; //1
    BeanDescriptor registryDescriptor = BeanDescriptor.createFromProvider(  //2
        MetricRegistry.class,
        Scope.SINGLETON,
        Collections.<Annotation>emptyList(),
        registryProvider);
    return new ServiceDescriptor(Arrays.asList(registryDescriptor));        //3
  }
1 Create a javax.inject.Provider that wraps the registry field
2 Create a singleton bean descriptor
3 Return the service descriptor with the registry bean

After the service is initialized, the service will be started, this event can be intercepted with the javax.annotation.PostConstruct callback: our service will use it to bind the registry into the static SharedMetricRegistries exposed by Metrics:

  @PostConstruct
  public void start() {
    SharedMetricRegistries.add(application.getPackageName(), registry);
  }

The registry is bound under the application package name, making sure that registries will be namespaced correctly to avoid collisions.

Intercepting the request

We have now a fully initiliazed Metrics registry and timer, let’s see how to intercept the Juzu requests to collect statistics in this timer. Intercepting a request is done by implementing the juzu.impl.request.RequestFilter interface for a specific request stage.

The application request is indeed decomposed into four stages:

  • unmarshalling : unmarshalls the request entity when there is one

  • handler : determine the handler arguments and get the application handler from the IOC container

  • lifecycle : trigger the controller lifecycle and calls the juzu.request.RequestLifeCycle interface when necessary

  • invoke : performs the handler method invocation on the controller

Our service can use mostly any of these stage as it just wants to count the number of requests, so it will use the invoke stage and thus our service implements the RequestFilter<Stage.Invoke> interface:

  @Override
  public Response handle(Stage.Invoke argument) {
    final Timer.Context context = responses.time();
    try {
      return argument.invoke();
    } finally {
      context.stop();
    }
  }

The implementation is quite trivial, it uses the responses timer to collect the request statistic.

Testing the plugin

We will test the plugin via the MockApplication object provided by Juzu, the test application is quite simple with a single controller:

public class Controller {

  @Inject
  public Controller(MetricRegistry registry) {
    registry.meter("custom");
  }

  @View
  public Response index() {
    return Response.ok("ok");
  }
}
  • the constructor is injected with the registry and it publishes a custom meter

  • the index method handles the application request and returns a simple ok value

Our test will assert three things:

  • the Metrics registry is published in the SharedMetricRegistries

  • the Metrics registry recorded the request succesfully

  • the Metrics registry can be used by the application

  @Test
  public void testTimer() throws Exception {
    SharedMetricRegistries.clear();                                                             //1
    MockApplication<File> application = application(InjectorProvider.GUICE, "examples.metrics");//2
    application.init();
    MockClient client = application.client();
    MockViewBridge view = client.render();                                                      //3
    assertEquals("ok", view.assertStringResponse());
    assertEquals(Collections.singleton("examples.metrics"), SharedMetricRegistries.names());    //4
    MetricRegistry registry = SharedMetricRegistries.getOrCreate("examples.metrics");
    Timer timer = registry.getTimers().get("juzu.responses");                                   //5
    assertEquals(1, timer.getCount());
    Meter meter = registry.getMeters().get("custom");                                           //6
    assertNotNull(meter);
  }
1 Clear the SharedMetricRegistries
2 Create the mock application
3 Invoke the application
4 Check our registry was published under the application package name
5 Get the timer and check it recorded the statistic
6 Check the application used the registry via injection succesfully