Wednesday, January 28, 2009

Testing Unplugged

For some reason, running an integration test against your web application or web services is never really awarding. I can come up with some reasons, but there are probably more, because I always find myself trying to avoid writing them, which is a bad habit. Here are some of the reasons why I don't like them:

  • Configuring the application server correctly for your purposes is just way too complicated
  • Starting the web server just takes way too much time.
  • Making sure that your build does not claim a port already in use by something else is just way too much work.
  • Setting up your sniffer to check what is actually going across the wire is way too much work
  • Having to dig through the application server's log files is just too much of a hassle

Now, there is something called Cargo, which was going to make life a lot easier. But it seems the project is no longer active, and I never really found it easy to use.

Last week, I wanted to test if my message authentication scheme was working correctly. So I needed to check if the client correctly signed a message sent to a web service, and then check if the server would correctly grant or deny access to that service. I resisted the temptation of going for Cargo, and had a look at some of the alternatives.

Embedding Jetty

I never really looked into the APIs for embedding Jetty inside of your process, but it is EASY. It's just perfect. Running Jetty from within your tests is hardly any work at all. This is about it:

server = new Server();
SelectChannelConnector remoteConnector = new SelectChannelConnector();
remoteConnector.setHost("127.0.0.1");
remoteConnector.setPort(8090);
server.setConnectors(new Connector[] { remoteConnector });
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setWar(getPath("src/main/webapp"));
context.setClassLoader(this.getClass().getClassLoader());
server.setHandler(context);
server.start();

Most of this is Jetty API. The only exception is the static
getPath() operation, which is expected to return the absolute path
for the relative path passed in. (Always guaranteed relative to the
Maven module's base directory, regardless of the execution
environment. So it returns the same absolute path both in Maven as
well as Eclipse.)

Embedding Jetty with a LocalConnector

So this works quite ok. By just adding a TestSetup, it would be possible to start and stop the server for a whole slew of tests. Pretty cool. But then - why do we actually need a connector listening on a socket? The client that is going to make the request is the test itself. It doesn't seem all that useful to set up a socket listener.

And it turns out that you don't have to do that. Instead of passing a SelectChannelConnector instance, you can actually also pass a LocalConnector. And the LocalConnector has an operation that expects the request as a String (or a buffer of bytes), and returns a String with the response (or a buffer of bytes). That way, you basically cut out the entire network transport. The only thing you need to do is make sure that your TestCase retains a reference to that LocalConnector, so that you it use it in each and every test.

localConnector = new LocalConnector();
server.setConnectors(new Connector[] { localConnector });
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setWar(getPath("src/main/webapp"));
context.setClassLoader(this.getClass().getClassLoader());
server.setHandler(context);
server.start();

Now, that's all pretty sweet. However, my service is based on Hessian. And I want to use the normal HessianProxyFactory and other Spring Hessian client code. And unfortunately, the Hessian classes expect a URL. And there is no protocol in the VM that allows me to send an HTTP request to non-socket listener. What can we do about it?

Loopback URLConnection

I knew that one of the ways to solve it would be to write my own URLStreamHandler for my own protocol specifier, and then have my own URLConnection subclass that would call the LocalConnector mentioned before. But it's not easy. First of all, no matter what base class you start of with, your URLConnection class will have to create the HTTP messages itself. And parse the HTTP response itself. The getOutputStream() and getInputStream() operation deal with the content only. And whatever I would do, it needed to be compatible with the normal way of interaction with a URLConnection and HttpURLConnection. And as it happens, the contract of HttpURLConnection and URLConnection is ridiculously ill-defined. Taking a look at the JavaDocs doesn't help. In fact, the documentation is sometimes just plain wrong.

But no matter what I tried, there was no way to work around that. If I wanted to use the Spring abstractions, then it would involve having a HessianProxyFactory, the endpoint would be identified with a URL, and the connection would be set up by opening a connection based on that URL.

So I sat down and created a first version. At first, I was writing my own HTTP requests, making sure the encoding was done properly, making sure the Content-Length matched the actual size of the content section, and so on and so forth. However, at some point, I realized it was getting way to complicated, so I called in help from commons-httpclient.

It took me some time before I got a grip on the API from commons-httpclient. I don't think the creators originally had something in mind like the stuff I wanted to do. I refactored my existing solution for a while, and then realized this wasn't going to cut it either.

And then I turned back to Jetty. It turns out Jetty has a very nice HttpGenerator and HttpParser. I liked the abstractions, but what I liked even better is that the HttpTester class basically formed a convenience wrapper around these classes. So I decided to start with HttpTester as the base class of my own HttpURLConnection subclass.

As it turns out, HttpUrlConnection has a lot of operation that all need to behave slightly differently depending on the state of the request. So, you cannot for instance change the request properties after the request has been sent. Having to deal with that in every method was just way more than I could bear. So I decided to make my own HttpURLConnection a simple facade to a strategy with implementation of these methods, and made sure that the strategy was replaced on state changes. Finding what to do in every state turns out even more complicated then implementing it, and in many cases I had to rely on bug reports to figure out how HttpURLConnection is actually implemented. (And how clients are expected to interact with it.)

And now, it works. So this is what I can do, in my client code:

LoopbackProcessorHolder.init();
LoopbackProcessorHolder.set(new JettyLoopbackProcessor(localConnector));

Once this is set up, I can use a specific type of URL to connect to the the LocalConnector. If the client connects using that type of URL, it will get a subclass of HttpURLConnection, so it is capable of treating it as an ordinary HttpURLConnection. But in reality, it is not the platform provided HttpURLConnection. It's my own that - using HttpTester - calls into the LocalConnector.

So, this is what the client code would be like, if you happened to be using Hessian:

String url = "loopback:///remoting/HelloService";
LoopbackProcessorHolder.set(new JettyLoopbackProcessor(localConnector));
HessianProxyFactory factory = new HessianProxyFactory();
HelloService service = (HelloService) factory.create(
HelloService.class, url);
System.out.println(service.sayHello());

As you can see, instead of using http://localhost:8080/remoting/HelloService, I am using loopback:/// as the protocol specifier. No host name, no port number, since all of that is not required. The Host header will however be set to localhost, just to be in line with the HTTP/1.1 spec.

A word on Hessian

As I said before, all of this was done to make sure I could test my message authentication scheme, and see how well it would work for authentication of a Hessian client. One of the things I found out that implementing this message authentication scheme into the existing Hessian client code was quite hard. The APIs don't have any hooks to append your own headers. It pretty much has to come from the existing abstractions, or subclasses of these abstractions. And subclassing Hessian classes is harder than it might seem. On the surface, everything is fine. However, there are many cases in which it is actually quite hard to get something sensible done.

Just as an example. HessianProxy is the class that eventually performs the request. Now, ideally, you would simply subclass this class and override a factory method for creating a HessianProxy with your own implementation. Unfortunately, HessianProxy's constructor is package private. So, first of all your HessianProxy subclass always ends up in the same package as HessianProxy itself - which is awkward.

Second, you cannot just override a factory method, since the factory method for a HessianProxy subclass is actually not defined on HessianProxyFactory - which is interesting, given its name. Instead, you have to override a much more general operation called create(), which is expected to return the actual proxying POJO, instead of the HessianProxy. The HessianProxy subclass is created somewhere deep down inside.

I would vote for having a mechanism that is a little bit easier to extend. Out of the box, Hessian only supports basic authentication, which - I think - clearly is not going to cut it. It's much more likely that clients will need some sort of API key that is used to digitally sign messages, rather than sending a password with every request, or obtaining a token once and then continuously send that token back and forth.

Tuesday, January 27, 2009

SpringONE and the community

I was just looking at the lineup for SpringONE this year. Interesting. Presenters from SpringSource only. So much for the openness. I mean, Sun got accused over and over again of dominating JavaONE. But at least *they do* accept talks from people outside of Sun. SpringONE has none at all. Apart from that, there are no BOFs, there's no unconferrence, no posters, no nothing. Well, there is a partner exhibition. More advertising.

It's interesting to see that a company that was built on open source displays no interest at all for getting community input. What do you think?

Thursday, January 15, 2009

Preon versus Google Protocol Buffers

Preon was mentioned in a discussion about implementing Google Protocol Buffers in JBoss. The author considers Preon to be slightly off-topic, but perhaps interesting. It makes you wonder if Preon actually bears some similarity with Google Protocol Buffers. Let's take a look at that.

  1. Preon like Google Protocol Buffers is about marshalling between the in-memory representation of a data structure, and its binary encoded representation. In that way, they are similar.
  2. Google Protocol Buffers is not just about encoding and decoding data: it also defines an RPC model. Preon does not; it's about the binary encoded representation only. That way, they are different.
  3. Google Protocol Buffers already has encoding implemented. For Preon, it's clear how it should be done, but since it is not backed by a large corporation yet (anyone?), I haven't been able to work on encoding yet. In that sense, they are different.
  4. Google Protocol Buffers relies on .proto files for defining the data structure. Preon doesn't. Preon allows you to define the mapping from a Java class to its binary encoded representation inside the class itself, relying on annotations. In that sense, they are different.
  5. Google Protocol Buffers generates source code. Preon doesn't. Preon builds the entire Codec at runtime. In Preon, the only objects that you have to deal with are the objects you wrote yourself. In that sense, Google Protocol Buffers and Preon are different.
  6. Google Protocol Buffers supports multiple languages. Now this is an interesting one. Since the Codec constructed by Preon captures exactly how the data is represented in a binary way, it should be fairly straightforward to generate code from it for different languages. Now, that would of course be a little unusual, but nevertheless doable. It that sense, they are currently different.
  7. Google Protocol Buffers is not extensible. Well, it is extensible, but not in the way Preon is extensible. It does not allow you to use other types of compression techniques, unless you do that in the application layer. (Let's just say, accept a byte array, and interpret that byte array at he compressed representation of something else.) Preon is extensible. It's like allowing the protocol buffer language to be extended to support new types. In Preon, you can create your own CodecFactory, and hook that up with the framework. From that point on, sky is the limit. In that sense, they are different.
  8. Google Protocol Buffers supports decoding the full data structure all at once, in a single pass. Preon was designed to decode data just in time, only if we need it. That was done deliberately. Preon originates from decoding map data. You don't want to decode a full map into memory all at once. It would blow up the heap, if you need to stay within the boundaries of a Java 32-bit VM. So Preon will try really hard not to decode all data all at once. In that sense, Google Protocol Buffers and Preon are completely different animals.
  9. Preon allows you to define dependencies between different fields, and have that influence the way data is decoded. In that sense, it's different from pretty much anything else out there - apart from the Flavor derivatives. So if you first read a numeric attribute, then you can reuse that attribute further along down the road, for instance by interpreting it as the number of elements in an array Preon has to read. For media content, this is fairly common. In typical serialization mechanisms, this is pretty uncommon. The expressions you can use to define these dependencies can be as complicated as you like. In that sense, Google Protocol Buffers and Preon are totally different.

In summary, Google Protocol Buffers and Preon are quite different, and address different needs. Preon is better suited for decoding existing media types. Google Protocol Buffers is better suited for integration projects.

Wednesday, January 14, 2009

RelaxNG Grammar for Log4j

Log4j configuration is driving me nuts. My brain is just to darn lazy to remember the rules for property-based configuration, and there doesn't seem to be any real tooling at all to make it any easier. So I decided to stick to XML-based configuration - but even then you are basically on your own.

Anyhow, in order to at least have context-sensitive tag completion, I decided to quickly roll a RelaxNG based grammar for it. That way, I can stick it into Emac's nxml-mode, and get some support for editing the files. I did it by hand, so some errors might have sneaked in, but I will update it once I find them.

This is the RelaxNG grammar:



<!--
Copyright (c) 2009, Wilfred Springer
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
ns="http://jakarta.apache.org/log4j/">

<start>
<choice>
<ref name="configuration"/>
<ref name="eventSet"/>
</choice>
</start>

<define name="configuration">
<element name="configuration">
<optional>
<attribute name="threshold">
<choice>
<value>all</value>
<value>debug</value>
<value>info</value>
<value>warn</value>
<value>error</value>
<value>fatal</value>
<value>off</value>
<value>null</value>
</choice>
</attribute>
</optional>
<optional>
<attribute name="debug">
<choice>
<value>true</value>
<value>false</value>
<value>null</value>
</choice>
</attribute>
</optional>
<zeroOrMore><ref name="renderer"/></zeroOrMore>
<zeroOrMore><ref name="appender"/></zeroOrMore>
<zeroOrMore>
<choice>
<ref name="category"/>
<ref name="logger"/>
</choice>
</zeroOrMore>
<optional><ref name="root"/></optional>
<optional><ref name="categoryFactory"/></optional>
</element>
</define>

<define name="appender">
<attribute name="name">
<data type="ID"/>
</attribute>
<attribute name="class">
<text/>
</attribute>
<element name="appender">
<optional><ref name="errorHandler"/></optional>
<zeroOrMore><ref name="param"/></zeroOrMore>
<optional><ref name="layout"/></optional>
<zeroOrMore><ref name="filter"/></zeroOrMore>
<zeroOrMore><ref name="appender-ref"/></zeroOrMore>
</element>
</define>

<define name="renderer">
<element name="renderer">
<attribute name="renderedClass"><text/></attribute>
<attribute name="renderingClass"><text/></attribute>
</element>
</define>

<define name="layout">
<element name="layout">
<attribute name="class"><text/></attribute>
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
</element>
</define>

<define name="filter">
<element name="filter">
<attribute name="class"><text/></attribute>
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
</element>
</define>

<define name="errorHandler">
<attribute name="class"><text/></attribute>
<element name="errorHandler">
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
<optional>
<ref name="root-ref"/>
</optional>
<zeroOrMore>
<ref name="logger-ref"/>
</zeroOrMore>
<zeroOrMore>
<ref name="appender-ref"/>
</zeroOrMore>
</element>
</define>

<define name="root-ref">
<element name="root-ref">
<empty/>
</element>
</define>

<define name="logger-ref">
<element name="logger-ref">
<attribute name="ref"><data type="IDREF"/></attribute>
<empty/>
</element>
</define>

<define name="param">
<element name="param">
<attribute name="name"><text/></attribute>
<attribute name="value"><text/></attribute>
<empty/>
</element>
</define>

<define name="priority">
<element name="priority">
<optional>
<attribute name="class"><text/></attribute>
</optional>
<attribute name="value"><text/></attribute>
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
</element>
</define>

<define name="level">
<element name="level">
<optional>
<attribute name="class"><text/></attribute>
</optional>
<attribute name="value"><text/></attribute>
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
</element>
</define>

<define name="category">
<element name="category">
<optional>
<attribute name="class"><text/></attribute>
</optional>
<attribute name="name"><text/></attribute>
<optional>
<attribute name="additivity">
<choice>
<value>true</value>
<value>false</value>
</choice>
</attribute>
</optional>
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
<optional>
<choice>
<ref name="priority"/>
<ref name="level"/>
</choice>
</optional>
<zeroOrMore>
<ref name="appender-ref"/>
</zeroOrMore>
</element>
</define>

<define name="logger">
<element name="logger">
<attribute name="name"><data type="ID"/></attribute>
<attribute name="additivity">
<optional>
<choice>
<value>true</value>
<value>false</value>
</choice>
</optional>
</attribute>
<optional>
<ref name="level"/>
</optional>
<zeroOrMore>
<ref name="appender-ref"/>
</zeroOrMore>
</element>
</define>

<define name="categoryFactory">
<element name="categoryFactory">
<attribute name="class"><text/></attribute>
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
</element>
</define>

<define name="appender-ref">
<element name="appender-ref">
<attribute name="ref"><data type="IDREF"/></attribute>
<empty/>
</element>
</define>

<define name="root">
<element name="root">
<zeroOrMore>
<ref name="param"/>
</zeroOrMore>
<optional>
<choice>
<ref name="priority"/>
<ref name="level"/>
</choice>
</optional>
<zeroOrMore>
<ref name="appender-ref"/>
</zeroOrMore>
</element>
</define>

<define name="eventSet">
<element name="eventSet">
<zeroOrMore>
<ref name="event"/>
</zeroOrMore>
</element>
</define>

<define name="event">
<element name="event">
<ref name="message"/>
<optional>
<ref name="NDC"/>
</optional>
<optional>
<ref name="throwable"/>
</optional>
<optional>
<ref name="locationInfo"/>
</optional>
</element>
</define>

<define name="message">
<element name="message">
<choice>
<text/>
<empty/>
</choice>
</element>
</define>

<define name="NDC">
<element name="NDC">
<choice>
<text/>
<empty/>
</choice>
</element>
</define>

<define name="throwable">
<element name="throwable">
<choice>
<text/>
<empty/>
</choice>
</element>
</define>

<define name="locationInfo">
<attribute name="class"><text/></attribute>
<attribute name="method"><text/></attribute>
<attribute name="file"><text/></attribute>
<attribute name="line"><text/></attribute>
</define>

</grammar>



This is the compact syntax grammar:



# Copyright (c) 2009, Wilfred Springer
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

default namespace = "http://jakarta.apache.org/log4j/"

start = configuration | eventSet
configuration =
element configuration {
attribute threshold {
"all"
| "debug"
| "info"
| "warn"
| "error"
| "fatal"
| "off"
| "null"
}?,
attribute debug { "true" | "false" | "null" }?,
renderer*,
appender*,
(category | logger)*,
root?,
categoryFactory?
}
appender =
attribute name { xsd:ID },
attribute class { text },
element appender {
errorHandler?, param*, layout?, filter*, appender-ref*
}
renderer =
element renderer {
attribute renderedClass { text },
attribute renderingClass { text }
}
layout =
element layout {
attribute class { text },
param*
}
filter =
element filter {
attribute class { text },
param*
}
errorHandler =
attribute class { text },
element errorHandler { param*, root-ref?, logger-ref*, appender-ref* }
root-ref = element root-ref { empty }
logger-ref =
element logger-ref {
attribute ref { xsd:IDREF },
empty
}
param =
element param {
attribute name { text },
attribute value { text },
empty
}
priority =
element priority {
attribute class { text }?,
attribute value { text },
param*
}
level =
element level {
attribute class { text }?,
attribute value { text },
param*
}
category =
element category {
attribute class { text }?,
attribute name { text },
attribute additivity { "true" | "false" }?,
param*,
(priority | level)?,
appender-ref*
}
logger =
element logger {
attribute name { xsd:ID },
attribute additivity { ("true" | "false")? },
level?,
appender-ref*
}
categoryFactory =
element categoryFactory {
attribute class { text },
param*
}
appender-ref =
element appender-ref {
attribute ref { xsd:IDREF },
empty
}
root = element root { param*, (priority | level)?, appender-ref* }
eventSet = element eventSet { event* }
event = element event { message, NDC?, throwable?, locationInfo? }
message = element message { text | empty }
NDC = element NDC { text | empty }
throwable = element throwable { text | empty }
locationInfo =
attribute class { text },
attribute method { text },
attribute file { text },
attribute line { text }

Tuesday, January 13, 2009

Build Fall ME Using Maven

I came across this project the other day: Spring type of approach for integration with MIDP interfaces.
That's interesting for obvious reasons.

Unfortunately, the project can only be built using NetBeans. I created a pom.xml file, with the intent to upload it to a Maven repository, one of these days.

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>net.java.fallme</groupId>
<artifactId>fallme</artifactId>
<version>0.6</version>
<name>Fall ME</name>
<dependencies>
<dependency>
<groupId>org.microemu</groupId>
<artifactId>midpapi20</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
</build>
</project>

Monday, January 12, 2009

Extending Spring Security (1)

Last week I started to look into what would be required to get Amazon S3 type of message authentication integrated with Spring Security. While I am nowhere even close to getting it done yet, I aim to keep track of my efforts through my blog.

Filters and AuthenticationProviders

A couple of conclusions from browsing the source code and documentation. It seems that - in general - there is a contract between an AuthenticationProvider and a filter, which could be a SpringSecurityFilter that defines a little bit more template code for what it normally is expected to do. In general, the filter should prepare an authentication request implementing the Authentication interface, and then leave it up to the AuthenticationManager to do the actual authentication. The AuthenticationManager manages a collection of AuthenticationProviders, and every AuthenticationProvider gets a chance to see if - given the authentication data passed in - it is able to perform authentication. AuthenticationProviders can register their interest for particular types of Authentication objects only.

Now, looking a little further, it turns out that the DigestProcessingFilter doesn't actually use the AuthenticationManager, nor an AuthenticationProvider implementation. It performs the whole task itself, and once succeeded, it sets the Authentication request as the authentication on the SecurityContextHolder. What I don't get though, is that this way the isAuthenticated() operation on that will always return false. There must be something that flips it over to true, but I just can't find it.

Looking a little further, I find out that the isAuthenticated() operation is actually expected to return false if the Authentication is expected to be processed by the AuthenticationManager. But hold on, didn't I see the BasicProcessingFilter calling the AuthenticationManager itself? It turns out it does. I don't understand it. Why would you have one filter interacting with the AuthenticationManager directly, and the other expecting the other things further down the chain to interact with it?

Wednesday, January 7, 2009

MultiReference Duck Typing?

I have been struggling with one of Preon's challenges for a while, and I haven't made up my mind about it yet. So I figured I would write it down here. Perhaps that helps.

So, here we go. First of all, if you don' t know anything at all about Preon, I suggest you read the introduction available at http://preon.flotsam.nl/. One of the sections in that document briefly discusses references in Preon. And those references are currently posing some challenges.

Let's just say this is your object model.


class A {
@Bound D valueOfD;
@If("valueOfD.value > 0");
@Bound int number;
}

class B extends D {
@Bound int value;
}

class C extends D {
@Bound String value;
}


Just to help you to decode the example above: if you would decode an instance of A, the first field encountered would be valueOfD. I left the annotations detailing how to decide between B or C out of here, for sake of simplicity. However, keep in mind that - since B and C are subtypes of D - valueOfD could either be an instance of B or C.

The next bound field in A is number. But that field will only be read if the value property of valueOfD is greater than zero. But wait a minute! The value property of the object referenced by valueOfD could either be an instance of B or an instance of C. So, that means that value is either an integer or a String. Which means that the expression 'valueOfD.value > 0' could either be valid or invalid.

Now, question is: what do you expect in cases like these? There are (at least) two options:

  • You expect the framework to generate an exception while creating the Codec. Since value can be either an int or a String, the expression might be invalid at runtime, and by raising an exception the user is aware of this potential problem.
  • You expect the framework to be able to deal with it. If there is an expression like valueOfD.value > 0, then the framework should basically assume that this is what the user means. So if this expression is only valid for instances of B, then the framework is expected to assume that this will be an instance of B, and not an instance of C. We only expect the framework to generate an exception if - at runtime - the instance of D referenced be valueOfD is not an instance of B.


I tend to lean towards the second option, but I wonder if I understand the consequences of all of that yet.

Now, I think the second option would be doable, and could be done fairly easily using the existing abstractions in Limbo, the language used in Preon. Whenever Preon encounters situations like the above, the Reference constructed from valueOfD.value is a socalled MultiReference. It basically is a Reference that captures the different options. We don't know exactly which of the options will hold at runtime, but we do know for sure it's either one of them.

One of the things that was built in recently is the option to narrow references to references that resolve to a certain type. The operation on Reference takes a type, and returns a new Reference that is guaranteed to resolve to an instance of that type. And if it is impossible to return something like that, it will return null.

This is something that seems to fit the above case fairly well. If a reference is used in an expression that assumes the reference to resolve to an integer type, we could narrow that reference to a reference of type integer, and be done with it.

The narrow operation will - in most cases - return the same reference or null. Only in case of the MultiReference it will have a serious impact. In case a MultiReference is pointing either to an int or a String, then narrowing it to Integer will generate a new MultiReference with the String reference dropped off.

So, given that almost all I need is there, what's the doubt? Hard to tell. Maybe gutt feeling. Or maybe it has to do with the fact that it is actually considerably different than what you have in other existing language. In a strongly typed language, your assumption on the receiving type would normally require you to add a cast. But adding a cast into an expression language that is expected to be easily readable doesn't seem quite right. Most languages don't allow you to leave this kind of uncertainty in.

... unless you consider dynamically typed language. But in dynamically typed languages, everything is evaluated at runtime. And you don't even bother keeping track of the different types in which a reference could be resolved.

Nevertheless, it would be sort of adding duck typing capabilities in a largely statically typed language. Duck typing to take away the ambiguity, rather than duck typing to avoid having to declare types.

I think I'm still in favor of the second approach. If only you have the slightest idea what this entry was about, and you feel differently, feel free to comment.

(O yeah, and I forgot to mention that I ran into this issue while trying to apply Preon on a parser for Java byte code. It's amazing what you run into when you try to disect bytecode. I can quite easily imagine that BlackBerry and Android are capable of turning a class in a more efficient representation...)

Sunday, January 4, 2009

Byebye Sun Blade

I still have a lot of old Sun systems at home.

  • An ULTRA 10
  • An UTRA 5
  • A Sun Blade 100 (see down below)
  • ... and some other stuff

Lazy as I am, I had the Sun Blade configured as my media server, running MediaTomb. I know, I know, it sounds awkward, and that's exactly what it is. Not only does it consume way to much power to be running all day, but even the simplest thing is getting hard when you are running Ubuntu on SPARC on what is not Sun's best system ever.

So, I bought the NSLU2 the other day, and figured that - if I would replace its firmware - it would be capable of doing everything I wanted my home server to do. That all worked out quite nice, but while I was at it, I also decided to upgrade the Blade 100 to Unbuntu Feisty. Now, that didn't work out all that well. I couldn't reboot it, no matter what I tried.

Unfortunately, the MP3 collection still resided on the built-in hard disk. Auch. I was no longer able to access that, and I didn't really feel like going through the pain of ripping our CD collection again.

So after trying at least four different Live CD distributions, I finally succeeded reconnecting the old home directory by booting with the System Rescue CD. I am currently rsyncing the data, and everything seems to be fine.

So what did I learn of this excercise?

  • I solemnly declare never to upgrade a system without making a backup first.
  • I solemnly declare to have backups of the MP3 collection all over the place.
  • I solemnly declare not to ever touch OpenSolaris based distro's ever again.

Regarding the last point. It just seems that - even though the OpenSolaris based distros for SPARC are booting ok on Blade 100 - they don't come with any tools at all to recover ext3 partitions. In fact, having used Linux mostly, trying to use OpenSolaris tools seems like black magic anyway. You are just much better of using Linux, and the System Rescue CD referenced before is a nice option. The SPARC distribution works fine on a Blade 100.

I'm tempted to add another new year's solution: never ever to run Linux on old SPARC hardware again. I'll think about that. The consequence would be that I basically don't have a real server back at home any longer. On the plus side: it would clear out a lot of space on the attic. I'm sure my wife would love it. (The old servers are in a small cabinet. The new NSLU2 based setup fits in a small shoebox.)

Technorati Tags: , , ,