Wednesday, December 24, 2008

Flexible Management Scripts in Groovy & JMX

It is commonplace to assert that application monitoring and management are important issues. It is less obvious though to implement such functionalities effectively. Management tasks usually require a good dose of flexibility since they deal frequently with urgent and unpredicted situations. Whereas popular implementation choices include GUIs such as web applications; or JMX with JConsole (or any other compatible client for the matter), the need for flexibility implies an implementation strategy that allows a reasonable degree of adaptation to unexpected situations and reusability. Moreover, the strategy we choose should minimize changes to the management interfaces as new requirements show up, in order to minimize the associated development and operational costs.

Monday, November 3, 2008

Spring Batch "Hello World" 3

In part 1 and part 2 of this tutorial we saw the basic concepts of Spring Batch and implemented a simple tasklet based job . The focus of this last part is on item-oriented batch processing. This approach consists of reading bulk data, performing some calculation and outputting the result, one item at a time. As an example think of processing a large flat file composed of records and writing the output to a database. Each line in the file corresponds to an item: it will be read, transformed and output separately.

Sunday, October 5, 2008

Spring Batch "Hello World" 2

Last time we implemented a simple PrintTasklet that prints a "Hello World!" message. In this part we will improve our tasklet a little bit by passing the message to print as a parameter through the command line. Thus, we will start using JobParameters.

Friday, May 23, 2008

Spring Batch "Hello World" 1

This is an introductory tutorial to Spring Batch. It does not aim to provide a complete guide to the framework but rather to facilitate the first contact. Spring Batch is quite rich in functionalities, and this is basically how I started learning it. Keep in mind that we will only be scratching the surface.

Monday, March 17, 2008

Running JAX-RPC Handlers in Spring-WS

Spring-WS's interceptors and JAX-RPC's handlers provide a similar interception mechanism around web services endpoints. They are particularly useful to process SOAP headers, perform logging, security checks and so on.
Recuperating a preexisting JAX-RPC handler and running it as is in a Spring-WS application could be useful in migration scenarios, or to benefit from a JAX-RPC library for instance.
I was working on WSS4J integration in Spring-WS when I first thought about that. While experimenting with different approaches, I found out that WSS4J provided a JAX-RPC handler. Laziness being a virtue in the world of programming, I thought I would get away with it by only writing a couple of lines of code that reuse the JAX-RPC handler. I thought I would sound smart too. For different reasons I ended up choosing another approach and writing more lines of code.

This blog entry is my second attempt to use the code I wrote and to sound smart.

How it works

The adapter pattern works well as Spring-WS interceptors and JAX-RPC handlers are quite similar. Just notice that Spring-WS splits interception in 2 interfaces EndpointInterceptor and ClientInterceptor whereas JAX-RPC employs the Handler interface on both sides. The two frameworks use similar message contexts to share objects among the various components. Thus we need 2 classes, JaxRpcHandlerAdapterInterceptor, that adapts a JAX-RPC handler to Spring-WS and
MessageContextAdapter that wraps Spring-WS's MessageContext in JAX-RPC's SOAPMessageContext.

Concretely speaking, the JaxRpcHandlerAdapterInterceptor encloses the target Handler and its HandlerInfo.
It implements EndpointInterceptor, ClientInterceptor plus InitializingBean and DisposableBean for lifecycle callbacks. The JaxRpcHandlerAdapterInterceptor delegates method calls to the handler and passes a wrapped MessageContext. As for the messageContextProperties property, it is just a convenience that I added to allow presetting the MessageContext with some values (see the example). Here's the code:

public class JaxRpcHandlerAdapterInterceptor implements
      SoapEndpointInterceptor, ClientInterceptor, 
      InitializingBean, DisposableBean {

    private Handler handler;
    private HandlerInfo handlerInfo;
    private Map messageContextProperties;
    private String[] roles;

    /* ---------- Server methods ---------- */
    public boolean handleFault(MessageContext mc, Object endpoint)
            throws Exception {
        return handler.handleFault(new MessageContextAdapter(mc,
                messageContextProperties, roles,false));
    }

    public boolean handleRequest(MessageContext mc, Object endpoint)
            throws Exception {
        return handler.handleRequest(new MessageContextAdapter(mc,
                messageContextProperties, roles,true));
    }

    public boolean handleResponse(MessageContext mc, Object endpoint)
            throws Exception {
        return handler.handleResponse(new MessageContextAdapter(mc,
                messageContextProperties, roles,false));
    }

    public boolean understands(SoapHeaderElement header) {
        QName[] names = handler.getHeaders();
        for (int i = 0; i < names.length; i++) {
            QName name = header.getName();
            if (name.equals(names[i])) {
                return true;
            }
        }
        return false;
    }

    /* ---------- Client methods ---------- */
    public boolean handleFault(MessageContext mc)
            throws WebServiceClientException {
        return handler.handleFault(new MessageContextAdapter(mc,
                messageContextProperties, roles,false));
    }

    public boolean handleRequest(MessageContext mc)
            throws WebServiceClientException {
        return handler.handleRequest(new MessageContextAdapter(mc,
                messageContextProperties, roles,true));
    }

    public boolean handleResponse(MessageContext mc)
            throws WebServiceClientException {
        return handler.handleResponse(new MessageContextAdapter(mc,
                messageContextProperties, roles,false));
    }

    /* ---------- Lifecycle methods ---------- */
    public void afterPropertiesSet() throws Exception {
        handler.init(handlerInfo);
    }

    public void destroy() throws Exception {
        handler.destroy();
    }

    /* ---------- Getters & setters ---------- */
    ...
}

The MessageContextAdapter simply wraps a MessageContext:

public class MessageContextAdapter implements SOAPMessageContext {

    private MessageContext context;
    private String[] roles;
    private final boolean isRequest;

    public MessageContextAdapter(MessageContext mc, Map properties, 
                 String[] roles, boolean isRequest) {
        this.context = mc;

        if (properties != null) {
            for (Iterator i = properties.entrySet().iterator(); i.hasNext();) {
                Entry entry = (Entry) i.next();
                context.setProperty((String) entry.getKey(), entry.getValue());
            }
        }

        this.roles = roles;
        this.isRequest = isRequest;
    }

    public boolean containsProperty(String name) {
        return context.containsProperty(name);
    }

    public Object getProperty(String name) {
        return context.getProperty(name);
    }

    public Iterator getPropertyNames() {
        return Arrays.asList(context.getPropertyNames()).iterator();
    }

    public void removeProperty(String name) {
        context.removeProperty(name);
    }

    public void setProperty(String name, Object value) {
        context.setProperty(name, value);
    }

    public SOAPMessage getMessage() {
        WebServiceMessage message = isRequest ? context
                .getRequest() : context.getResponse();

        return ((SaajSoapMessage) message).getSaajMessage();
    }

    public String[] getRoles() {
        return roles;
    }

    public void setMessage(SOAPMessage message) {
        ((SaajSoapMessage) context.getRequest()).setSaajMessage(message);
    }
}

An Example with WSS4J

The next example is only a proof on concept; its goal is to show the interceptor in action with a non-trivial JAX-RPC handler on the server and client sides. Be aware that the preferred way to secure Spring-WS applications with WSS4J is Wss4jSecurityInterceptor.

For the sake of simplicity, the example is based on the outstanding echo sample from Spring-WS. Let's imagine the following scenario: We want to secure the exchange between the client and echo service. We will set the service to authenticate incoming requests with a username token. Furthermore, it will encrypt the response. Thus the client needs to add a username token with its credentials to the request and to decrypt the response.

First, let's secure the echo service. Add the following bean definition and don't forget to add it to the interception chain:

<bean id="wss4jHandlerAdaptorInterceptor" class="jaxrpc.JaxRpcHandlerAdapterInterceptor">
    <property name="handler">
        <bean class="org.apache.ws.security.handler.WSS4JHandler"/>
    </property>
    <property name="messageContextProperties">
        <util:map>
            <entry key="passwordCallbackRef">
                <bean class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
                    <property name="users">
                        <props>
                            <prop key="bob">hotdog</prop>
                        </props>
                    </property>
                </bean>
            </entry>
        </util:map>
    </property>
    <property name="handlerInfo">
        <bean class="javax.xml.rpc.handler.HandlerInfo">
            <property name="handlerConfig">
                <util:map>
                    <entry key="deployment" value="server"/>
                    <entry key="receive.action" value="UsernameToken"/>
                    <entry key="send.action" value="Encrypt"/>
                    <entry key="actor" value="abc"/>
                    <entry key="encryptionPropFile" value="encryptCrypto.properties"/>
                    <entry key="encryptionUser" value="rsakey"/>
                </util:map>
            </property>
        </bean>
    </property>
</bean>

Now, let's add the interceptor to the Spring-WS client. Starting from 1.5, Spring-WS provides a ClientInterceptor interface, which the JaxRpcHandlerAdapterInterceptor implements:

<bean id="echoClient" class="org.springframework.ws.samples.echo.client.sws.EchoClient">
    <property name="defaultUri" value="http://localhost:8080/echo/services"/>
    <property name="request" value="classpath:org/springframework/ws/samples/echo/client/sws/echoRequest.xml"/>
    <property name="interceptors">
        <list>
            <ref local="wss4jHandlerAdaptorInterceptor"/>
        </list>
    </property>
</bean>
    
<bean id="wss4jHandlerAdaptorInterceptor" class="jaxrpc.JaxRpcHandlerAdapterInterceptor">
    <property name="handler">
        <bean class="org.apache.ws.security.handler.WSS4JHandler"/>
    </property>
    <property name="messageContextProperties">
        <util:map>
            <entry key="passwordCallbackRef">
                <bean class="org.springframework.ws.samples.echo.client.sws.SimpleCallbackHandler">
                      <property name="users">
                        <props>
                            <prop key="bob">hotdog</prop>
                            <prop key="rsakey">123456</prop>
                        </props>
                    </property>
                </bean>
            </entry>
        </util:map>
    </property>
    <property name="handlerInfo">
        <bean class="javax.xml.rpc.handler.HandlerInfo">
            <property name="handlerConfig">
                <util:map>
                    <entry key="deployment" value="client"/>
                    <entry key="send.action" value="UsernameToken"/>
                    <entry key="receive.action" value="Encrypt"/>
                    <entry key="actor" value="abc"/>
                    <entry key="user" value="bob"/>
                    <entry key="decryptionPropFile" value="encryptCrypto.properties"/>
                </util:map>
            </property>
        </bean>
    </property>
</bean>

When everything is set up properly, run the client and you will be gratified with an echo response containing Hello.

As you can see, the configuration xml is not very succinct. It has the merit of being functional though. To improve that, JaxRpcHandlerAdapterInterceptor could be extended and handler-specific properties could be added to the subclass.

You can dowload the code here.