implements Elegance {

// Elwyn Malethan's musings on software development, mountain biking and general navel–gazing...

Articles published in category Java

Unit testing with Commons HttpClient

I‘ve been adding some test coverage to some existing code today. This code under test uses Commons HTTP Client to fetch data from an external resource. I ran into problems with mocking/stubbing the response to the HTTP requests.

I am not the only one who has faced problems with this Http Client. In that article, Florin provides a good solution using a concrete subclass of HttpClient in order to mock it‘s behaviour. His article was very useful in helping me formulate my approach.

I use JMock for dynamic mock objects and so I was keen not to have to mix of JMock-based mocks and concrete mock objects. So my approach is to use JMock‘s custom actions to provide an implementation that populates the right values in the right way. Although, I had to use some reflective cheating to set the necessary values.

private static Action willRespondWith(final int code, final String status, final String body) {
    return new CustomAction("will respond with status: " + code +  ", and contents: " + body) {
        @Override
        public Object invoke(Invocation invocation) throws Throwable {
            final Object method = invocation.getParameter(0);

            final Field statusLine = HttpMethodBase.class.getDeclaredField("statusLine");
            statusLine.setAccessible(true);
            statusLine.set(method, new StatusLine("HTTP/1.0 " + code + " " + status)); //Although, 'OK' could be anything 

            final Method setResponseStream = HttpMethodBase.class.getDeclaredMethod("setResponseStream", InputStream.class);
            setResponseStream.setAccessible(true);
            setResponseStream.invoke(method, new ByteArrayInputStream(body.getBytes("UTF-8")));

            return code;
        }
    };
}

This is intended to be used as follows:

@Test
public void testSomeHttpStuff() throws Exception {

    jmock.checking(new Expectations() {{
        allowing(client).executeMethod(with(any(HttpMethod.class)));
        will(willRespondWith(200, "OK", "{some: 'value'}"));
    }});
        
    sendHttpRequest("http://some.server/some/resource.json");
        
}

Now I can simulate all sorts of responses from the external resource.

First published on Apr 26, 2010. Last updated on: Apr 26, 2010.

How to catch GWT HorizontalSplitPanel double click event

I was using GWT's HorizontalSplitPanel. The thing is that it was a quite good solution but not everything I wanted. GWT standard widget–set is known for being on the Spartan side. I have no complaint about this, it is just a fact. The added behaviour I was after is the ability to double-click the splitter in order to toggle a fully collapsed or restored state. I'm not the only one, it seems.

This was not as straight–forward to achieve as I thought it would be. This is an account of the dead-end strategies I followed in trying to achieve this and the solution I settled on.

Inheritance strategy

My first (possibly lazy) approach was to use an inheritance strategy to extend HorizontalSplitPanel. Anyone whose familiar with the GWT standard widget set will know that this approach is a non–starter, since HorizontalSplitPanel is final so it can't be extended and — one step further up the class hierarchy — SplitPanel has package-local access so that can‘t be extended either (not in a class outside the same package in any event).

So of course, I put my best–practice hat back on to try and solve the problem properly.

Composition

So I used a SimplePanel as the base class for my widget as follows.

public class ElegantHorizSplitPanel extends SimplePanel {
    private String presetPosition;
    private HorizontalSplitPanel splitPanel;

    public ElegantHorizSplitPanel() {
        splitPanel = new HorizontalSplitPanel();
        this.add(splitPanel);
        setSplitPosition("30%");
    }

    public void setLeftWidget(Widget widget) {
        splitPanel.setLeftWidget(widget);
    }

    public void setRightWidget(Widget widget) {
        splitPanel.setRightWidget(widget);
    }

    public void setSplitPosition(String position) {
        presetPosition = position;
        splitPanel.setSplitPosition(position);
    }
}

This implementation does not support all the functionality provided by HorizontalSplitPanel — in fact it does nothing more than delegate what little functionality it does support directly to HorizontalSplitPanel. However, it provides enough detail to demonstrate the technique. The methods providing all the other functionality could be added fairly easily.

So now on to adding double-lick behaviour. To do this I needed to get a reference to the the splitter DOM element. Unfortunately — but probably for good reasons — the getter for this element is protected in HorizontalSplitPanel . So, this means we have to cheat a little. GWT exposes some of the DOM traversal JavaScript methods in the Widget API, so provided I could get hold of an element in splitter‘s ancestry somewhere there was hope.

I used Firebug to find out what HTML was generated by my new widget and found the following.

Illustration of the splitter DOM-element using Firebug

So in order to get a reference to the splitter element I need the element returned by:

this.getElement().getFirstChildElement().getFirstChildElement().getFirstChildElement().getNextSiblingElement()

But that – as we all know – is a what @unclebobmartin (and others) describes as a train wreck, so I added the following methods to ElegantHorizSplitPanel

public class ElegantHorizSplitPanel extends SimplePanel {

    // ...

    private Element getSplitterElement() {
        return getLeftElement().getNextSiblingElement();
    }

    private Element getLeftElement() {
        return getSplitPanelInnerElement().getFirstChildElement();
    }

    private Element getSplitPanelInnerElement() {
        return getSplitPanelOuterElement().getFirstChildElement();
    }

    private Element getSplitPanelOuterElement() {
        return getElement().getFirstChildElement();
    }

    // ...

}

Caveat: I checked IE HTML as well and it uses more or less the same HTML, though I suppose it's possible that compiling for different user agents could result in different HTML. I could probably add some test coverage for this using Matt Raible's guide to testing GWT libraries with Selenium, something to look into in future.

Adding double-click behaviour

I‘m more familiar with JavaScript and the DOM than I am GWT so my first approach to adding the behaviour was add native JavaScript code to attach the behaviour to the splitter element.

public class ElegantHorizSplitPanel extends SimplePanel {

    // ...

    private void toggleLeftPanel() {
        int leftWidth = getLeftElement().getClientWidth();
        if(leftWidth == 0) {
            splitPanel.setSplitPosition(presetPosition);
        } else {
            splitPanel.setSplitPosition("0px");
        }
    }

    private native void addBehaviour(Element splitter)/*-{
        var panel = this;
        splitter.ondblclick = function() {
            panel.@com.malethan.gwt.ui.widgets.client.ElegantHorizSplitPanel::toggleLeftPanel()()
        };
    }-*/;

    // ...

}

This actually works just fine in IE but is patchy in Firefox for some reason. But more importantly it introduces a reference cycle and is an almost guaranteed way to introduce a memory leak in most browsers.

Reference cycles & memory leaks.

Well, Google had already thought of that. They provide a standard, non–native way to add event handlers to DOM elements. So the actual code we use to add the double–click behaviour to the splitter element is the following:

public class ElegantHorizSplitPanel extends SimplePanel {

    // ...

    private  void addBehaviour(Element splitter) {
        Event.setEventListener(splitter, new EventListener() {
            public void onBrowserEvent(Event event) {
                if(event.getTypeInt() == Event.ONDBLCLICK) {
                    toggleLeftPanel();
                }
            }
        });
        Event.sinkEvents(splitter, Event.ONDBLCLICK);
    }

    // ...

}

N.B. When I started this post I had only tested the above technique in IE. It works great. Unfortunately it became quickly apparent that when I tried this in Firefox (running on Ubuntu Jaunty) it worked sporadically if at all. If anyone knows of a way to get this working in Firefox, please let me know and I'll post a correction.

First published on Nov 30, 2009. Last updated on: Dec 29, 2009.

Pingback Java API

A couple of weeks ago I set about implementing Pingback 1.0 for this website. The first logical step was trying to see if there was an existing open–source project for Java implementations of Pingback or whether there were any easily reusable examples to borrow on the intarwebz.

My searches came up dry, so I rolled my own. And, so I have something to write about too! Here‘s how I did it.

The first thing I looked at was identifying links to other pages within the articles of my site. There are loads of regular expressions claiming some degree of effectiveness at identifying URLs, I chose a regex based on this one.

/**
 * This regex checks for both Textile ("blah":url) and HTML (<a href="url">blah</a>) links.
 */
public static final String URL_REGEX = "((\":)|href=\")((http(s?)\\:\\/\\/|~/|/)?((\\w+:\\w+@)?(([-\\w]+\\.)+(com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))|localhost)(:[\\d]{1,5})?(((/([-\\w~!$+|.,=]|%[a-f\\d]{2})+)+|/)+|\\?|#)?((\\?([-\\w~!$+|.,*:]|%[a-f\\d{2}])+=([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)(&([-\\w~!$+|.,*:]|%[a-f\\d{2}])+=([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)*)*(#([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)?)"

Regular expressions are incomprehensible when they get that big! And, this is probably overkill and too specific (e.g. it will ignore any new top–level–domains that are invented).

Anyway, my regex matches any URLs that are either the value for a href attribute in HTML (e.g. href="some_url"...) or part of Textile markup ("Some label":some_url). I check for both because Textile allows for HTML to be embedded so just parsing links in Textile won‘t do. Also this allows me to use the same regex to check remote pages for links to my own site for Pingback server compliance as I use to check my own Textile articles for outgoing links.

The codebase for the API has turned out to be quite tiny. I wouldn‘t say that it is innovative but it certainly re-usable and should simplify the task for anyone who is trying to do the same as I have done. The source is available here. It's in the form of a maven project, so if you want to build it, just type mvn install .

Pingback Client

It is for implementing Pingback clients that this API provides most value. This is the case because I found it very difficult to decouple the Pingback server functionality from the specific implementation of my website. That‘s the subject for another post, however.

Here‘s how the code in my website uses the API.

package com.malethan.blog.app;

import com.malethan.blog.RequestUtil;
import com.malethan.blog.models.BlogPost;
import com.malethan.pingback.Link;
import com.malethan.pingback.PingbackClient;
import com.malethan.pingback.LinkLoader;
import com.malethan.pingback.PingbackException;
import com.malethan.seemorej.AfterFilter;
import static com.malethan.seemorej.SeemoreJ.*;
import static com.malethan.seemorej.Flash.*;
import com.malethan.seemorej.hibernate.crud.CrudControllerHibernate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.beans.factory.xml.XmlBeanFactory;

import java.util.List;
import java.util.ArrayList;

/**
 * <p>The controller for managing articles/blog posts</p>
 */
public class BlogPostController extends CrudControllerHibernate<BlogPost, Long> {
    //----------------------------------------------------------------------- Static Properties and Constants

    private static final Log log = LogFactory.getLog(BlogPostController.class);

    //----------------------------------------------------------------------- Static Methods
    //----------------------------------------------------------------------- Instance Properties

    XmlBeanFactory beanFactory;
    PingbackClient pingbackClient;
    LinkLoader linkLoader;
    List<String> failedPings;

    //----------------------------------------------------------------------- Constructors

    public BlogPostController() {
        super(BlogPost.class, Long.class);
        beanFactory = new XmlBeanFactory(new ClassPathResource("/applicationContext.xml", getClass()));
    }

    //----------------------------------------------------------------------- Filters

    @AfterFilter(include = {"create", "update"})
    public void createOutgoingLinks() throws Exception {
        BlogPost blogPost = (BlogPost) request().getAttribute(modelNameLower);
        if (blogPost.isPublished()) {
            initialiseClientAndLinkLoader();
            failedPings = new ArrayList<String>();
            for (String linkAddress : linkLoader.findLinkAddresses(blogPost.getBody())) {
                if (!blogPost.hasOutgoingLinkToUrl(linkAddress)) {
                    loadRemotePageAndSendPingbacks(blogPost, linkAddress);
                }
            }

            dao.saveOrUpdate(blogPost);

            if (failedPings.size() > 0) {
                notifyUserOfBadPingbacks(failedPings);
            }
        }
    }

    //----------------------------------------------------------------------- Actions
    //----------------------------------------------------------------------- Getters and Setters
    //----------------------------------------------------------------------- Instance Methods

    private void initialiseClientAndLinkLoader() {
        pingbackClient = (PingbackClient) beanFactory.getBean("pingBackClient");
        linkLoader = (LinkLoader) beanFactory.getBean("pingbackLinkLoader");
    }

    private void loadRemotePageAndSendPingbacks(BlogPost blogPost, String linkAddress) {
        Link link = linkLoader.loadLink(linkAddress);
        if(link.isSuccess()) {
            if(link.isPingbackEnabled()) {
                sendPingback(blogPost, link);
            } else {
                blogPost.addOutGoingLink(link.getTitle(), link.getUrl());
            }
        }
    }

    private void sendPingback(BlogPost blogPost, Link link) {
        try {
            String permaLink = RequestUtil.getAppURL(request()) + "/article/" + blogPost.getSlug() + ".html";
            pingbackClient.sendPingback(permaLink, link);
            blogPost.addOutGoingLink(link.getTitle(), link.getUrl());
        } catch (PingbackException e) {
            log.error("Pingback to '" + link.getUrl() + "' failed", e);
            failedPings.add("Pingback to " + link.getUrl() + " failed because of " + e.getMessage() + " ");
            if (PingbackClient.PINGBACK_ALREADY_REGISTERED == e.getFaultCode()) {
                blogPost.addOutGoingLink(link.getTitle(), link.getUrl());
            }
        }
    }

    private void notifyUserOfBadPingbacks(List<String> failedPings) {
        String errMsg = "";
        for (String failedPing : failedPings) {
            errMsg += failedPing;
        }
        flash(NOTICE, errMsg);
    }
}

The annotation  @AfterFilter(include = {"create", "update"}) causes the method createOutgoingLinks() to be invoked after an action is invoked if the action is called create or update. Those two actions are part of the SeemoreJ CRUD framework (that's another post as well, if I ever get around to it). Hopefully, it's easy to make out what's going on. Essentially, if a post is published it, looks for all links with fully qualified URLs in the article and – if the remote resources support it – attempts to send them a pingback. Any failures are displayed using a Rails–style flash system.

I‘ve noticed that this chugs a little if there are a few links in a page and/or certain resources are slow loading. Still, it‘s not publicly visible so I‘ll deal with it for the moment.

Also, this example uses Spring to load the default implementations of LinkLoader and PingbackClient both interfaces defined in the library. It would work just as well with concrete instantiations. Though, it would be more difficult to test :)

It was certainly fun to write, I hope somebody finds it useful :)

First published on Mar 20, 2009. Last updated on: Dec 30, 2009.

JavaFX All your screens are belong to us

Since I keep hearing a lot about it, I recently had a look at the JavaFX site and after waiting an inordinately long time for something to happen (it seems to take longer to load than Flash). I saw the this popup…

 

Well, it wasn‘t exactly what it said but that‘s what I saw! Anyway, it was a loooong time to wait for something that looked a lot like Flash.

I‘m tempted to bitch about the whole new declarative language used to produce JavaFX apps. It looks Java–like, and it also looks JSON–like but is probably neither. But, I won‘t bitch about it just yet, I haven‘t looked into it enough to form an opinion — and certainly not enough to express an opinion.

First published on Feb 19, 2009. Last updated on: Feb 19, 2009.

Humanise CamelCase in Java (non hungover version)

Yesterday, I posted a hangover–inspired camel–case humaniser. Today – with the benefit of a clearer mind I decided I didn't like what I'd written much. In fact I thought it was at best ugly, at worst not at all that clear. So I set about implementing a cleaner solution and factoring the changes into Seemore.

There are those who say that it doesn‘t matter what code looks like as long as it passes the tests. They‘ll say that if it passes the tests then it does what it‘s meant to do, who cares that it looks like a turd?! Neither the customer nor the JVM (in the case of Java) cares what the code looks like, so why should we? Some even say that even unit tests don't matter — there's entertaining discussion at the end of that article as well.

Any experienced developer will know that it does matter what code looks like. Or, more specifically how readable it is. Devs who‘ve been about for a while will have been on the receiving end of a plethora of badly written classes – I know I have over the years – only to spend hours tracing through the execution with a debugger and more hours trying to decipher badly named classes. methods and variables. All in a vain attempt to extract some meaning.

It matters what code looks like! I heard somewhere (can't remember where) that – when actively developing (i.e. producing code) – developers spend only 10% of their time writing code, the rest of the time is spent reading existing code. It matters what code looks like!

It also matters a great deal that there are unit tests. In this case, if there were no unit tests, evaluating the success of the following re-implementation would have been far more difficult, certainly less repeatable. Anyway, here‘s the (hopefully) more readable version.

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class HumaniseCamelCase {
    //----------------------------------------------------------------------- Static Properties and Constants

    private static final String CAMEL_CASE_PATTERN = "([A-Z]|[a-z])[a-z]*";

    //----------------------------------------------------------------------- Instance Properties

    private String humanisedString;
    private String acronym;

    //----------------------------------------------------------------------- Instance Methods

    /**
     * Converts a camelCase to a more human form, with spaces. E.g. 'Camel case'
     *
     * @param camelCaseString
     * @return a humanised version of a camelCaseString if it is indeed camel-case. Returns the
     * original string if it is'nt camel-case
     */
    public String humanise(String camelCaseString) {
        reset();
        Matcher wordMatcher = camelCaseWordMatcher(camelCaseString);
        while(wordMatcher.find()) {
            String word = wordMatcher.group();
            boolean wordIsSingleCapitalLetter = word.matches("^[A-Z]$");
            if(wordIsSingleCapitalLetter) {
                addToAcronym(word);
            } else {
                appendAcronymIfThereIsOne();
                appendWord(word);
            }
        }
        appendAcronymIfThereIsOne();
        return humanisedString.length() > 0 ? humanisedString : camelCaseString;
    }

    private Matcher camelCaseWordMatcher(String camelCaseString) {
        return Pattern.compile(CAMEL_CASE_PATTERN).matcher(camelCaseString);
    }

    private void reset() {
        humanisedString = "";
        acronym = "";
    }

    private void addToAcronym(String word) {
        acronym += word;
    }

    private void appendWord(String word) {
        boolean firstWord = humanisedString.length() == 0;
        humanisedString += firstWord ? capitaliseFirstLetter(word) : " " + word.toLowerCase();
    }

    private void appendAcronymIfThereIsOne() {
        if(acronym.length() > 0) {
            boolean firstWord = humanisedString.length() == 0;
            humanisedString += firstWord ? acronym : " " + acronym;
            acronym = "";
        }
    }

    private String capitaliseFirstLetter(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

}

I‘m torn as to whether more readable means more elegant, but that can be a belly–button inspection for another day.

First published on Feb 9, 2009. Last updated on: Dec 30, 2009.

Humanise CamelCase in Java

In an effort to make my CRUD scaffolder for Seemore more friendly I embarked on the modest endeavour of implementing a utility method to convert camelCase variable or class names to something more human friendly.

A nice, easy little task to try and forget the hangover I managed to get myself last night (thanks Dave!). Here‘s the code.

/**
 * Converts a camelCase to a more human form, with spaces. E.g. 'Camel case'
 *
 */
public String humaniseCamelCase(String word) {
    Pattern pattern = Pattern.compile("([A-Z]|[a-z])[a-z]*");

    Vector<String> tokens = new Vector<String>();
    Matcher matcher = pattern.matcher(word);
    String acronym = "";
    while(matcher.find()) {
        String found = matcher.group();
        if(found.matches("^[A-Z]$")) {
            acronym += found;
        } else {
            if(acronym.length() > 0) {
                //we have an acronym to add before we continue
                tokens.add(acronym);
                acronym  = "";
            }
            tokens.add(found.toLowerCase());
        }
    }
    if(acronym.length() > 0) {
        tokens.add(acronym);
    }
    if (tokens.size() > 0) {
        String humanisedString = capitaliseFirstLetter(tokens.remove(0));
        for (String s : tokens) {
            humanisedString +=  " " + s;
        }
        return humanisedString;
    }

    return word;
}

The test case for this can be seen below.

import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;
import java.util.Collection;

@RunWith(Parameterized.class)
public class StringUtilTest {

    private static StringUtils util;

    @BeforeClass
    public static void setUpBeforeClass() {
        util = new StringUtils();
    }

    @Parameterized.Parameters
    public static Collection regExValues() {
     return Arrays.asList(new String[][] {
         {"camel", "Camel"},
         {"Camel", "Camel"},
         {"camelCase", "Camel case"},
         {"CamelCase", "Camel case"},
         {"doubleCamelCase", "Double camel case"},
         {"DoubleCamelCase", "Double camel case"},
         {"somethingRandomInTheHouse", "Something random in the house"},
         {"aTLA", "A TLA"},
         {"aTLAAndSomeMore", "A TLA and some more"},
         {"NOTCAMELCASE", "NOTCAMELCASE"},
         {"Certainly not camel case", "Certainly not camel case"}
      });
    }

    String input;
    String expectedOutcome;

    public StringUtilTest(String input, String expectedOutcome) {
        this.input = input;
        this.expectedOutcome = expectedOutcome;
    }

    @Test
    public void humaniseShouldHandleCamelCase() {
        assertEquals(expectedOutcome, util.humaniseCamelCase(input));
    }
}

I‘m not sure I like the way JUnit does the parameterised tests. It‘s certainly an improvement on having to write each test out individually (who‘d do that!?) and it‘s probably better than lumping all scenarios/criteria into one test. However, the reporting of each scenario/run isn‘t any more detailed than doing just that. The only difference is that the array index of the failing parameters is given – hardly useful when the failed assert already tells us what‘s wrong.

When you compare the above to something like how it would look implemented in Rspec, it looks just plain ugly. I don't like ugly. I must look into TestNG, to see if it has a more elegant approach. Failing that, I'll have a look at how the JtestR project is coming along and start thinking about writing some tests using Rspec again.

Update: There's a better, more considered implementation of this here.

First published on Feb 8, 2009. Last updated on: Dec 30, 2009.

Caching

By changing the layout of my site the other day I caused myself some problems. I knew that my markup processing code – that translates a combination of textile formatted text with embedded source fragments – was a tad inefficient. I rolled my own processor that uses Textile4J to process the text with an added filter-style system for the source fragments, formatted with JHighlight. So a fragment of this page may look like this:

I know have one with some extra functionality. Namely the option to cache the output of the markup 
processor so that any subsequent call to the same tag&ndash;library with the same value will use 
the cached version.

<textfu:jhighlight language="xml">
<tf:out value="${blogPost.body}" engine="textile" useCache="true"/>
</textfu:jhighlight>

_Voila!_ Faster loading pages and a much happier VPS(Virtual Private Server).

h2. Caching implementation

I knew it was inefficient but it was brought home quite how inefficient yesterday.

The day before yesterday I changed the way my site is laid out so that there is more content on the home page and the listing pages. No more excerpt or intro text, straight to the main article. This meant that my cobbled together – or mashed up perhaps (makes it sound cool rather than stupid) – markup processor was doing a lot more work per request.

It may be a coincidence but my Gandi–hosted virtual server bombed yesterday. Happy to accept that I may have been to blame, I concluded that I should at least eliminate the code from my enquiries.

Incidentally, Gandi have still not responded to the support ticket I raised yesterday. As my friend Keeran quite rightly put it:

[Gandi] has potential to be huge (because of the pricing), but if the support is that weak they‘re going to FAIL.

Caching

The solution I came up with isn‘t ideal and I haven‘t given much thought to best–practice or the design that much.

I have this additional code in my tag–library class. And yes, I called my markup processor Textfu. I thought for ages about a suitable, meaningful and succinct name for it. In the end I failed, so Textfu had to do. I wonder if the inventor of attachment_fu went through the same process and ended up just settling on that name.

String html;
if (useCache) {
    log.debug("Using CacheFu");
    String key = new BASE64Encoder().encode(MessageDigest.getInstance("MD5").digest(bodyText.getBytes()));
    if(CacheFu.get(key) != null) {
        log.debug("Found cached string for key " + key);
        html = CacheFu.get(key);
    } else {
        log.debug("No value found in cache for " + key);
        html = TextFuFactory.getProcessor(engine).decorate(bodyText);
        CacheFu.put(key, html);
    }
} else {
    html = TextFuFactory.getProcessor(engine).decorate(bodyText);
}

Where before I had a tag–library that read the following:

<tf:out value="${blogPost.body}" engine="textile" />

I know have one with some extra functionality. Namely the option to cache the output of the markup processor so that any subsequent call to the same tag–library with the same value will use the cached version.

<tf:out value="${blogPost.body}" engine="textile" useCache="true"/>

Voila! Faster loading pages and a much happier VPS.

Caching implementation

I am uncertain as to whether what I‘ve implemented is a suitable solution for any large scale project or whether it‘s a big no no in terms of best–practice. It seems to be working well for my site in any case. If what I've done has any flaws, please let me know. Note the imaginative name of the class again.

package com.malethan.blog.textfu.taglib;

import java.util.Map;
import java.util.HashMap;

public class CacheFu {
    //----------------------------------------------------------------------- Static Properties and Constants

    private static ThreadLocal<Map<String,String>> LOCAL_CACHE = new ThreadLocal<Map<String, String>>();

    //----------------------------------------------------------------------- Static Methods

    public static String get(String key) {
        return getCache().get(key);
    }

    public static void put(String key, String value) {
        getCache().put(key, value);
    }

    private  static Map<String, String> getCache() {
        if (LOCAL_CACHE.get() == null) {
            LOCAL_CACHE.set(new HashMap<String, String>());
        }
        return LOCAL_CACHE.get();
    }

}

First published on Jan 28, 2009. Last updated on: Jan 29, 2009.

Maven Troubles

I‘ve been having a bit of a mare this morning with trying to get my first Maven archetype for SeemoreJ up and running. I‘ve created a SeemoreJ example application from which I want to generate an arcehtype.

I‘ve recently been following Rick Hightower's efforts with Crank and noticed he‘s been tackling maven based issues as well. Though with rather more success than me.

Anyway, as per Nino Martinez's tip I used mvn archetype:create-from-project to attempt to create an archetype from my example project.

First I get this error, despite the fact that – as I understand it – the file maven complains about being missing is not actually required and that it should prompt me for the values usually found in this file.

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building seemorej-example
[INFO]    task-segment: [archetype:create-from-project]
[INFO] ------------------------------------------------------------------------
[INFO] [archetype:create-from-project]
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Cannot create archetype from this project.

Embedded error: /xxxx/seemorej-example/src/main/archetype/archetype.properties (No such file or directory)
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Sat Jan 17 12:06:10 GMT 2009
[INFO] Final Memory: 4M/67M
[INFO] ------------------------------------------------------------------------

So, I add archetype.properties with some values suggested from this page and now it builds "successfully". Quotes used because I think it kind of worked in that it copied the pom.xml file over and the contents of src/main/java, src/main/resources and src/test/java into a target/archetype.jar but completely ignored the contents of my web application folder (in src/main/webapp). Also the plugin doesn't seem to behave like any of the documentation suggests. Mine seems to generate the file target/archetype.jar, unlike what Rick and Nino both describe should happen, which is the archetype project should be generated in target/generated-sources.

Well, enough sitting in front of my computer now. I‘m going to prepare my flat for some GSI (like DIY but lazier), which is in-turn to prepare it for tenants in a month or so. If anyone is looking to rent a city-centre flat in Cardiff, I‘m your man! Get in touch.

First published on Jan 17, 2009. Last updated on: Mar 12, 2009.

Comments finally enabled on my website

Some blog my website could claim to be without the possibility to leave comments here. It took a lot of work because – as usual – I decided to take the long way around to getting it done.

Modeling the comments was relatively easy using JPA annotations and Hibernate. It was also easy to get a form on the site so that information could be input. The thing is, I wanted to be able to moderate the comments to prevent any dissent. Only kidding! I wanted to prevent spammers, idiots and pr0n peddlers from making me crazy with shitty comments.

That‘s where it started to get involved and time-consuming. I ended up implementing a CRUD scaffolding system for SeemoreJ so I could manage any data I wanted. Though, it was rather more of an academic pursuit rather than a practical one – just to see if it could be done (or, more accurately, whether I could do it). I'm happy to be corrected but – as far as I am aware – the only other dynamic scaffolding available in a Java web framework is Grails.

I‘ll produce a proper write up of the code but here‘s a quick taster in the meantime.

public class CommentsController extends CrudController<Comment, Long> {

    public CommentsController() {
        super(Comment.class, Long.class);
    }

}

The code above is all that is required to produce a fully functional CRUD application. At the moment it only supports Hibernate entities, but generic JPA support shouldn‘t be too difficult. Also, it doesn‘t allow one to manage relationships with other entities but that‘s not too much more work.

No time for any more. I have plenty of work to tidy up SeemoreJ so I can get the first public release available. Watch this space!

Oh and please leave comments! :-)

First published on Jan 6, 2009. Last updated on: Jan 7, 2009.

Testing context for UrlRewrite and JUnit4

Absolutely ages ago, I found this great article on JUnit testing for UrlRewrite by Sujit Pal. It was very useful as at the time as I was looking for a way of testing that my usage of UrlRewrite was working correctly without having a servlet container running. Together with my contribution, both inbound and outbound rules are covered.

The solution is great for JUnit 3 but not really in the spirit of JUnit 4, where the test cases aren't necessarily part of an inheritance hierarchy, as this article demonstrates.

I had cause to test some rewrites again recently. However, I‘ve moved over to JUnit4 as a preference these days, so I decided to refresh Sujit‘s solution, decouple it from TestCase.

package some.pakage.name;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.tuckey.web.MockRequest;
import org.tuckey.web.MockResponse;
import org.tuckey.web.filters.urlrewrite.Conf;
import org.tuckey.web.filters.urlrewrite.RewrittenUrl;
import org.tuckey.web.filters.urlrewrite.UrlRewriteWrappedResponse;
import org.tuckey.web.filters.urlrewrite.UrlRewriter;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * <p>A context for testing UrlRewrite rules for JUnit4</p>
 */
public class UrlRewriteTesting {
    //----------------------------------------------------------------------- Instance Properties

    protected Conf conf;
    protected UrlRewriter rewriter;

    //----------------------------------------------------------------------- Constructors

    public UrlRewriteTesting(Conf conf) {
        org.tuckey.web.filters.urlrewrite.utils.Log.setLevel("DEBUG");
        this.conf = conf;
        rewriter = new UrlRewriter(conf);
    }

    public UrlRewriteTesting(String pathToCfg, String confFile) throws FileNotFoundException {
        this(new Conf(new FileInputStream(pathToCfg + "/" + confFile), confFile));
    }

    //----------------------------------------------------------------------- Instance Methods

    /**
     * Assertion to rewrite the URL using the UrlRewriteFilter and verify
     * that fromUrl is rewritten to toUrl using rewriting rules in conf.
     *
     * @param fromUrl the URL to be rewritten from.
     * @param toUrl   the URL to be rewritten to.
     */
    public void assertInboundRewrite(String fromUrl, String toUrl) {
        RewrittenUrl rewrittenUrl = rewriter.processRequest(new MockRequest(fromUrl), new MockResponse());

        assertNotNull("Could not rewrite URL from:" + fromUrl + " to:" + toUrl, rewrittenUrl);

        assertEquals("Rewrite from:" + fromUrl + " to:" + toUrl + " did not succeed", toUrl, rewrittenUrl.getTarget());
    }

    /**
     * Tests that an outbound url is processed correctly by the outbound rules
     *
     * @param fromUrl the url as you would be writing it in your JSPs
     * @param toUrl what you expect it to be rewritten to when rendered
     */
    public void assertOutboundRewrite(String fromUrl, String toUrl) {
        UrlRewriteWrappedResponse wrappedResponse =
                new UrlRewriteWrappedResponse(new MockResponse(), new MockRequest(fromUrl), new UrlRewriter(conf));

        assertEquals("Rewrite from:" + fromUrl + " to:" + toUrl + " did not succeed", toUrl, wrappedResponse.encodeURL(fromUrl));
    }

}

Usage

Below is an example of how SeemoreJ's rewrite rules in urlrewrite.xml for this site might look for the home page. At the time of writing, this site does not use UrlRewrite, so it's entirely hypothetical.

<!-- Index/Home -->
    <rule>
        <from>^/$</from>
        <to>/seemore?sjController=blog&amp;sjAction=home&amp;sjFormat=html</to>
    </rule>
    <rule>
        <from>^/index.(xml|html)$</from>
        <to>/seemore?sjController=blog&amp;sjAction=home&amp;sjFormat=$1</to>
    </rule>

    <outbound-rule>
        <from>/seemore\?sjController=blog&amp;sjAction=home&amp;sjFormat=(xml|html)</from>
        <to>/index.$1</to>
    </outbound-rule>

I might be making numerous minor or major changes to this file and I want the unit tests to defend against unwanted side-effects. So the test case below will (hopefully) make sure I don‘t mess things up.

package com.malethan.blog.urlrewrite;

import some.pakage.name.UrlRewriteTesting;
import org.junit.Test;

import java.io.FileNotFoundException;

public class UrlRewriteRulesTest {
    //----------------------------------------------------------------------- Instance Properties

    UrlRewriteTesting context;

    //----------------------------------------------------------------------- Constructors

    public UrlRewriteRulesTest() throws FileNotFoundException {
        context = new UrlRewriteTesting(System.getProperty("basedir") +"/src/main/webapp/WEB-INF", "urlrewrite.xml");
    }

    //----------------------------------------------------------------------- Tests

    @Test
    public void testIndexInbound() {
        context.assertInboundRewrite("/", "/seemore?sjController=blog&sjAction=home&sjFormat=html");
        context.assertInboundRewrite("/index.html", "/seemore?sjController=blog&sjAction=home&sjFormat=html");
        context.assertInboundRewrite("/index.xml", "/seemore?sjController=blog&sjAction=home&sjFormat=xml");
    }

    @Test
    public void testIndexOutbound() {
        context.assertOutboundRewrite("/seemore?sjController=blog&sjAction=home&sjFormat=html", "/index.html");
        context.assertOutboundRewrite("/seemore?sjController=blog&sjAction=home&sjFormat=xml", "/index.xml");
    }
}

First published on Dec 20, 2008. Last updated on: Dec 30, 2009.

 
People I like
Other sites