The Tribe Blog

50 Shades of TomEE

6193
2 Comments

I don’t know if we’ll get a film after the international success of it but since few months the world is all about microservices.

Whatever your opinion on it is you will surely have to work with it a little bit. One common way to go to production with microservices is to do a shade of your application and simply deploy an executable jar.

Let go through common Microservice solutions which work with TomEE flavors.

TomEE Shades

A shade is a Maven plugin to aggregate project dependencies in a single jar. It can be done with Maven dependency plugin with some hack (basically unpacking all dependencies in target/classes) but Maven shade plugin provides more control over the merge policy thanks to Transformer API.

To do an executable jar using Maven shade plugin you need to know two information:

  • what is the main class
  • what files need a specific merging and which policy it needs

All TomEE flavors share the same second point, which we’ll develop just after having tackled the first one.

Specify your Main Class

Depending which flavor of TomEE you use the main will be different but in all cases it will boot your application.

In all cases once you have the main class you will rely on you’ll be able to specify it in Maven shade plugin using the following configuration:

<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  <mainClass>org.myapp.Main</mainClass>
</transformer>

ApplicationComposer

Since TomEE 2.x you can start manually an ApplicationComposer application as a standalone main:

@EnableServices(jaxrs = true)
@Classes(context = "/", value = { MyResource.class, MyService.class })
public class MyApp {
    public static void main(String[] args) {
        ApplicationComposers.run(MyApp.class, args);
    }
}

Just write your own main using ApplicationComposers and specify it in shade configuration to boot your application.

TomEE Embedded

TomEE embedded is surely one of the best choices for a TomEE shade since it provides a Main class out of the box. Just specify org.apache.tomee.embedded.Main as the mainClass in the shade ManifestResourceTransformerconfiguration and you are done.

<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  <mainClass>org.apache.tomee.embedded.Main</mainClass>
</transformer>

If you don’t use JSF you should exclude META-INF/faces-config.xml to ensure JSF is not automatically started. Add the following to your maven-shade-plugin configuration.

<filters>
  <filter> <!-- we don't want JSF to be activated -->
    <artifact>*:*</artifact>
    <excludes>
      <exclude>META-INF/faces-config.xml</exclude>
    </excludes>
  </filter>
</filters>

TomEE (remote)

TomEE remote can be controlled using OpenEJB RemoteServer class and this is mainly what does tomee:exec goal. You can also use catalina.sh commands to start/stop your application.

In all cases the fact TomEE remote needs as a plain Tomcat a particular layout – it is not embedded, it makes it a bit harder to shade.
My advice would be to not try to rely on TomEE remote for an executable jar without using tomee:exec (detailed later).

Merging of conflicting resources

When using the maven-shade-plugin and taking the contents of several jars and turning them into one larger jar, it can be common to run into file conflicts that need to be handled.

Some cases, such as META-INF/services/ service providers, are solved smoothly with by shade plugin our of the box with the default configuration. Others require explicit action.

CXF and TomEE need META-INF/cxf/bus-extensions.txt extensions. Here you’ll get conflicts and you need to ensure merging is the same as the one done automatically for service providers. For it you can just rely onAppendingTransformer in your plugin config as shown below:

<transformer implementation="org.apache.Maven.plugins.shade.resource.AppendingTransformer">
  <resource>META-INF/cxf/bus-extensions.txt</resource>
</transformer>

Recent OpenWebBeans versions need the build-in configuration files to be merged. Specifically, META-INF/openwebbeans/openwebbeans.properties files. Even if TomEE tries to ensure defaults are in place it is better to configure it:

<transformer implementation="org.apache.Maven.plugins.shade.resource.AppendingTransformer">
  <resource>META-INF/openwebbeans/openwebbeans.properties</resource>
</transformer>
Note: here we use AppendingTransformer to ensure we don’t miss any default key but if you want a full control of it in your application you can also merge it manually and provide the file (put it in META-INF/openwebbeans/openwebbeans.properties in src/main/resources in your project.

Put it all together

So finally Maven shade configuration should look like:

<plugin>
  <groupId>org.apache.Maven.plugins</groupId>
  <artifactId>Maven-shade-plugin</artifactId>
  <version>2.3</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <transformers>
          <transformer implementation="org.apache.Maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>org.apache.tomee.embedded.Main</mainClass>
          </transformer>
          <transformer implementation="org.apache.Maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/cxf/bus-extensions.txt</resource>
          </transformer>
          <transformer implementation="org.apache.Maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/openwebbeans/openwebbeans.properties</resource>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Then just run:

mvn package

And you can run your application:

java -jar myapp.jar

Feeling Lazy? Try tomee:exec

If you already used tomee-maven-plugin you are surely use to the tomee:run command but do you know about tomee:exec?

The tomee:exec goal is interesting since it will create an executable jar which will package a tomee distribution already set up with your application and a runner able to unpack it and run it. This works with any Maven war project, no Maven Shade Plugin or special setup required beyond adding the TomEE Maven Plugin to your pom.xml.

<build>
    <plugins>
      <plugin>
        <groupId>org.apache.openejb.maven</groupId>
        <artifactId>tomee-maven-plugin</artifactId>
        <version>${tomee.version}</version>
        <configuration>
          <tomeeVersion>$1.7.1</tomeeVersion>
          <tomeeClassifier>jaxrs</tomeeClassifier>
        </configuration>
      </plugin>
    </plugins>
  </build>

Once you packaged your application with a mvn clean install tomee:exec you can run it as easily as:

java -jar target/mytomeeapp.jar

If you want to override or configure the runtime properties passed to TomEE on start, you can use the additionalSystemProperties system property. So if you provided a server.xml setting the http port via my.http.port system property you can run it with:

java -DadditionalSystemProperties=-Dmy.http.port=7080 -jar mytomeeapp.jar

The TomEE Maven Plugin the plugin is also able to attach the produced artifact to the build so you can even publish it.

However as described earlier tomee:exec relies on two processes:

  • The TomEE process itself
  • A runner process which waits for the server to shutdown

The runner is a very light process but this is still something you might wish to avoid. Still, very useful and for demos it is just awesome!.

Test it yourself

If you want to go further two samples are available on github: https://github.com/tomitribe/50-shades-of-tomee

One uses ApplicationComposer and the other one is using TomEE Embedded. Both have a README with getting started instructions.


Romain

About the author

Romain Manni-Bucau

Senior Software Engineer
http://rmannibucau.wordpress.com
Follow Romain Manni-Bucau
Romain is a contributor of the Apache TomEE project since July 2010 and a Senior Software Engineer at Tomitribe. In his plethora of Apache projects, he’s involved in OpenEJB, OpenWebBeans, Geronimo, CFX, BVal and DeltaSpike. Romain is a founding member of the Sirona and BatchEE project and brought JCache implementation to the Apache Commons JCS project. He regularly speaks at JUG and conferences to spread the word about all the Apache goodness. Since Java EE 6, he is convinced that REST architectures and design are the future of Java EE and not only for web technologies. Romain started as a Java EE expert at Atos transversal unit. He later joined Swissquote Bank as a backend developer. Today he is a part of the Tomitribe adventure and continues his mission with all the Apache projects, especially TomEE. Romain likes "coding on the edge," always proposing solutions of tomorrow and that's why he joined the Tribe!