Important
for deep understanding of settings purpose declared in web.xml, you should take a look at the WUIC configuration design.

Configuring the wuic.xml

The table bellow describes each tag and their hierarchy in the wuic.xml file:

Root Level 0 Level 1 Level 2 Level 3
wuic
|____ nut-dao-builders
| |_________ nut-dao-builder
| |_________ properties
| |_________ property
|____ nut-filter-builders
| |_________ nut-filter-builder
| |_________ properties
| |_________ property
|____ heaps
| |_________ heap
| |_________ nut-path
| |_________ heap
| |_________ heap-id
|____ engine-builders
| |_________ engine-builder
| |_________ properties
| |_________ property
|____ workflow-templates
|_________ workflow-template
|_________ engine-chain
|_________ engine-builder-id
|____ workflows
|_________ workflow

wuic

This is simply the root tag, nothing else matter ;-)

<wuic>
    ...
</wuic>

nut-dao-builders

The NutDao builders usable in the context. Each builder will be usable from the heap.

<wuic>
    <nut-dao-builders>
        ...
    </nut-dao-builders>
</wuic>

nut-dao-builder

Each builder creates a NutDao thanks to a set of properties. When a factory is created, it is used to build NutDao thanks to a String representation of its path. Defines an unique ID to be referenced somewhere else. Also declares the class name as a class attribute.

Finally, an optional regex attribute could be specified (default value is false). If true, the nut names must be a compilable pattern.

<wuic>
    <nut-dao-builders>
        <nut-dao-builder id="http-resource-builder" type="HttpNutDaoBuilder">
            ...
        <nut-dao-builder>
    </nut-dao-builders>
</wuic>
Tip
id attribute is optional. If not set, the properties will be applied to the default instance of the type.
Tip
type attribute is optional. The default value is ClasspathNutDaoBuilder (for classpath access).

nut-filter-builders

The NutFilter builders usable in the context. Each builder will be used inside the context

<wuic>
    <nut-filter-builders>
        ...
    </nut-filter-builders>
</wuic>

nut-filter-builder

Each builder creates a NutFiler thanks to a set of properties. Objects are built thanks to a String representation of its path. Defines an unique ID to be referenced somewhere else. Also declares the class name as a class attribute. When any heap is built from the context, its paths are previously filtered with all defined filters.

<wuic>
    <nut-filter-builders>
        <nut-filter-builder id="remove-regex-filter-builder" type="RegexRemoveNutFilterBuilder">
            ...
        <nut-filter-builder>
    </nut-filter-builders>
</wuic>
Tip
id attribute is optional. If not set, the properties will be applied to the default instance of the component indicated in the type.

engine-builders

Defines the engine builders usable in any workflow.

<wuic>
   <engine-builders>
       ...
   </engine-builders>
</wuic>

engine-builder

An EngineBuilder is always identified by an unique ID to be referenced somewhere else. Also defines the class to be instantiated.

<wuic>
   <engine-builders>
       <engine-builder id="yuicomspressor-js" type="YuiCompressorJavascriptEngineBuilder" />
   </engine-builders>
</wuic>
Tip
id attribute is optional. If not set, the properties will be applied to the default instance of the component indicated in the type. Note that default instances are injected by default in any workflow.

properties

The properties define a list of settings for both nut-dao-builder and engine-builder elements.

<wuic>
    <nut-dao-builders>
        <nut-dao-builder id="http-resource-builder" type="HttpNutDaoBuilder">
            <properties>
                ...
            <properties>
        <nut-dao-builder>
    </nut-dao-builders>
</wuic>

or

<wuic>
    <engine-builders>
        <engine-builder id="jsSprite" type="ImageAggregatorEngineBuilder">
            <properties>
                ...
            </properties>
        </engine-builder>
    </engine-builders>
</wuic>

property

A property used to initialize the builder. Defines a key attribute and a value as a child node.

<wuic>
    <nut-dao-builders>
        <nut-dao-builder id="http-resource-builder" type="HttpNutDaoBuilder">
            <properties>
                <property key="c.g.wuic.httpServerDomain">gdrouet.github.io</property>
                <property key="c.g.wuic.httpBasePath">wuic</property>
            <properties>
        <nut-dao-builder>
    </nut-dao-builders>
</wuic>

or

<wuic>
    <engine-builders>
        <engine-builder id="jsSprite" type="ImageAggregatorEngineBuilder">
            <properties>
                <property key="c.g.wuic.engine.spriteProviderClassName">javascript</property>
            </properties>
        </engine-builder>
    </engine-builders>
</wuic>

heaps

Defines the different heaps of nuts you can load in your application.

<wuic>
    <heaps>
        ...
    </heaps>
</wuic>

heap

A heap is identified by an unique ID and must defines a builder to use (dao-builder-id attribute). The builder is referenced thanks to its ID.

<wuic>
    <heaps>
        <heap id="common-js" dao-builder-id="classPathBuilder">
            ...
        </heap>
    </heaps>
</wuic>
Tip
dao-builder-id is optional. By default, the default ClasspathNutDaoBuilder will be used.

nut-path

The nut-path defines the path that allows to access a nut has child node. Finally, you can represent a set of nuts if your associated DAO considers paths as regex.

<wuic>
    <heaps>
        <heap id="common-js" default-builder="classPathBuilder">
            <nut-path>/js/common.js</nut-path>
            <nut-path>/js/misc/*.js</nut-path>
        </heap>
    </heaps>
</wuic>

heap-id

Your heap could be a composition of another heaps. Inside a heap, you can refer an existing one with heap-id or declare a new heap on the fly.

<wuic>
    <heaps>
        <heap id="homepage-js" dao-builder-id="classPathBuilder">
           <heap-id>common-js</heap-id>
           <heap id="homepage-js" dao-builder-id="http-resource-builder">
               <nut-path>http://com.myapp/js/foo.js</nut-path>
           </heap>
           <nut-path>js/bar.js</nut-path>
        <heap>
    </heaps>
</wuic>
Warning
nuts retrieved from nut-path are always read before nuts retrieved from nested and referenced heaps. If order matter, you should not mix nut-path with heaps and only use heap and heap-id to preserve order.

workflow-templates

The workflow templates describe the way the nut could be processed.

<wuic>
    <workflow-templates>
           ...
    </workflow-templates>
</wuic>

workflow-template

The workflow template is declared to contain a list of engines. It is identified with an unique ID.

Below, the example shows that a workflow template will be created and identified with tpl ID.

<wuic>
    <workflow-templates>
        <workflow-template id="tpl">
            ...
        </workflow-template>
    </workflow-templates>
</wuic>

engine-chain

The engines chain will refers all the engines to use when processing the workflow. They could be specified in any order, WUIC will order them by kind, especially to guarantee that cache engine will be at the head of the chain.

<wuic>
    <workflow-templates>
        <workflow-template id-prefix="js-image" heap-id-pattern="sprite-">
            <engine-chain>
                ...
            </engine-chain>
        </workflow-template>
    </workflow-templates>
</wuic>

engine-builder-id

The engine-builder-id contains has child text node the ID of an existing engine builder to be added in the chain of responsibility executed by the workflow.

<wuic>
    <workflow-templates>
        <workflow-template id-prefix="js-image" heap-id-pattern="sprite-">
            <engine-chain>
                <engine-builder-id>jsSprite</engine-builder-id>
            </engine-chain>
        </workflow-template>
    </workflow-templates>
</wuic>

workflows

The workflows are the bridge between the heaps and the workflow template that list the engines to use.

<wuic>
    <workflows>
           ...
    </workflows>
</wuic>

workflow

The workflow is declared to be applied on a set of heaps described with the heap-id-pattern property interpreted as a regex. Each heap’s name matching the regex will be associated to a workflow identified by the heap name and eventually a prefix specified in id-prefix property.

The workflow is always built on top of a template referenced with workflow-template-id property.

Below, the example shows that a workflow will be created for each heap with a name containing image word. Those workflows will be named with a string starting with sprite-.

<wuic>
    <workflows>
        <workflow id-prefix="sprite-" workflow-template-id="tpl" heap-id-pattern=".*image" />
    </workflows>
</wuic>

Another possibility is to replace id-prefix attribute by an id attribute. In this case, only one workflow is created identified by the value in the id attribute. This workflow is associated to a heap which is a composition of all heaps with an ID matching the heap-id-pattern attribute regex value.

<wuic>
    <workflows>
        <workflow id="workflow" workflow-template-id="tpl" heap-id-pattern=".*image" />
    </workflows>
</wuic>

Configuring WUIC components

Configuring the engines

Engines could be configured with specific properties used to define an engine builder. In XML, this looks like this:

    <engine-builders>
        <engine-builder id="jsSprite" type="ImageAggregatorEngineBuilder">
            <properties>
                <property key="c.g.wuic.engine.spriteProviderClassName">javascript</property>
            </properties>
        </engine-builder>
    </engine-builders>

The possible properties for an engine are tightly coupled to the underlying project and its purpose.

Important
if you’re going to configure an engine provided by an extension, make sure the dependency has been added to your pom.xml! Find available extensions here

Here is the list of all possible properties for each engine builder. Find description of each property here

Components discovered under package com.github.wuic.engine

Note: In property name, * at the beginning of the name should be replaced by c.g.wuic.
Class/Property *computeVersionAsynchronously *engine.aggregate *engine.bestEffort *engine.cache *engine.cacheProviderClass *engine.charset *engine.command *engine.compress *engine.convert *engine.disableOptimizations *engine.ecmaScriptVersion *engine.inputNutType *engine.inspect *engine.libraries *engine.lineBreakPos *engine.obfuscate *engine.outputNutType *engine.packerClassName *engine.pathSeparator *engine.preserveLineBreakPos *engine.preserveSemiColons *engine.serverHint *engine.spriteProviderClassName *engine.timeToLive *engine.useNodeJs *engine.verbose *engine.wrapPattern
CommandLineConverterEngineBuildertrue N/A N/A N/A N/A N/A Empty String N/A true N/A N/A Empty String N/A Empty String N/A N/A Empty String N/A N/A N/A N/A N/A N/A N/A N/A N/A
CssInspectorEngineBuilderN/A N/A N/A N/A N/A UTF-8 N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
EhCacheEngineBuilderN/A N/A false true net.sf.ehcache.Cache N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
GzipEngineBuilderN/A N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
HtmlCompressorEngineBuilderN/A N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A false N/A N/A N/A N/A N/A N/A N/A
HtmlInspectorEngineBuilderN/A N/A N/A N/A N/A UTF-8 N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A
ImageAggregatorEngineBuilderN/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A com.github.wuic.engine.core.BinPacker N/A N/A N/A N/A N/A N/A N/A N/A N/A
ImageCompressorEngineBuilderN/A N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
JavascriptInspectorEngineBuilderN/A N/A N/A N/A N/A UTF-8 N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A Empty String
MemoryMapCacheEngineBuilderN/A N/A false true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A -1 N/A N/A N/A
SpriteInspectorEngineBuilderN/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A true N/A N/A N/A N/A N/A N/A N/A N/A N/A com.github.wuic.engine.core.CssSpriteProvider N/A N/A N/A N/A
TextAggregatorEngineBuildertrue true N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
TypeScriptConverterEngineBuildertrue N/A N/A N/A N/A N/A N/A N/A true N/A ES3 N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A false N/A N/A
YuiCompressorCssEngineBuilderN/A N/A N/A N/A N/A UTF-8 N/A true N/A N/A N/A N/A N/A N/A -1 N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
YuiCompressorJavascriptEngineBuilderN/A N/A N/A N/A N/A UTF-8 N/A true N/A true N/A N/A N/A N/A -1 true N/A N/A N/A N/A true N/A N/A N/A N/A false N/A

Configuring the NutDao

There are several ways to access resources:

  • inside your webapp (Classpath, WAR, RequestDispatcher)

  • or outside (FTP, HTTP, SSH, etc)

WUIC access provides support for each protocol. A protocol is wrapped by a NutDao implementation which is built thanks to a NutDaoBuilder implementation. You can choose to use a protocol when you refer a NutDaoBuilder in your heap. In your wuic.xml, you will declare it like this:

    <nut-dao-builder id="sourceRootProvider" class="ClasspathNutDaoBuilder" />

Here are the possible classes for each protocol:

  • RequestDispatcher: RequestDispatcherNutDaoBuilder (typically for statics under src/main/webapp)

  • Classpath: ClasspathNutDaoBuilder (typically for statics under src/main/resources)

  • Webapp: WebappNutDaoBuilder (typically for statics under src/main/webapp/WEB-INF except src/main/webapp/WEB-INF/lib which is ignored)

  • HTTP: HttpNutDaoBuilder

  • SSH: SshNutDaoBuilder

  • FTP: FtpNutDaoBuilder

  • Disk: DiskNutDaoBuilder

  • Amazon S3: S3NutDaoBuilder

  • Google Storage: GStorageNutDaoBuilder

Important
if you’re going to configure a DAO provided by an extension, make sure the dependency has been added to your pom.xml! Find available extensions here

Each time you specify a class, you can override its default properties. For instance, you will override the FTP domain server like this:

    <nut-dao-builder id="sourceRootProvider" class="FtpNutDaoBuilder">
        <property key="c.g.wuic.serverDomain">mycompany.com</property>
    </nut-dao-builder>

Not all properties are supported by each builder. Here is a table which describe them and their support by builder.

Note: you can find description of each property here

Components discovered under package com.github.wuic.nut.dao

Note: In property name, * at the beginning of the name should be replaced by c.g.wuic.
Class/Property *computeVersionAsynchronously *dao.basePath *dao.basePathAsSystemProperty *dao.cloudBucket *dao.contentBasedVersionNumber *dao.downloadToDisk *dao.login *dao.password *dao.pollingInterval *dao.proxyUris *dao.regex *dao.secret *dao.serverDomain *dao.serverPort *dao.wildcard *fixedVersionNumber
ClasspathNutDaoBuildertrue / false N/A false N/A N/A N/A -1 null false N/A N/A N/A false Empty String
DiskNutDaoBuildertrue . false N/A false N/A N/A N/A -1 null false N/A N/A N/A false Empty String
FtpNutDaoBuildertrue Empty String false N/A false false Empty String Empty String -1 null false false localhost 21 N/A Empty String
GStorageNutDaoBuildertrue Empty String false Empty String false N/A Empty String Empty String -1 null N/A N/A N/A N/A N/A Empty String
HttpNutDaoBuildertrue Empty String false N/A N/A N/A N/A N/A -1 N/A N/A false localhost 80 N/A Empty String
S3NutDaoBuildertrue Empty String false Empty String false N/A Empty String Empty String -1 null false N/A N/A N/A N/A Empty String
SshNutDaoBuildertrue . false N/A false N/A Empty String Empty String -1 null false N/A localhost 22 N/A Empty String

Configuring the NutFilter

In some context, you might want to remove some nuts from the declared heap. For instance, you can add debug files to your page to be removed once you are in production. Filters like RegexRemoveNutFilterBuilder can help you if you enable them. They can remove some of the nuts once without the need to do it manually.

In XML, configuring a filter looks like this:

    <nut-filter-builder id="regexRemoveNutFilter" type="RegexRemoveNutFilterBuilder">
        <properties>
            <property key="c.g.wuic.filter.regexExpressions">
                .*.js
                ref.css
            </property>
        </properties>
    </nut-filter-builder>
Important
please note that filters are global and apply to all declared heaps.

Not all properties are supported by each builder. Here is a table which describe them and their support by builder.

Note: you can find description of each property here

Components discovered under package com.github.wuic.nut.filter

Note: In property name, * at the beginning of the name should be replaced by c.g.wuic.
Class/Property *filter.enable *filter.regexExpressions
RegexRemoveNutFilterBuildertrue Empty String

Intercept component creation

When WUIC instantiates all its components, a list of registered ObjectBuilderInspector is chained and called to modify the instance. The interface corresponds to the following code:

public interface ObjectBuilderInspector {
    <T> T inspect(T object);
}

Any instance can be registered:

  • By declaring the class names in web.xml configuration.

  • By relying on ServiceLoader. This can be achieved by creating a file that contains the class names of different implementations and called META-INF/services/com.github.wuic.config.ObjectBuilderInspector.

By default, any object is inspected. If you want to specify for which type of object your inspector is supposed to be invoked, you can annotate your class with the @InspectedType annotation like this:

@ObjectBuilderInspector.InspectedType({IFoo.class, Bar.class})
class InspectBarAndFoo extends I implements ObjectBuilderInspector {
}

In this example, any created object will be inspected by the inspector if it IS-A Foo or Bar.

Configuring the web.xml

Introduction

Basic use case is to use WUIC inside a servlet container configured traditionally with a web.xml file. This documentation described how to configure three main components:

  • WuicServletContextListener: the listener that bootstraps WUIC

  • HtmlParserFilter: the filter that optimizes HTML pages

  • WuicServlet: the servlet that served the statics

Configuring the ContextListener

wuic-servlet.jar contains a ContextListener annotated with the servlet 3 @WebListener annotation and allows WUIC to bootstrap.

You can configure the execution of the listener with the following context-param.

Reminder for default implementation:

    <context-param>
        <param-name>your param name</param-name>
        <param-value>your param value</param-value>
    </context-param>

Note for those who don’t want to use init-param: you will see the particular c.g.wuic.initParameterClass init-param in the table below. If you want to provide parameters in a different way, specify an implementation of com.github.wuic.util.BiFunction (inspired from Java 8). It must be parameterized with String type only. The first parameter of apply() expects the key and the second parameter the default value. The method returns the value associated to the given key. If you set this init-param, no other init-param with a key mentioned bellow will be interpreted since your implementation will be used.

In the Parameter name column bellow, replace the first * character from all keys and replace it with c.g.wuic.

Parameter name Description Default value
*.facade.wuicContextPath Virtual base path for any nut name Empty string
*.facade.wuicXmlPath String used to build a `java.net.URL` expected to point to a `wuic.xml` file /wuic.xml in the classpath
*.facade.wuicXmlPathAsSystemProperty Considers the `c.g.wuic.facade.wuicXmlPath` as a system property to get to build the URL false
*.facade.propertiesPath String used to build a `java.net.URL` expected to point to a `wuic.properties` file /wuic.properties in the classpath
*.facade.propertiesPathAsSystemProperty Considers the `c.g.wuic.facade.propertiesPath` as a system property to get to build the URL false
*.facade.useDefaultContextBuilderConfigurators Injects in WUIC the default builders to have basic `NutDao` and `Engine` available during configuration true
*.facade.additionalBuilderConfiguratorClasses List of comma-separated class names extending ContextBuilderConfigurator that will be used in the facade. Empty string
*.facade.additionalBuilderInspectorClasses List of comma-separated class names extending ObjectBuilderInspector that will be used in the facade. Empty string
*.facade.wuicMultipleConfigInTagSupport For tag support (Thymeleaf, JSP, etc): tell to parse the configuration every time the tag is run false
*.facade.wuicWarmupStrategy When a context is built, a warmup strategy could be specified run all known workflows asynchronously (`ASYNC`), synchronously (`SYNC`) or not (`NONE`) NONE
*.initParameterClass Indicates the com.github.wuic.util.BiFunction implementation which retrieves a value for a given parameter. Of course, default implementation relies on init-param in web.xml file. Internal InitParamProperties class

Configuring the WuicServlet

If you want to serve directly the statics from your webapp, you need to configure the servlet:

    <servlet>
        <description>WUIC servlet</description>
        <servlet-name>wuic</servlet-name>
        <servlet-class>com.github.wuic.servlet.WuicServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>wuic</servlet-name>
        <url-pattern>/wuic/*</url-pattern>
    </servlet-mapping>

Configuring the HtmlParserFilter

Warning
parsing the HTML takes time. You should enable the best effort mode: if the HTML has been parsed before and the result still exists in the cache, it applies replacements. However, it just return the unparsed HTML to deliver as fast as possible the response and process scripts asynchronously.

Install the filter

If your pages are served from your application server, you can filter them with the HTML filter:

<filter>
    <filter-name>htmlParserFilter</filter-name>
    <filter-class>com.github.wuic.servlet.HtmlParserFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>htmlParserFilter</filter-name>
    <url-pattern>/html/*</url-pattern>
</filter-mapping>

Supported settings

Parameter name Description Default value
c.g.wuic.filter.disableServerPush Never use HTTP/2 server-push even if possible and use server-hints instead false
c.g.wuic.forceDynamicContent Always consider the filtered HTML as dynamic instead of checking if tag support (JSP or Thymeleaf) has been used to generate the response false

Extend the filter

Custom DAO

By default WUIC uses a RequestDispatcherNutDao. The javadoc describes how you can extend the filter to specify another DAO or even a complete chain of engines to use. Note that if you use FilterRegistration then you can instantiate the class with different constructors instead of using the default one.

Custom page identification
Important
WUIC computes an unique ID for each filtered page. For each ID, WUIC will associate all the filtered statements and cache them. This means that if two page lead to the same ID, you will start facing weird issues. By default, the servlet path is used to compute the ID. If other discriminators are used, you can create a class that extends the HtmlParserFilter and override it like that:
    /**
     * {@inheritDoc}
     */
    @Override
    protected byte[][] extractWorkflowId(final HttpServletRequest httpRequest) {
        final byte[][] bytes = new byte[NumberUtils.TWO][];
        bytes[0] = httpRequest.getServletPath().getBytes();
        bytes[1] = httpRequest.getQueryString() != null ? httpRequest.getQueryString().getBytes() : new byte[0];

        return bytes;
    }
}

In this example, we identify the page with all parameters in query string in addition to the servlet path.

Complete sample

You have the sample here.

Parameter name Description Default value
c.g.wuic.filter.disableServerPush Never use HTTP/2 server-push even if possible and use server-hints instead false
c.g.wuic.forceDynamicContent Always consider the filtered HTML as dynamic instead of checking if tag support (JSP or Thymeleaf) has been used to generate the response false

Built-in HTML templating

Built-in templating is a set of features that you can use when your HTML content is optimized by WUIC (using the servlet Filter or by declaring it in a heap).

When WUIC optimizes HTML content, it uses by default the HtmlInspectorEngine component that supports several tags and attributes to customize the way your HTML template is optimized.

data-wuic-skip: don’t optimize the script

If you want WUIC skips files referenced by the HTML file, you can use the data-wuic-skip in the tag. This is useful if you don’t want to aggregate a particular resource for some reason. Moreover you can use it when WUIC does not already supports some features or you find a bug :) (don’t forget to file an issue in that case).

Example:

<script data-wuic-skip src="script-to-skip.js"></script>

wuic:html-import: import workflow

Any declared workflow can be executed to inject the result in your HTML page just by adding <wuic:html-import /> tag with the desired ID associated to the attribute workflowId.

Example:

<wuic:html-import workflowId="myWorkflow" />

Java Config

Purpose

WUIC could be integrated without necessarily use the XML configuration API. All XML configuration points are directly provided by a Java API which could be preferred in several use cases, especially for frameworks that want integrate WUIC.

Note: for deep understanding of Java Config purpose, you should take a look at the WUIC configuration structure.

Create the facade

WUIC provides its facade which helps to invoke workflow and configure mainly:

  • DAOs (the way you access nuts)

  • Heaps (the sets of nuts)

  • Engines (the different transformations applied on nuts)

  • The chains (the engines called to process the heaps)

You can create a new facade like this:

        try {
            final WuicFacade facade = new WuicFacadeBuilder().contextPath("/statics").build();
        } catch (WuicException e) {
            log.error("Unable to build the facade.", e);
        }

We indicate the processed nuts will be served on your HTTP server from /statics. Here all the URLs will be rewritten using this prefix during process (like background-url inside CSS). This means that the result of any process must be reached from this root path (http://localhost/statics for instance).

By default the facade injects DAOs and engines with default settings to make your configuration faster. This could be disabled with:

        try {
            final WuicFacade facade = new WuicFacadeBuilder()
                    .noDefaultContextBuilderConfigurator()
                    .build();
        } catch (WuicException e) {
            log.error("Unable to build the facade.", e);
        }

Check the javadoc to see other configurations points exposed by the WuicFacadeBuilder.

Default instances are created for all DAOs / Engine discovered in the classpath by WUIC. They are identified by wuicDefault[SimpleClassName][Builder], for instance wuicDefaultTextAggregatorEngineBuilder for the default instance of TextAggregatorEngine:

For default properties:

Additional DAOs and Engine will be available regarding the extensions you add to your classpath.

Configure the facade

To configure the facade, you can extend ContextBuilderConfigurator and implement its two abstract methods:

  • getTag(): identifies all the settings you perform in your class. This helps WUIC to keep them when other configurators want to reset their previous operations.

  • internalConfigure(ContextBuilder): the ContextBuilder used inside the facade where you can define everything you need.

For instance, use can access the WuicFacadeBuilder internal ContextBuilder and modify it like this:

        final WuicFacadeBuilder builder =  new WuicFacadeBuilder();
        final String engineId = ContextBuilder.getDefaultBuilderId(TextAggregatorEngine.class);
        final String daoId = ContextBuilder.getDefaultBuilderId(DiskNutDao.class);

        try {
            final WuicFacade facade = builder.noDefaultContextBuilderConfigurator()
                    .contextBuilder()
                    // tag the configuration, always release the tag in a finally block to not face deadlock issue
                    .tag("custom")
                    // create a ContextNutDaoBuilder which produces DAO of type DiskNutDao
                    .contextNutDaoBuilder(DiskNutDao.class)
                    // override default property by telling that any path specified is relative to /static
                    .property("c.g.wuic.dao.basePath", "/statics")
                    // back to ContextBuilder
                    .toContext()
                    // create a heap using "daoId" with two nuts "darth.js" and "vader.js"
                    .heap("heap", daoId, new String[] { "dark.js", "vador.js"} )
                    // create a ContextEngineBuilder which produces engine of type TextAggregatorEngine
                    .contextEngineBuilder(TextAggregatorEngine.class)
                    // back to ContextBuilder
                    .toContext()
                    // creates a template "tpl" that describes a process that call the engine
                    .template("tpl", new String[]{ engineId })
                    // creates a workflow "starwarsWorkflow" with heap "heap" and the process described by "tpl"
                    .workflow("starwarsWorkflow", true, "heap", "tpl")
                    // release the tag before build
                    .releaseTag()
                    // back to FacadeBuilder
                    .toFacade()
                    // Build facade
                    .build();
        } catch (IOException ioe) {
            log.error("Unable to build the facade.", ioe);
        } catch (WuicException e) {
            log.error("Unable to build the facade.", e);
        } finally {
            builder.contextBuilder().releaseTag();
        }

Alternatively, you can create your own implementation of a ContextBuilderConfigurator to configure the ContextBuilder:

    public class MyContextBuilderConfigurator extends ContextBuilderConfigurator {

        @Override
        public int internalConfigure(final ContextBuilder ctxBuilder) {
            // ...
            return -1;
        }

        @Override
        public String getTag() {
            return "myCfg";
        }

        @Override
        public ProcessContext getProcessContext() {
            return ProcessContext.DEFAULT;
        }

        @Override
        protected Long getLastUpdateTimestampFor(final String path) throws IOException {
            return -1L;
        }
    }

You can inject an instance in your facade like this:

        try {
            final WuicFacade facade = new WuicFacadeBuilder().contextBuilderConfigurators(new MyContextBuilderConfigurator()).build();
        } catch (WuicException e) {
            log.error("Unable to build the facade.", e);
        }
Tip
you can automatically install any custom ContextBuilderConfigurator by relying on ServiceLoader. This can be achieved by creating a file that contains the class names of different implementations and called META-INF/services/com.github.wuic.context.ContextBuilderConfigurator.

Note that you can also force a facade to be refreshed with a ContextBuilderConfigurator:

        try {
            facade.configure(new MyContextBuilderConfigurator());
        } catch (WuicException e) {
            log.error("Unable to build the facade.", e);
        }

Run a workflow

Finally, when your facade has been configured, you can then run any created workflow like this:

        try {
            // Contains one nut
            final List<ConvertibleNut> nut = facade.runWorkflow("starwarsWorkflow", ProcessContext.DEFAULT);

            nut.get(0).getName();    // aggregate.js
            nut.get(0).openStream(); // InputStream
        } catch (WuicException e) {
            log.error("Unable to build the facade.", e);
        } catch (IOException ioe) {
            log.error("Unable to build the facade.", ioe);
        }

Note that the facade is thread safe so you can use it with concurrency.