0

Building Dropwizard with Ant

Dropwizard is an amazing framework for anyone who wishes to build web services, and I heartily recommend it. However, for those sitting behind closed corporate intranets without any proxy Maven repositories, it can prove to be a bit of a hassle to set up.

Firstly, one has to transitively follow the dependencies and download the dependent JARs. This shouldn’t be much of an issue, it’s just tedious. The more interesting issue that I encountered was the exclusion of digital signatures from signed JARs while writing an Ant script.

My initial attempt was to add the file pattern as an exclusion attribute for the zipgroupfileset task. However, it seems that there’s no way to filter files when using zipgroupfileset as the include/excludes applies to the zips to be merged, not the content within them. After some consultation with a developer’s best friend, I came across the following solution:

<jar jarfile="dist/external-libs.jar" filesetmanifest="mergewithoutmain">
  <zipgroupfileset dir="lib/">
    <include name="**/*.jar"/>
  </zipgroupfileset>
</jar>
<sleep seconds="1"/>
<jar jarfile="${dist}/lib/historadar-${DSTAMP}.jar" filesetmanifest="mergewithoutmain">
  <manifest>
    <attribute name="Main-Class" value="com.example.helloworld"/>
    <attribute name="Class-Path" value="."/>
  </manifest>
  <fileset dir="classes/"/>
  <zipfileset src="dist/external-libs.jar">
    <exclude name="**/*.SF"/>
  </zipfileset>
</jar>

Assuming that one has already compiled the classes to the classes/ directory, the first jar task then puts all the jars it finds in lib/ into external-libs.jar. It then waits for one second to avoid getting warnings about the files having modification dates in the future. Next, the second jar task merges my class files from the classes/ directory with the content of external-libs.jar while excluding all digital signatures from the signed JARs.

With this, one should be able to build an executable Dropwizard JAR via Ant.

4

Microservices with Jetty and Jersey

When it comes to deploying REST web services with an embedded server such as Jetty, one would typically go about accomplishing it by specifying the WAR file in Jetty or running it from its exploded source components.

However, I wanted to avoid even the slightest hint of WAR files and web.xml files and deploy microservices that are as similar to POJOs as possible. After fiddling around with Jetty and Jersey, I’ve managed to come up with a simple way to deploy services that’s almost like plain old Java. In fact, I find that it’s much more pleasant to work with pure Java as I don’t have to worry about specifying pesky classes and configuration files.

Imagine that we have a simple resource:

package org.microservice;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/test")
public class HelloWorldResource
{
	@GET
	@Produces(MediaType.TEXT_PLAIN)
	public String helloWorld()
	{
		return "Hello World!";
	}
}

Next, we just need the following main class and we’re done:

package org.microservice.runner;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.thread.QueuedThreadPool;

import com.sun.jersey.spi.container.servlet.ServletContainer;

public class HelloWorldService
{
	public static void main(String[] args) throws Exception
	{
		try
		{
			Server server = new Server(8081);
			ServletHolder servletHolder = new ServletHolder(ServletContainer.class);

			servletHolder.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
					"com.sun.jersey.api.core.PackagesResourceConfig");
            // IMPORTANT: you have to specify the package where your resources are located in order for Jetty to pick them up
			servletHolder.setInitParameter("com.sun.jersey.config.property.packages", "org.microservice");
                        
            // comment out to hide debug information
			servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true");
			servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
			servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters",
					"com.sun.jersey.api.container.filter.LoggingFilter");
			servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters",
					"com.sun.jersey.api.container.filter.LoggingFilter");

			ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
			context.setContextPath("/");
			context.addServlet(servletHolder, "/*");

			server.setHandler(context);

			QueuedThreadPool queuedThreadPool = new QueuedThreadPool(10);
			queuedThreadPool.setName("ApiServe");
			server.setThreadPool(queuedThreadPool);

			server.start();
			server.join();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
}

Once you’ve exported it out as a runnable .jar file, you can start your lightweight microservice with

$ java -jar <your_jar_filename>.jar