July 2007


Job and Social22 Jul 2007 03:44 am

Last Friday, when I was about to go home, I was given a brand new laptop empowered with 2G RAM and a high speed HDD.
So, now my workplace looks like a Shuttle Launch Center:
My Sonopia workplace

Code snippets and Java16 Jul 2007 08:06 am

Introduction

Nowadays, every modern web development environment offers a way to manipulate URL on the fly using a rule-based configuration rather than hard coded program logic. Probably every approach has its origins in famous Apache mod_rewrite module. In the Java world, de facto standard is a wonderful Url Rewrite Filter. It can do everything what you expect from such tool and has some delicious topping as a benefit:

  • analyze URL against a pattern (regexp or wildcard)
  • analyze all possible HTTP data like cookies, request parameters, host, remote info, etc
  • change data like cookie, session, request attributes
  • redirect or forward to static or dynamically(based on analysis data) formed URL
  • run your own rolled Java code (e.g. logging, statistics)

During the last few days I got more familiar with this powerful tool and want to show the value it can bring into any Java based Web application. I won’t describe the syntax of the configuration file because there is a comprehensive manual which outlines all options. Also I’m not going to describe simplest use cases, let’s start from something interesting like the first step in integration with affiliate partner.
For instance, in case of integration with Commission Junction affiliate service provider, your application have to set a cookie which identifies a user that come from an affiliate partner, and then redirect the user to the page stated as a request parameter.
So, there are some steps I want to implement with UrlRewrite library:

1. User came to your site by clicking on a banner with link http://example.com/?CJURL=http%3a%2f%2fexample.com%2fregister%2fnew.html (parameter is encoded string http://example.com/register/new.html) Tip: to url encode test data you can use a simple online encoding tool.
2. Your application recognizes a CJURL request parameter and set a cookie (expire time >= 24h) to know that the user came from CJ affiliate program
3. Redirect the user to the landing page equal to CJURL parameter

Setting cookies

This snippet sets cookie if a user comes from our affiliate partner. Despite of the fact that in UrlRewrite manual stated that expire time have to be set in minutes, it actually is in seconds. Probably it is just a typo in the manual, but be careful and alway test real expire date with your browser. It is possible to set all parameters (value can be in the format “[value][:domain[:lifetime[:path]]]”), although we use only two parameters.

<rule>
    <condition type="query-string">^CJURL=(.*)$</condition>
        <from>^(.*)$</from>
        <!– Affiliate service provider –>
        <!– expire time in seconds–>
        <set type="cookie" name="asp">cj::86400</set>
</rule>
 

Redirecting to a request parameter value

It seems to be a simple task to get a value from request query and redirect to url created from that parameter. But you can’t do it explicitly in UrlRewrite. Setting request parameters in is not allowed. There is a technique to parse a query and use the regexp back reference as a value, but you’ll have an encoded value as a result. We need a real request parameter, because in this case the value will be decoded.
To make it clear I’ll give some illustration:
1. The ideal solution if UrlRewrite supported it would be:

<rule>
    <condition type="query-string">^CJURL=(.*)$</condition>
        <from>^(.*$)</from>
        <to type="redirect">%{parameter:CJURL}</to>
 

But as I stated earlier, unfortunately we can’t use request parameter value in <to> clause.

2. If we had a simple parameter like [a-zA-z0-9] without special symbols used in regular URL we can parse it from query string. This approach can be used in beautifying urls according to REST style:

<rule>
<rule match-type="wildcard">
        <from>/*/*/*</from>
        <to type="forward">/$1.do?$2=$3</to>
</rule>
 

But we need to decode this strings, because we can’t redirect to http%3a%2f%2fexample.com before we convert it to http://example.com. This conversion is done by container when you ask for a request parameter value. Therefore this solution WON’T work either:

<rule>
    <condition type="query-string">^CJURL=(.*)$</condition>
        <from>^(.*)?CJURL=(.*)$</from>
        <to type="redirect">$2</to>
</rule>
 

3. Luckily we can use in <to> clause a request attribute. The only problem we have to solve is to write the request parameter value to request attribute somehow, and then read this attribute in <to> clause. I didn’t investigate heavily is it possible using UrlRewrite declarative facilities and employed another great option: calling self rolled Java code. The final version is something like:
urlrewrite.xml:

<!– Affiliates tracking –>
<rule>
    <note>Commission Junction affiliate program</note>
    <condition type="query-string">^CJURL=(.*)$</condition>
        <from>^(.*)?CJURL=(.*)$</from>
        <run class="com.example.web.util.RequestToAttributeSetter">
            <init-param>
                <param-name>parameterName</param-name>
                <param-value>CJURL</param-value>
            </init-param>
    </run>
</rule>
<rule>
    <condition type="query-string">^CJURL=(.*)$</condition>
        <from>^(.*)?CJURL=(.*)$</from>
        <to type="redirect">%{attribute:CJURL}</to>
        <!– Affiliate service provider –>
        <!– expire time in minutes –>
        <set type="cookie" name="asp">cj::86400</set>
</rule>
 

Java code:

package com.example.web.util;

import javax.servlet.ServletConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * Workaround of UrlRewrite filter restriction which doesn’t allow setting request parameter as
 * an redirect target in <to> tag. <br/>
 * Similar solution: http://sujitpal.blogspot.com/2006/09/search-and-replace-with.html
 * @author Andrey Gomilko
 */

public class RequestToAttributeSetter {

    private String parameterName;

    public void run(ServletRequest request, ServletResponse response) {
        if (parameterName != null) {
            HttpServletRequest req = (HttpServletRequest) request;
            Object value = req.getParameter(parameterName);
            req.setAttribute(parameterName, value);
        }
    }

    public void init(ServletConfig config) {
        this.parameterName = config.getInitParameter("parameterName");
    }

    public void destroy() {
    }

}

 

Unit testing of UrlRewrite configuration

Let’s assume you have already written your own urlrewrite.xml file with filter configuration and want to test it. If you decide testing rules on the working server (e.g. Tomcat), you’ll have to restart it every time you have changed something. More convenient way is to use JUnit tests for this purpose. Fortunately URLRewrite has all necessary internal classes and request/response mock classes to dry run this filter without container and analyze the result. The very good example which covers basic use cases is A JUnit test for UrlRewriteFilter. To test rules corresponding to CJ example we need to test cookies in addition to standard tests. Since our UrlRewrite rule is based on the host HTTP header value, you have to set header values to the MockRequest because it doesn’t parse propagated url itself. To test CJ example, I got as a base the test snippet from A JUnit test for UrlRewriteFilter and added some specific methods:

    private void assertRedirect(String fromUrl, String toUrl, Cookie cookie) throws Exception {
        UrlRewriter rewriter = new UrlRewriter(conf);
        MockRequest request = new MockRequest(fromUrl);
        try{
            URL url = new URL(fromUrl);
            request.addHeader("host", url.getHost());
           
            if (url.getQuery() != null) {
                request.setQueryString(url.getQuery());

                StringTokenizer st = new StringTokenizer(url.getQuery(), "&");
                while(st.hasMoreElements()) {
                    String token = st.nextToken();
                    String[] parts = token.split("=");
                    String name = parts[0];
                    String value = parts[1];
                   
                    request.addParameter(name, java.net.URLDecoder.decode(value, "UTF-8"));
                }
            }
           
        } catch(MalformedURLException me){
             // do nothing
        }
       
        MockResponse response = new MockResponse();
        RewrittenUrl rewrittenUrl = rewriter.processRequest(request, response);
        assertNotNull("Could not redirect URL from:" + fromUrl + " to:" + toUrl, rewrittenUrl);

        assertEquals("Redirect from:" + fromUrl + " to:" + toUrl + " did not succeed", toUrl
                , rewrittenUrl.getTarget());
       
        assertTrue(rewrittenUrl.isRedirect());
       

        List cookies = response.getCookies();
        assertEquals(1, cookies.size());
        Cookie setCookie = (Cookie)cookies.get(0);
       
        assertEquals(cookie.getMaxAge(), setCookie.getMaxAge());
        assertEquals(cookie.getName(), setCookie.getName());
        assertEquals(cookie.getValue(), setCookie.getValue());
    }

    public void testCJRewriteDecoded() throws Exception {
        String fromUrl = "http://example.com/?CJURL=http%3a%2f%2fexample.com%2fregister%2fnew.html";
        String toUrl = "http://example.com/reqister/new.html";
       
        Cookie cookie = new Cookie("asp", "cj");
        cookie.setMaxAge(86400); // 24h
        assertRedirect(fromUrl, toUrl, cookie);
    }
 

Conclusion

The main idea of such tools is to reduce coding and transfer all possible application logic to the well-proven tools which can be easily tuned through configuration files. This approach eliminates number of possible bugs and keep tied logic in one place. So, before writing your own filter, think once more about UrlRewrite, probably it’ll fit your needs!

And stay tuned!

Perl and Programming and Java10 Jul 2007 02:22 pm

Europa release

With a short delay after Europa release announcement, I’ve moved to it. Thanks to the fact that Eclipse doesn’t require an installation process and can be just unzipped and run, the last few times I got the tuned Eclipse from my co-workers. Those distributions were well-tuned for J2EE development, with all necessary plugins, project checkstyles, attached sources and so on. Seeing as this time nobody around me offered me such a favor, I did everything on my own.
Actually, to develop a J2EE project, you need to install a dozen of plugins (depends on which frameworks are employed) in addition to the bare distribution, so it’s better to have a cheat sheet every time you start this Eclipse tuning campaign. Since I didn’t have such a plan, I used my current Eclipse 3.1 working set as an example.
This time, I wrote some short notes during the installation process, and I’d like to share it here, to have something in the future to stick with.

Download

Firstly, you need to download an appropriate Eclipse distribution. However there is already a bundle for J2EE developer, I was interested in installing everything I want from the scratch. Therefore I went to http://www.eclipse.org/downloads/ and downloaded Eclipse Classic distribution for Windows (140 MB). It was extracted to C:\Java\eclipse3.3 directory where I store all Java stuff like IDEs, JDKs, etc. Then, as usually I wanted to create a custom shortcut with extended memory allocation for Eclipse, but suddenly noticed eclipse.ini file. To allow Eclipse allocation of more memory, just edit the eclipse.ini file (increase Xms and Xmx values):

-showsplash
org.eclipse.platform
–launcher.XXMaxPermSize
256m
-vmargs
-Xms256m
-Xmx512m
 

Web tools

Some general notes. All plugins can be installed in two common ways: through cute Help->Software Updates->Find and Install… and copying all unzipped stuff to ECLIPSE_HOME/plugins directory. Of course I prefer the first option, and every plugin I’ll be installing through this wizard, except of Sysdeo.
By “default plugins” I mean plugins which can be installed through “Europa Discovery Site” (run the mentioned wizard and find it to be accustomed, if not yet).

From the past experience I knew that I was using a WTP (stands for Web Tools Platform) plugin for web development. The problem was that there were no mentioned WTP plugin on the “Europa Discovery Site”. I carried brief investigation and dig out that the main part of that plugin is a WST subproject (the web standard tools subproject).
Steps to reproduce after Help->Software Updates->Find and Install…:
WST plugin
When I checked WST check box, the wizard apparently gave a tip to select all dependent (required by WST) things too. After I installed a WST, the link to WTP update site suddenly appeared (I guess that it was due to WST), and I decided to install it to have a full stack.
WTP plugin

Subversion integration

When I installed all useful tools from the Europa repository, I moved to things which update sites have to be added manually. The process is almost the same as when we were updating standard components, the only difference is the update site where the plugin is stored. We need to add http://subclipse.tigris.org/update_1.2.x as a New Remote Site…
Update manager

Tomcat launcher

The simplest and the most valuable plugin for Eclipse invoking I ever used is a Sysdeo Tomcat launcher. Download the archive and install according to Installation section steps. Here, the unzipped archive should be placed manually to the ECLIPSE_HOME/plugins directory.
Sysdeo butons

Useful tools

As you know how to install plugins, I’ll mention only links to update site:

  1. http://eclipse-cs.sourceforge.net/update - checkstyle plugin, helps to maintain your coding style due to different available code conventions (Sun, Eclipse, your own)
  2. http://springide.org/updatesite/SpringIDE - Spring related things like bean definitions, xml configuration auto completion
  3. http://e-p-i-c.sf.net/updates - Perl IDE, just for fun to play with RegExps or to write some admin tools
  4. http://www.fabioz.com/pydev/updates - PyDev (Python IDE) not to be restricted only by Java world and be more broadminded
  5. http://eclipse-tools.sourceforge.net/implementors/ - nice Alt+F3 short key usage, allows quick jumps to implementation from interfaces.

Stay tuned!
P.S. I know that saying this phrase is almost as popular as mentioning iPhone in the blog post :)

Shopping and Social02 Jul 2007 12:16 am

This weekend I found out probably the best gift for a little child. I’ve got a 4 years old nephew, and I had to choose a toy to make him a present and congratulate on his birthday. Me and my dear wife spent about 2 hours choosing a right toy and eventually we bought an Infinitoy ZOOB building kit. We couldn’t wait to present it and play ourselves.
Infinitoy
The kit contains lots of pieces of four different kind. Each piece is made from very durable bright colored plastic and has a life-term guarantee, so every broken piece can be replaced for nothing. The pieces work like a joints and can be connected with each other to form different shapes, creatures and vehicles. I think that it is very helpful in child creativity skills development. Beginning from the simplest shapes like snake, a child learn variety of bright constructs from the manual.
To sum up, I’d recommend to buy it if you’re looking for a good gift which might bring fun to both child and parents. In Kiev you can buy 250 pieces set for about 60$. Also there are some cheaper sets with less number of pieces.
Bike plastic scorpion