Skip to content
Provides some specialized panels and some related utilities that enables users to work with Mustache and Apache Wicket.
Java
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
library
samples
.gitignore
README.md
pom.xml

README.md

wicket-mustache

Provides a specialized panel and some related utilities that enables users to work with Mustache and Apache Wicket.

Current build status: Build Status

wicket-mustache dependes on mustache.java.

Documentation:

Add maven dependency:

<dependency>
  <groupId>de.agilecoders.wicket.mustache</groupId>
  <artifactId>wicket-mustache</artifactId>
  <version>0.1.0</version>
</dependency>

Installation:

    /**
     * @see org.apache.wicket.Application#init()
     */
    @Override
    public void init() {
        super.init();

        WicketMustache.install(this);
    }

Usage

Example template file:

{{#items}}
Name: {{name}}
Price: {{price}}
  {{#features}}
  Feature: {{description}}
  {{/features}}
{{/items}}

Might be powered by some backing code:

public class Context implements IScope {
  List<Item> items() {
    return Arrays.asList(
      new Item("Item 1", "$19.99", Arrays.asList(new Feature("New!"), new Feature("Awesome!"))),
      new Item("Item 2", "$29.99", Arrays.asList(new Feature("Old."), new Feature("Ugly.")))
    );
  }

  static class Item {
    Item(String name, String price, List<Feature> features) {
      this.name = name;
      this.price = price;
      this.features = features;
    }
    String name, price;
    List<Feature> features;
  }

  static class Feature {
    Feature(String description) {
       this.description = description;
    }
    String description;
  }
}

And would result in:

Name: Item 1
Price: $19.99
  Feature: New!
  Feature: Awesome!
Name: Item 2
Price: $29.99
  Feature: Old.
  Feature: Ugly.

Evaluation of the template proceeds serially. For instance, if you have blocking code within one of your callbacks you the system will pause while executing them:

static class Feature {
  Feature(String description) {
    this.description = description;
  }

  String description() throws InterruptedException {
    Thread.sleep(1000);
    return description;
  }
}

If you change description to return a Callable instead it will automatically be executed in a separate thread if you have provided an ExecutorService when you created your MustacheFactory.

Callable<String> description() throws InterruptedException {
  return new Callable<String>() {

    @Override
    public String call() throws Exception {
      Thread.sleep(1000);
      return description;
    }
  };
}

This enables scheduled tasks, streaming behavior and asynchronous i/o. Check out the samples module in order to see a complete end-to-end example:

package de.agilecoders.wicket;

import de.agilecoders.wicket.mustache.IScope;
import de.agilecoders.wicket.mustache.MustachePanel;
import org.apache.wicket.core.util.resource.PackageResourceStream;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.resource.IResourceStream;

import java.util.Arrays;
import java.util.List;

public class HomePage extends WebPage {
    private static final long serialVersionUID = 1L;

    public HomePage(final PageParameters parameters) {
        super(parameters);

        IModel<IScope> scopeModel = new LoadableDetachableModel<IScope>() {
            @Override
            public IScope load() {
                return new Example();
            }
        };

        add(new MustachePanel("template", scopeModel) {
            @Override
            protected IResourceStream newTemplateResourceStream() {
                return new PackageResourceStream(HomePage.class, "template.mustache");
            }
        });
    }

    public static class Example implements IScope {

        public List<Item> items() {
            return Arrays.asList(
                    new Item("Item 1", "$19.99", Arrays.asList(new Feature("New!"), new Feature("Awesome!"))),
                    new Item("Item 2", "$29.99", Arrays.asList(new Feature("Old."), new Feature("Ugly.")))
            );
        }

        static class Item {
            Item(String name, String price, List<Feature> features) {
                this.name = name;
                this.price = price;
                this.features = features;
            }

            String name, price;
            List<Feature> features;
        }

        static class Feature {
            Feature(String description) {
                this.description = description;
            }

            String description;
        }
    }
}

Client Side Rendering

If you want to render your mustache template on client side you have two options: ClientSideMustachePanel and LazyLoadingClientSideMustachePanel.

add(new ClientSideMustachePanel("template-client", scopeModel) {
    @Override
    protected IResourceStream newTemplateResourceStream() {
        return new PackageResourceStream(HomePage.class, "template.mustache");
    }
});

add(new LazyLoadingClientSideMustachePanel("template-lazy", scopeModel) {
    @Override
    protected IResourceStream newTemplateResourceStream() {
        return new PackageResourceStream(HomePage.class, "template.mustache");
    }

    @Override
    protected CharSequence loading() {
        return "please wait...";
    }

    @Override
    protected Duration delay() {
        return Duration.seconds(5);
    }
});
You can’t perform that action at this time.