Docker Cloud Spring Boot Integration

It’s been a long time since my last post, but I am still up and running!

Lately I have been taking a deeper look into docker and how I could integrate my Spring Boot Applications or basically any application. I think Docker can especially be helpful in microservice environments, where you deal with a lot of small services, which interact with each other and somehow have to be linked.
Using docker-compose you even can define and bootstrap whole environments based on any docker image within minutes!

Since Docker requires you to specify your environment (dependencies, installation, ports ..) in a dedicated file called “Dockerfile”, it also serves as a basic documentation.

Anyway, this article should handle dockers latest creation “Docker Cloud”.

Docker Cloud (formerly tutum.co) allows seamless integration of docker images for existing Cloud Providers (right now AWS and Digital Ocean) as well as your own nodes, which could be any server.

So here is what we want to try to achieve in this post:

  1. Integrate a node (in this case a vServer) into our Docker Cloud
  2. Integrate Docker into a Spring Boot Application
  3. Push the built image into the central DockerHub Repository
  4. Configure a Service based on our Image in Docker Cloud

Once we completed all these steps, we will have a continuous integration of our docker based application into our vServer: Every time we push a new docker image to our DockerHub repository, it will immediately be redeployed on our vServer. Awesome!

In future you might want to enhance this setup using a CI environment. In this case our CI Server would be responsible for publishing the docker image!

1. Integrate your node into Docker Cloud

What you need to start:

  • vServer (with docker installed)
  • a Docker/Docker Cloud Account

Integrating your node is as simple as this:

Open the Nodes Tab in your Docker Cloud Dashboard and “bring your own node”. This will ask you to execute the given command on your server shell. Once the installation is done, you should be able to see your host in the nodes list. That’s it!

2/3. Integrate your Spring Boot Application

To integrate your existing Spring Boot Application, you first have to “dockerize” your application.

First step is to create your Dockerfile in src/main/docker. Here a very basic sample file:

FROM java:8
ADD api-gateway.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-jar","/app.jar"]

Once you have done, that, we need to configure the docker-maven-plugin as following:

<build>
	<finalName>${project.artifactId}</finalName>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>

		<plugin>
			<groupId>com.spotify</groupId>
			<artifactId>docker-maven-plugin</artifactId>
			<version>0.3.9</version>
			<configuration>
				<imageName>yourdockerhubusername/${project.artifactId}</imageName>
				<dockerDirectory>src/main/docker</dockerDirectory>
				<resources>
					<resource>
						<targetPath>/</targetPath>
						<directory>${project.build.directory}</directory>
						<include>${project.build.finalName}.jar</include>
					</resource>
				</resources>
			</configuration>
		</plugin>
	</plugins>
</build>

Hint: As you might have seen, we changed our final jar name to omit the version number, otherwise we would need to change our Dockerfile, every time the version changes.

Make sure you have the docker repository created in your DockerHub Account!

Having the docker-maven-plugin in place, we can now build our docker image as follows:

mvn clean package

mvn docker:build

mvn docker:push

You might need to add your dockerhub credentials to your maven settings.xml to be able to push. As an alternative, just run “docker login” and “docker push youraccountname/yourartifactid”.

After your image has been pushed, your are now able to set up a service or stack in Docker Cloud, which uses your image.

4. Configure your Docker Cloud Service

Now that our image is published, we can configure a service based on our Docker Image.

Go to the Docker Cloud Service Tab and create a new service:

  • Choose your docker image
  • Choose your node
  • Enable autodeployment
  • Save and run!

Once you completed this, it will automatically be deployed to your Server. To verify, run “docker ps” on your server and it should appear in the list.

Done!

Having all steps completed you should now see your service being redeployed, every time you push a new release of your image.

In the future you might define your whole environment using a stack. The stack configuration is similar to docker-compose!

Remarks:

  • Docker Cloud will just provide you one free node configuration. Additional nodes are around 14$
  • You just get one free private repository. If you don’t mind making your image publicly available use the public unlimited repositories!

Liferay: Test your Spring MVC Portlets easily!

Hey folks, just on short notice: I recently released spring-test-portlet-mvc, a framework which makes integration testing of Spring MVC Features like Controller or Interceptors very easy. Checkout the project at Check out the project including basic samples at Github: https://github.com/markusf/spring-test-portlet-mvc

There will be an upcoming blog post about this in the near future!

Liferay: Share Object in session between a Hook and Portlet

Since Liferay maintains several Sessions – yes, there is even more than a Portlet and HttpSession thanks to Liferays wrapped and nested *ServletRequests – there is no obvious way to share a session object between a hook (or maybe a servlet filter) and a portlet for example.

Here is the way how you can do it easily:

In your hook, just use the default HttpSession like this:

public class MyAction extends Action {

public void run(HttpServletRequest req, HttpServletResponse res) {

req.getSession().setAttribute("foo", "bar");

...

In your portlet you can now access the session via PortalSessionThreadLocal:

String foo = (String) PortalSessionThreadLocal.getHttpSession().getAttribute("foo");

System.out.println(foo); // prints out "bar"

Jackrabbit Explorer / Browser

Just recently I was in need of a standalone Jackrabbit Explorer.

After some research I found these two:

JCR Browser 0.9.6 – by sandro_boehme (http://sourceforge.net/projects/jcrbrowser/)

Subshell Toromiro (http://www.subshell.com/en/toromiro/)

JCR Browser
Almost any Jackrabbit Explorer is named some kind of “JCR Browser”. “JCR Browser 0.9.6” is being developed actively and free for use / open source. Browsing is based heavily on XPath (have fun copying UUIDs ;)). It does not support JCR 2.x repositories.

Subshell Toromiro
Tomiro is a commercial explorer, which comes with a 30 day trial. It also supports JCR 2.0 repositories. Browsing is easy: Parent / Child / Connected nodes can be reached by simple clicks.

Fazit
If you are working with jackrabbit on a day to day basis, use Toromiro. If you just want to take a quick glance at your repository, take a look at JCR Browser!

Tapestry: yuicompressor not working on tomcat / jboss

I just wanted to deploy my web application on tomcat and realized that my javascript libraries wouldn’t be minified. Minification failed with strange “StringIndexOutOfBoundsException” Exceptions:

[ERROR] AssetsModule.ResourceMinimizer String index out of range: 142644
java.lang.StringIndexOutOfBoundsException: String index out of range: 142644
        at java.lang.String.substring(String.java:1934)
        at com.yahoo.platform.yui.compressor.JavaScriptCompressor.printSourceString(JavaScriptCompressor.java:267)

There seems to be a bug with yuicompressor and some specially patched rhino classes. See https://github.com/greenlaw110/greenscript/pull/29#issuecomment-4017147 and http://stackoverflow.com/questions/6652550/yui-compressor-stringindexoutofboundsexception-on-jboss.

The solution was to modify the pom.xml as follows:

        <dependency>
            <groupId>org.apache.tapestry</groupId>
            <artifactId>tapestry-yuicompressor</artifactId>
            <version>${tapestry-release-version}</version>
            <exclusions>
				<exclusion>
					<artifactId>yuicompressor</artifactId>
					<groupId>com.yahoo.platform.yui</groupId>
				</exclusion>
	     </exclusions>
        </dependency>
        

		<dependency>
			<groupId>com.yahoo.platform.yui</groupId>
			<artifactId>yuicompressor</artifactId>
			<version>2.4.7</version>
			<exclusions>
				<exclusion>
					<groupId>rhino</groupId>
					<artifactId>js</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

Liferay: PortletDisplay is empty in ActionRequests -Update-

Recently I wanted to do a simple permission check in a portlet based on the “RootPortletId” and the “PortletResourcePK” (InstanceID), which I retrieved from the PortletDisplay-Object.
In RenderRequests the permission check worked just fine, however in ActionRequests the current user never had the given permission, though he should have had.
I then discovered, that all PortletDisplay Values are empty, if the request is an ActionRequest.

My next step was to find out, how to retrieve the RootPortletId and the PortletResourcePK without accessing the PortletDisplay.

– Update –
The PortletId is accessible via the Request-Attribute “WebKeys:

String portletResourcePK = (String) request.getAttribute(WebKeys.PORTLET_ID);

The PortletResourcePK (Portlet Primary Key) is not equal to the PortletID, it can be retrieved via PortletPermissionUtil:

		String portletPrimaryKey = PortletPermissionUtil.getPrimaryKey(
				themeDisplay.getLayout().getPlid(), portletId);

Finally, the RootPortletID can be retrieved by the PortletID:

String rootPortletId = PortletConstants.getRootPortletId(portletId);

Liferay: Predefine Portlet Title

Portlet titles can be predefined and internationalized via the Portlet Preference “portlet-setup-title-*” in the portlet.xml.

The pattern is: “portlet-setup-title-” + locale.getLanguage() and if present + “_” + locale.getCountry()

Here a quick example:

<portlet-preferences>
	<preference>
		<name>portlet-setup-title-en_US</name>
		<value>English Title</value>
	</preference>
	<preference>
		<name>portlet-setup-title-de_DE</name>
		<value>German Title</value>
	</preference>
</portlet-preferences>

Delayed Socket Close – TCP Retransmission Timeout

This is something that I wanted to share a long time ago, which got into my mind again recently. It’s rather specific but could be usefull to some of you folks.

I remember writing a simple Comet WebApplication using the Tomcat Comet API / CometProcessor. Back then, I used the iframe technique to stream data endlessly to the Browser. The CometProcessor Class is triggered by CometEvents like BEGIN or END. The END-Event is trigged when the User closes his browser or leaves the page.
This was working fine, but however, when the browser was closed abruptly the END-Event was triggered about 15 minutes – if I remember correct – later. Such delay was unacceptable, so I investigated the cause.

After some research (thanks to netstat!), I recognized that this behaviour is controlled by the underlying TCP connection: There is a TCP retransmission timeout (RTO), which occurs when ACKs do not arrive on time or not arrive at all.

The retransmission timeout is not a fixed value, it’s a bit more complex. Linux allows its configuration via tcp_retries2 in /proc/sys/net/ipv4.
tcp_retries2 controlls the number of retransmissions before linux disconnects the socket. Time between retransmissions grows exponentially.

The official description states:

tcp_retries2 – INTEGER
This value influences the timeout of an alive TCP connection,
when RTO retransmissions remain unacknowledged.
Given a value of N, a hypothetical TCP connection following
exponential backoff with an initial RTO of TCP_RTO_MIN would
retransmit N times before killing the connection at the (N+1)th RTO.

The default value of 15 yields a hypothetical timeout of 924.6
seconds and is a lower bound for the effective timeout.
TCP will effectively time out at the first RTO which exceeds the
hypothetical timeout.

RFC 1122 recommends at least 100 seconds for the timeout,
which corresponds to a value of at least 8.

In my case I lowered tcp_retries2 to 5 and connections died much quicker.

Spring MVC: Create your own custom Method Handler Annotations

Thanks to the introduction of some new classes in Spring 3.1 release, it’s now easy to create Custom Handler Method Anntotations. Unfortunately these classes are not present for Portlet-Environments, but hopefully will be implemented soon.

Here is a short guide on how to implement your own method annotations:

Step 1: Create Annotation Interface

@Target(value=METHOD)
@Retention(value=RUNTIME)
public @interface MyAnnotation {
	boolean test() default true;
}

Step 2: Implement Interceptor-Class

Here is the magic:
As you can see, it’s now possible to access Annotations by casting the handler-Object to “HandlerMethod” and retrieve it via “handlerMethod.getMethodAnnotation()”.


public class MyInterceptor extends HandlerInterceptorAdapter {

	@Override
	public preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
		HandlerMethod handlerMethod = (HandlerMethod ) handler;

		MyAnnotation myAnnotation = handlerMethod.getMethodAnnotation(MyAnnotation.class);

		if (myAnnotation.test()) {
			return true; // forward in pipeline
		} else {
			response.sendRedirect(&amp;quot;/bye&amp;quot;);
			return false; // cancel default lifecycle
		}
	}

}

Step 3: Configure Interceptor in Application Context

If you are using XML-Configuration, make sure to use the new “RequestMappingHandlerMapping”-Class instead of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.


	&amp;lt;bean id=&amp;quot;myInterceptor&amp;quot; class=&amp;quot;MyInterceptor&amp;quot;/&amp;gt;

	&amp;lt;bean class=&amp;quot;org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping&amp;quot;&amp;gt;
		&amp;lt;property name=&amp;quot;interceptors&amp;quot;&amp;gt;
			&amp;lt;list&amp;gt;
				&amp;lt;ref bean=&amp;quot;myInterceptor&amp;quot;/&amp;gt;
			&amp;lt;/list&amp;gt;
		&amp;lt;/property&amp;gt;
	&amp;lt;/bean&amp;gt;

Step 4: Annotate your Handler-Method(s)

@RequestMapping
@MyAnnotation(test = true)
public String test(HttpServletRequest request) {
	...
}