Simple init script for Tomcat

With an init script for your Tomcat (or other programs) you can handle two demands:

  1. You can specify the required options like JAVA_OTPS in this script
  2. Your Tomcat will be startet after server restart

In this post I will use a Tomcat for Solr as example. So first we need to define a init script:

$ touch /etc/init.d/solr
$ chmod a+x /etc/init.d/solr

The content of /etc/inid.d/solr looks like this:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          tomcat-solr
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Solr
# Description:       Solr Tomcat
### END INIT INFO

NAME="solr"
TOMCAT_DIR="/opt/tomcat-solr"
export JAVA_OPTS="-Dsolr.solr.home=/my-solr-home-dir"
export CATALINA_PID="$TOMCAT_DIR/catalina.pid"

case "$1" in
    start)
        $TOMCAT_DIR/bin/startup.sh
        ;;
    stop)
        $TOMCAT_DIR/bin/shutdown.sh -force
        ;;
    restart)
        $0 stop
        $0 start
        ;;
    status)
        if [ -f $CATALINA_PID ] && ps --no-heading -p `cat $CATALINA_PID`; then
                echo "$NAME is running"
        else
                echo "$NAME is not running"
        fi
        ;;
    *)
        echo "Usage: /etc/init.d/$NAME {start|stop|restart|status}" >&2
        exit 1
        ;;

esac

exit 0

Now we can test the script with service solr status

Last step is to create the required symlinks for the several runlevels. This can be done with update-rc.d:

$ update-rc.d solr defaults 99
 Adding system startup for /etc/init.d/solr ...
   /etc/rc0.d/K99solr -> ../init.d/solr
   /etc/rc1.d/K99solr -> ../init.d/solr
   /etc/rc6.d/K99solr -> ../init.d/solr
   /etc/rc2.d/S99solr -> ../init.d/solr
   /etc/rc3.d/S99solr -> ../init.d/solr
   /etc/rc4.d/S99solr -> ../init.d/solr
   /etc/rc5.d/S99solr -> ../init.d/solr

Used Versions: Ubuntu 12, Tomcat 7
References:

Posted in Tomcat. Tags: . Leave a Comment »

Grails: Simple locale/language selector

How you can change locales in Grails is described in the Reference Documentation. Normally you want to do this in form of a language selector. Here’s an example taglib how you can do that:

import org.springframework.web.servlet.support.RequestContextUtils;
import groovy.xml.MarkupBuilder;

class LocaleTagLib {
	static namespace = 'locale'
	
	List<Locale> locales = [Locale.GERMAN, Locale.ENGLISH]

	/**
	 * Renders a locale selector. 
	 * Adds the class <code>active</code> to the list-element of the current language. 	
	 */
	def selector = {
		Locale requestLocale = RequestContextUtils.getLocale(request)
		
		MarkupBuilder mb = new MarkupBuilder(out)
		mb.ul('id': 'locale-selector') {
			locales.each { Locale locale ->
				li(requestLocale.language == locale.language ? ['class': 'active'] : [:]) {
					mb.yield(
						link( controller: controllerName, action: actionName, params: params + [lang: locale.language], 
							 { locale.getDisplayLanguage(locale) } ).toString(),
						false 
						)
				}
			}
		}
	}
}

What you probably have to change is the collection of locales. You don’t have to provide messages for the locales, the getDisplayLanguage()-method of Locale provides the translation.

Usage:

<locale:selector />

.

Posted in Grails. Tags: , . 3 Comments »

Grails: Set sitemesh layout depending on request parameter

For Fancyboxes/Lightboxes you may want to reuse your existing views with just another layout. In the Reference Documentation you’ll find some methods to trigger the layout in a static manner.
If you want to do this dependening on a request parameter (for example layout=embedded) you have two possibilities:

1. Use a expression in the meta tag

<head>
    <meta name="layout" content="${params.layout ?: 'main'}">
...

With this approach you have to use the meta tag in your views and use the expression in every view where you want the layout to be changeable.

2. Define a filter

import org.codehaus.groovy.grails.web.sitemesh.GroovyPageLayoutFinder

/**
 * Set layout depending on request parameter. This layout has the highest priority.
 */
class LayoutFilters {
    def filters = {
        all(controller:'*', action:'*') {
            before = {
				if (params.layout) {
					request[GroovyPageLayoutFinder.LAYOUT_ATTRIBUTE] = params.layout
				}
            }
        }
    }
}

With this filter you have the ability to change the layout for every view in your application. If you only want this mechanism for some controller/actions, change the filter expression (see Applying Filters).

Grails Fields Plugin: select with internationalized labels

If you are using the Fields Plugin and want to have a select box with internationalized labels you have two options:

Assuming you have a Weekday enumeration com.mycompany.Weekday

package com.mycompany

enum Weekday {
	MONDAY,
	TUESDAY,
	WEDNESDAY,
	THURSDAY,
	FRIDAY
}

and the following messages

com.mycompany.Weekday.MONDAY = Monday
com.mycompany.Weekday.TUESDAY = Tuesday
com.mycompany.Weekday.WEDNESDAY = Wednesday
com.mycompany.Weekday.THURSDAY = Thursday
com.mycompany.Weekday.FRIDAY = Friday

1. Pass the valueMessagePrefix to the field tag.

<f:field property="weekday" 
         input-valueMessagePrefix="com.mycompany.Weekday" 
         input-noSelection="['':'- choose weekday -']" />

Please note the input- prefix which is used to pass attributes to the underlying tag.

2. Customize field rendering for all enumerations

Create the following GSP in grails-app/views/_fields/enum/_input.gsp

<g:select name="${property}"
		from="${type?.values()}"
 		keys="${type?.values()*.name()}"
 		value="${value}"
 		valueMessagePrefix="${type.name}" />

I prefer the 2nd option because you have to do it only once for all enumerations and the labels for an are probably the same whereever you use it.

Update 20.2.2013
The above code snippet doesn’t work if you are using a prefix, so I adjusted the name attribute. You can omit the keys attribute if you don’t override toString() of the enum.

<g:select name="${(prefix ?: '') + property}"
		from="${type?.values()}"
 		value="${value}"
 		valueMessagePrefix="${type.name}" />
Posted in Grails. Tags: . 1 Comment »

Java SSL: unable to find valid certification path to requested target

While accessing a webservice over SSL, I got an SSLHandshakeException: PKIX path building failed. This is normally due to problems with the SSL certificate, so I tested the certifcate directly:

import java.io.IOException;
import java.net.UnknownHostException;
import java.security.cert.Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class CertTest {
	public static void main(String[] args) throws UnknownHostException, IOException {
		int port = 443;
		String hostname = "webservice.com";

        // get debug information of SSL
        System.setProperty("javax.net.debug", "ssl");

	    SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
	    SSLSocket socket = (SSLSocket) factory.createSocket(hostname, port);

	    socket.startHandshake();

	    System.out.println("===============");

	    Certificate[] serverCerts = socket.getSession().getPeerCertificates();
	    System.out.println("number of found certificates: " + serverCerts.length);
	    System.out.println("===============");
	    for (Certificate certificate : serverCerts) {
	    	System.out.println(certificate.getPublicKey());
			System.out.println(certificate);
			System.out.println("===============");
		}

	    socket.close();
	}
}

With CertTest I got the same error:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1584)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:848)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106)
	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495)
	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:877)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1089)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1116)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1100)
	at de.raumobil.apcoa.ws.CertTest.main(CertTest.java:20)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:221)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:145)
	at sun.security.validator.Validator.validate(Validator.java:203)
	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:172)
	at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(SSLContextImpl.java:320)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:841)
	... 8 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:236)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:194)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:216)
	... 13 more

The exception indicates that the key chain of the certificate is broken or that it’s simply a self signed certifcate.
To check that you can use: SSL Checker.

If In both cases you can create a keystore and import this certificate (you can download/export it with your browser) as trusted certificate:
keytool -import -trustcacerts -file webservice.com.pem -alias webservice -keystore myKeystore

In the CertTest you have to add the following lines to use the keystore:
System.setProperty("javax.net.ssl.trustStore","myKeystore");
System.setProperty("javax.net.ssl.trustStorePassword","myPassword");

If the SSL Checker said that everything is fine: “The certificate should be trusted by all major web browsers (all the correct intermediate certificates are installed).”, you propably ran in the Java bug Presence of a critical subjectAltName causes JSSE’s SunX509 to fail trusted checks. This Bug was fixed in Java 6 Update 10. So with updating to the current version everything should work well.

Resources

Posted in Java. Tags: , . Leave a Comment »

Grails: Listing the available message codes for errors

The following snippet is often used to list all errors of a form.

<g:eachError bean="${contactForm}">
     <li><g:message error="${it}" /></li>
</g:eachError>

If you do not specify any custom messages you will get the default ones. For example
Property [name] of class [class com.myCompany.ContactForm] cannot be blank

To overwrite the default message you have in Grails several possibilities which are too many to remember. So I’m using the following snippet to show which is the current error messsage and which codes would be possible.

<g:eachError bean="${contactForm}" var="error">
    ${error.field}: <g:message error="${error}" />
    <ul>
    <g:each in="${error.codes}" var="code">
        <li>${code}</li>
    </g:each>
    </ul>
</g:eachError>

Example output:

name: Property [name] of class [class com.myCompany.ContactFormCommand] cannot be blank

  • com.myCompany.ContactFormCommand.name.blank.error.com.myCompany.ContactFormCommand.name
  • com.myCompany.ContactFormCommand.name.blank.error.name
  • com.myCompany.ContactFormCommand.name.blank.error.java.lang.String
  • com.myCompany.ContactFormCommand.name.blank.error
  • contactFormCommand.name.blank.error.com.myCompany.ContactFormCommand.name
  • contactFormCommand.name.blank.error.name
  • contactFormCommand.name.blank.error.java.lang.String
  • contactFormCommand.name.blank.error
  • com.myCompany.ContactFormCommand.name.blank.com.myCompany.ContactFormCommand.name
  • com.myCompany.ContactFormCommand.name.blank.name
  • com.myCompany.ContactFormCommand.name.blank.java.lang.String
  • com.myCompany.ContactFormCommand.name.blank
  • contactFormCommand.name.blank.com.myCompany.ContactFormCommand.name
  • contactFormCommand.name.blank.name
  • contactFormCommand.name.blank.java.lang.String
  • contactFormCommand.name.blank
  • blank.com.myCompany.ContactFormCommand.name
  • blank.name
  • blank.java.lang.String
  • blank

So now you can easily choose the best message code.

References

WKBReader: ParseException: Unknown WKB type x

I’m using the Java API JTS Topology Suite to do spatial operations. To convert a byte array into a Geometry object the following helper class was used:

public class JTSHelper {
	static WKBReader wkbReader = new WKBReader();

	public static Geometry bytesToGeometry(byte geometryBytes[]) throws ParseException {
		return wkbReader.read(geometryBytes);
	}
}

This seemed to work well, but in the logfile we saw intermittent failures caused by this class:
ParseException: Unknown WKB type 139
ParseException: Unknown WKB type 0
ParseException: Unknown WKB type 17

The WKB type numbers were always different, but when checking the incoming byte arrays everything seems to be OK.

With apache benchmark tool the failures could be reproduced when increasing the number of concurrent requests:
ab -n 1000 -c 10 http://localhost:8080/project/test-action

A look at JavaDoc of WKBReader shows that this class is not thread-safe. Therefore the solution is to put WKBReader in ThreadLocal:

public class JTSHelper {
	static ThreadLocal<WKBReader> wkbReader	= new ThreadLocal<WKBReader>() {
		protected WKBReader initialValue() { return new WKBReader(); };
	};

	public static Geometry bytesToGeometry(byte geometryBytes[]) throws ParseException {
		WKBReader reader = wkbReader.get();
		return reader.read(geometryBytes);
	}
}

Versions: JTS 1.8, JDK 5

Posted in Java. Tags: , , . Leave a Comment »
Follow

Get every new post delivered to your Inbox.