23 June 2013

Testing cron expression

Many people, using spring scheduling, write
@Scheduled("* * 3 * * ?")
public void myCronJob() {...
and then they wait a few days to check logs if the job is triggered correctly. And what about:
0 0/5 14,18,3-39,52 ? JAN,MAR,SEP MON-FRI 2002-2010
Fortunately, testing a cron expression is simple. But first we need a constant:
public static final String EVERYDAY_3_AM = "* * 3 * * ?"
And now, with spring's scheduling, we can use org.springframework.scheduling.support.CronSequenceGenerator
import static org.fest.assertions.api.Assertions.assertThat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.scheduling.support.CronSequenceGenerator;

import com.googlecode.zohhak.api.Coercion;
import com.googlecode.zohhak.api.TestWith;
import com.googlecode.zohhak.api.runners.ZohhakRunner;

@RunWith(ZohhakRunner.class)
public class CronTest {

  static CronSequenceGenerator everyday_3am;

  @TestWith({
    "2013-06-10 22:20,    2013-06-11 03:00",
    "2013-06-13 01:12,    2013-06-13 03:00"
  })
  public void should_trigger_at_the_nearest_3_AM(Date now, Date nearest_3am) {

    // when
    Date nextExecution = everyday_3am.next(now);
  
    //then
    assertThat(nextExecution).isEqualTo(nearest_3am);
  }

  @BeforeClass
  static public void parseExpression() {
    everyday_3am = new CronSequenceGenerator(Constants.EVERYDAY_3_AM);
  }

  @Coercion
  public Date coerce(String date) throws ParseException {
    return new SimpleDateFormat("yyyy-MM-dd hh:mm").parse(date);
  }
}
We use static variable just to avoid multiple parsing of the same expression, as for complex scenarios there might be many parameters.
The same can be achieved with quartz library. To do this just replace CronSequenceGenerator with org.quartz.CronExpression
Date nextExecution = everyday_3am.getNextValidTimeAfter(now);
everyday_3am = new CronExpression(Constants.EVERYDAY_3_AM);

9 June 2013

CodeGenerationException and proxies

Recently I saw one of tests failed with the message:
Exception of type java.lang.IllegalStateException expected but was not thrown. 
Instead an exception of type class org.mockito.cglib.core.CodeGenerationException 
with message 'java.lang.reflect.InvocationTargetException-->null' was thrown.
But let's start from the beginning. We have a spring web application that contains only 2 classes. First one is a standard session scoped component:
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MySessionComponent {
 
    public void doError() {
        throw new IllegalStateException(); 
    }

    public void doNothing() {}
}
Nothing new, right? Second component is a standard singleton:
@Component
public class MySingleton {
 
    @Autowired MySessionComponent mySessionComponent;

    public void sampleAction() {
        mySessionComponent.doNothing();
    }
}
That's the whole application. Now let's test it.
import org.junit.Test;
import static com.googlecode.catchexception.apis.CatchExceptionBdd.*;

public class MySessionComponentTest {

    @Test
    public void test() {
        when(new MySessionComponent()).doError();
        thenThrown(IllegalStateException.class);
    }
}
I use catch exception v1.0.4 and test passes. Now, let's do an integration test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class MySingletonTest {
 
    @Configuration @ComponentScan static class TestAppContext {} // just registers 2 components
 
    @Autowired MySingleton myController;
 
    @Test
    public void test() {
        myController.sampleAction();
    }
}
All tests pass. And now, let's suppose that we need, for whatever reason, to combine those tests:
@Test
public void test() {
    myController.sampleAction();

    when(new MySessionComponent()).doError();
    thenThrown(IllegalStateException.class);
}
And we get the exception. WTF? After some time spent with debugger I found InvocationTargetException thrown inside org.mockito.cglib.core.AbstractClassGenerator. The problem is there is no cause nor detailed message and therefore it's not propagated anywhere so you can't find the real reason in any logs. However this exception has target field and there we can find:
java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader): 
attempted  duplicate class definition for name: "MySessionComponent$$FastClassByCGLIB$$441a78f3"
At first spring creates proxy for MySessionComponent in order to autowire beans with different scopes. Then catch-exception tries to create proxy for the same class. It seems that both frameworks generates the same name for the class and two classes with same name are not allowed within one classloader.

When we change the order of method invocations (the order of creating proxies)
@Test
public void deleteEbook() {
    when(new MySessionComponent()).doError();
    thenThrown(IllegalStateException.class);

    myController.sampleAction();
}
spring throws an exception but now you can see the real cause in the stacktrace:
org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
 at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
...
Caused by: java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "MySessionComponent$$FastClassByCGLIB$$441a78f3"
Btw, this behavior is strange because cglib claims it can detect name clashes. Maybe it's about repackaging cglib in almost every framework?

29 May 2013

Functional language for a java developer

Why should you learn it? IMHO, very important and underestimated argument is: it makes you a better programmer. What is more, you are probably already using it (javascript) and clojure and scala get more and more attention so it may be a good investment. But there is another, less obvious reason: it will help get a java job. A lot of interview questions are short algorithmic tasks. You can find one at almost every interview. Just pick the task, say that it would be easier to write it in a functional language and do it. Let's see a few examples. I asked google for 'programming interview questions' and I landed here. You can easily pick some tasks:

Create all permutations of a string. Here, haskell version is really impressive
permutation [] = [[]]
permutation xs = [x:ys | x <- nub (xs), ys <- permutation (delete x xs)]
In an array 1-100 numbers are stored, one number is missing how do you find it?
missing = succ . length . takeWhile id . zipWith (==) [1..] . sort
In an array 1-100 exactly one number is duplicate how do you find it?
duplicated = length . takeWhile id . zipWith (==) [1..] . sort
or after removing duplication:
increasingPrefixLength = length . takeWhile id . zipWith (==) [1..] . sort
missing = succ . increasingPrefixLength
duplicated = increasingPrefixLength
just for clarification, let's see how it works:
missing [1,3,2,5,6]
-- 4
duplicated [3,2,1,2,4]
-- 2
From other source: sum of digits of decimal expansion of 100!
(apply + (map #(Integer/parseInt (str %)) (str (apply *' (range 1 101)))))
number of zeros in decimal expansion of 100!
(count (filter #(= \0 %) (str (apply *' (range 1 101)))))
and the same in haskell (with currying and compact syntax for function composition)
sum . map digitToInt . show $ product [1..100]
length . filter (== '0') . show $ product [1..100]
Why functional style is useful? Often it's simpler because it has less edge cases (yes, you have to know the language and understand the FP). Of course above tasks aren't much more difficult in procedural approach and still, during the interview, you will probably have to solve them also in java. But I guarantee you: after such an answer you are a few points ahead of your competitors.

26 May 2013

Everything is a nail

How many times have you rejected someone's idea to use new tool in a (new) project? How many times have you done it without knowing the pros and cons of the tool? Just because you wasn't familiar with it? Why do you use the language / framework / library you use? Because it's best? Sufficient? If you really believe it, read the famous Beating the Averages (or at least the paragraph about The Blub Paradox).

Quiz


Before you expand code snippets, think for a while how would you solve the problem. Just try to estimate the complexity.

Question 1

What's the name of the following method? You know this method. If you don't, you should
public static boolean xxx(String str) {
    int strLen;
    if (str == null || (strLen = str.length()) == 0) {
      return true;
    }
    for (int i = 0; i < strLen; i++) {
      if ((Character.isWhitespace(str.charAt(i)) == false)) {
        return false;
      }
    }
    return true;
  }
How much time did you need to read and understand one of the most common functions?

Question 2

Can you do it better? Can you make this code more readable? Pick any tool you want.
isBlank = all isSpace

Question 3

Search all subdirectories and find all mp3 files greater than 9mb.
find -iname "*.mp3" -size +9M
Tiny academic examples? Maybe. Let's try something bigger and more complex.

Question 4

Write sudoku solver. The following solution is from Manuel Rotter's blog.
:- use_module(library(clpfd)). 

sudoku(Rows) :- 
  append(Rows, Vs), Vs ins 1..9,
  maplist(all_distinct, Rows),
  transpose(Rows, Columns),    
  maplist(all_distinct, Columns),    
  Rows = [A,B,C,D,E,F,G,H,I],    
  blocks(A, B, C), blocks(D, E, F), blocks(G, H, I),    
  maplist(label, Rows).     
 
blocks([], [], []).      
blocks([A,B,C|Bs1], [D,E,F|Bs2], [G,H,I|Bs3]) :-    
  all_distinct([A,B,C,D,E,F,G,H,I]),     
  blocks(Bs1, Bs2, Bs3)
Not a real life examples? No company would ever use such strange languages to make money? Well... they and they do.

Question 5

Something from corpo world. Typical security for web application. Only users with admin role (based on company's ldap) can access the application and only via https. Secondary log in of the same user should terminate his previous session. Each login should create new session id to prevent session fixation attack. Css files should not be protected because of performance.
<ldap-server url="ldap://mycompany.com:389/dc=mycompany,dc=com" />
<ldap-authentication-provider 
                         user-dn-pattern="uid={0},ou=people"
                         group-search-base="ou=groups" />

<http pattern="/css/**" security="none"/>
<http auto-config='true'>
    <form-login login-page='/login.jsp'/>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" 
                                         requires-channel="https"/>
    <intercept-url pattern="/**" access="ROLE_ADMIN" requires-channel="https"/>

    <session-management>
        <concurrency-control max-sessions="1" />
   </session-management>
</http>
End of quiz. If you have other examples of a language/tool perfectly suited for a specific task, send them to me! Disclosure: prolog and spring examples haven't been tested.

Of course, you can't freely mix languages. Cost of integrating different languages, not designed for it, is rather high. Complicated build process, nonexchangeable data types, different runtimes, bad IDE support and so on. So, before each project, choose your language wisely. Will it cover most of requirements? Will it cover the most time-consuming ones? Then you won't add another language just to write isBlank but at some point it may be worth it. Will you recognize it when you reach that point? Cause when all you have is a hammer...