Changes in log4j.properties are ignored, when running sl4fj under Tomcat

Lately, I run into this very subtle bug:
my logs were all visible, like intended and configured in log4j.properties (or log4j.xml), when I fired up my web-application in development-mode under Jetty with mvn jetty:run.
But if I installed the application on the production-server, which uses a Tomcat 7 servlet-container, no special logger-configuration where picked up from my configuration-file.
But – very strange – my configuration-file was not ignored completely.
The appender-configuration and the log-level from the root-logger where picked up from my configuration-file.
Only all special logger-configuration were ignored.

Erroneous logging-configuration

Here is my configuration, as it was when I run into the problem:

  • Logging was done with slf4j
  • Logs were written by log4j with the help of slf4j-log4j12
  • Because I was using some legacy libraries, that were using other logging-frameworks, I had to include some bridges to be able to include the log-messages, that were logged through this frameworks in my log-files.
    I used: jcl-over-slf4j and log4j-over-slf4j.

Do not use sl4fj-log4j and log4j-over-slf4j together!

As said before:
All worked as expected while developing under Jetty and in production under Tomcat, only special logger-confiugrations where ignored.

Because of that, it took me quiet a while and a lot of reading, to figure out, that this was not a configuration-issue, but a clash of libraries.
The cause of this strange behaviour were the fact, that one must not use the log4j-binding slf4j-log4j12 and the log4j-bridge log4j-over-slf4j together.

This fact is quiet logically, because it should push all your logging-statements into an endless loop, where they are handed back and forth between sl4fj and log4j as stated in the sl4fj-documentation here.
But if you see all your log-messages in development and in production only the configuration behaves strangley, this mistake is realy hard to figure out!
So, I hope I can save you some time by dragging your attention to this.

The solution

Only the cause is hard to find.
The solution is very simple:
Just switch from log4j to logback.

There are some more good reasons, why you should do this anyway, over which you can learn more here.

Configure HTTPS for jetty-maven-plugin 9.0.x

For the impatient

If you do not want to know why it does not work and how I fixed it, just jump to the quick fix!

jetty-maven-plugin 9.0.x breaks the HTTPS-Connector

With Jetty 9.0.x the configuration of the jetty-maven-plugin (formaly known as maven-jetty-plugin) has changed dramatically. Since then, it is no more possible to configure a HTTPS-Connector in the plugin easily. Normally, connecting your development-container via HTTPS was not often necessary. But since Snowden, encryption is on everybodys mind. And so, testing the encrypted part of your webapp becomes more and more important.

Why it is “broken” in jetty-maven-plugin 9.0.x

A bug-report stats, that

Since the constructor signature changed for Connectors in jetty-9 to require the Server instance to be passed into it, it is no longer possible to configure Connectors directly with the plugin (because maven requires no-arg constructor for any <configuration> elements).

The documentation includes an example, how to configure a HTTPS Connector with the help of a jetty.xml-file. But unfortunatly, this example is broken. Jetty refuses to start with the following error: [ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.0.5.v20130815:run (default-cli) on project FOOBAR: Failure: Unknown configuration type: New in org.eclipse.jetty.xml.XmlConfiguration@4809f93a -> [Help 1].

Get HTTPS running again

So, here is, what you have to do to fix this broken example: the content shown for the file jetty.xml in the example is wrong. It has to look like the other example-files. That is, ith has to start with a <Configure>-tag. The corrected content of the file looks like this:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<!-- ============================================================= -->
<!-- Configure the Http Configuration                              -->
<!-- ============================================================= -->
<Configure id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
  <Set name="secureScheme">https</Set>
  <Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
  <Set name="outputBufferSize">32768</Set>
  <Set name="requestHeaderSize">8192</Set>
  <Set name="responseHeaderSize">8192</Set>
  <Set name="sendServerVersion">true</Set>
  <Set name="sendDateHeader">false</Set>
  <Set name="headerCacheSize">512</Set>

  <!-- Uncomment to enable handling of X-Forwarded- style headers
  <Call name="addCustomizer">
    <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
  </Call>
  -->
</Configure>

But it’s not running!

If you are getting the error [ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.0.5.v20130815:run (default-cli) on project FOOBAR: Failure: etc/jetty.keystore (file or directory not found) -> [Help 1] now, this is because you have to create/get a certificate for your HTTPS-Connector. For development, a selfsigned certificate is sufficient. You can easily create one like back in the good old maven-jetty-plugin-times, with this command: keytool -genkey -alias jetty -keyalg RSA -keystore src/test/resources/jetty.keystore -storepass secret -keypass secret -dname "CN=localhost". Just be sure, to change the example file jetty-ssl.xml, to reflect the path to your new keystore file and password. Your jetty-ssl.xml should look like:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<!-- ============================================================= -->
<!-- Configure a TLS (SSL) Context Factory                         -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- and either jetty-https.xml or jetty-spdy.xml (but not both)   -->
<!-- ============================================================= -->
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
  <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="src/test/resources/jetty.keystore"/></Set>
  <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="secret"/></Set>
  <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="secret"/></Set>
  <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="src/test/resources/jetty.keystore"/></Set>
  <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="secret"/></Set>
  <Set name="EndpointIdentificationAlgorithm"></Set>
  <Set name="ExcludeCipherSuites">
    <Array type="String">
      <Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
      <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
      <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
      <Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
      <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
      <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
      <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
    </Array>
  </Set>

  <!-- =========================================================== -->
  <!-- Create a TLS specific HttpConfiguration based on the        -->
  <!-- common HttpConfiguration defined in jetty.xml               -->
  <!-- Add a SecureRequestCustomizer to extract certificate and    -->
  <!-- session information                                         -->
  <!-- =========================================================== -->
  <New id="sslHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
    <Arg><Ref refid="httpConfig"/></Arg>
    <Call name="addCustomizer">
      <Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
    </Call>
  </New>

</Configure>

But it’s still not running!

Unless you are running mvn jetty:run as root, you should see another error now: [ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.0.5.v20130815:run (default-cli) on project FOOBAR: Failure: Permission denied -> [Help 1]. This is, because the ports are set to the numbers 80 and 443 of the privileged port-range.

You have to change jetty-http.xml like this:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<!-- ============================================================= -->
<!-- Configure the Jetty Server instance with an ID "Server"       -->
<!-- by adding a HTTP connector.                                   -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <!-- =========================================================== -->
  <!-- Add a HTTP Connector.                                       -->
  <!-- Configure an o.e.j.server.ServerConnector with a single     -->
  <!-- HttpConnectionFactory instance using the common httpConfig  -->
  <!-- instance defined in jetty.xml                               -->
  <!--                                                             -->
  <!-- Consult the javadoc of o.e.j.server.ServerConnector and     -->
  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
  <!-- that may be set here.                                       -->
  <!-- =========================================================== -->
  <Call name="addConnector">
    <Arg>
      <New class="org.eclipse.jetty.server.ServerConnector">
        <Arg name="server"><Ref refid="Server" /></Arg>
        <Arg name="factories">
          <Array type="org.eclipse.jetty.server.ConnectionFactory">
            <Item>
              <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                <Arg name="config"><Ref refid="httpConfig" /></Arg>
              </New>
            </Item>
          </Array>
        </Arg>
        <Set name="host"><Property name="jetty.host" /></Set>
        <Set name="port"><Property name="jetty.port" default="8080" /></Set>
        <Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set>
      </New>
    </Arg>
  </Call>

</Configure>

… and jetty-https.xml like this:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<!-- ============================================================= -->
<!-- Configure a HTTPS connector.                                  -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- and jetty-ssl.xml.                                            -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <!-- =========================================================== -->
  <!-- Add a HTTPS Connector.                                      -->
  <!-- Configure an o.e.j.server.ServerConnector with connection   -->
  <!-- factories for TLS (aka SSL) and HTTP to provide HTTPS.      -->
  <!-- All accepted TLS connections are wired to a HTTP connection.-->
  <!--                                                             -->
  <!-- Consult the javadoc of o.e.j.server.ServerConnector,        -->
  <!-- o.e.j.server.SslConnectionFactory and                       -->
  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
  <!-- that may be set here.                                       -->
  <!-- =========================================================== -->
  <Call id="httpsConnector" name="addConnector">
    <Arg>
      <New class="org.eclipse.jetty.server.ServerConnector">
        <Arg name="server"><Ref refid="Server" /></Arg>
          <Arg name="factories">
            <Array type="org.eclipse.jetty.server.ConnectionFactory">
              <Item>
                <New class="org.eclipse.jetty.server.SslConnectionFactory">
                  <Arg name="next">http/1.1</Arg>
                  <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
                </New>
              </Item>
              <Item>
                <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                  <Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
                </New>
              </Item>
            </Array>
          </Arg>
          <Set name="host"><Property name="jetty.host" /></Set>
          <Set name="port"><Property name="https.port" default="8443" /></Set>
          <Set name="idleTimeout"><Property name="https.timeout" default="30000"/></Set>
        </New>
    </Arg>
  </Call>
</Configure>

Now, it should be running, but…

That is all much to complex. I just want a quick fix to get it running!

So, now it is working. But you still have to clutter your project with several files and avoid some pitfalls (belive me or not: if you put the filenames in the <jettyXml>-tag of your pom.xml on separate lines, jetty won’t start!). Last but not least, the HTTP-Connector will stop working, if you forget to add the jetty-http.xml, that is mentioned at the end of the example.

Because of that, I’ve created a simple 6-step quick-fix-guide to get the HTTPS-Connector of the jetty-maven-plugin running.

Quick Fix

  1. Download jetty.xml or copy it from above and place it in src/test/resources/jetty.xml
  2. Download jetty-http.xml or copy it from above and place it in src/test/resources/jetty-http.xml
  3. Download jetty-ssl.xml or copy it from above and place it in src/test/resources/jetty-ssl.xml
  4. Download jetty-https.xml or copy it from above and place it in src/test/resources/jetty-https.xml
  5. Download jetty.keystore or generate it with the command keytool-command from above and place it in src/test/resources/jetty.keystore
  6. Update the configuration of the jetty-maven-plugin in your pom.xml to include the XML-configurationfiles. But be aware, the ordering of the files is important and there should be no newlines inbetween. You have been warned! It should look like:
    
    <plugin>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-maven-plugin</artifactId>
      <configuration>
        <jettyXml>
          ${project.basedir}/src/test/resources/jetty.xml,${project.basedir}/src/test/resources/jetty-http.xml,${project.basedir}/src/test/resources/jetty-ssl.xml,${project.basedir}/src/test/resources/jetty-https.xml
        </jettyXml>
      </configuration>
    </plugin>
      

That’s it. You should be done!

Combining jetty-maven-plugin and wro4j-maven-plugin for Dynamic Reloading of LESS-Resources

Ever searched for a simple configuration, that lets you use your jetty-maven-plugin as you are used to, while working with LESS to simplify your stylesheets?

You cannot do both, use the Client-side mode of LESS to ease development and use the lesscss-maven-plugin to automatically compile the LESS-sources into CSS for production. That does not work, because your stylesheets must be linked in different ways if you are switching between the client-side mode – which is best for development – and the pre-compiled mode – which is best for production. For the client-side mode you need something like:


<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="less.js" type="text/javascript"></script>

While, for the pre-compiled mode, you want to link to your stylesheets as usual, with:


<link rel="stylesheet" type="text/css" href="styles.css" />

While looking for a solution to this dilemma, I stumbled accross wro4j. Originally intended, to speed up page-delivery by combining and minimizing multiple resources into one through the use of a servlet-filter, this tool also comes with a maven-plugin, that let you do the same offline, while compiling your webapp.

The idea is, to use the wro4j-maven-plugin to compile and combine your LESS-sources into CSS for production and to use the wro4j filter, to dynamically deliver the compiled CSS while developing. This way, you do not have to alter your HTML-code, when switching between development and production, because you always link to the CSS-files.

So, lets get dirty!

Step 1: Configure wro4j

First, we configure wro4j, like as we want to use it to speed up our page. The details are explained and linked on wro4j’s Getting-Started-Page. In short, we just need two files: wro.xml and wro.properties.

wro.xml

wro.xml tells wro4j, which resources should be combined and how the result should be named. I am using the following configuration to generate all LESS-Sources beneath base/ into one CSS-file called base.css:


<groups xmlns="http://www.isdc.ro/wro">
  <group name="base">
    <css>/less/base/*.less</css>
  </group>

wro4j looks for /less/base/*.less inside the root of the web-context, which is equal to src/main/webapp in a normal maven-project. There are other ways to specifie the resources, which enable you to store them elswhere. But this approach works best for our goal, because the path is understandable for both: the wro4j servlet-filter, we are configuring now for our development-environment, and the wro4j-maven-plugin, that we will configure later for build-time compilation.

wro.properties

wro.properties in short tells wro4j, how or if it should convert the combined sources and how it should behave. I am using the following configuration to tell wro4j, that it should convert *.less-sources into CSS and do that on every request:


managerFactoryClassName=ro.isdc.wro.manager.factory.ConfigurableWroManagerFactory
preProcessors=cssUrlRewriting,lessCssImport
postProcessors=less4j
disableCache=true

First of all we specify the ConfigurableWroManagerFactory, because otherwise, wro4j would not pick up our pre- and post-processor-configuration. This is a little bit confusing, because wro4j is already reading the wro.properties-file – otherwise wro4j would never detect the managerFactoryClassName-directive – and you might think: “Why? He is already interpreting our configuration!” But belive me, he is not! You can read more about that in wro4j’s documentation. The disableCache=true is also crucial, because otherwise, we would not see the changes take effect when developing with jetty-maven-plugin later on. The pre-processors lessCssImport and cssUrlRewriting merge together all our LESS-resources under /less/base/*.less and do some URL-rewriting, in case you have specified paths to images, fonts or other resources inside your LESS-code, to reflect that the resulting CSS is found under /css/base.css and not /css/base/YOURFILE.css like the LESS-resources.

You can do much more with your resources here, for example minimizing. Also, there are countless configuration options to fine-tune the behaviour of wro4j. But for our goal, we are now only intrested in the compilation of our LESS-sources.

Step 2: Configure the wro4j servlet-filter

Configuring the filter in the web.xml is easy. It is explained in wro4j’s installation-insctuctions. But the trick is, that we do not want to configure that filter for the production-version of our webapp, because we want to compile the resources offline, when the webapp is build. To acchieve this, we can use the <overrideDescriptor>-Parameter of the jetty-maven-plugin.

<overrideDescriptor>

This parameter lets you specify additional configuration options for the web.xml of your webapp. I am using the following configuration for my jetty-maven-plugin:


<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <configuration>
    <webApp>
      <overrideDescriptor>${project.basedir}/src/test/resources/jetty-web.xml</overrideDescriptor>
    </webApp>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>ro.isdc.wro4j</groupId>
      <artifactId>wro4j-core</artifactId>
      <version>${wro4j.version}</version>
    </dependency>
    <dependency>
      <groupId>ro.isdc.wro4j</groupId>
      <artifactId>wro4j-extensions</artifactId>
      <version>${wro4j.version}</version>
      <exclusions>
        <exclusion>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
        </exclusion>
        <exclusion>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.google.code.gson</groupId>
          <artifactId>gson</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.google.javascript</groupId>
          <artifactId>closure-compiler</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.github.lltyk</groupId>
          <artifactId>dojo-shrinksafe</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.jruby</groupId>
          <artifactId>jruby-core</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.jruby</groupId>
          <artifactId>jruby-stdlib</artifactId>
        </exclusion>
        <exclusion>
          <groupId>me.n4u.sass</groupId>
          <artifactId>sass-gems</artifactId>
        </exclusion>
        <exclusion>
          <groupId>nz.co.edmi</groupId>
          <artifactId>bourbon-gem-jar</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.codehaus.gmaven.runtime</groupId>
          <artifactId>gmaven-runtime-1.7</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>jshint</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>emberjs</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>handlebars</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>coffee-script</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>jslint</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>json2</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.webjars</groupId>
          <artifactId>jquery</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</plugin>

The dependencies to wro4j-core and wro4j-extensions are needed by jetty, to be able to enable the filter defined below. Unfortunatly, one of the transitive dependencies of wro4j-extensions triggers an uggly error when running the jetty-maven-plugin. Therefore, all unneeded dependencies of wro4j-extensions are excluded, as a workaround for this error/bug.

jetty-web.xml

And my jetty-web.xml looks like this:


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  version="2.5">
  <filter>
    <filter-name>wro</filter-name>
    <filter-class>ro.isdc.wro.http.WroFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>wro</filter-name>
    <url-pattern>*.css</url-pattern>
  </filter-mapping>
</web-app>

The filter processes any URI’s that end with .css. This way, the wro4j servlet-filter makes base.css available under any path, because for exampl /base.css, /css/base.css and /foo/bar/base.css all end with .css.

This is all, that is needed to develop with dynamically reloadable compiled LESS-resources. Just fire up your browser and browse to /what/you/like/base.css. (But do not forget to put some LESS-files in src/main/webapp/less/base/ first!)

Step 3: Install wro4j-maven-plugin

All that is left over to configure now, is the build-process. If you would build and deploy your webapp now, the CSS-file base.css would not be generated and the link to your stylesheet, that already works in our jetty-maven-plugin environment would point to a 404. Hence, we need to set up the wro4j-maven-plugin. I am using this configuration:


<plugin>
  <groupId>ro.isdc.wro4j</groupId>
  <artifactId>wro4j-maven-plugin</artifactId>
  <version>${wro4j.version}</version>
  <configuration>
    <wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory</wroManagerFactory>
    <cssDestinationFolder>${project.build.directory}/${project.build.finalName}/css/</cssDestinationFolder>
  </configuration>
  <executions>
    <execution>
      <phase>prepare-package</phase>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>

I connected the run-goal with the package-phase, because the statically compiled CSS-file is needed only in the final war. The ConfigurableWroManagerFactory tells wro4j, that it should look up further configuration options in our wro.properties-file, where we tell wro4j, that it should compile our LESS-resources. The <cssDestinationFolder>-tag tells wro4j, where it should put the generated CSS-file. You can adjust that to suite your needs.

That’s it: now the same CSS-file, which is created on the fly by the wro4j servlet-filter when using mvn jetty:run and, thus, enables dynamic reloading of our LESS-resources, is generated during the build-process by the wro4j-maven-plugin.

Cleanup and further considerations

lesscss-maven-plugin

If you already compile your LESS-resources with the lesscss-maven-plugin, you can stick with it and skip step 3. But I strongly recommend giving wro4j-maven-plugin a try, because it is a much more powerfull tool, that can speed up your final webapp even more.

Clean up your mess

With a configuration like the above one, your LESS-resources and wro4j-configuration-files will be packed into your production-war. That might be confusing later, because neither wro4j nor LESS is used in the final war. You can add the following to your pom.xml to exclude these files from your war for the sake of clarity:


<plugin>
  <artifactId>maven-war-plugin</artifactId>
  <configuration>
    <warSourceExcludes>
      WEB-INF/wro.*,
      less/**
    </warSourceExcludes>
  </configuration>
</plugin>

What’s next?

We only scrached the surface, of what can be done with wro4j. Based on this configuration, you can easily enable additional features to fine-tune your final build for maximum speed. You really should take a look at the list of available Processors!