Archive November 2009

Toggle view

Spring has its own Expression Language as of version 3.0

Recently I have switched from the log4j logging framework to the logback framework. logback seems to have evolved into something better than log4j. It has cool features like the ability of logging into context specific logging files almost out-of-the-box (Using a sifting appender).
However the application has to provide the context (usually as MDC variables) which is kind of boring task to do.

So, I have implemented a fairly generic servlet that is able to provide almost any servlet request information for an active HTTP request. This servlet accepts a set of SpEL expressions (SpEL will be available with Spring 3.0) which are parsed and evaluated.
Finally it produces the evaluation results as MDC variables through the org.slf4j.MDC api (So I guess that might be usable for log4j as well).


	slf4jmdc
	at...SpringExpressionSlf4jMdcRequestFilter
	
mdcKeyExpression
contextPath=${request.contextPath};username=${request.userPrincipal?.name}
	

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
	StandardEvaluationContext context = new StandardEvaluationContext(new RootObject(request));
	ExpressionParser parser = new SpelExpressionParser();

	String[] mdc = StringUtils.delimitedListToStringArray(mdcKeyExpression, ";");
	Properties expressions = StringUtils.splitArrayElementsIntoProperties(mdc, "=");

	Enumeration keyNames = expressions.propertyNames();
	while (keyNames.hasMoreElements()) {
		String key = keyNames.nextElement().toString();
		try {
			Expression exp = parser.parseExpression(expressions.getProperty(key), new TemplateParserContext());
			Object value = exp.getValue(context);
			if (value != null) {
				MDC.put(key, value.toString());
			}
		} catch (ParseException e) {
			LOGGER.error("Parsing expression", e);
		}
	}

	try {
		filterChain.doFilter(request, response);
	} finally {
		while (keyNames.hasMoreElements()) {
			MDC.remove(keyNames.nextElement().toString());
		}
	}
}

This servlet can be used about anywhere MDC variables are needed!

Migrating Spring projects to Spring 3.0.0 bundle repositories

Since Spring has started its strong support for OSGi, all spring libraries have been turned into OSGi bundles internally. Subprojects (e.g. Webflow) eventually also started to publish their jars using the bundle naming scheme. With Spring 3.0 it looks we are at the final destination. As long as you stick to the more populare frameworks you get a pretty complete repository of Maven artifacts.

On one side it is good to see a unique naming for all of the spring + subproject artifacts. But for those of you starting to migrate existing projects this causes a few headaches. Everything is fine as long as you can get all of your favourite libraries from one of the SpringSpource bundle repositories


	
		SpringSource Enterprise Bundle Repository - External Bundle Milestones
		http://repository.springsource.com/maven/bundles/milestone
	
	
		SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases
		http://repository.springsource.com/maven/bundles/release
	
	
		SpringSource Enterprise Bundle Repository - External Bundle Releases
		http://repository.springsource.com/maven/bundles/external
	

Fortunately they also provide a really helpful tool for searching their repositories.

But sometimes you won’t find your favourite ones and need to fall back to non-bundle style artifacts from non-Springsource repositories.
And here is the trouble: SpringSource is renaming the Maven artifactId for all of the bundles stored in their repositories (e.g. com.springsource.org.apache.commons.logging is the bundle equivalent of org.apache.commons.logging).

So let’s say you depend on artifact A that comes from the bundle repository (that depends on logging) and also depend on artifact B that comes from the standard maven repository (and also dependes on logging).
This will end up with a 2 dependencies to the logging artifact and Maven will not be able to distinguish since they have a different artifactId.

To resolve that, start adding dependency exclusions and dependencies for first level transitive dependencies.

I’m showing an example for the hades project that actually has a bug in their dependency description.


	org.synyx.hades
	org.synyx.hades
	1.0
	
		
			org.aspectj
			aspectjrt
		
	


	org.aspectj
	com.springsource.org.aspectj.runtime
	1.6.1

Why offshore development never pays off….at

During many project engagements I have been involved in offshore development environments. Personally I always felt like “that’s not going to pay off”, you spend way more time in communication and mostly so-called “Offshore Senior Level Engineers” didn’t have the proper level of education as you would expect locally.

I was forwarded an extremely hilarious communication between an offshore senior Java EE developer and a local developer. Just make up your mind…

[10/15/2009 2:23:57 PM] LOCAL_STAFF says: ok, let's try it different:
[10/15/2009 2:24:03 PM] LOCAL_STAFF says:     public int retrieveOverallHealthStatus(Integer[] states)
    {
        for (Integer result : states)
        {
            switch ((Integer) (result))
            {
            case ERROR:
                return ERROR;
            case WARNING:
                return WARNING;
            case GOOD:
                break;
            }
        }
        return GOOD;
    }
[10/15/2009 2:24:27 PM] LOCAL_STAFF says: This is basically the same method, only it receives the list already as input. So no jGroups here, no JMX.
[10/15/2009 2:25:28 PM] LOCAL_STAFF says: This method still has the same problem, if we provide two elements in the list with

states[0] = WARNING
states[1] = ERROR

then we return "WARNING" as highest overall state, which is simply not true, as there is an ERROR state as well.

This is the problem that this Ticket talks about!
[10/15/2009 2:31:30 PM] OFFSHORE_STAFF says: in this particualr example you gaveme, it will run through the loop and willl check the last element in the array which is  states[1] that is ERROR
[10/15/2009 2:32:32 PM] OFFSHORE_STAFF says: it will break of 2nd time from the switch stament with state ERRO
[10/15/2009 2:32:37 PM] LOCAL_STAFF says: in the first iteration of the loop, it will reach the "return WARNING" for the states[0] already and there it will return WARNING, where it should return ERROR in this case from the method.
[10/15/2009 2:33:49 PM] OFFSHORE_STAFF says: so you are saying that instead of checking it chronologicallay, one shouldb check it in a combined format
[10/15/2009 2:33:59 PM] OFFSHORE_STAFF says: instead of switch
[10/15/2009 2:36:41 PM] OFFSHORE_STAFF says: we will use  if (  ( state[0] == ERRO || sate[1]==ERROR] retnr error;
[10/15/2009 2:37:01 PM] OFFSHORE_STAFF says: right?
[10/15/2009 2:40:33 PM] OFFSHORE_STAFF says: something like
[10/15/2009 2:40:35 PM] OFFSHORE_STAFF says: public int retrieveOverallHealthStatus(Integer[] states)
    {
        for (Integer result : states)
        {
            if states[0]==ERROR || states[1]==ERROR
   return ERROR;
        }
        return GOOD;
    }
[10/15/2009 2:40:57 PM] OFFSHORE_STAFF says: sorry
[10/15/2009 2:41:33 PM] OFFSHORE_STAFF says: public int retrieveOverallHealthStatus(Integer[] states)
    {
        for (Integer result : states)
        {
            if states[i]==ERROR    return ERROR;
        }
        return GOOD;
    }
[10/15/2009 2:41:47 PM] OFFSHORE_STAFF says: is that what you are sussgesting?
[10/15/2009 2:42:39 PM] LOCAL_STAFF says: no, sorry
[10/15/2009 2:47:16 PM] OFFSHORE_STAFF says: public int retrieveOverallHealthStatus(Integer[] states)
    {
        for (Integer result : states)
        {
            if states.toInteger().value().equals(ERROR)
   return ERROR;
        }
        return GOOD;
    }
[10/15/2009 2:49:17 PM] OFFSHORE_STAFF says: perhaps
[10/15/2009 2:49:20 PM] OFFSHORE_STAFF says: public int retrieveOverallHealthStatus(Integer[] states)
    {
        for (Integer result : states)
        {
            if states.toInteger().value().equals(ERROR)
   return ERROR;

   if states.toInteger().value().equals(WARNING)
   return WARNING;
        }
        return GOOD;
    }
[10/15/2009 2:49:43 PM] OFFSHORE_STAFF says: is that what you were implying
[10/15/2009 2:50:09 PM] LOCAL_STAFF says: they all don't solve the case that I showed above, just try to step through your code with the input that I gave, or better, write a small unit test...
[10/15/2009 2:50:39 PM] OFFSHORE_STAFF says: is it easier for mathias or yourself ot do it?
[10/15/2009 2:51:44 PM] LOCAL_STAFF says: no, we've got ClearCase disconnected over here today...
[10/15/2009 2:51:56 PM] OFFSHORE_STAFF says: hehe
[10/15/2009 2:52:02 PM] OFFSHORE_STAFF says: not being funny
[10/15/2009 2:52:14 PM] OFFSHORE_STAFF says: but can you email me what you think is the right soltiuion
[10/15/2009 2:52:53 PM] OFFSHORE_STAFF says: i mean this is basic prgramming right
[10/15/2009 2:52:59 PM] OFFSHORE_STAFF says: as yu mentioned earlier

Change appearance of UI elements based on validation results

In my previous post I showed how simple it is to control rendering of UI elements based on validation results.

Today I want to put this idea a little bit further and add another convenicent facelets tag that will allow to assign a style class to any UI element based on validation results. In order to create an appealing form that clearly indicates the position where validation fails very often you see that input elements change their visual appearance based on the validation state. For example any invalid input element is shown with red background. With no component you end up with tedious (or complex) EL expressions that are assigned to the styleClass attribute.

To make that concept reusable and simple to apply I show how to create a facelets tag setStyleClassIfMessages that evaluates the faces messages available for a specific component, looks for the message with highest severity and uses the severity to apply a CSS style class to any component.



	
	

The tag implementation is quite straightforward, I have stripped some obvious details from the code.

public class SetStyleClassIfMessagesTagHandler extends MessagesTagHandler {

	protected final TagAttribute[] classAttributes = new TagAttribute[5];

	public SetStyleClassIfMessagesTagHandler(TagConfig config) {
		super(config);
		classAttributes[0] = getAttribute("passedClass");
		classAttributes[FacesMessage.SEVERITY_INFO.getOrdinal() + 1] = getAttribute("infoClass");
		classAttributes[FacesMessage.SEVERITY_WARN.getOrdinal() + 1] = getAttribute("warnClass");
		classAttributes[FacesMessage.SEVERITY_ERROR.getOrdinal() + 1] = getAttribute("errorClass");
		classAttributes[FacesMessage.SEVERITY_FATAL.getOrdinal() + 1] = getAttribute("fatalClass");
	}

	public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
			ELException {
		if (forAttribute != null) {
			UIComponent forComponent = getForComponent(ctx.getFacesContext(), forAttribute.getValue(ctx), parent);
			if (forComponent != null) {
				setMaximumSeverityStyleClass(ctx, forComponent);
			} else {
				LOGGER.warn("No component {} found.", forAttribute.getValue(ctx));
			}
		} else if (parent != null) {
			setMaximumSeverityStyleClass(ctx, parent);
		}
	}

	private void setMaximumSeverityStyleClass(FaceletContext ctx, UIComponent forComponent) {
		FacesMessage message = findMostSevereMessage(ctx.getFacesContext(), forComponent);
		if (PropertyUtils.isWriteable(forComponent, STYLE_CLASS_PROPERTY_NAME)) {
			TagAttribute messageStyleClass = message == null ? classAttributes[0] : classAttributes[message
					.getSeverity().getOrdinal() + 1];
			try {
				StringBuilder newStyleClass = new StringBuilder(messageStyleClass == null ? "" : messageStyleClass
						.getValue(ctx));
				// read style and remove style class from previous post-back,
				// then set new style class
				String oldStyleClass = (String) PropertyUtils
						.getSimpleProperty(forComponent, STYLE_CLASS_PROPERTY_NAME);

				Set<String> classNames = new HashSet<String>();
				for (TagAttribute classAttribute : classAttributes) {
					if (classAttribute != null) {
						classNames.add(classAttribute.getValue());
					}
				}
				StringTokenizer tokenizer = new StringTokenizer(oldStyleClass == null ? "" : oldStyleClass, " ");
				while (tokenizer.hasMoreElements()) {
					String styleClass = tokenizer.nextToken();
					if (classNames.contains(styleClass)) {
						continue;
					}
					newStyleClass.append(' ').append(styleClass);
				}
				PropertyUtils.setSimpleProperty(forComponent, STYLE_CLASS_PROPERTY_NAME, newStyleClass.toString());
			} catch (Exception e) {
				throw new FaceletException(e);
			}
		}
	}
}

Create a server certificate with OpenSSL

A long time ago I had created some certificate for my mail server. Very recently it expired so I had to renew it now.
Back then I had used 2 quite complex OpenSSL commands that I found @ some blog.

# create key + csr (-nodes == key is not encrypted)
openssl req -new -nodes -newkey rsa:1024 -keyout domain.key.pem -out domain.csr.pem
# create certificate (self signed)
openssl x509 -req -days 365 -in domain.csr.pem -signkey domain.key.pem -out domain.crt.pem

I had documented them somewhere but when I looked at them again, it was like “don’t know what’s going on here”! So I tried to break them up into multiple steps. Also I came up with some naming convention since quite a few file are created during the whole process.

A key file is using the file suffix .key.pem, a certificate signing request uses .csr.pem and a certificate .crt.pem .
And the filename would always be prefixed with the domain name. E.g. for domain google.com a key file would be google.com.key.pem .

Prepare for creating certificates

1. Create a certificate authority

For convenience before using OpenSSL I would set up a certificate authority (CA) with a key file and a certificate file. Assuming that OpenSSL is already installed I configure some defaults in /etc/ssl/openssl.cnf .

[ CA_default ]
dir                = /etc/ssl              # Where everything is kept
certificate      = $dir/private/cacert.pem       # The CA certificate
private_key    = $dir/private/cakey.pem   # The private key
...
[ req_distinguished_name ]
...

And we create a few files/directories in /etc/ssl:

echo 01>/etc/ssl/serial
touch /etc/ssl/index.txt
mkdir /etc/ssl/newcerts

The execution of the next OpenSSL command will create the CA files and prompt for some input. Note that here for common name it is sufficient to use your real name. Finally we make the key file readable for root only.

openssl req -new -x509 -newkey rsa:2048 -keyout /etc/ssl/private/cakey.pem -out /etc/ssl/private/cacert.pem -days 730

chmod 600 /etc/ssl/private/cakey.pem

Ok here we go: these are the steps to create a certificate

2. Create a key for the server certificate

openssl genrsa -out domain.key.pem -aes128 2048 -days 730

That creates a password phrase protected key file. However since it so not fun to be prompted during server startup we remove the password phrase again.

openssl rsa -in domain.key.pem -out domain.key.pem

It actually would be better to safe the password protected key to some safe location before and creating the unprotected using a new file name!!!

Create a certificate signing request (CSR) and have a CA sign it

1. Create certificate signing request (CSR)

openssl req -new -key domain.key.pem -out domain.csr.pem -nodes

That creates a csr that later must be signed by a certificate authority (CA). It is of importance that here we have to use the full domain name of the server for the common name. Otherwise the client would not accept that certificate.

2. Have a CA sign the certificate signing request

A CA now has to sign the request. Either you contact one of the official authorities (like Thawte) and pay lots of bucks or you use the CA you created in the beginning (as we show now).

openssl ca -in domain.csr.pem -notext -out domain.crt.pem

3. Install certificate

First move the certificate to /etc/ssl/certs and move the key file to /etc/ssl/private. Make sure that only root can read the key files.

Finally you need to install your certificates which depends on the product you are using. Maybe I will write a blog entry on how to install a certificate for a mail provider or Apache web server later on.

green red blue grey