Tapestry 5.4.3 Demos (in progress) : Chain Of Command

In this example, we shall construct a chain of command using the Chain of command builder service from Tapestry IOC. More specifically, the chain to be constructed have two commands, arranged in an ordered sequence, and each of them tries to parse a common date in a given format.

  1. CommandA : Try to parse a given date in format yyyy MMMMM dd (eg 2006 November 12)
  2. CommandB : Try to parse a given date in format dd MMM yyyy(eg 13 Jan 2007)
We first need to create an interface for the command.

package com.man.testTapestry5.ioc.chain;

import java.util.Map;

public interface ICommand {

    /**
     *
     * @return True if operation is successful. Otherwise returns false.
     */
    public boolean execute(Map<String,Object>context);

}


In our example, each implementation of ICommand.java will be a subclass of AbstractCommand.java.
package com.man.testTapestry5.ioc.chain;

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

import org.apache.log4j.Logger;

public abstract class AbstractCommand implements ICommand {
    private final static Logger log = Logger.getLogger(AbstractCommand.class);

        public final static  String DATE_KEY="date";

        public final static String PARSED_DATE_KEY = "ans";

        public abstract SimpleDateFormat getDateFormater();

        public boolean execute(Map<String, Object>context) {
                boolean success = true;
                String dateToBeParsed = (String) context.get(DATE_KEY);
                SimpleDateFormat sdf = getDateFormater();
                try{
                        log.info("Trying to parse " + dateToBeParsed + " with format " +
                                          sdf.toPattern());
                        Date parsedDate = sdf.parse(dateToBeParsed);
            context.put(PARSED_DATE_KEY, parsedDate);

                }
                catch (ParseException pe){
                        log.info("Parser exception :" + pe + "\n pattern=" +
                                        sdf.toPattern());
                        success = false;
                }


                return success;
        }
}

Here are the two implementations of ICommand.java as described eariler.
package com.man.testTapestry5.ioc.chain;

import java.text.SimpleDateFormat;

public class ParserCommandA extends AbstractCommand {
	   @Override
       public SimpleDateFormat getDateFormater() {
               // 2006 November 12
           SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMMMM dd");
           sdf.setLenient(false);
           return sdf;
       }
	 
}


package com.man.testTapestry5.ioc.chain;

import java.text.SimpleDateFormat;

public class ParserCommandB extends AbstractCommand {

    @Override
    public SimpleDateFormat getDateFormater() {
            // 13 Jan 2007
        SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");
        sdf.setLenient(false);
        return sdf;
    }

}

Add the following piece of java code to AppModule.java to create a chain of command, which consists of command ParserCommandA.java and ParserCommandB.java.
 
public static ICommand buildDateParsers(List<ICommand> commands,
		@InjectService("ChainBuilder")
		ChainBuilder chainBuilder) {
	return chainBuilder.build(ICommand.class, commands);
}


public static void contributeDateParsers(OrderedConfiguration<ICommandɚ configuration)
	{
	// The chain will be created from the contribution below.
	configuration.add("parser1", new ParserCommandA());
	configuration.add("parser2", new ParserCommandB());
	}    
A JUnit test to verify the chain created by the service dateParsers.
package com.man.testTapestry5.ioc.chain;

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

import junit.framework.TestCase;

import org.apache.tapestry.ioc.Registry;
import org.apache.tapestry.ioc.RegistryBuilder;

import com.man.testTapestry5.services.AppModule;

public class CommandTest extends TestCase {

	public void testChain() {

		RegistryBuilder builder = new RegistryBuilder();

		builder.add(AppModule.class);

		Registry registry = builder.build();

		registry.performRegistryStartup();

		ICommand chain = registry.getService("dateParsers", ICommand.class);

		// Failed commandA and Failed commadB
		Map<String, Object> context = new HashMap<String, Object>();
		context.put(AbstractCommand.DATE_KEY, "2006 November 40");
		boolean validDate = chain.execute(context);
		assertFalse(validDate);

		// Failed commandA and Passed commadB
		context.clear();
		context.put(AbstractCommand.DATE_KEY, "12 Jun 2008");
		validDate = chain.execute(context);
		assertTrue(validDate);
		GregorianCalendar cal = new GregorianCalendar(2008, 5, 12);
		assertEquals(cal.getTime(), context
				.get(AbstractCommand.PARSED_DATE_KEY));

		// Passed commandA
		context.clear();
		context.put(AbstractCommand.DATE_KEY, "2008 January 8");
		validDate = chain.execute(context);
		assertTrue(validDate);
		cal = new GregorianCalendar(2008, 0, 8);
		assertEquals(cal.getTime(), context
				.get(AbstractCommand.PARSED_DATE_KEY));

	}

}


To use the service dateParsers in a page .java, just inject it as a normal service.