April 20, 2006

Crappy java.sql.Timestamp pretending to be java.util.Date

So I started getting ClassCastExceptions when comparing two java.util.Dates. Tracking it down, I realised (and in fact the stack trace told me) that one of the java.util.Dates was actually a java.sql.Timestamp. So looking at the code, I was a bit surprised to realise that I was actually casting the objects to java.util.Date….which is valid because java.sql.Timestamp extends java.util.Date.

So why doesn't it work, and whose fault is it?

On the face of it, it would appear java.util.Timestamp is at fault because it is a java.util.Date and should therefore be able to be used in place of a java.util.Date; quite a fundamental OO rule (substitution). But then thinking a bit more, I realised it isn't quite so clear cut... The substitution rule states that you must be able to use any subclass in place of it's parent, but it doesn't state that the sub class must behave exactly like it's parent...which is obvious when you think about it. If this wasn't the case, you would never be allowed to change the behaviour of any of the methods. Arguably, you should never make the behaviour inconsistent with the intention of the super classes' method.

In otherwords, java.util.Date.compareTo(java.util.Timestamp) must work, but there is no guarantee that java.util.Timestamp.compareTo(java.util.Date) needs to work..

And in fact, it was java.sql.Timestamp.compareTo(java.util.Date) was throwing the exception.

So it seems java.sql.Timestamp is technically correct, even if it isn't very friendly :(

Still think it is wrong, but not sure it is technically wrong…..


April 18, 2006

Testing configuration in spring

Useful tips for unit testing the configuration in spring:

If you have lots of references like "/WEB-INF/xyz" then Spring will convert these FieSystemResources. This is fine, if your root directory contains "/WEB-INF/", but it probably doesn't. Our project structure has "/WEB-INF" living underneath "/war". To fix this simply provide your own FileSystemResourceLoader:


        FileSystemResourceLoader fileSystemResourceLoader = new FileSystemResourceLoader() {
            protected Resource getResourceByPath(String path) {
                path = "/war" + path;
                return super.getResourceByPath(path);
            }
        };

Secondly, if you have an applicationContext and a number of -servlet and you are not explicitly listing the -servlet.xml in the ContextLoader then spring creates the parent applicationContext.xml and then creates child applicationContexts for each -servlet. You need to mirror this hierarchy, otherwise you may end up running into namespace clashes:


        GenericWebApplicationContext parentCtx = new GenericWebApplicationContext();
        parentCtx.setServletContext(new MockServletContext());

        /**
         * Files are referenced (e.g.) "/WEB-INF" however that won't resolve during this test
         * so correct the path.
         */
        FileSystemResourceLoader fileSystemResourceLoader = new FileSystemResourceLoader() {
            protected Resource getResourceByPath(String path) {
                path = "/war" + path;
                return super.getResourceByPath(path);
            }
        };
        FileSystemResourceLoader loader = fileSystemResourceLoader;
        parentCtx.setResourceLoader(loader);
        
        configureSystemProperties();

        XmlBeanDefinitionReader parentXmlReader = new XmlBeanDefinitionReader(parentCtx);

        /**
         * Cannot use classpath because crappy Eclipse (or my crappy knowledge
         * of eclipse ;)) won't let you have a folder as a classpath and show
         * in package explorer. Besides which web-inf/classes is already on the
         * classpath (for Chris + tomcat) and eclipse definately won't allow
         * nested classpaths (i.e. /web-inf)
         */
        String[] contextFiles = {
                "applicationContext.xml",
                "sitebuilderAdmin-servlet.xml",
                "sitebuilderApi-servlet.xml",
                "sitebuilderEdit-servlet.xml",
                "sitebuilderError-servlet.xml",
                "sitebuilderRender-servlet.xml",
                "sitebuilderUser-servlet.xml"
        };
        
        /**
         * Must load each context into it's own file to prevent name space clashes.
         */
        for (String contextFile: contextFiles) {
            GenericWebApplicationContext childCtx = new GenericWebApplicationContext();
            childCtx.setServletContext(new MockServletContext());
            childCtx.setParent(parentCtx);
            childCtx.setResourceLoader(loader);
            XmlBeanDefinitionReader childXmlReader = new XmlBeanDefinitionReader(parentCtx);
            childXmlReader.loadBeanDefinitions(new FileSystemResource(FILE_PREFIX + contextFile));
            childCtx.refresh();
        }

And finally; move all external beans (JNDI, DataSource etc.) out of the applicationContext and into their own contexts. I had already done this, and the applicationContext imported them as it is good practice to fragment large XML files into smaller atomic units. Rather than applicationContext importing them directly, wire them up in the contextLoader:


  
    contextConfigLocation
    /WEB-INF/applicationContext.xml, /WEB-INF/hibernate-context.xml, /WEB-INF/tiles-context.xml
  

The last tip is rewrite crappy crappy tilesConfigurer! The problem is that the tilesConfigurer doesn't expect a number of resources, it expects a single comma seperated String :( This means that if you specify "/WEB-INF/" then everything will break because the directory doesn't exist (it is /war/WEB-INF).

The whole thing would have been much simpler if eclipse allowed you to specify a folder as being on the classpath and showed it in package explorer. At the moment as soon as a folder is marked as being on the class path it is hidden from the explorer.

HTH


Interesting article about blogs

Writing about web page http://elliottback.com.nyud.net:8080/wp/?p=1351

Nice article summarising the top 10 blogs (from a design point of view).

link


April 15, 2006

Performance of Spring CGLIB and JDK proxies

So I noticed a couple of questions popping up on the Spring forums asking about the cost of using AOP in Spring. This is really a question of how expensive CGLIB or JDK proxies are.

Since I had no real idea (there are lots of "not than expensive" comments around) I decided to write a little test.

Essentially I construct X instances of a class, X instances of a CGLIB proxy of that class (cglib sub classes the target class) and X instances of a JDK proxy, and then called the same method on each instance and measured the time. Hardly conclusive, but enough to give an idea.

I assumed the impact was minimal; when X is 10000:

Unproxied: 926654(ns) 9(ms)
cglib: 23986289(ns) 239(ms)
Proxy: 70206129(ns) 702(ms)

I expected some over head, but notwhere near that much….. I was also suprised that CGLIB was almost 3 times quicker than JDK proxies (JDK1.5.0_06 on WinXP SP2).

It is still a long way away from being the bottleneck in any system I am likely to write, but good to know :)

I expect AspectJ style weaving is probably a lot more efficient because (IIUI) it modified the byte code directly. Of course, there is an overhead of the modification, but that is a one off…. But I may be so completely wrong :)

Code:


public class MyClassImpl implements MyClass {
    public void doSomething() {
        
    }
}

public interface MyClass {
    void doSomething();
}

import junit.framework.TestCase;

import org.springframework.aop.framework.ProxyFactoryBean;

public final class ProxyTest extends TestCase {
    public void testPerformance() {
        int numberToExecute = 10000;
        MyClass[] classes = new MyClass[numberToExecute];
        for (int i = 0; i< numberToExecute; i++) {
            classes[i] = new MyClassImpl();
        }
        
        MyClass[] cglibProxyClasses = new MyClassImpl[numberToExecute];
        for (int i = 0; i< numberToExecute; i++) {
            ProxyFactoryBean factoryBean = new ProxyFactoryBean();
            factoryBean.setProxyTargetClass(true);
            factoryBean.setTarget(classes[i]);
            cglibProxyClasses[i] = (MyClass) factoryBean.getObject();
        }
        
        MyClass[] proxyClasses = new MyClass[numberToExecute];
        for (int i = 0; i< numberToExecute; i++) {
            ProxyFactoryBean factoryBean = new ProxyFactoryBean();
            factoryBean.setProxyTargetClass(false);
            factoryBean.setInterfaces(new Class[] {MyClass.class });
            factoryBean.setTarget(classes[i]);
            proxyClasses[i] = (MyClass) factoryBean.getObject();
        }
        
        long unproxyExecution = executeClasses(numberToExecute, classes);
        displayResults("Unproxied", unproxyExecution);
        
        long cglibExecution = executeClasses(numberToExecute, cglibProxyClasses);
        displayResults("cglib", cglibExecution);

        long proxyExecution = executeClasses(numberToExecute, proxyClasses);
        displayResults("Proxy", proxyExecution);
    }

    private void displayResults(String label, long unproxyExecution) {
        System.out.println(label + ": " + unproxyExecution + "(ns) " + (unproxyExecution / 100000) + "(ms)");
    }

    private long executeClasses(int numberToExecute, MyClass[] classes) {
        long start = System.nanoTime();
        for (int i = 0; i< numberToExecute; i++) {
            classes[i].doSomething();
        }
        long end = System.nanoTime();
        long execution = end – start;
        return execution;
    }
}

April 12, 2006

Yeah! Hibernate doesn't require cglib

Writing about web page http://hibernate.org/250.html#A37

There has been a long running problem with the combination of hibernate, CGLIB and an application server resulting in memory leaks. There seems to be some debate about whether it is purely a fault of CGLIB or not, and I don't know enough (or care) to make a guess. I do know that CGLIB is a fantastic and extremely powerful library :)

The problem manifests itself in only being able to deploy a handful of times on before running out of heap space.

Anyways, it appears Hibernate 3.2 is no longer dependant upon CGLIB. Yeah :)

Given that we do not use CGLIB in spring (we use JDK proxies) this might just mean we can deploy more than 5 times :) Very useful when developing ;)


April 05, 2006

Crappy crappy SortedSet!!! Why oh why???

Writing about web page http://java.sun.com/j2se/1.4.2/docs/api/java/util/SortedSet.html

So, what is the contract for a set?:

A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.

So what is the contract for a SortedSet?:

A set that further guarantees that its iterator will traverse the set in ascending element order, sorted according to the natural ordering of its elements (see Comparable), or by a Comparator provided at sorted set creation time. Several additional operations are provided to take advantage of the ordering. (This interface is the set analogue of SortedMap.)

Simple, sets do not support duplicates, SortedSets add an order? Right? Yes, but SortedSets also utterly break the contract of Sets (or at least add a stupid restriction); it completely ignores equals and uses compareTo instead! Why!. The java doc kinda hints at this:

Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the Set interface. (See the Comparable interface or Comparator interface for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

I took this to mean that if the two objects are equals, then compareTo must return 0, but not, it means if compareTo returns 0 then a SortedSet treats them as equal, even if equal returns false!!!!

Code to prove it:

    class TestClass implements Comparable {
        private final Integer id;
        private final String s;

        public TestClass(final Integer id, final String s) {
            this.id = id;
            this.s = s;
        }

        public int compareTo(final Object o) {
            if (equals(o)) {
                return 0;
            } 
            return ((TestClass)o).s.compareTo(s);
        }
        
        public boolean equals(final Object o) {
            return ((TestClass)o).id.equals(id);
        }
    }
    
    public void testTheProblem() {
        TestClass firstTestClass = new TestClass(1, "same string");
        TestClass secondTestClass = new TestClass(2, "same string");
        
        assertFalse("equality", firstTestClass.equals(secondTestClass));
        assertTrue("comparison", firstTestClass.compareTo(secondTestClass) == 0);
        
        SortedSet testClasses = new TreeSet();
        assertTrue("adding first item", testClasses.add(firstTestClass));
        // this fails!!!
        assertTrue("adding second item", testClasses.add(secondTestClass));        
    }

March 27, 2006

Threading in JBoss, hibernate + spring

The project I am currently working on has an OM which looks like:

page -> content -> contentFetcher

The page typically has 4 contents (links, toolbars, main and rhs) which are sequentially loaded. This seems like a good candidate for threading; there are no dependencies between them and they are each potentially expensive to created (coming from remote servers etc.).

As an experiment I wrapped added the call to retrieve them in it's own thread and deployed. Unfortunately it all went horribly wrong….and (I think) it is because we are using spring OSIV which creates a single session for the entire thread. The stack trace is:


java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
        at java.util.HashMap$ValueIterator.next(HashMap.java:817)
        at org.hibernate.pretty.Printer.toString(Printer.java:90)
        at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListen
er.java:97)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1009)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:356)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)

which is a shame.

(As an aside, it is OK to create threads within JBoss, or rather to retrieve threads from a custom threadpool; thus allowing JBoss to shut down without your threads holding anything up.)

I am sure I can work around this, and I have only spent 5 minutes on this so far, but I don't think we will be able to use SessionPerView…..

P.S link


Charsets ; I hate them :(

So the project I am working on uses a number of technologies including JSTL and freemarker.

Somebody had entered the following character: "" which was displaying perfectly in JSP, but freemarker was replacing it with "?".

Of course I thought, it must be freemarkers fault :) I was meticulously careful about never converting a byte[] into a String using the string constructor unless the charset was specified, but I never realised you had to do it the other way as well :( When calling getBytes(), the encoding of the string is completely ignored and the platform default is used…. Why?

So the following will do bad things:


  new String(new String("some string with a funny character ", encoding).getBytes(), encoding);

lame.

The problem was also a little bit more interesting because on windows machines the default platform is unicode based, on solaris it isn't, so the problem only exhibited itself on solaris.

I have (I am ashamed to say) never really delved into the joy of charsets and text encoding, instead preferring to stick my head in the sand. Luckily Chris May sits next on the desk next to me :)


March 21, 2006

Expert Spring MVC + Spring Web Flow errata

Writing about web page http://apress.com/book/bookDisplay.html?bID=10048

Below are the changes in Chapter 11 + Chapter 12 as a result of upgrading to Spring Web Flow 1.0 EA:

[global changes]
_flowExecutionId has been renamed to _flowExecutionKey
org.springframework.webflow.manager has been renamed to org.springframework.webflow.executor
FlowExecutionManager has been renamed to FlowExecutor
FlowExecutionManagerImpl has been renamed to FlowExecutorImpl
FlowExecutionContinuationKey has been renamed to FlowExecutionKey
FlowExecutionManagerParameterExtractor has been renamed to FlowExecutorArgumentExtractor

Chapter 11

– Figure 11–3 (page 7) has four boxes which all contain text starting "webflow.manager.". The word "manager" needs to be replaced with the word "executor", i.e the first box should read webflow.executor.struts.FlowAction etc.

– The first line of the last paragraph on page 7 refers to "FlowExecutionManager". This has been renamed to "FlowExecutor".

– Page 8 refers to "org.springframework.webflow.execution.FlowExecutionRepository". This has been renamed to "org.springframework.webflow.execution.repository.FlowExecutionRepository".

– Page 17 refers to "AbstractFlowexecutionTests" but the e after "Flow" should be capitalised: "AbstractFlowExecutionTests".

– The first two methods in Listing 11–8 are duplicates. Please remove the first method. The second method needs to change from:

protected Resource getFlowLocation() {

File flowDir = new File(.......);

return new FileSyste…..
}

to:

protected Resource getFlowLocation() {

File flowDir = new File(.......);

FileSystemResource resource = new FileSystemResource(new File(flowDir, "purchase-flow.xml"));

return new ExternalizedFlowDefinition("purchaseFlow", resource);
}

so essentially the first line stays the same, and the second line is replaced with two new lines.

– Listing 11–13 on page 22 refers to "org.springframework.webflow.manager.
mvc.FlowController" The word "manager" needs to be replaced with the word "executor".

– The next paragragh on page 22 contains a reference to "org.springframework.webflow.mvc.FlowController". This should be "org.springframework.webflow.executor.mvc.FlowController".

– Page 26 refers to " org.springframework.webflow.config.FlowBuilder". This should be "org.springframework.webflow.builder.FlowBuilder".

Chapter 12

[global and specific changes]
– Page 8, first sentence contains " org.springframework.binding.AttributeMapper". Should be "org.springframework.binding.mapping.AttributeMapper".

– Page 9, first paragraph contains "ParameterizableFlowAttributeMapper", should be DefaultFlowAttributeMapper.

– Page 9, Listing 12–9 first method signature is "public Map createSubflowInput(Request…..". Should be "public AttributeMap createSubflowInput(Request….".
First line in first method is "Map map = new HashMap()" should be "AttributeMap map = new AttributeMap()".
Second method signature is "public void mapSubflowOuput(Map subflowOutput…." should be "public void mapSubflowOutput(UnmodifiableAttributeMap…".

– Page 12, In "Integration With Web Frameworks" the term FlowExecutionManager needs to be replaced with FlowExecutor. There are 5 occurences (although any others you spot should also be changed).

The last but one sentence "Both methods accept org…... and return org…." should read "Both methods accept org.springframework.webflow.ExternalContext in their parameters and return org.springframework.webflow.executor.ResponseInstruction , from which the org.springframework.webflow.ViewSelection can be obtained."

Listing 12–11 has completely changed:

public interface ExternalContext {

public String getContextPath();

public String getDispatcherPath();

public String getRequestPathInfo();

public ParameterMap getRequestParameterMap();

public AttributeMap getRequestMap();

public SharedAttributeMap getSessionMap();

public SharedAttributeMap getApplicationMap();

public interface SharedMap extends Map {

public Object getMutex();

}

public static class SharedAttributeMap extends AttributeMap {

public SharedAttributeMap(SharedMap sharedMap) {

super(sharedMap);

}

public SharedMap getSharedMap() {

return (SharedMap)getMapInternal();

}

public Object getMutex() {

return getSharedMap().getMutex();

}

}
}

– Page 13 Last entry in Table 12–2 contains the word "manager." should be "executor."

"The FlowExecutionManager" should be renamed "FlowExecutor".
Listing 12–12 heading should be changed to "org.springframework.webflow.executor.FlowExecutor".
Both methods return "ViewSelection". They should return "ResponseInstruction".
Within the Note, "FlowExecutionManager" should be renamed to "FlowExecutor".
The next two paragraphs require all instances of "FlowExecutionManager" to be changed to "FlowExecutor". I count 2 instances
The next two paragraphs require all instances of "_flowExecutionId" to be changed to "_flowExecutionKey". I count 2 instances
The "org.springframework.webflow.executor.support.FlowExecutionManagerParameterExtractor" needs to be "org.springframework.webflow.executor.FlowExecutorArgumentExtractor".

-Page 15, Listing 12–13 Please remove the last method "rehydrate".

Listing 12–14 FlowExecutionContext has changed. It essentially needs to be:

public interface FlowExecutionContext extends FlowExecutionStatistics {

public Flow getFlow();

public AttributeMap getScope();

FlowSession getActiveSession();
}

The next paragraph contains the phrase "the active flow definition, the current state, and" which needs to be replaced with "conversation scope and".

The next paragraph contains the phrase "The root flow" which needs to be replaced with "The flow". The last sentence contains "getActiveFlow()" which needs to be "getFlow()".

Page 17, Listing 12–15 has changed. It should now be:

public interface RequestContext {

public Flow getActiveFlow() throws IllegalStateException;

public State getCurrentState() throws IllegalStateException;

public AttributeMap getRequestScope();

public AttributeMap getFlowScope();

public AttributeMap getConversationScope();

public ParameterMap getRequestParameters();

public ExternalContext getExternalContext();

public FlowExecutionContext getFlowExecutionContext();

public Event getLastEvent();

public Transition getLastTransition();

public UnmodifiableAttributeMap getAttributes();

public void setAttributes(AttributeCollection attributes);

public UnmodifiableAttributeMap getModel();
}

Page 18 contains two references to "org.springframework.webflow.manager.ConditionalFlowExecutionListenerLoader". They should be "org.springframework.webflow.executor.ConditionalFlowExecutionListenerLoader ".

Listing 12–17 on Page 18 contains a reference to "org.springframework.webflow.manager.FlowExecutionManagerImpl". It should be "org.springframework.webflow.executor.FlowExecutorImpl".

Page 19, Listing 12–18 has completely changed:

public interface FlowExecutionRepository {

public FlowExecution createFlowExecution(String flowId);

public FlowExecutionKey generateKey(FlowExecution flowExecution) throws FlowExecutionRepositoryException;

public FlowExecutionKey generateKey(FlowExecution flowExecution, Serializable conversationId) throws FlowExecutionRepositoryException;

public ConversationLock getLock(Serializable conversationId);

public FlowExecution getFlowExecution(FlowExecutionKey key) throws FlowExecutionRepositoryException;

public void putFlowExecution(FlowExecutionKey key, FlowExecution flowExecution) throws FlowExecutionRepositoryException;

public FlowExecutionKey getCurrentFlowExecutionKey(Serializable conversationId) throws FlowExecutionRepositoryException;

public ViewSelection getCurrentViewSelection(Serializable conversationId) throws FlowExecutionRepositoryException;

public void setCurrentViewSelection(Serializable conversationId, ViewSelection viewSelection) throws FlowExecutionRepositoryException;

public void invalidateConversation(Serializable conversationId) throws FlowExecutionRepositoryException;
}

– Page 22 contains a number of references to FlowExecutionContinuationKey. This has been renamed to FlowExecutionKey.

– Page 22 contains a number of references to _flowExecutionId. This has been renamed to _flowExecutionKey.

– Page 22 at the bottom contains a reference to "org.springframework.webflow.execution.repository.SimpleFlowExecutionRepository ". It should be "org.springframework.webflow.execution.repository.support.SimpleFlowExecutionRepository".

Page 23. The note should read "This is the default implementation."

Page 23 contains a reference to "_flowExecutionId", it should be "_flowExecutionKey".

Page 24 contains two references to "_flowExecutionId", they should be "_flowExecutionKey".

Page 30, Table 12–10 contains a reference to "RedirectViewSelector". Should be "ExternalRedirectSelector".

Table 12–11 is wrong, should be:

ApplicationViewSelector If viewName is specified.
ApplicationViewSelector If redirect:viewName is specified.
ExternalRedirectSelector If externalRedirect:/url?par1=x is specified
FlowRedirectSelector If flowRedrect:/url is specified
YourViewSelector If bean=yourBean is specified.

– Page 31 contains three references to "FlowExecutionManagerParameterExtractor". They should all be "FlowExecutorArgumentExtractor".

– Page 31 contains three references to "FEMPE". They should all be "FEAE".

– Page 34 contains a reference to "InvalidConversionationContinuationException". Should be "CannotContinueConversationException".


March 16, 2006

Any decent, easy to use online backup clients out there?

I am looking for an online backup solution for my technically disadvantaged (I am being really unfair ;)) father in law.

Ideally it would transparently upload any modified documents automatically without any user intervention. Anything which requires him getting involved in the process isn’t really acceptable.

Any ideas? Less than 10/mnth would be good.


August 2022

Mo Tu We Th Fr Sa Su
Jul |  Today  |
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31            

Search this blog

Tags

Galleries

Most recent comments

  • Interesting… While I'm not completely convinced in such microbenchmarks, I'm pretty sure that 1ms … by Alexander Snaps on this entry
  • Hello. I bought the book yesterday. I was trying to find the source code for chapter 11 and chapter … by Suleman on this entry
  • http://woosight.net/account/login?username=demo by live mashup demo on this entry
  • Thanks mate ….. This blog was really helpful. by Maaz Hurzuk on this entry
  • Ty. Not directly helpful for my problem, but pointed me in the right direction. You will also get th… by Mike E. on this entry

Blog archive

Loading…
RSS2.0 Atom
Not signed in
Sign in

Powered by BlogBuilder
© MMXXII