[Tynstep-svn] r141 - in trunk/step-web-server: . src src/main src/main/java src/main/java/com src/main/java/com/tyndalehouse src/main/java/com/tyndalehouse/step src/main/java/com/tyndalehouse/step/web src/main/java/com/tyndalehouse/step/web/server src/main/java/com/tyndalehouse/step/web/server/common src/main/java/com/tyndalehouse/step/web/server/db src/main/java/com/tyndalehouse/step/web/server/db/framework src/main/java/com/tyndalehouse/step/web/server/db/timeline src/main/java/com/tyndalehouse/step/web/server/guice src/main/java/com/tyndalehouse/step/web/server/handler src/main/java/com/tyndalehouse/step/web/server/handler/util src/main/java/com/tyndalehouse/step/web/server/handler/util/passage src/main/java/com/tyndalehouse/step/web/server/jsword src/main/java/com/tyndalehouse/step/web/server/jsword/com src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/web src/test src/test/java src/test/java/com src/test/java/com/tyndalehouse src/test/java/com/tyndalehouse/step src/test/java/com/tyndalehouse/step/web src/test/java/com/tyndalehouse/step/web/server src/test/java/com/tyndalehouse/step/web/server/db src/test/java/com/tyndalehouse/step/web/server/db/helper src/test/java/com/tyndalehouse/step/web/server/handlers src/test/resources src/test/resources/com src/test/resources/com/tyndalehouse src/test/resources/com/tyndalehouse/step src/test/resources/com/tyndalehouse/step/web src/test/resources/com/tyndalehouse/step/web/server src/test/resources/com/tyndalehouse/step/web/server/db src/test/resources/com/tyndalehouse/step/web/server/db/queries src/test/resources/com/tyndalehouse/step/web/server/db/queries/tests

ChrisBurrell at crosswire.org ChrisBurrell at crosswire.org
Fri Jun 25 13:30:48 MST 2010


Author: ChrisBurrell
Date: 2010-06-25 13:30:48 -0700 (Fri, 25 Jun 2010)
New Revision: 141

Added:
   trunk/step-web-server/pom.xml
   trunk/step-web-server/src/
   trunk/step-web-server/src/main/
   trunk/step-web-server/src/main/java/
   trunk/step-web-server/src/main/java/com/
   trunk/step-web-server/src/main/java/com/tyndalehouse/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/util/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/com/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/web/
   trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/web/server/
   trunk/step-web-server/src/test/
   trunk/step-web-server/src/test/java/
   trunk/step-web-server/src/test/java/com/
   trunk/step-web-server/src/test/java/com/tyndalehouse/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/StepQueryRunnerImplTest.java
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestProcessor.java
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestQueryImpl.java
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetCurrentBibleTextHandlerTest.java
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetDictionaryDefinitionHandlerTest.java
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetTimelineUISetupHandlerTest.java
   trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/JSwordInstallTest.java
   trunk/step-web-server/src/test/resources/
   trunk/step-web-server/src/test/resources/com/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/queries/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/queries/tests/
   trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/queries/tests/test_query_params_different_types.sql
Log:
creation of server side code for web-server

Added: trunk/step-web-server/pom.xml
===================================================================
--- trunk/step-web-server/pom.xml	                        (rev 0)
+++ trunk/step-web-server/pom.xml	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,156 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<parent>
+		<groupId>com.tyndalehouse</groupId>
+		<artifactId>step-parent</artifactId>
+		<version>0.1-SNAPSHOT</version>
+		<relativePath>..</relativePath>
+	</parent>
+
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>com.tyndalehouse</groupId>
+	<artifactId>step-web-server</artifactId>
+	<packaging>jar</packaging>
+	<name>step-web-server</name>
+
+
+	<dependencies>
+		<dependency>
+			<groupId>com.tyndalehouse</groupId>
+			<artifactId>step-web-shared</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+
+
+		<dependency>
+			<groupId>org.crosswire</groupId>
+			<artifactId>jsword</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.google.gwt</groupId>
+			<artifactId>gwt-servlet</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.google.gwt</groupId>
+			<artifactId>gwt-user</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>com.google.inject</groupId>
+			<artifactId>guice</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.google.inject.extensions
+			</groupId>
+			<artifactId>guice-servlet</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>net.customware.gwt.dispatch</groupId>
+			<artifactId>gwt-dispatch</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-logging</groupId>
+			<artifactId>commons-logging</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-dbcp</groupId>
+			<artifactId>commons-dbcp</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.jmock</groupId>
+			<artifactId>jmock</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.jmock</groupId>
+			<artifactId>jmock-junit4</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.derby</groupId>
+			<artifactId>derbyclient</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.derby</groupId>
+			<artifactId>derby</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<version>2.5</version>
+				<configuration>
+					<systemPropertyVariables>
+						<db.driver>${db.driver}</db.driver>
+						<connection.string>${db.connection.string}</connection.string>
+						<step.proxy.host>${step.http.proxy}</step.proxy.host>
+						<step.proxy.port>{step.http.port}</step.proxy.port>
+					</systemPropertyVariables>
+					<includes>
+						<include>**/*Test.java</include>
+					</includes>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>cobertura-maven-plugin</artifactId>
+				<version>2.3</version>
+				<configuration>
+					<check>
+						<branchRate>85</branchRate>
+						<lineRate>85</lineRate>
+						<haltOnFailure>false</haltOnFailure>
+						<totalBranchRate>60</totalBranchRate>
+						<totalLineRate>60</totalLineRate>
+						<packageLineRate>60</packageLineRate>
+						<packageBranchRate>60</packageBranchRate>
+						<!--
+							<regexes> <regex>
+							<pattern>com.example.reallyimportant.*</pattern>
+							<branchRate>90</branchRate> <lineRate>80</lineRate> </regex>
+							<regex> <pattern>com.example.boringcode.*</pattern>
+							<branchRate>40</branchRate> <lineRate>30</lineRate> </regex>
+							</regexes>
+						-->
+					</check>
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>clean</goal>
+							<goal>check</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+
+
+		</plugins>
+	</build>
+</project>

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,45 @@
+package com.tyndalehouse.step.web.server.common;
+
+import java.lang.reflect.ParameterizedType;
+
+import net.customware.gwt.dispatch.server.ActionHandler;
+import net.customware.gwt.dispatch.shared.Action;
+import net.customware.gwt.dispatch.shared.Result;
+
+import org.apache.log4j.Logger;
+
+/**
+ * To abstract away the need for declaring getActionType every time.
+ * 
+ * @author CJBurrell
+ * 
+ * @param <A>
+ *            the action in question
+ * @param <R>
+ *            the response to be sent back to the client
+ */
+public abstract class AbstractStepHandler<A extends Action<R>, R extends Result> implements ActionHandler<A, R> {
+
+    /**
+     * Logger for a particular instance of a handler
+     */
+    private final Logger logger = Logger.getLogger(this.getClass());
+
+    @SuppressWarnings("unchecked")
+    /*
+     * returns the type of the action
+     * 
+     * @return the type of the action
+     */
+    public final Class<A> getActionType() {
+        final ParameterizedType pt = (ParameterizedType) getClass().getGenericSuperclass();
+        return (Class<A>) pt.getActualTypeArguments()[0];
+    }
+
+    /**
+     * @return the logger
+     */
+    protected final Logger getLogger() {
+        return logger;
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,28 @@
+package com.tyndalehouse.step.web.server.common;
+
+/**
+ * an exceptoin to indicate that the configuration properties have not been
+ * loaded
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class ConfigNotLoadedException extends Exception {
+
+    /**
+     * serial id for serialization
+     */
+    private static final long serialVersionUID = 1644291687028980017L;
+
+    /**
+     * public constructor an exceptoin to indicate that the configuration
+     * properties have not been loaded
+     * 
+     * @param e
+     *            the base exception
+     */
+    public ConfigNotLoadedException(final Exception e) {
+        super("The configuration files could not be loaded", e);
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,99 @@
+package com.tyndalehouse.step.web.server.common;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+/**
+ * Config Provider for Step. TODO: Possibly should be rewritten to have a Guice
+ * element to it, with @Singleton tag
+ * 
+ * @author CJBurrell
+ * 
+ */
+public final class ConfigProvider {
+    /**
+     * internal static provider
+     */
+    private static ConfigProvider pr;
+
+    /**
+     * Internal properties object
+     */
+    private final Properties p = new Properties();
+
+    /**
+     * private constructor to prevent initialisation.
+     * 
+     * @throws ConfigNotLoadedException
+     *             exception should it fail to look up the parameter name
+     */
+    private ConfigProvider() throws ConfigNotLoadedException {
+        load();
+    }
+
+    /**
+     * Loads or reloads a properties file from the classpath. TODO: investigate
+     * issue with concurrency here, since we might access p before it's fully
+     * loaded...
+     * 
+     * @throws ConfigNotLoadedException
+     *             exception should it fail to look up the parameter name
+     */
+    public void load() throws ConfigNotLoadedException {
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        final URL url = loader.getResource("com/tyndalehouse/step/web/server/config/environment.properties");
+        try {
+            p.load(url.openStream());
+        } catch (final IOException e) {
+            throw new ConfigNotLoadedException(e);
+        }
+    }
+
+    /**
+     * Gets the value of a param.
+     * 
+     * @param name
+     *            the name of the param
+     * @return the value of the param
+     * @throws ConfigNotLoadedException
+     *             A problem occured during loading of the config
+     */
+    public synchronized static String get(final String name) throws ConfigNotLoadedException {
+        if (ConfigProvider.pr == null) {
+            ConfigProvider.pr = new ConfigProvider();
+        }
+
+        String value = System.getProperty(name);
+        if (value == null) {
+            value = ConfigProvider.pr.readProperty(name);
+        }
+
+        return value;
+
+    }
+
+    /**
+     * reads a property on the properties object.
+     * 
+     * @param name
+     *            name of the property
+     * @return the value
+     */
+    private String readProperty(final String name) {
+        return p.getProperty(name);
+    }
+
+    /**
+     * returns an integer corresponding to the name of the parameter.
+     * 
+     * @param paramName
+     *            the name of the parameter
+     * @return an integer value for paramName
+     * @throws ConfigNotLoadedException
+     *             exception should it fail to look up the parameter name
+     */
+    public static int getInt(final String paramName) throws ConfigNotLoadedException {
+        return Integer.parseInt(get(paramName));
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,53 @@
+package com.tyndalehouse.step.web.server.common;
+
+/**
+ * Constants to map back to the correct JSword modules, index entries
+ * 
+ * @author CJBurrell
+ * 
+ */
+public final class JSwordConstants {
+    /**
+     * the pattern with which strong references in OSIS start
+     */
+    public static final String STRONG_PATTERN_START = "strong:";
+
+    /**
+     * a greek marker for strong numbers, e.g. strong:Gxxxx
+     */
+    public static final char STRONG_GREEK_MARKER = 'G';
+
+    /**
+     * Strong hebrew marker, for e.g. strong:Hxxxx
+     */
+    public static final char STRONG_HEBREW_MARKER = 'H';
+
+    /**
+     * Initials of default Hebrew JSword module to use for lookup of dictionary
+     * definitions
+     */
+    public static final String STRONG_HEBREW_DICTIONARY_INITIALS = "StrongsHebrew";
+
+    /**
+     * Initials of default Strong JSword greek dictionary module for lookup of
+     * dictionary definitions
+     */
+    public static final String STRONG_GREEK_DICTIONARY_INITIALS = "StrongsGreek";
+
+    /**
+     * Default hebrew text for interlinear purposes
+     */
+    public static final String DEFAULT_HEBREW_INTERLINEAR_TEXT = "LXX";
+
+    // TODO:This gives us greek!
+    /**
+     * Default Greek text for interlinear purposes
+     */
+    public static final String DEFAULT_GREEK_INTERLINEAR_TEXT = "BYZ";
+
+    /**
+     * hiding default constructor
+     */
+    private JSwordConstants() {
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,47 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * Query to be thrown if the query file cannot be parsed by our framework.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class MalformedStepQueryException extends Exception {
+
+    /**
+     * serial id
+     */
+    private static final long serialVersionUID = -3607780460262284122L;
+
+    /**
+     * to instantiate the exception when a particular parameter name is
+     * incorrect
+     * 
+     * @param paramName
+     *            parameter name that is incorrect
+     * @param sql
+     *            sql in which parameter name was incorrect
+     */
+    public MalformedStepQueryException(final String paramName, final String sql) {
+        super(String.format("The argument %s was not recognised in query:\n %s", paramName, sql));
+    }
+
+    /**
+     * @param message
+     *            the message
+     * @param ex
+     *            base exception to be passed up to the super class
+     */
+    public MalformedStepQueryException(final String message, final Exception ex) {
+        super(message, ex);
+    }
+
+    /**
+     * 
+     * @param message
+     *            simple message to instantiate the default exception
+     */
+    public MalformedStepQueryException(final String message) {
+        super(message);
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,21 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * The interface for any enum describing the queries to be run
+ * 
+ * @author CJBurrell
+ * 
+ */
+public interface Query {
+    /**
+     * @return the component name
+     */
+    String getComponent();
+
+    /**
+     * returns the name of the enum
+     * 
+     * @return the name of the query
+     */
+    String name();
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,51 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * List of queries to be executed against DB
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum QueryImpl implements Query {
+    /**
+     * gets events for a particular date range
+     */
+    GET_EVENTS_FOR_DATE_RANGE("timeline"),
+
+    /**
+     * gets timeline description data
+     */
+    GET_TIMELINE_SETUP_DATA("timeline"),
+
+    /**
+     * looks up which is the closest event, and on which timeline a given
+     * scripture passage is
+     */
+    LOOKUP_TIMELINE_ORIGIN("timeline");
+
+    /**
+     * component (folder) in which the component can be found
+     */
+    private final String component;
+
+    /**
+     * default constructor for this enum
+     * 
+     * @param component
+     *            component/folder where the query resides
+     */
+    QueryImpl(final String component) {
+        this.component = component;
+    }
+
+    /**
+     * (non-Javadoc)
+     * 
+     * @see com.tyndalehouse.step.web.server.db.framework.Query#getComponent()
+     * @return component/folder where the query resides
+     */
+    public String getComponent() {
+        return component;
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,47 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+
+/**
+ * @author CJBurrell This is used by the query runner to process result sets
+ * @param <T>
+ *            the type of bean to be returned
+ */
+public interface ResultSetProcessor<T> {
+    /**
+     * returns the parameters. Typically this would only be called by the query
+     * framework
+     * 
+     * @return a map, mapping the parameter name to the object to be passed into
+     *         the query (generally native types or Strings)
+     */
+    Map<String, Object> getParameters();
+
+    /**
+     * Returns the enum defining which query should be executed.
+     * 
+     * @return the query to be executed.
+     */
+    Query getQuery();
+
+    /**
+     * This method will be called after a query has been run by the query
+     * framework. It returns a list of beans to the caller
+     * 
+     * @param rs
+     *            ResultSet to be processed
+     * @return a list of beans to the UI of type T
+     * @throws MalformedStepQueryException
+     *             the query run was malformed
+     * @throws ConfigNotLoadedException
+     *             an error occured during the loading of the database config
+     * @throws SQLException
+     *             a SQL exception occurred
+     */
+    List<T> process(ResultSet rs) throws MalformedStepQueryException, ConfigNotLoadedException, SQLException;
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,170 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Step Query to be executed against the database. This this is then given to
+ * the StepQueryRunner and executed It contains the list of arguments, the types
+ * of those parameters and the sql statement to be executed
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class StepQuery {
+    /**
+     * list of expected arguments
+     */
+    private final List<String> arguments;
+
+    /**
+     * the types of the expected parameters
+     */
+    private final Map<String, Integer> paramTypes;
+
+    /**
+     * the SQL statements
+     */
+    private String sql;
+
+    /**
+     * public constructor which initialises the arguments and parameters.
+     */
+    public StepQuery() {
+        arguments = new ArrayList<String>();
+        paramTypes = new HashMap<String, Integer>();
+    }
+
+    /**
+     * adding an argument as found in the query definition: e.g. <code>
+	 * select 1 from table where value = #paramName#
+	 * </code>
+     * 
+     * @param paramName
+     *            param name to be added to the query definition
+     * 
+     */
+    public void addArgument(final String paramName) {
+        arguments.add(paramName);
+    }
+
+    /**
+     * addings a mapping from the definitions at the top of the file
+     * 
+     * @param paramName
+     *            parameter name
+     * @param type
+     *            type of the parameter
+     */
+    public void addParamTypeMapping(final String paramName, final Integer type) {
+        paramTypes.put(paramName, type);
+    }
+
+    /**
+     * returns the SQL that gets executed
+     * 
+     * @return the SQL query
+     */
+    public String getSQLText() {
+        return sql;
+    }
+
+    /**
+     * Sets the sql for the step query to be run
+     * 
+     * @param sql
+     *            sql representing the query to be run
+     */
+    public void setSQLText(final String sql) {
+        this.sql = sql;
+    }
+
+    /**
+     * Sets up the prepared statement arguments in the correct order.
+     * 
+     * @param ps
+     *            the prepared statement
+     * @param passedArguments
+     *            the map of named arguments
+     * @throws SQLException
+     *             this is thrown if the passed in arguments do not match the
+     *             expected parameters as loaded from disk
+     * 
+     */
+    public void setupParameters(final PreparedStatement ps, final Map<String, Object> passedArguments)
+            throws SQLException {
+        int argIndex = 1;
+        for (final String argName : arguments) {
+            setArgument(ps, paramTypes.get(argName), passedArguments.get(argName), argIndex++);
+        }
+    }
+
+    /**
+     * Validates the query loaded, to ensure that the number of arguments found
+     * in the query match the number of arguments found in the declarations
+     * 
+     * @throws MalformedStepQueryException
+     *             this is thrown if the validation fails
+     */
+    public void validate() throws MalformedStepQueryException {
+        for (final String arg : arguments) {
+            if (!paramTypes.containsKey(arg)) {
+                throw new MalformedStepQueryException(arg, sql);
+            }
+        }
+
+        // TODO: optimize by compiling prepared statement here!
+    }
+
+    /**
+     * Sets up the parameter into the prepared statement
+     * 
+     * @param ps
+     *            prepared statement
+     * @param sqlType
+     *            the type of the parameter
+     * @param value
+     *            the value of the parameter
+     * @param argIndex
+     *            the position at which the parameter is to be placed in the
+     *            prepared statement
+     * @throws SQLException
+     *             an exception thrown in case something goes wrong
+     */
+    private void setArgument(final PreparedStatement ps, final int sqlType, final Object value, final int argIndex)
+            throws SQLException {
+        // check for null first
+        if (value == null) {
+            ps.setNull(argIndex, sqlType);
+            return;
+        }
+
+        // at this stage, we do not need to worry about null variables
+        switch (sqlType) {
+            case Types.INTEGER:
+                ps.setInt(argIndex, (Integer) value);
+                break;
+            case Types.VARCHAR:
+                ps.setString(argIndex, (String) value);
+                break;
+            case Types.BIGINT:
+                ps.setLong(argIndex, (Long) value);
+                break;
+            case Types.SMALLINT:
+                ps.setShort(argIndex, (Short) value);
+                break;
+            case Types.LONGVARCHAR:
+                ps.setString(argIndex, (String) value);
+                break;
+            default:
+                throw new SQLException(String.format(
+                        "The STEP query framework does not yet support this type/value (%d, %s)", sqlType, value
+                                .toString()));
+        }
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,38 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.util.List;
+
+/**
+ * StepQueryRunner interface defining what should be present for the clients to
+ * use this as a library
+ * 
+ * @author CJBurrell
+ * 
+ */
+public interface StepQueryRunner {
+
+    /**
+     * Clears the cache of parsed queries that are currently in the query runner
+     */
+    void clearCache();
+
+    /**
+     * Tears down the database pool and starts it up again
+     */
+    void restartDatasourcePool();
+
+    /**
+     * To run a query in the database
+     * 
+     * @param <T>
+     *            Type of bean to be returned
+     * @param processor
+     *            Processor to be invoked: @see {@link ResultSetProcessor}
+     * @return a list of beans of type T
+     * @throws UnableToRunQueryException
+     *             if the configuration was not loaded or a sql exception during
+     *             parsing or execution of the call
+     */
+    <T> List<T> run(final ResultSetProcessor<T> processor) throws UnableToRunQueryException;
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,363 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.common.ConfigProvider;
+
+/**
+ * This class is the crux of the database access. An enum identifies the SQL
+ * file to be loaded. Arguments get defined in the query file as define
+ * variableName as sqlType A map can be passed in that ensures all arguments are
+ * mapped to the correct location in the prepared statement
+ * 
+ * @author CJBurrell
+ */
+ at Singleton
+public class StepQueryRunnerImpl implements StepQueryRunner {
+    /**
+     * query to indicate whether to cache prepared statements. Currently doesn't
+     * work well with Apache Derby
+     */
+    private static final Object CACHE_QUERY_PROPERTY = "query.runner.cache";
+
+    /**
+     * Datasource object which gets loaded through a conection pool
+     */
+    private static DataSource datasource = null;
+
+    /**
+     * pattern definition of a declaration of argument at the top of a SQL file
+     */
+    private static final String DEFINITION_PATTERN = "define (\\w+) as (\\w+)";
+
+    /**
+     * the HASH character
+     */
+    private static final String HASH = "#";
+
+    /**
+     * the hashmap containing the cache of all queries
+     */
+    private static HashMap<Query, StepQuery> queries = new HashMap<Query, StepQuery>();
+
+    /**
+     * the ?, QUESTION MARK character
+     */
+    private static final String QUESTION_MARK = "?";
+
+    /**
+     * a pointer to the Log4J log
+     */
+    private final Log log;
+
+    /**
+     * prevent instantiation
+     * 
+     * @param log
+     *            default logger to use throughout implementation
+     */
+    @Inject
+    public StepQueryRunnerImpl(final Log log) {
+        this.log = log;
+    }
+
+    public void clearCache() {
+        StepQueryRunnerImpl.queries.clear();
+    }
+
+    public void restartDatasourcePool() {
+        // TODO: feature is to kill off all connections, and reload it.
+
+    }
+
+    /**
+     * returns a list of beans of type T
+     * 
+     * @param processor
+     *            processor to be used
+     * @param <T>
+     *            the type of the bean to be returned
+     * @return list of beans of type T
+     * @throws UnableToRunQueryException
+     *             unable to run the query for various reasons
+     * @see com.tyndalehouse.step.web.server.db.StepQueryRunner#run(com.tyndalehouse
+     *      .step.web.server.db.ResultSetProcessor)
+     */
+    public <T> List<T> run(final ResultSetProcessor<T> processor) throws UnableToRunQueryException {
+        ResultSet rs;
+        Connection connection = null;
+        PreparedStatement ps = null;
+
+        // check for null
+        if (processor == null) {
+            log.error("The passed in ResultSetProcessor was null.");
+            throw new UnableToRunQueryException(new NullPointerException());
+        }
+
+        final long tInit = System.currentTimeMillis();
+        StepQuery stepQuery = null;
+        try {
+            stepQuery = prepareStepQuery(processor.getQuery());
+
+            final long tAfterLoad = System.currentTimeMillis();
+            connection = StepQueryRunnerImpl.datasource.getConnection();
+            ps = connection.prepareStatement(stepQuery.getSQLText());
+
+            final long tAfterParse = System.currentTimeMillis();
+            stepQuery.setupParameters(ps, processor.getParameters());
+
+            logStepQuery(processor, stepQuery);
+            final long tAfterLog = System.currentTimeMillis();
+
+            // TODO: not returning anything!
+            rs = ps.executeQuery();
+            final long tAfterExecute = System.currentTimeMillis();
+
+            final List<T> results = processor.process(rs);
+            final long tAfterParseResults = System.currentTimeMillis();
+
+            if (log.isInfoEnabled()) {
+                log.info(String.format("StepQueryRunner (load, parse, execute, return) = (%d, %d, %d, %d)", tAfterLoad
+                        - tInit, tAfterParse - tAfterLoad, tAfterExecute - tAfterLog, tAfterParseResults
+                        - tAfterExecute));
+            }
+
+            return results;
+        } catch (final ConfigNotLoadedException e) {
+            log.error("Unable to load the configuration file to set up datasource.");
+            throw new UnableToRunQueryException(e, stepQuery);
+        } catch (final MalformedStepQueryException e) {
+            log.error("An exception occured during the execution of the sql query");
+            throw new UnableToRunQueryException(e, stepQuery);
+        } catch (final SQLException e) {
+            log.error("An exception occured file trying to locate the file.");
+            throw new UnableToRunQueryException(e, stepQuery);
+        } finally {
+            // close the statement
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (final SQLException exception) {
+                    log.error("Error finalising connection", exception);
+                }
+            }
+
+            // close the connection
+            if (connection != null) {
+                try {
+                    connection.close();
+                } catch (final SQLException exception) {
+                    log.error("Error finalising connection", exception);
+                }
+            }
+        }
+    }
+
+    /**
+     * if logging is enabled at trace level, then the query is output, with all
+     * its parameters
+     * 
+     * @param processor
+     *            processor to process results of the query, which contains the
+     *            parameters
+     * @param stepQuery
+     *            the query to be logged
+     */
+    private void logStepQuery(final ResultSetProcessor<?> processor, final StepQuery stepQuery) {
+        if (log.isTraceEnabled()) {
+            final StringBuffer logOutput = new StringBuffer();
+            logOutput.append("Query is: ");
+            logOutput.append(stepQuery.getSQLText());
+
+            for (final String paramName : processor.getParameters().keySet()) {
+                logOutput.append(' ');
+                logOutput.append(paramName);
+                logOutput.append('=');
+                logOutput.append(processor.getParameters().get(paramName));
+                logOutput.append(", ");
+            }
+            log.trace(logOutput.toString());
+        }
+    }
+
+    /**
+     * Faster than a regexp, so use this , in which we expect that there are
+     * arguments to be parsed These would be defined as #query-param# within the
+     * sql text. The function works by looking for a open and then a closed #
+     * Unfortunately, it is not perfect and will have TODO; be rewritten to
+     * ensure that the programmer can use the charact # in his query
+     * 
+     * @param q
+     *            is the query
+     * @return a object of type {@link StepQuery}
+     */
+    private StepQuery parseArguments(final StringBuffer q) {
+        final StepQuery query = new StepQuery();
+
+        int openingHash = 0;
+        while ((openingHash = q.indexOf(StepQueryRunnerImpl.HASH)) != -1) {
+            final int endingHash = q.indexOf(StepQueryRunnerImpl.HASH, openingHash + 1);
+            final String paramName = q.substring(openingHash + 1, endingHash);
+            query.addArgument(paramName);
+            q.replace(openingHash, endingHash + 1, StepQueryRunnerImpl.QUESTION_MARK);
+        }
+
+        return query;
+    }
+
+    /**
+     * Look for all lines containing the pattern define variable_name as type
+     * Then removes those into a map before continuing
+     * 
+     * @param queryText
+     *            sql text as loaded from disk
+     * @param q
+     *            query text to look through
+     * @return a object of type {@link StepQuery}
+     * @throws MalformedStepQueryException
+     *             an exception is thrown to indicate an
+     */
+    private StepQuery parseDefinitions(final StringBuffer queryText, final StepQuery q)
+            throws MalformedStepQueryException {
+        // all sql files with parameters will have definitions for their
+        // parameters at the top.
+        final Pattern p = Pattern.compile(StepQueryRunnerImpl.DEFINITION_PATTERN);
+        final Matcher m = p.matcher(queryText);
+
+        // iterate through definitions that have been found
+        while (m.find()) {
+            final String paramName = m.group(1);
+            final String paramType = m.group(2);
+
+            try {
+                final Integer type = Types.class.getField(paramType.toUpperCase()).getInt(null);
+                q.addParamTypeMapping(paramName, type);
+            } catch (final IllegalArgumentException e) {
+                throw new MalformedStepQueryException(String.format("Could not parse argument type: %s", paramType), e);
+            } catch (final SecurityException e) {
+                throw new MalformedStepQueryException(String.format("Could not parse argument type: %s", paramType), e);
+            } catch (final IllegalAccessException e) {
+                throw new MalformedStepQueryException(String.format("Could not parse argument type: %s", paramType), e);
+            } catch (final NoSuchFieldException e) {
+                throw new MalformedStepQueryException(String.format("Could not parse argument type: %s", paramType), e);
+            }
+        }
+
+        q.setSQLText(m.replaceAll(""));
+        return q;
+    }
+
+    /**
+     * @param query
+     *            query to be executed. If already cached, then this query is
+     *            returned otherwise, it is loaded from disk
+     * @return a object of type {@link StepQuery}
+     * @throws ConfigNotLoadedException
+     *             if an issue occured during loading of the configuration for
+     *             STEP
+     * @throws MalformedStepQueryException
+     *             an exception is thrown to indicate an issue with the sql file
+     *             that could not be parsed
+     */
+    private StepQuery prepareStepQuery(final Query query) throws ConfigNotLoadedException, MalformedStepQueryException {
+        StepQuery stepQuery = StepQueryRunnerImpl.queries.get(query);
+        // check whether query is in cache
+        if (stepQuery == null) {
+            stepQuery = readQueryFromFile(query);
+        }
+
+        // now check if datasource is null
+        if (StepQueryRunnerImpl.datasource == null) {
+            StepQueryRunnerImpl.datasource = setupDatasource();
+        }
+        return stepQuery;
+    }
+
+    /**
+     * Reads a query from the file
+     * 
+     * @param query
+     *            query to be loaded
+     * @return returns a loaded {@link StepQuery} object
+     * @throws ConfigNotLoadedException
+     *             failed to load the configuration
+     * @throws MalformedStepQueryException
+     *             thrown if arguments found don't match a declaration
+     */
+    private StepQuery readQueryFromFile(final Query query) throws ConfigNotLoadedException, MalformedStepQueryException {
+        // get base path from file
+        final String basePath = ConfigProvider.get("query.repository.path");
+        final String baseComponent = query.getComponent();
+        final String filenameBase = query.name();
+
+        // read query from file
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        final String filename = String.format("%s%s/%s.sql", basePath, baseComponent, filenameBase.toLowerCase());
+        final URL fileLocation = loader.getResource(filename);
+        StepQuery stepQuery = null;
+        StringBuffer q;
+
+        // check file location is non null:
+        if (fileLocation == null) {
+            throw new MalformedStepQueryException(String.format("The filename %s does not exist.", filename));
+        }
+
+        try {
+            q = new StringBuffer(FileUtils.readFileToString(new File(fileLocation.getFile())));
+            stepQuery = parseDefinitions(q, parseArguments(q));
+            stepQuery.validate();
+
+            // check whether or not to cache the query:
+            if (ConfigProvider.get("query.runner.cache").equals(StepQueryRunnerImpl.CACHE_QUERY_PROPERTY)) {
+                StepQueryRunnerImpl.queries.put(query, stepQuery);
+            }
+        } catch (final IOException e) {
+            throw new MalformedStepQueryException(String.format("Error reading query file: %s", filenameBase), e);
+        }
+
+        return stepQuery;
+    }
+
+    /**
+     * sets up the datasource from properties
+     * 
+     * @return the datasource properly configured
+     * @throws ConfigNotLoadedException
+     *             throws if properties aren't found
+     */
+    private DataSource setupDatasource() throws ConfigNotLoadedException {
+        final BasicDataSource ds = new BasicDataSource();
+        ds.setDriverClassName(ConfigProvider.get("db.driver"));
+        ds.setUsername(ConfigProvider.get("db.user"));
+        ds.setPassword(ConfigProvider.get("db.password"));
+        ds.setUrl(ConfigProvider.get("connection.string"));
+        ds.setInitialSize(ConfigProvider.getInt("db.pool.initialSize"));
+        ds.setMaxActive(ConfigProvider.getInt("db.pool.maxSize"));
+        // ds.setValidationQuery(ConfigProvider.get("db.pool.validation.query"));
+        // ds.setPoolPreparedStatements(true); //NOT Supported by java DB :(
+        ds.setMaxOpenPreparedStatements(ConfigProvider.getInt("db.pool.prepared.size"));
+        ds.setDefaultAutoCommit(false);
+
+        return ds;
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,60 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * An issue occurred during the parsing or running of a query
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class UnableToRunQueryException extends Exception {
+
+    /**
+	 * 
+	 */
+    private static final long serialVersionUID = -7810594097160119720L;
+
+    /**
+     * The StepQuery at the origin of the exception
+     */
+    private StepQuery stepQuery;
+
+    /**
+     * Pass in the root cause of the exception
+     * 
+     * @param e
+     *            the root exception
+     */
+    public UnableToRunQueryException(final Exception e) {
+        super(e);
+    }
+
+    /**
+     * Unable to run a query exception, with the stepQuery itself, and the root
+     * exception
+     * 
+     * @param e
+     *            the exception to be wrapped
+     * @param stepQuery
+     *            a step query that was attempted to be executed
+     */
+    public UnableToRunQueryException(final Exception e, final StepQuery stepQuery) {
+        this(e);
+        this.stepQuery = stepQuery;
+    }
+
+    /**
+     * @return the stepQuery
+     */
+    public final StepQuery getStepQuery() {
+        return stepQuery;
+    }
+
+    /**
+     * @param stepQuery
+     *            the stepQuery to set
+     */
+    public final void setStepQuery(final StepQuery stepQuery) {
+        this.stepQuery = stepQuery;
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,145 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.QueryImpl;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineEventBean;
+
+/**
+ * Processes a list of timebands from the database
+ * 
+ * @author CJBurrell cjburrell
+ * 
+ */
+public class TimeBandVisibleDateProcessor implements ResultSetProcessor<TimelineEventBean> {
+
+    /**
+     * event type id
+     */
+    private static final String EVENT_TYPE_ID = "event_type_id";
+    /**
+     * certainty
+     */
+    private static final String CERTAINTY = "certainty";
+    /**
+     * importance if
+     */
+    private static final String IMPORTANCE_ID = "importance_id";
+    /**
+     * timeband id
+     */
+    private static final String TIMEBAND_ID = "timeband_id";
+    /**
+     * name
+     */
+    private static final String NAME = "name";
+    /**
+     * to precision
+     */
+    private static final String TO_PRECISION = "to_precision";
+    /**
+     * from precision
+     */
+    private static final String FROM_PRECISION = "from_precision";
+    /**
+     * to date
+     */
+    private static final String TO_DATE = "to_date";
+    /**
+     * from date
+     */
+    private static final String FROM_DATE = "from_date";
+    /**
+     * event id
+     */
+    private static final String EVENT_ID = "event_id";
+    /**
+     * min date
+     */
+    private static final String MIN_DATE = "min_date";
+    /**
+     * max date
+     */
+    private static final String MAX_DATE = "max_date";
+    /**
+     * params to be passed in to the query
+     */
+    private final Map<String, Object> params;
+
+    /**
+     * public constructor to create the processor with default parameters
+     * 
+     * @param minDate
+     *            min date to be passed to the query
+     * @param maxDate
+     *            max date to be passed to the query
+     * @param timebandId
+     *            the timeband id to be looked up
+     */
+    public TimeBandVisibleDateProcessor(final long minDate, final long maxDate, final int timebandId) {
+        params = new HashMap<String, Object>();
+        params.put(TimeBandVisibleDateProcessor.MIN_DATE, minDate);
+        params.put(TimeBandVisibleDateProcessor.MAX_DATE, maxDate);
+        params.put(TimeBandVisibleDateProcessor.TIMEBAND_ID, timebandId);
+    }
+
+    /**
+     * @see {@link ResultSetProcessor}
+     * @return the map of parameters
+     */
+    public final Map<String, Object> getParameters() {
+        return params;
+    }
+
+    /**
+     * @see {@link ResultSetProcessor}
+     * @return the query to be executed
+     */
+    public final Query getQuery() {
+        return QueryImpl.GET_EVENTS_FOR_DATE_RANGE;
+    }
+
+    /**
+     * 
+     * @param rs
+     *            result set to be processed
+     * @see com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor#process(java.sql.ResultSet)
+     * @return a list of {@link TimelineEventBean} returned by the query
+     * @exception MalformedStepQueryException
+     *                an error occurred during the execution of the query
+     * @exception ConfigNotLoadedException
+     *                an error occurred during the loading of the configuration
+     * @exception SQLException
+     *                an runtime SQL exception occurred
+     */
+    public final List<TimelineEventBean> process(final ResultSet rs) throws MalformedStepQueryException,
+            ConfigNotLoadedException, SQLException {
+        // TODO: parse the event in some object, as opposed to just fields like
+        // that!
+        // in particular the precision type
+        final List<TimelineEventBean> events = new ArrayList<TimelineEventBean>();
+        while (rs.next()) {
+            final Long toDate = rs.getObject(TimeBandVisibleDateProcessor.TO_DATE) == null ? null : rs
+                    .getLong(TimeBandVisibleDateProcessor.TO_DATE);
+            final TimelineEventBean teb = new TimelineEventBean(rs.getInt(TimeBandVisibleDateProcessor.EVENT_ID), rs
+                    .getLong(TimeBandVisibleDateProcessor.FROM_DATE), toDate, rs
+                    .getString(TimeBandVisibleDateProcessor.FROM_PRECISION), rs
+                    .getString(TimeBandVisibleDateProcessor.TO_PRECISION), rs
+                    .getString(TimeBandVisibleDateProcessor.NAME), rs.getInt(TimeBandVisibleDateProcessor.TIMEBAND_ID),
+                    rs.getInt(TimeBandVisibleDateProcessor.IMPORTANCE_ID), rs
+                            .getString(TimeBandVisibleDateProcessor.CERTAINTY), rs
+                            .getInt(TimeBandVisibleDateProcessor.EVENT_TYPE_ID));
+            events.add(teb);
+        }
+        return events;
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,79 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * Timeline Origin DB Bean, containing the default configuration for each
+ * timeband
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineOriginDbBean {
+
+    /**
+     * origin in time (milli seconds since epoch)
+     */
+    private long origin;
+    /**
+     * recommended time unit to be displayed
+     */
+    private Unit unit;
+
+    /**
+     * timeband id to be looked up
+     */
+    private int timebandId;
+
+    /**
+     * @return the origin
+     */
+    public final long getOrigin() {
+        return origin;
+    }
+
+    /**
+     * @return the unit
+     */
+    public final Unit getUnit() {
+        return unit;
+    }
+
+    /**
+     * Sets the origin field
+     * 
+     * @param origin
+     *            value in ms for oring
+     */
+    public final void setOrigin(final long origin) {
+        this.origin = origin;
+    }
+
+    /**
+     * Sets the unit for the bean
+     * 
+     * @param unit
+     *            unit that should be shown on screen
+     */
+    public final void setUnit(final String unit) {
+        this.unit = Unit.valueOf(unit);
+    }
+
+    /**
+     * returns the timeband id
+     * 
+     * @return timeband id
+     */
+    public final int getTimebandId() {
+        return timebandId;
+    }
+
+    /**
+     * @param timebandId
+     *            the timebandId to set
+     */
+    public final void setTimebandId(final int timebandId) {
+        this.timebandId = timebandId;
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,79 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.QueryImpl;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+
+/**
+ * Step Processor to retrieve the origin event, given a scripture passage
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineOriginProcessor implements ResultSetProcessor<TimelineOriginDbBean> {
+    /** result column origin */
+    private static final String ORIGIN = "origin";
+
+    /** input qry end,, verse no for which to restrict the query */
+    private static final String QRY_END = "qry_end";
+
+    /** input qry start, verse no for which to restrict the query */
+    private static final String QRY_START = "qry_start";
+
+    /** result column timeband id */
+    private static final String TIMEBAND = "timeband_id";
+
+    // TODO: move to enum
+    /** result column unit */
+    private static final String UNIT = "unit";
+
+    /** parameters to pass in to the query */
+    private final Map<String, Object> params;
+
+    /**
+     * Given a scripture range, it
+     * 
+     * @param qryStart
+     *            minimum verse no to restrict range lookup
+     * @param qryEnd
+     *            maximum verse no to restrict range lookup
+     */
+    public TimelineOriginProcessor(final int qryStart, final int qryEnd) {
+        params = new HashMap<String, Object>();
+        params.put(TimelineOriginProcessor.QRY_START, qryStart);
+        params.put(TimelineOriginProcessor.QRY_END, qryEnd);
+    }
+
+    public Map<String, Object> getParameters() {
+        return params;
+
+    }
+
+    public Query getQuery() {
+        return QueryImpl.LOOKUP_TIMELINE_ORIGIN;
+    }
+
+    public List<TimelineOriginDbBean> process(final ResultSet rs) throws MalformedStepQueryException,
+            ConfigNotLoadedException, SQLException {
+        final List<TimelineOriginDbBean> origins = new ArrayList<TimelineOriginDbBean>();
+
+        while (rs.next()) {
+            final TimelineOriginDbBean bean = new TimelineOriginDbBean();
+            bean.setOrigin(rs.getLong(TimelineOriginProcessor.ORIGIN));
+            bean.setUnit(rs.getString(TimelineOriginProcessor.UNIT));
+            bean.setTimebandId(rs.getInt(TimelineOriginProcessor.TIMEBAND));
+            origins.add(bean);
+        }
+        return origins;
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,69 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.QueryImpl;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+
+/**
+ * Data processor for the Step Query framework, to parse results from the
+ * timeline setup sql query
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineSetupDataProcessor implements ResultSetProcessor<TimelineBean> {
+    /**
+     * the result column timeband_description
+     */
+    private static final String TIMEBAND_DESCRIPTION = "timeband_description";
+
+    /** the result column timeband_id */
+    private static final String TIMEBAND_ID = "timeband_id";
+
+    /** the result column timeband unit */
+    private static final String TIMEBAND_UNIT = "timeband_unit";
+
+    /** the parameters to pass in to the query */
+    private final Map<String, Object> params;
+
+    /**
+     * public constructor
+     */
+    public TimelineSetupDataProcessor() {
+        params = new HashMap<String, Object>();
+    }
+
+    public Map<String, Object> getParameters() {
+        return params;
+
+    }
+
+    public Query getQuery() {
+        return QueryImpl.GET_TIMELINE_SETUP_DATA;
+    }
+
+    public List<TimelineBean> process(final ResultSet rs) throws MalformedStepQueryException, ConfigNotLoadedException,
+            SQLException {
+        final List<TimelineBean> timelines = new ArrayList<TimelineBean>();
+
+        while (rs.next()) {
+            final TimelineBean bean = new TimelineBean();
+            bean.setTimelineId(rs.getInt(TimelineSetupDataProcessor.TIMEBAND_ID));
+            bean.setTimelineDescription(rs.getString(TimelineSetupDataProcessor.TIMEBAND_DESCRIPTION));
+            bean.setUnit(rs.getString(TimelineSetupDataProcessor.TIMEBAND_UNIT));
+            timelines.add(bean);
+        }
+        return timelines;
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,49 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import net.customware.gwt.dispatch.server.Dispatch;
+import net.customware.gwt.dispatch.server.service.DispatchServiceServlet;
+
+import org.apache.commons.logging.Log;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * Step dispatch servlet to use for the dispatchin of queries
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at Singleton
+public class CustomDispatchServiceServlet extends DispatchServiceServlet {
+
+    /**
+	 * 
+	 */
+    private static final long serialVersionUID = -6063357416925075136L;
+
+    /**
+     * default logger
+     */
+    private final Log logger;
+
+    /**
+     * normal constructor
+     * 
+     * @param dispatch
+     *            dispath object
+     * @param logger
+     *            logger to be provided
+     */
+    @Inject
+    public CustomDispatchServiceServlet(final Dispatch dispatch, final Log logger) {
+        super(dispatch);
+        this.logger = logger;
+    };
+
+    @Override
+    protected void doUnexpectedFailure(final Throwable e) {
+        logger.error("An unexpected error happened on the bridge between server and client", e);
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import com.google.inject.servlet.ServletModule;
+
+/**
+ * Servlet module for the Jetty/Tomcat server
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class DispatchServletModule extends ServletModule {
+
+    @Override
+    public void configureServlets() {
+        // NOTE: the servlet context will probably need changing
+
+        serve("/step/dispatch").with(CustomDispatchServiceServlet.class);
+    }
+
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,43 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.impl.Log4JLogger;
+
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * A Gin provider for logging purposes.
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at Singleton
+public class LogProvider implements Provider<Log> {
+    // enforce singleton to allow static methods to get to the same log
+    /**
+     * TODO: there should be a logger per class really. All appending to the
+     * same file, but so that we can turn them on and off
+     * 
+     */
+    private static Log logger = new Log4JLogger("step.jetty");
+
+    /**
+     * The static equivalent of the above, so that static contexts can log as
+     * well
+     * 
+     * @return the log to use
+     */
+    public static Log getLogger() {
+        return LogProvider.logger;
+    }
+
+    /**
+     * The instantiated log to be returned
+     * 
+     * @return the Log file to be used
+     */
+    public Log get() {
+        return LogProvider.logger;
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,19 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
+
+/**
+ * The servlet configuraiton for Guice, which creates an injector
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class MyGuiceServletConfig extends GuiceServletContextListener {
+
+    @Override
+    protected Injector getInjector() {
+        return Guice.createInjector(new ServerModule(), new DispatchServletModule());
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,37 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import net.customware.gwt.dispatch.server.guice.ActionHandlerModule;
+
+import org.apache.commons.logging.Log;
+
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunnerImpl;
+import com.tyndalehouse.step.web.server.handler.GetAvailableBibleVersionsHandler;
+import com.tyndalehouse.step.web.server.handler.GetBibleBooksHandler;
+import com.tyndalehouse.step.web.server.handler.GetCurrentBibleTextHandler;
+import com.tyndalehouse.step.web.server.handler.GetDictionaryDefinitionHandler;
+import com.tyndalehouse.step.web.server.handler.GetEventsForDateRangeHandler;
+import com.tyndalehouse.step.web.server.handler.GetTimelineOriginForScriptureHandler;
+import com.tyndalehouse.step.web.server.handler.GetTimelineUISetupHandler;
+
+/**
+ * Module which binds the handlers and configurations
+ * 
+ */
+public class ServerModule extends ActionHandlerModule {
+
+    @Override
+    protected void configureHandlers() {
+        bindHandler(GetAvailableBibleVersionsHandler.class);
+        bind(Log.class).toProvider(LogProvider.class).in(Singleton.class);
+        bindHandler(GetBibleBooksHandler.class);
+        bindHandler(GetCurrentBibleTextHandler.class);
+        bindHandler(GetEventsForDateRangeHandler.class);
+        bindHandler(GetTimelineUISetupHandler.class);
+        bindHandler(GetTimelineOriginForScriptureHandler.class);
+        bindHandler(GetDictionaryDefinitionHandler.class);
+
+        bind(StepQueryRunner.class).to(StepQueryRunnerImpl.class).in(Singleton.class);
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,72 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookCategory;
+import org.crosswire.jsword.book.Books;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.shared.command.GetAvailableBibleVersionsCommand;
+import com.tyndalehouse.step.web.shared.result.GetAvailableBibleVersionsResult;
+import com.tyndalehouse.step.web.shared.result.beans.BibleVersion;
+
+/**
+ * Command handler returning all available bible versions
+ * 
+ * @author CJBurrell TODO: add logging to this class
+ */
+public class GetAvailableBibleVersionsHandler extends
+        AbstractStepHandler<GetAvailableBibleVersionsCommand, GetAvailableBibleVersionsResult> {
+    /**
+     * Default logger
+     */
+    private final Log logger;
+
+    /**
+     * normal constructor
+     * 
+     * @param logger
+     *            provided by Gin
+     */
+    @Inject
+    public GetAvailableBibleVersionsHandler(final Log logger) {
+        this.logger = logger;
+    }
+
+    public GetAvailableBibleVersionsResult execute(final GetAvailableBibleVersionsCommand cmd,
+            final ExecutionContext arg1) throws ActionException {
+        // TODO: add handling of different types of book: bibles, commentaries,
+        // versions, etc.
+        @SuppressWarnings("unchecked")
+        final List<Book> books = Books.installed().getBooks();
+        final SortedMap<String, String> map = new TreeMap<String, String>();
+
+        final List<BibleVersion> versions = new ArrayList<BibleVersion>();
+        for (final Book b : books) {
+            if (b.getBookCategory().equals(BookCategory.BIBLE)) {
+                final BibleVersion bibleVersion = new BibleVersion();
+                bibleVersion.setInitials(b.getInitials());
+                bibleVersion.setName(b.getName());
+                bibleVersion.setLanguage(b.getLanguage().getName());
+                versions.add(bibleVersion);
+            }
+        }
+        final GetAvailableBibleVersionsResult result = new GetAvailableBibleVersionsResult();
+        result.setBibleVersions(versions);
+        return result;
+    }
+
+    public void rollback(final GetAvailableBibleVersionsCommand arg0, final GetAvailableBibleVersionsResult arg1,
+            final ExecutionContext arg2) throws ActionException {
+        logger.error("Rolling back GetAvailableBibleVersions");
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,68 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.crosswire.jsword.passage.NoSuchVerseException;
+import org.crosswire.jsword.versification.BibleInfo;
+import org.crosswire.jsword.versification.BibleNames;
+import org.crosswire.jsword.versification.BookName;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.shared.command.GetBibleBooksCommand;
+import com.tyndalehouse.step.web.shared.result.GetBibleBooksCommandResult;
+
+/**
+ * Command handler for retrieving the different names of the books in a
+ * particular version TODO: only currently works for KJV
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetBibleBooksHandler extends AbstractStepHandler<GetBibleBooksCommand, GetBibleBooksCommandResult> {
+    /**
+     * public constructor
+     */
+    @Inject
+    public GetBibleBooksHandler() {
+    }
+
+    public GetBibleBooksCommandResult execute(final GetBibleBooksCommand command, final ExecutionContext arg1)
+            throws ActionException {
+
+        getLogger().debug("GetBibleBooksCommandResult has been called...");
+
+        // TODO: on start up, we should check a whole load of things: jsword
+        // installed, database can be started, database has got data
+
+        // find selection of books and then add stuff to the suggestbox.
+        final ArrayList<String> suggestions = new ArrayList<String>();
+
+        // http://www.crosswire.org/jsword/java2html/org/crosswire/jsword/bridge/BibleScope.java.html
+        // TODO: currently based on KJV versification, when better to base it on
+        // preferred version
+        // of the bible...
+        try {
+            final int booksInBible = BibleInfo.booksInBible();
+            BookName bn;
+            final BibleNames all = new BibleNames(Locale.getDefault());
+            for (int ii = 1; ii <= booksInBible; ii++) {
+                bn = all.getName(ii);
+                suggestions.add(bn.getPreferredName());
+            }
+        } catch (final NoSuchVerseException e) {
+            getLogger().error("Failed to generate list of bible books", e);
+        }
+
+        return new GetBibleBooksCommandResult(suggestions);
+    }
+
+    public void rollback(final GetBibleBooksCommand arg0, final GetBibleBooksCommandResult arg1,
+            final ExecutionContext context) throws ActionException {
+
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,536 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.transform.TransformerException;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.lang.StringUtils;
+import org.crosswire.common.util.Reporter;
+import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+import org.crosswire.common.xml.XMLUtil;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.BookMetaData;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.book.OSISUtil;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.jdom.Attribute;
+import org.jdom.Content;
+import org.jdom.Element;
+import org.jdom.Text;
+import org.jdom.filter.Filter;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.common.JSwordConstants;
+import com.tyndalehouse.step.web.server.handler.util.passage.StrongMorphMap;
+import com.tyndalehouse.step.web.server.jsword.ConfigurableHTMLConverter;
+import com.tyndalehouse.step.web.shared.command.GetCurrentBibleTextCommand;
+import com.tyndalehouse.step.web.shared.result.GetCurrentBibleTextResult;
+import com.tyndalehouse.step.web.shared.scripture.Milestone;
+import com.tyndalehouse.step.web.shared.scripture.Note;
+import com.tyndalehouse.step.web.shared.scripture.OSISConstants;
+import com.tyndalehouse.step.web.shared.scripture.Passage;
+import com.tyndalehouse.step.web.shared.scripture.TextualElement;
+import com.tyndalehouse.step.web.shared.scripture.Title;
+import com.tyndalehouse.step.web.shared.scripture.TransChange;
+import com.tyndalehouse.step.web.shared.scripture.Verse;
+import com.tyndalehouse.step.web.shared.scripture.VerseContent;
+import com.tyndalehouse.step.web.shared.scripture.Word;
+
+/**
+ * Command handler returning a portion of scripture in different formats
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetCurrentBibleTextHandler extends
+        AbstractStepHandler<GetCurrentBibleTextCommand, GetCurrentBibleTextResult> {
+
+    /**
+     * default constructor with the getLogger
+     * 
+     */
+    @Inject
+    public GetCurrentBibleTextHandler() {
+
+    }
+
+    public GetCurrentBibleTextResult execute(final GetCurrentBibleTextCommand command, final ExecutionContext arg1)
+            throws ActionException {
+        final String version = command.getVersion();
+        final String reference = command.getReference();
+
+        // check information has been passed in
+        // TODO: ensure error handling is handled properly
+        if (StringUtils.isEmpty(version)) {
+            throw new ActionException("Version was not provided");
+        }
+        if (StringUtils.isEmpty(reference)) {
+            throw new ActionException("Reference was not provided");
+        }
+
+        final GetCurrentBibleTextResult result = new GetCurrentBibleTextResult();
+
+        final BookData data = getBookData(version, reference);
+
+        switch (command.getTypeOfLookup()) {
+            case CLASSIC_INTERLINEAR:
+                addClassicInterlinear(result.getPassage(), reference);
+                break;
+            case LOGICAL:
+                addLogicalLookup(result, data);
+                break;
+            case PLAIN_TEXT:
+                try {
+                    result.setPassageText(OSISUtil.getCanonicalText(data.getOsis()));
+                } catch (final BookException e) {
+                    throw new ActionException("Unable to get simple canonical text from book", e);
+                }
+                break;
+            case REVERSE_INTERLINEAR:
+                addLogicalLookup(result, data);
+                addReverseInterlinear(result.getPassage(), reference);
+                break;
+            case XSLT:
+                result.setXsltedText(doXslt(data));
+                break;
+            default:
+                // do nothing since nothing was requested
+                break;
+        }
+        return result;
+    }
+
+    public void rollback(final GetCurrentBibleTextCommand arg0, final GetCurrentBibleTextResult arg1,
+            final ExecutionContext arg2) throws ActionException {
+        getLogger().error("Get Current Bible Text rolling back");
+
+    }
+
+    /**
+     * does a classic interlinear and populates the Passage
+     * 
+     * @param p
+     *            the logical passage to be populated
+     * @param reference
+     *            the reference
+     */
+    private void addClassicInterlinear(final Passage p, final String reference) {
+        // TODO: feature
+        // identify the hebrew/greek version of the text, and get book data for
+        // the appropriate version
+        // final VerseRange vrf = VerseRangeFactory.fromString(reference);
+        // TODO updgrade to latest jsword version
+
+        // VerseRange.remainder(vrf, null);
+
+        // getBookData(version, reference);
+    }
+
+    /**
+     * adds a logical lookup to the result objet
+     * 
+     * @param result
+     *            the result object to populate
+     * @param data
+     *            the data to base the lookup upon
+     * @throws ActionException
+     *             an exception thrown if the parsing or lookup goes bad
+     */
+    private void addLogicalLookup(final GetCurrentBibleTextResult result, final BookData data) throws ActionException {
+        final Passage p = parseForGwt(data);
+        result.setPassage(p);
+    }
+
+    /**
+     * doing a reverse interlinear
+     * 
+     * @param translatedText
+     *            the passage as looked up in an non-original version
+     * @param reference
+     *            the reference of the text so we can add the original text onto
+     *            it
+     * @throws ActionException
+     *             action exception thrown during execution of the reverse
+     *             interlinear process
+     */
+    private void addReverseInterlinear(final Passage translatedText, final String reference) throws ActionException {
+        // first lookup passage from LXX or TODO user chosen version
+        // TODO: cope with Hebrew
+        String versionToUse;
+        StrongMorphMap strongMorphMap;
+
+        if (isGreek(translatedText)) {
+            versionToUse = JSwordConstants.DEFAULT_GREEK_INTERLINEAR_TEXT;
+        } else {
+            // assume Hebrew
+            versionToUse = JSwordConstants.DEFAULT_HEBREW_INTERLINEAR_TEXT;
+        }
+
+        // TODO: we need to do something different here,
+        // we don't need to parse through the whole lot, and probably JDom
+        // allows us to use filters to get all children of a certain kind,
+        // we want to end up with a keyed map, looking like [strong, morph?] ->
+        // word
+        try {
+            strongMorphMap = getStrongMorphMap(getBookData(versionToUse, reference));
+        } catch (final BookException e) {
+            throw new ActionException("Unable to lookup source text and parse to StrongMorphMap", e);
+        }
+
+        mergePassages(translatedText, strongMorphMap);
+    }
+
+    /**
+     * parsing a milestone into a logical element
+     * 
+     * @param verseContent
+     *            the Content on which to append the logical element
+     * @param v
+     *            the verse
+     */
+    private void doMilestone(final Element verseContent, final Verse v) {
+        final Milestone m = new Milestone();
+        m.setMarker(verseContent.getAttributeValue(OSISConstants.MARKER));
+        m.setType(verseContent.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+        v.addTextualElement(m);
+    }
+
+    /**
+     * parsing a note into a logical element
+     * 
+     * @param verseContent
+     *            the Content on which to append the logical element
+     * @param v
+     *            the verse
+     */
+    private void doNote(final Element verseContent, final Verse v) {
+        final Note n = new Note();
+        n.setType(verseContent.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+        n.setText(verseContent.getText());
+        v.addTextualElement(n);
+    }
+
+    /**
+     * parses a title
+     * 
+     * @param titleElement
+     *            the xml title element
+     * @param passage
+     *            the passage to be parsed into
+     */
+    private void doTitle(final Element titleElement, final Passage passage) {
+        final Title title = new Title();
+        title.setType(titleElement.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+        title.setText(titleElement.getText());
+        passage.addPassageElement(title);
+    }
+
+    /**
+     * parses a TransChange element
+     * 
+     * @param verseContent
+     *            the trans change element
+     * @param v
+     *            the verse to be parsed into
+     */
+    private void doTransChange(final Element verseContent, final Verse v) {
+        final TransChange t = new TransChange();
+        t.setType(verseContent.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+        t.setText(verseContent.getText());
+        v.addTextualElement(t);
+    }
+
+    /**
+     * parses a verse xml element
+     * 
+     * @param e
+     *            the verse element
+     * @param passage
+     *            the passage to be parsed into
+     */
+    private void doVerse(final Element e, final Passage passage) {
+        final List<Content> verseWords = e.getContent();
+        final Verse v = new Verse();
+        v.setOsisID(e.getAttributeValue(OSISUtil.OSIS_ATTR_OSISID));
+        passage.addPassageElement(v);
+
+        for (final Content c : verseWords) {
+            if (c instanceof Element) {
+                final Element verseContent = (Element) c;
+                final String tagName = verseContent.getName();
+                if (tagName.equals(OSISUtil.OSIS_ELEMENT_W)) {
+                    doWord(verseContent, v);
+                } else if (tagName.equals(OSISUtil.OSIS_ELEMENT_NOTE)) {
+                    doNote(verseContent, v);
+                } else if (tagName.equals(OSISConstants.MILESTONE)) {
+                    doMilestone(verseContent, v);
+                } else if (tagName.equals(OSISConstants.TRANS_CHANGE)) {
+                    doTransChange(verseContent, v);
+                } else {
+                    getLogger().warn(String.format("Unexpected element %s", tagName));
+                }
+            } else if (c instanceof Text) {
+                final Text textElement = (Text) c;
+                final com.tyndalehouse.step.web.shared.scripture.Text t = new com.tyndalehouse.step.web.shared.scripture.Text(
+                        textElement.getText());
+                v.addTextualElement(t);
+            } else {
+                // we're in trouble
+                getLogger().warn("Content c is not recognised: " + c.getClass().getCanonicalName());
+            }
+        }
+    }
+
+    /**
+     * processes a word from the bible text passed in as XML
+     * 
+     * @param verseContent
+     *            verseContent in XML
+     * @param v
+     *            the object version of this word
+     */
+    private void doWord(final Element verseContent, final Verse v) {
+        final Word w = new Word();
+
+        final String lemmas = verseContent.getAttributeValue(OSISUtil.ATTRIBUTE_W_LEMMA);
+        final String morphs = verseContent.getAttributeValue(OSISUtil.ATTRIBUTE_W_MORPH);
+
+        // TODO: make a constant
+        if (lemmas != null) {
+            w.addLemmas(lemmas.split(" "));
+        }
+        if (morphs != null) {
+            w.addMorphs(morphs.split(" "));
+        }
+        w.setText(verseContent.getText());
+        v.addTextualElement(w);
+    }
+
+    /**
+     * does an xslt transformation on some OSIS text
+     * 
+     * @param data
+     *            data of the book to use and the key in the book.
+     * @return the passage xslted version
+     */
+    private String doXslt(final BookData data) {
+        if (data == null) {
+            return "";
+        }
+
+        // Make sure Hebrew displays from Right to Left
+        final BookMetaData bmd = data.getFirstBook().getBookMetaData();
+        if (bmd == null) {
+            return "";
+        }
+
+        try {
+            final SAXEventProvider osissep = data.getSAXEventProvider();
+
+            final TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) new ConfigurableHTMLConverter()
+                    .convert(osissep);
+            final String text = XMLUtil.writeToString(htmlsep);
+            return text;
+        } catch (final SAXException e) {
+            Reporter.informUser(this, e);
+        } catch (final BookException e) {
+            Reporter.informUser(this, e);
+        } catch (final TransformerException e) {
+            Reporter.informUser(this, e);
+        }
+        return "";
+    }
+
+    /**
+     * returns the book data using the JSword API
+     * 
+     * @param version
+     *            version to be looked up
+     * @param reference
+     *            reference of the passage
+     * @return the JSword BookData object
+     * @throws ActionException
+     *             an exception should an problem happen
+     */
+    private BookData getBookData(final String version, final String reference) throws ActionException {
+        try {
+            final Book currentBook = Books.installed().getBook(version);
+            final BookData data = new BookData(currentBook, currentBook.getKey(reference));
+            return data;
+        } catch (final NoSuchKeyException e) {
+            getLogger().error("An error occurred looking up the passage", e);
+            throw new ActionException(e);
+        }
+    }
+
+    /**
+     * given a book data (referencing a biblical reference + a book), retrieves
+     * the morphs and the Strong numbers (lemmas) in the passage to help in the
+     * interlinear processing
+     * 
+     * @param bookData
+     *            the bookData from JSword specialised for the reference and
+     *            bible book
+     * @return a map of strong numbers and morphs
+     * @throws BookException
+     *             an exception occuring during parsing of the OSIS XML
+     */
+    @SuppressWarnings("unchecked")
+    private StrongMorphMap getStrongMorphMap(final BookData bookData) throws BookException {
+        final Element osis = bookData.getOsisFragment();
+        final StrongMorphMap strongMorphMap = new StrongMorphMap();
+        final Iterator<Element> it = osis.getDescendants(new Filter() {
+            /**
+             * serial id
+             */
+            private static final long serialVersionUID = 4171956787222841308L;
+
+            public boolean matches(final Object obj) {
+                return obj instanceof Element && ((Element) obj).getName().equals(OSISUtil.OSIS_ELEMENT_W);
+            }
+
+        });
+
+        while (it.hasNext()) {
+            final Element word = it.next();
+            final Attribute lemmaAttribute = word.getAttribute(OSISUtil.ATTRIBUTE_W_LEMMA);
+            final Attribute morphAttribute = word.getAttribute(OSISUtil.ATTRIBUTE_W_MORPH);
+
+            if (lemmaAttribute != null) {
+                if (morphAttribute != null) {
+                    strongMorphMap.addWord(lemmaAttribute.getValue(), morphAttribute.getValue(), word.getValue());
+                } else {
+                    strongMorphMap.addWord(lemmaAttribute.getValue(), word.getValue());
+                }
+            }
+        }
+
+        return strongMorphMap;
+    }
+
+    /**
+     * Look at the first word with a lemma and return lemma[0] == 'G'
+     * 
+     * @param p
+     *            passage to be looked up
+     * @return true if the word with the first lemma is in Greek
+     */
+    private boolean isGreek(final Passage p) {
+        for (final VerseContent vc : p.getVerseContent()) {
+            if (vc instanceof Verse) {
+                final Verse v = (Verse) vc;
+                for (final TextualElement te : v.getVerseContent()) {
+                    if (te instanceof Word) {
+                        final Word w = (Word) te;
+                        if (w.getLemma() != null) {
+                            return w.getLemma().get(0).charAt(JSwordConstants.STRONG_PATTERN_START.length()) == JSwordConstants.STRONG_GREEK_MARKER;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Iterates through the master passage and incorporates into it, the text
+     * given and mapped in the strongMorphMap
+     * 
+     * @param masterPassage
+     *            the passage to be enriched
+     * @param strongMorphMap
+     *            the map containing the links.
+     */
+    // TODO: tidy up all the different iterator approaches, widely using
+    // instanceof
+    private void mergePassages(final Passage masterPassage, final StrongMorphMap strongMorphMap) {
+        // iterate through the masterPassage, and lookup the strong morph map
+        final List<VerseContent> verseContent = masterPassage.getVerseContent();
+        List<String> lemma, morph;
+        for (final VerseContent vc : verseContent) {
+            if (vc instanceof Verse) {
+                final Verse v = (Verse) vc;
+                for (final TextualElement te : v.getVerseContent()) {
+                    if (te instanceof Word) {
+                        final Word w = (Word) te;
+
+                        // we have several lemmas for each word, and therefore,
+                        // we need to loop round them
+                        lemma = w.getLemma();
+                        morph = w.getMorph();
+
+                        final StringBuffer alternativeWording = new StringBuffer(64);
+
+                        // we iterate through each lemma, knowing that we may
+                        // not have morphs at all (Hebrew text)
+                        // we cannot use the morph without the lemma, although
+                        // TODO: check what we're supposed to do
+                        // when we only have one morphology for several lemmas
+                        // always 0 or equal to number of lemmas
+                        for (int ii = 0; ii < lemma.size(); ii++) {
+                            final String l = lemma.get(ii);
+                            final String m = ii < morph.size() ? morph.get(ii) : null;
+                            final String text = strongMorphMap.get(l, m);
+                            if (text != null) {
+                                alternativeWording.append(text);
+                                alternativeWording.append(' ');
+                            }
+                            w.setAlternativeWord(alternativeWording.toString());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * parsing an element
+     * 
+     * @param data
+     *            the book data to used as a basis for parsing
+     * @return the passage once parsed, et al.
+     * @throws ActionException
+     *             an exception to bubble up to the web UI
+     */
+    @SuppressWarnings("unchecked")
+    // TODO: upgrade to latest JSword version for generics
+    private Passage parseForGwt(final BookData data) throws ActionException {
+        Element osisFragment;
+        try {
+            osisFragment = data.getOsisFragment();
+        } catch (final BookException e1) {
+            throw new ActionException("Unable to get OSIS Fragment from selected version");
+        }
+
+        final List<Content> l = osisFragment.getContent();
+        final Passage passage = new Passage();
+
+        // First level can be title or verse
+        for (final Content el : l) {
+            // check whether we've just got text, or a verse or something
+            if (el instanceof Element) {
+                final Element e = (Element) el;
+
+                if (e.getName().equals(OSISUtil.OSIS_ELEMENT_TITLE)) {
+                    doTitle(e, passage);
+                } else if (e.getName().equals(OSISUtil.OSIS_ELEMENT_VERSE)) {
+                    doVerse(e, passage);
+                }
+            } else {
+                // this shouldn't happen
+                getLogger().warn("Unexpected text while parsing gwt");
+            }
+        }
+
+        return passage;
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,176 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+
+import javax.xml.transform.TransformerException;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.lang.StringUtils;
+import org.crosswire.common.util.Reporter;
+import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+import org.crosswire.common.xml.XMLUtil;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.jdom.Element;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.common.JSwordConstants;
+import com.tyndalehouse.step.web.server.jsword.ConfigurableHTMLConverter;
+import com.tyndalehouse.step.web.shared.command.GetDictionaryDefinitionCommand;
+import com.tyndalehouse.step.web.shared.result.GetDictionaryDefinitionResult;
+
+/**
+ * Looks up the dictionary definition in a JSword module and returns it to the
+ * client
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetDictionaryDefinitionHandler extends
+        AbstractStepHandler<GetDictionaryDefinitionCommand, GetDictionaryDefinitionResult> {
+
+    /**
+     * The dictionary definition handler's constructor
+     */
+    @Inject
+    public GetDictionaryDefinitionHandler() {
+    }
+
+    public GetDictionaryDefinitionResult execute(final GetDictionaryDefinitionCommand command,
+            final ExecutionContext arg1) throws ActionException {
+        final List<String> referenceList = command.getLookupReferencce();
+        final GetDictionaryDefinitionResult result = new GetDictionaryDefinitionResult();
+
+        final StringBuffer definitions = new StringBuffer(300);
+        // for each definition: TODO : probably want to pass back a list of
+        // definitions, and tab them
+        // on the popup!
+        for (final String reference : referenceList) {
+            definitions.append(lookUpDefinition(reference));
+            definitions.append("<hr />");
+
+        }
+        result.setDefinition(definitions.toString());
+        return result;
+    }
+
+    public void rollback(final GetDictionaryDefinitionCommand arg0, final GetDictionaryDefinitionResult arg1,
+            final ExecutionContext arg2) throws ActionException {
+        getLogger().error("Get Dictionary definition Text rolling back");
+
+    }
+
+    /**
+     * does a simple xslt transformation to show the definition on the screen
+     * 
+     * @param data
+     *            data to be shown
+     * @param osisFragment
+     *            osisFragment to transform
+     * @return the xslted definition ready to be displayed on the user's screen
+     */
+    private String doXslt(final BookData data, final Element osisFragment) {
+        if (data == null) {
+            return "";
+        }
+
+        try {
+            final SAXEventProvider osissep = data.getSAXEventProvider();
+            // TODO: do some work on the XSLT definition
+            final TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) new ConfigurableHTMLConverter()
+                    .convert(osissep);
+            final String text = XMLUtil.writeToString(htmlsep);
+            return text;
+        } catch (final SAXException e) {
+            Reporter.informUser(this, e);
+        } catch (final BookException e) {
+            Reporter.informUser(this, e);
+        } catch (final TransformerException e) {
+            Reporter.informUser(this, e);
+        }
+        return "";
+    }
+
+    /**
+     * dependant on the reference, we return a different module to lookup the
+     * definition. For e.g. we use a Greek dictionary to lookup a reference
+     * starting strong:Gxxxxx
+     * 
+     * @param reference
+     *            reference to be looked up
+     * @return the module initials to use for the dictionary lookup
+     * @throws ActionException
+     *             an exception to be thrown if the reference is not recognised
+     */
+    private String getInitialsFromReference(final String reference) throws ActionException {
+        if (reference.toLowerCase().startsWith(JSwordConstants.STRONG_PATTERN_START)) {
+            final int charPosition = JSwordConstants.STRONG_PATTERN_START.length();
+            if (reference.charAt(charPosition) == JSwordConstants.STRONG_HEBREW_MARKER) {
+                return JSwordConstants.STRONG_HEBREW_DICTIONARY_INITIALS;
+            } else if (reference.charAt(charPosition) == JSwordConstants.STRONG_GREEK_MARKER) {
+                return JSwordConstants.STRONG_GREEK_DICTIONARY_INITIALS;
+            }
+            // continuing will throw exception
+        }
+        throw new ActionException(String.format("Dictionary reference not recognised: %s", reference));
+    }
+
+    /**
+     * returns the actual reference, removing the strong pattern + first
+     * initial. For e.g. removes strong:H from "strong:H00002"
+     * 
+     * @param reference
+     *            reference to parse
+     * @return the key in the dictionary to be used for lookup purposes
+     * @throws ActionException
+     *             the action exception
+     */
+    private String getLookupKeyFromReference(final String reference) throws ActionException {
+        if (reference.toLowerCase().startsWith(JSwordConstants.STRONG_PATTERN_START)) {
+            // remove strong:H or strong:G
+            return reference.substring(JSwordConstants.STRONG_PATTERN_START.length() + 1);
+        }
+        throw new ActionException(String.format("Lookup key not recognised: %s", reference));
+    }
+
+    /**
+     * Looks up a definition given a reference in the default JSword module
+     * 
+     * @param reference
+     *            reference, for e.g. a Strong number
+     * @return the definition
+     * @throws ActionException
+     *             an exception occurring if the reference is invalid
+     */
+    private String lookUpDefinition(final String reference) throws ActionException {
+        if (StringUtils.isEmpty(reference)) {
+            throw new ActionException("Reference was not provided");
+        }
+        getLogger().error("definition lookup command");
+        final String initials = getInitialsFromReference(reference);
+        final String lookupKey = getLookupKeyFromReference(reference);
+
+        try {
+            // TODO: ensure a lookup key exists!
+            // TODO: make a common adapter api to access JSword
+            final Book currentBook = Books.installed().getBook(initials);
+            final BookData data = new BookData(currentBook, currentBook.getKey(lookupKey));
+            final String xsltedDefinition = doXslt(data, data.getOsisFragment());
+            return xsltedDefinition;
+        } catch (final NoSuchKeyException e) {
+            getLogger().error("An error occurred looking up the passage", e);
+            throw new ActionException(e);
+        } catch (final BookException e) {
+            getLogger().error("A book exception has occurred whilte looking up the passage", e);
+            throw new ActionException(e);
+        }
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,101 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.timeline.TimeBandVisibleDateProcessor;
+import com.tyndalehouse.step.web.shared.command.GetEventsForDateRangeCommand;
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineEventBean;
+import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
+
+/**
+ * Command that gets relevant events on a date range. Currently this executes
+ * multiple queries against the database
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetEventsForDateRangeHandler extends
+        AbstractStepHandler<GetEventsForDateRangeCommand, GetEventsForDateRangeResult> {
+
+    /**
+     * The step query runner to run queries against the database
+     */
+    private final StepQueryRunner queryRunner;
+
+    /**
+     * public constructor for this handler
+     * 
+     * @param queryRunner
+     *            the query runner object to use for executing the query
+     */
+    @Inject
+    public GetEventsForDateRangeHandler(final StepQueryRunner queryRunner) {
+        this.queryRunner = queryRunner;
+    }
+
+    // TODO: this needs to change to take into account the three different types
+    // of date precision but for now,
+    // let's get something working
+    public GetEventsForDateRangeResult execute(final GetEventsForDateRangeCommand event, final ExecutionContext arg1)
+            throws ActionException {
+        final GetEventsForDateRangeResult result = new GetEventsForDateRangeResult();
+        final List<TimeBandVisibleDate> timebands = event.getVisbleDates();
+        try {
+            for (final TimeBandVisibleDate tvd : timebands) {
+                List<TimelineEventBean> events;
+                events = queryRunner.run(new TimeBandVisibleDateProcessor(tvd.getMinDate(), tvd.getMaxDate(), tvd
+                        .getTimebandId()));
+                result.getEvents().addAll(events);
+            }
+        } catch (final UnableToRunQueryException e) {
+            getLogger().error("An error occured while trying to retrieve new events from the datbase", e);
+            throw new ActionException(e);
+        }
+
+        logEventsRetrieved(result.getEvents());
+        return result;
+    }
+
+    public void rollback(final GetEventsForDateRangeCommand arg0, final GetEventsForDateRangeResult arg1,
+            final ExecutionContext arg2) throws ActionException {
+
+    }
+
+    /**
+     * Logs which events have been retrieved in trace mode
+     * 
+     * @param events
+     *            events to be traced
+     */
+    private void logEventsRetrieved(final List<TimelineEventBean> events) {
+        final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy G");
+
+        if (getLogger().isTraceEnabled()) {
+            for (final TimelineEventBean teb : events) {
+                if (teb.getFromDate() != null && teb.getToDate() != null) {
+                    getLogger().trace(
+                            String.format("returning: %s %s-%s (tb_id: %d)", teb.getName(), sdf.format(new Date(teb
+                                    .getFromDate())), sdf.format(new Date(teb.getToDate())), teb.getTimelineId()));
+
+                } else if (teb.getFromDate() != null) {
+                    getLogger().trace(
+                            String.format("returning: %s %s (tb_id: %d)", teb.getName(), sdf.format(new Date(teb
+                                    .getFromDate())), teb.getTimelineId()));
+                } else {
+                    getLogger().trace(String.format("returning: %s (tb_id: %d)", teb.getName(), teb.getTimelineId()));
+                }
+            }
+        }
+        getLogger().trace(String.format("Returning %d events to the client", events.size()));
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,50 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.shared.command.GetLocationsCommand;
+import com.tyndalehouse.step.web.shared.result.GetLocationsResult;
+
+/**
+ * The GetLocations command gets geographical locations from the server
+ * datasources and sends them back to the client
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetLocationsHandler extends AbstractStepHandler<GetLocationsCommand, GetLocationsResult> {
+
+    /**
+     * Default constructor
+     * 
+     * @param queryRunner
+     *            a query runner
+     */
+    @Inject
+    public GetLocationsHandler(final StepQueryRunner queryRunner) {
+        // this.queryRunner = queryRunner;
+    }
+
+    public GetLocationsResult execute(final GetLocationsCommand arg0, final ExecutionContext arg1)
+            throws ActionException {
+        // try {
+        // final List<GeoLoc> timelines = queryRunner.run(new
+        // TimelineSetupDataProcessor());
+        final GetLocationsResult r = new GetLocationsResult();
+        return r;
+        // } catch (final UnableToRunQueryException e) {
+        // getLogger().error("An error occured while loading the config for the query",
+        // e);
+        // throw new ActionException(e);
+        // }
+    }
+
+    public void rollback(final GetLocationsCommand arg0, final GetLocationsResult arg1, final ExecutionContext arg2)
+            throws ActionException {
+        getLogger().error("Get Locations Handler rolling back");
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,118 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.crosswire.jsword.passage.Key;
+import org.crosswire.jsword.passage.KeyFactory;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.crosswire.jsword.passage.PassageKeyFactory;
+import org.crosswire.jsword.passage.RestrictionType;
+import org.crosswire.jsword.passage.RocketPassage;
+import org.crosswire.jsword.passage.VerseRange;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.timeline.TimelineOriginDbBean;
+import com.tyndalehouse.step.web.server.db.timeline.TimelineOriginProcessor;
+import com.tyndalehouse.step.web.shared.command.GetTimelineOriginForScriptureCommand;
+import com.tyndalehouse.step.web.shared.result.GetTimelineOriginForScriptureResult;
+
+/**
+ * returns the timeline origin, i.e the best (closest in time) event for a given
+ * verse range.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineOriginForScriptureHandler extends
+        AbstractStepHandler<GetTimelineOriginForScriptureCommand, GetTimelineOriginForScriptureResult> {
+    /**
+     * The step query runner to run queries against the database
+     */
+    private final StepQueryRunner queryRunner;
+
+    /**
+     * constructor for this handler
+     * 
+     * @param queryRunner
+     *            the query runner framework
+     */
+    @Inject
+    public GetTimelineOriginForScriptureHandler(final StepQueryRunner queryRunner) {
+        this.queryRunner = queryRunner;
+    }
+
+    // TODO: build a proper sql statement to query all time bands in one go
+    // TODO: this needs to change to take into account the three different types
+    // of date precision but for now,
+    // let's get something working
+    public GetTimelineOriginForScriptureResult execute(final GetTimelineOriginForScriptureCommand event,
+            final ExecutionContext arg1) throws ActionException {
+        try {
+            // TODO: this is bad - look at JSword to work out how to properly
+            // get the verserange out
+            final RocketPassage passage = (RocketPassage) resolveScriptureToVerseNumbers(event.getScriptureReference());
+
+            if (passage.isEmpty()) {
+                getLogger().warn("No passage was requested");
+            } else {
+
+                // TODO: we're doing only the first range - ignoring others...
+                // What would we do with several ranges? Interesting question -
+                // perhaps we could use as min/max
+                final VerseRange range = passage.getRangeAt(0, RestrictionType.NONE);
+                final int startVerseNo = range.getStart().getOrdinal();
+                final int endVerseNo = range.getEnd().getOrdinal();
+
+                final ResultSetProcessor<TimelineOriginDbBean> originProcessor = new TimelineOriginProcessor(
+                        startVerseNo, endVerseNo);
+
+                // TODO: should be able to ensure this is implied, rather having
+                // to cast directly
+                final List<TimelineOriginDbBean> originList = queryRunner.run(originProcessor);
+
+                if (originList.size() != 0) {
+                    final TimelineOriginDbBean origin = originList.get(0);
+                    return new GetTimelineOriginForScriptureResult(origin.getOrigin(), origin.getUnit(), origin
+                            .getTimebandId());
+                } // else {
+                // // TODO: work out the nearest passage and redo this...
+                // }
+            }
+        } catch (final NoSuchKeyException e) {
+            getLogger().warn("Could not resolve verse number", e);
+            // TODO: return a proper exception and show error message on the UI
+            return new GetTimelineOriginForScriptureResult(true);
+        } catch (final UnableToRunQueryException e) {
+            getLogger().error("An error occured while loading the config for the query", e);
+            throw new ActionException(e);
+        }
+        return new GetTimelineOriginForScriptureResult(true);
+    }
+
+    public void rollback(final GetTimelineOriginForScriptureCommand arg0,
+            final GetTimelineOriginForScriptureResult arg1, final ExecutionContext arg2) throws ActionException {
+
+    }
+
+    /**
+     * resolves a string to a range of verses
+     * 
+     * @return the OSIS key to use to look up a particular scripture reference
+     *         in a JSword module
+     * @throws NoSuchKeyException
+     *             thrown if the passed in reference cannot be parsed //TODO:
+     *             make into seperate util classes
+     */
+    private Key resolveScriptureToVerseNumbers(final String scriptureReference) throws NoSuchKeyException {
+        final KeyFactory keyFactory = PassageKeyFactory.instance();
+        return keyFactory.getKey(scriptureReference);
+
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,65 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.timeline.TimelineSetupDataProcessor;
+import com.tyndalehouse.step.web.shared.command.GetTimelineUISetupCommand;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+import com.tyndalehouse.step.web.shared.result.GetTimelineUISetupResult;
+
+/**
+ * the timeline UI setup handler, which returns the initial set of data for the
+ * timeline module including the different bands, their recommended scales, etc.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineUISetupHandler extends AbstractStepHandler<GetTimelineUISetupCommand, GetTimelineUISetupResult> {
+    /**
+     * The step query runner to run queries against the database
+     */
+    private final StepQueryRunner queryRunner;
+
+    /**
+     * Default constructor
+     * 
+     * @param queryRunner
+     *            a query runner
+     */
+    @Inject
+    public GetTimelineUISetupHandler(final StepQueryRunner queryRunner) {
+        this.queryRunner = queryRunner;
+    }
+
+    // TODO: this can be cached quite succesfully on the server
+
+    public GetTimelineUISetupResult execute(final GetTimelineUISetupCommand cmd, final ExecutionContext arg1)
+            throws ActionException {
+        try {
+            final List<TimelineBean> timelines = queryRunner.run(new TimelineSetupDataProcessor());
+            final GetTimelineUISetupResult r = new GetTimelineUISetupResult();
+            r.setTimelines(timelines);
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug(String.format("Returning %d timebands to the client.", timelines.size()));
+            }
+            return r;
+        } catch (final UnableToRunQueryException e) {
+            getLogger().error("An error occured while loading the config for the query", e);
+            throw new ActionException(e);
+        }
+    }
+
+    public void rollback(final GetTimelineUISetupCommand arg0, final GetTimelineUISetupResult arg1,
+            final ExecutionContext arg2) throws ActionException {
+        getLogger().error("Get Timeline UI Setup Handler rolling back");
+
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,147 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.Set;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.crosswire.common.progress.JobManager;
+import org.crosswire.common.progress.Progress;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.book.install.sword.HttpSwordInstaller;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.shared.command.InstallJswordModuleCommand;
+import com.tyndalehouse.step.web.shared.result.InstallJswordModuleResult;
+
+/**
+ * Handler that installs a JSword module (bible, etc.) on to the server (perhaps
+ * a localhost server)
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class InstallJswordModuleHandler extends
+        AbstractStepHandler<InstallJswordModuleCommand, InstallJswordModuleResult> {
+
+    // TODO: move the lookup to properties file
+    /**
+     * proxy to use to access the internet from step
+     */
+    private static final String PROXY_HOST = "step.proxy.host";
+
+    /**
+     * proxy port to use for accessing the internet form step
+     */
+    private static final String PROXY_PORT = "step.proxy.port";
+
+    /**
+     * the time to wait for installer to kick in, so that we can then wait for
+     * it
+     */
+    private static final int WAIT_TIME_FOR_INSTALLER = 2000;
+
+    /**
+     * constructor to create this handler, usually via Guice
+     */
+    @Inject
+    public InstallJswordModuleHandler() {
+    }
+
+    public InstallJswordModuleResult execute(final InstallJswordModuleCommand cmd, final ExecutionContext context)
+            throws ActionException {
+
+        final String initials = cmd.getInitials();
+        if (initials == null) {
+            throw new ActionException("Module initials provided was null");
+        }
+
+        try {
+            final HttpSwordInstaller newCustomInstaller = getNewCustomInstaller();
+
+            // remove if already installed
+            final Book installed = Books.installed().getBook(initials);
+            if (installed != null) {
+                // remove first
+                // Books.installed().removeBook(installed);
+                installed.getDriver().delete(installed);
+                getLogger()
+                        .debug(
+                                String.format("%s (%s) is already installed, so removing first", initials, installed
+                                        .getName()));
+            }
+
+            // now kick off install
+            final Book bookToBeInstalled = newCustomInstaller.getBook(initials);
+            newCustomInstaller.install(bookToBeInstalled);
+
+            getLogger().debug(String.format("Installing %s", initials));
+
+            // finally wait for install to finish
+            // hack to wait for the thread to register with the manager
+            // TODO: check with jsword community
+            // TODO: use a timer instead...
+            Thread.sleep(InstallJswordModuleHandler.WAIT_TIME_FOR_INSTALLER);
+
+            @SuppressWarnings("unchecked")
+            final Set<Progress> jswordJobs = JobManager.getJobs();
+            for (final Progress p : jswordJobs) {
+                if (p.getJobName().equals("Installing book: " + bookToBeInstalled.getName())) {
+                    // TODO: expose join on the thread and wait for it to exit
+                    // this will depend on the JSword community
+                    while (!p.isFinished()) {
+                        // sleep
+                        Thread.sleep(InstallJswordModuleHandler.WAIT_TIME_FOR_INSTALLER);
+                    }
+                }
+            }
+        } catch (final BookException e) {
+            getLogger().error("An error occured during the installation of the book", e);
+        } catch (final InterruptedException e) {
+            getLogger().error("An error occurred during the downloading of the book", e);
+        }
+
+        // wait for module to be completed
+
+        return new InstallJswordModuleResult(true);
+    }
+
+    public void rollback(final InstallJswordModuleCommand arg0, final InstallJswordModuleResult arg1,
+            final ExecutionContext arg2) throws ActionException {
+        getLogger().error("Rolling back InstallJswordModule");
+    }
+
+    /**
+     * TODO: needs redoing to ensure we take all the installers provided by
+     * JSword
+     * 
+     * @return a custom installer configured with the crosswire proxy
+     */
+    private HttpSwordInstaller getNewCustomInstaller() {
+        getLogger().info("Creating new installer for JSword");
+        final HttpSwordInstaller resourceInstaller = new HttpSwordInstaller();
+
+        getLogger().info("Currently hardcoded installer host to:" + "www.crosswire.org");
+        getLogger().info("Currently hardcoded property names for step");
+        final String host = "www.crosswire.org";
+        final String proxyHost = System.getProperty(InstallJswordModuleHandler.PROXY_HOST);
+        final String proxyPort = System.getProperty(InstallJswordModuleHandler.PROXY_PORT);
+        getLogger().info(String.format("Setting to (%1$s via %2$s:%3$s)", "www.crosswire.org", proxyHost, proxyPort));
+
+        resourceInstaller.setHost(host);
+        if (proxyHost != null) {
+            resourceInstaller.setProxyHost(proxyHost);
+        }
+        if (proxyPort != null) {
+            resourceInstaller.setProxyPort(Integer.parseInt(proxyPort));
+        }
+
+        getLogger().info("Setting package and catalog directories");
+        resourceInstaller.setPackageDirectory("/ftpmirror/pub/sword/packages/rawzip");
+        resourceInstaller.setCatalogDirectory("/ftpmirror/pub/sword/raw");
+        return resourceInstaller;
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,126 @@
+package com.tyndalehouse.step.web.server.handler.util.passage;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This map will store the mapping for strong,morph to the word However
+ * sometimes the morphology of the word is not present in the passage and since
+ * we still want to be able to render some sort of interlinear, it would be best
+ * to match just on the word as a result each entity will have the the three
+ * values associated to it text (what the word is) the strong number the
+ * morphology (optional) The map is keyed my strong number.
+ * 
+ * In order to ensure rapid lookup, we will use the following way of mapping
+ * elements Strong numbers will map either directly to the word when no morph is
+ * available, or through a morph to the word
+ * 
+ * TODO: It is assumed that given a strong and morph the text is unique TODO:
+ * change this, since there are multiple morphs per lemma and word strong
+ * ---------> morph --------> word (1) or strong ------------------------> word
+ * (2) A mapping (2) will not be stored if (1) is available, and therefore
+ * lookups lookup the morph first as this is prefered.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class StrongMorphMap {
+    // lemmas morphs word
+    /**
+     * this map maps strong numbers to morphs. it is the first level of
+     * indirection to the map of morphs which maps to a word
+     */
+    private final Map<String, Map<String, String>> strongToMorph;
+
+    /**
+     * this map maps the strong number ot the word directly
+     */
+    private final Map<String, String> strongToWord;
+
+    /**
+     * Default constructor that initialises the two maps
+     */
+    public StrongMorphMap() {
+        strongToMorph = new HashMap<String, Map<String, String>>();
+        strongToWord = new HashMap<String, String>();
+    }
+
+    /**
+     * only to be used if no morph is available
+     * 
+     * @param strong
+     *            the strong number or lemma
+     * @param word
+     *            the word to be stored
+     */
+    public final void addWord(final String strong, final String word) {
+        strongToWord.put(strong, word);
+    }
+
+    /**
+     * adds a word to the map
+     * 
+     * @param strong
+     *            the lemma/strong number
+     * @param morph
+     *            the morph / indicating morphology
+     * @param word
+     *            the word
+     */
+    public final void addWord(final String strong, final String morph, final String word) {
+        if (morph == null) {
+            addWord(strong, word);
+            return;
+        }
+
+        Map<String, String> morphsToWords = strongToMorph.get(strong);
+        if (morphsToWords == null) {
+            morphsToWords = new HashMap<String, String>();
+            strongToMorph.put(strong, morphsToWords);
+        }
+
+        // guaranteed non-null map
+        morphsToWords.put(morph, word);
+    }
+
+    /**
+     * Looks up the (lemma, morph) key in the map. If morph is null, lookup is
+     * done solely on strong number, and takes the first of the morphs
+     * 
+     * @param lemma
+     *            lemma associated to a a word
+     * @param morph
+     *            morph, can be passed in null, refering to the grammar of a
+     *            word in a language
+     * @return the word associated in the map to the (lemma, morph) combination
+     */
+    // TODO: check for nulls on lemma
+    public final String get(final String lemma, final String morph) {
+        final Map<String, String> morphToWord = strongToMorph.get(lemma);
+
+        if (morphToWord != null) {
+            if (morph != null) {
+                // use the chain from morphs to word
+                final String word = morphToWord.get(morph);
+                if (word != null) {
+                    return word;
+                } else {
+                    // well we didn't find our morph, so the best option is to
+                    // return another morph for the same strong number
+                    final Collection<String> words = morphToWord.values();
+                    final Iterator<String> wordsIterator = words.iterator();
+                    if (wordsIterator.hasNext()) {
+                        return wordsIterator.next();
+                    }
+                }
+            }
+        }
+
+        // if we get here, there is nothing valuable in the map going through
+        // the morphs
+        // therefore, let's just return something from the other map
+        return strongToWord.get(lemma);
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,172 @@
+/**
+ * Distribution License:
+ * BibleDesktop is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/gpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: ConfigurableSwingConverter.java 1583 2007-07-30 17:04:04Z dmsmith $
+ */
+package com.tyndalehouse.step.web.server.jsword;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.MissingResourceException;
+
+import javax.xml.transform.TransformerException;
+
+import org.crosswire.common.util.FileUtil;
+import org.crosswire.common.util.NetUtil;
+import org.crosswire.common.util.ResourceUtil;
+import org.crosswire.common.util.URIFilter;
+import org.crosswire.common.xml.Converter;
+import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+
+/**
+ * Turn XML from a Bible into HTML according to a Display style.
+ * 
+ * @see gnu.gpl.License for license details. The copyright to this program is
+ *      held by it's authors.
+ * @author Joe Walker [joe at eireneh dot com]
+ */
+public class ConfigurableHTMLConverter implements Converter {
+    /**
+     *
+     */
+    static final class XSLTFilter implements URIFilter {
+
+        public boolean accept(final String name) {
+            return name.endsWith(FileUtil.EXTENSION_XSLT);
+        }
+    }
+
+    /**
+     * The font to be used in OSIS->HTML generation
+     */
+    private static String font = "Serif-PLAIN-14"; //$NON-NLS-1$
+
+    /**
+     * The stylesheet we are transforming using
+     */
+    private static String style = "simple.xsl"; //$NON-NLS-1$
+
+    /**
+     * ripped off JSWord: TODO: needs to be down properly
+     */
+    public ConfigurableHTMLConverter() {
+
+    }
+
+    //
+    // /**
+    // * Accessor for the stylesheet we are transforming using
+    // */
+    // public static Font toFont()
+    // {
+    // return null;
+    // //return GuiConvert.string2Font(font);
+    // }
+
+    // /**
+    // * Accessor for the stylesheet we are transforming using
+    // */
+    // public static void setFont(String font)
+    // {
+    // ConfigurableHTMLConverter.font = font;
+    // XSLTProperty.FONT.setState(font);
+    // }
+
+    /**
+     * Accessor for the stylesheet we are transforming using
+     * 
+     * @return the font
+     */
+    public static String getFont() {
+        return ConfigurableHTMLConverter.font;
+    }
+
+    /**
+     * Accessor for the stylesheet we are transforming using
+     * 
+     * @return the resource name
+     */
+    public static String getResourceName() {
+        return ConfigurableHTMLConverter.style;
+    }
+
+    /**
+     * Accessor for the stylesheet we are transforming using
+     * 
+     * @param style
+     *            returns the resource name given a style
+     */
+    public static void setResourceName(final String style) {
+        ConfigurableHTMLConverter.style = style;
+    }
+
+    /**
+     * 
+     * 
+     * @see org.crosswire.common.xml.Converter#convert(org.crosswire.common.xml.
+     *      SAXEventProvider)
+     * @param xmlsep
+     *            the sax event provider
+     * @return the converted SAX event provider
+     * @throws TransformerException
+     *             thrown if something bad happens during the transformation of
+     *             the xml
+     */
+    public SAXEventProvider convert(final SAXEventProvider xmlsep) throws TransformerException {
+        try {
+            final String path = "xsl/cswing/" + ConfigurableHTMLConverter.style; //$NON-NLS-1$
+            final URL xslurl = ResourceUtil.getResource(path);
+
+            final TransformingSAXEventProvider tsep = new TransformingSAXEventProvider(NetUtil.toURI(xslurl), xmlsep);
+            // We used to do:
+            // tsep.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            // however for various reasons, now we don't but nothing seems to be
+            // broken ...
+            return tsep;
+        } catch (final MissingResourceException ex) {
+            throw new TransformerException(ex);
+        }
+    }
+
+    /**
+     * Get an array of the available style names for a given subject. Different
+     * subjects are available for different contexts. For example - for
+     * insertion into a web page we might want to use a set that had complex
+     * HTML, or IE/NS specific HTML, where as a JFC HTMLDocument needs simpler
+     * HTML - and special tags like the starting &lt;HTML> tags.
+     * <p>
+     * If the protocol of the URL of the current directory is not file then we
+     * can't use File.list to get the contents of the directory. This will
+     * happen if this is being run as an applet. When we start doing that then
+     * we will need to think up something smarter here. Until then we just
+     * return a zero length array.
+     * 
+     * @return An array of available style names
+     */
+    public String[] getStyles() {
+        try {
+            final String search = "xsl/cswing/" + NetUtil.INDEX_FILE; //$NON-NLS-1$
+            final URL index = ResourceUtil.getResource(search);
+            return NetUtil.listByIndexFile(NetUtil.toURI(index), new XSLTFilter());
+        } catch (final IOException ex) {
+            return new String[0];
+        }
+    }
+}

Added: trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java
===================================================================
--- trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java	                        (rev 0)
+++ trunk/step-web-server/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,335 @@
+/**
+ * Distribution License:
+ * BibleDesktop is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/gpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: XSLTProperty.java 1583 2007-07-30 17:04:04Z dmsmith $
+ */
+package com.tyndalehouse.step.web.server.jsword;
+
+import java.io.File;
+import java.io.Serializable;
+import java.net.MalformedURLException;
+
+import org.crosswire.common.util.NetUtil;
+import org.crosswire.common.util.Reporter;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+
+/* TODO: redo this class properly to behave as per where it cam from!
+ * 
+ */
+
+/**
+ * Defines properties that control the behavior of translating OSIS to HTML.
+ * 
+ * @see gnu.gpl.License for license details. The copyright to this program is
+ *      held by it's authors.
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+ at SuppressWarnings(value = {})
+public final class XSLTProperty implements Serializable {
+    /**
+     * What is the base of the current document. Note this needs to be set each
+     * time the document is shown.
+     */
+    public static final XSLTProperty BASE_URL = new XSLTProperty("baseURL", "", true); //$NON-NLS-1$ //$NON-NLS-2$
+
+    /**
+     * Show book, chapter and verse numbers.
+     */
+    public static final XSLTProperty BCV = new XSLTProperty("BCVNum", false); //$NON-NLS-1$
+
+    /**
+     * What is the base of the current document.
+     */
+    public static final XSLTProperty CSS = new XSLTProperty("css", "", true); //$NON-NLS-1$ //$NON-NLS-2$
+
+    /**
+     * Show chapter and verse numbers.
+     */
+    public static final XSLTProperty CV = new XSLTProperty("CVNum", false); //$NON-NLS-1$
+
+    /**
+     * What is the base of the current document. Note this needs to be set each
+     * time the document is shown.
+     */
+    public static final XSLTProperty DIRECTION = new XSLTProperty("direction", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+    /**
+     * What is the base of the current document. Note this needs to be set each
+     * time the font changes.
+     */
+    public static final XSLTProperty FONT = new XSLTProperty("font", "Serif-PLAIN-14"); //$NON-NLS-1$ //$NON-NLS-2$
+
+    /**
+     * Should headings be shown
+     */
+    public static final XSLTProperty HEADINGS = new XSLTProperty("Headings", true); //$NON-NLS-1$
+
+    /**
+     * Determines whether Word Morphology (e.g. Robinson) should show
+     */
+    public static final XSLTProperty MORPH = new XSLTProperty("Morph", false); //$NON-NLS-1$
+
+    /**
+     * Show no verse numbers
+     */
+    public static final XSLTProperty NO_VERSE_NUMBERS = new XSLTProperty("NoVNum", false); //$NON-NLS-1$
+
+    /**
+     * Should notes be shown
+     */
+    public static final XSLTProperty NOTES = new XSLTProperty("Notes", true); //$NON-NLS-1$
+
+    /**
+     * Determines whether verses should start on a new line.
+     */
+    public static final XSLTProperty START_VERSE_ON_NEWLINE = new XSLTProperty("VLine", false); //$NON-NLS-1$
+
+    /**
+     * Determines whether Strong's Numbers should show
+     */
+    public static final XSLTProperty STRONGS_NUMBERS = new XSLTProperty("Strongs", false); //$NON-NLS-1$
+
+    /**
+     * Show verse numbers as a superscript.
+     */
+    public static final XSLTProperty TINY_VERSE_NUMBERS = new XSLTProperty("TinyVNum", true); //$NON-NLS-1$
+
+    /**
+     * Show verse numbers
+     */
+    public static final XSLTProperty VERSE_NUMBERS = new XSLTProperty("VNum", true); //$NON-NLS-1$
+
+    /**
+     * Should cross references be shown
+     */
+    public static final XSLTProperty XREF = new XSLTProperty("XRef", true); //$NON-NLS-1$
+
+    /**
+     * Support for serialization
+     * 
+     */
+    private static int nextObj;
+
+    /**
+     * Serialization ID
+     */
+    private static final long serialVersionUID = 3257567325749326905L;
+
+    /**
+     * list of xslt properties
+     */
+    private static final XSLTProperty[] VALUES = { XSLTProperty.STRONGS_NUMBERS, XSLTProperty.MORPH,
+            XSLTProperty.START_VERSE_ON_NEWLINE, XSLTProperty.VERSE_NUMBERS, XSLTProperty.CV, XSLTProperty.BCV,
+            XSLTProperty.NO_VERSE_NUMBERS, XSLTProperty.TINY_VERSE_NUMBERS, XSLTProperty.HEADINGS, XSLTProperty.NOTES,
+            XSLTProperty.XREF, XSLTProperty.BASE_URL, XSLTProperty.DIRECTION, XSLTProperty.FONT, XSLTProperty.CSS, };
+
+    /**
+     * Whether the string state should be converted to an URL when setting the
+     * property.
+     */
+    private final boolean asURL;
+
+    /**
+     * The default state of the XSLTProperty
+     */
+    private final String defaultState;
+
+    /**
+     * The name of the XSLTProperty
+     */
+    private final String name;
+
+    /**
+     * TODO: don't know what this does, this class is a copy from JSword which
+     * needs revamping
+     */
+    private final int obj = XSLTProperty.nextObj++;
+
+    /**
+     * The current state of the XSLTProperty
+     */
+    private String state;
+
+    /**
+     * @param name
+     *            The name of this property
+     * @param defaultState
+     *            The initial state of the property.
+     */
+    private XSLTProperty(final String name, final boolean defaultState) {
+        this(name, Boolean.toString(defaultState));
+    }
+
+    /**
+     * @param name
+     *            The name of this property
+     * @param defaultState
+     *            The initial state of the property.
+     */
+    private XSLTProperty(final String name, final String defaultState) {
+        this(name, defaultState, false);
+    }
+
+    /**
+     * @param name
+     *            The name of this property
+     * @param defaultState
+     *            The initial state of the property.
+     * @param asURL
+     *            whether it is a uRl?
+     */
+    private XSLTProperty(final String name, final String defaultState, final boolean asURL) {
+        this.name = name;
+        this.defaultState = defaultState;
+        this.state = defaultState;
+        this.asURL = asURL;
+    }
+
+    /**
+     * Lookup method to convert from an integer
+     * 
+     * @param i
+     *            gets a particular xslt property
+     * @return the XSLT property matching the index
+     */
+    public static XSLTProperty fromInteger(final int i) {
+        return XSLTProperty.VALUES[i];
+    }
+
+    /**
+     * Lookup method to convert from a String
+     * 
+     * @param name
+     *            a linear search for a property and returns the XSLT property
+     * @return a XSLT property
+     */
+    public static XSLTProperty fromString(final String name) {
+        for (int i = 0; i < XSLTProperty.VALUES.length; i++) {
+            final XSLTProperty o = XSLTProperty.VALUES[i];
+            if (o.name.equalsIgnoreCase(name)) {
+                return o;
+            }
+        }
+        assert false;
+        return null;
+    }
+
+    /**
+     * 
+     * @param provider
+     *            sets the SAX provider
+     */
+    public static void setProperties(final TransformingSAXEventProvider provider) {
+        for (int i = 0; i < XSLTProperty.VALUES.length; i++) {
+            XSLTProperty.VALUES[i].setProperty(provider);
+        }
+    }
+
+    /**
+     * 
+     * @return default state
+     */
+    public boolean getDefaultState() {
+        return Boolean.valueOf(defaultState).booleanValue();
+    }
+
+    /**
+     * 
+     * @return default state as a string
+     */
+    public String getDefaultStringState() {
+        return defaultState;
+    }
+
+    /**
+     * @return the name of the property
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return the state
+     */
+    public boolean getState() {
+        return Boolean.valueOf(state).booleanValue();
+    }
+
+    /**
+     * 
+     * @return state as a string
+     */
+    public String getStringState() {
+        return state;
+    }
+
+    /**
+     * 
+     * @param provider
+     *            a SAX provider
+     */
+    public void setProperty(final TransformingSAXEventProvider provider) {
+        if (state != null && state.length() > 0) {
+            String theState = state;
+            if (asURL) {
+                try {
+                    theState = NetUtil.getURI(new File(state)).toURL().toString();
+                } catch (final MalformedURLException ex) {
+                    Reporter.informUser(this, ex);
+                }
+            }
+            provider.setParameter(name, theState);
+        }
+    }
+
+    /**
+     * @param newState
+     *            sets the state to newState
+     */
+    public void setState(final boolean newState) {
+        state = Boolean.toString(newState);
+    }
+
+    /**
+     * @param newState
+     *            sets the state to newState
+     */
+    public void setState(final String newState) {
+        state = newState;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * TODO: redo this whole class
+     * 
+     * @return an object
+     */
+    Object readResolve() {
+        return XSLTProperty.VALUES[obj];
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/StepQueryRunnerImplTest.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/StepQueryRunnerImplTest.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/StepQueryRunnerImplTest.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,85 @@
+package com.tyndalehouse.step.web.server.db;
+
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.apache.commons.logging.Log;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunnerImpl;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.helper.TestProcessor;
+
+/**
+ * Tests the StepQueryRunner framework
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at RunWith(JMock.class)
+public class StepQueryRunnerImplTest {
+
+    /** the mock object */
+    private final Mockery context = new Mockery();
+
+    /** tests running a query */
+    @Test
+    public void testRunQuery() throws UnableToRunQueryException {
+        // set up the test
+        final TestProcessor processor = new TestProcessor();
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final StepQueryRunnerImpl impl = new StepQueryRunnerImpl(log);
+
+        // Take an example ResultSet
+
+        final List<String> events = impl.run(processor);
+        Assert.assertNotNull(events);
+        // Assert.assertEquals("Bantu expansion from Cameroon to Central Africa",
+        // events.get(0));
+        // Assert.assertEquals("Events in Africa", events.get(1));
+
+        // TODO: Db Date has changed. this needs investigation
+        // Assert.assertEquals("First date on the Mayan Long Count calendar",
+        // events.get(2));
+    }
+
+    /**
+     * tests and expects a exception to be returned
+     * 
+     * @throws UnableToRunQueryException
+     *             the query expected to be return on invalid query passed in
+     */
+    @Test(expected = UnableToRunQueryException.class)
+    public void testRunQueryWithNull() throws UnableToRunQueryException {
+        // set up the test
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                allowing(log).debug(with(any(String.class)));
+                allowing(log).trace(with(any(String.class)));
+                allowing(log).info(with(any(String.class)));
+                allowing(log).isDebugEnabled();
+                allowing(log).isTraceEnabled();
+                allowing(log).isInfoEnabled();
+                allowing(log).isErrorEnabled();
+                atLeast(1).of(log).error(with(any(String.class)));
+            }
+        });
+
+        final StepQueryRunnerImpl impl = new StepQueryRunnerImpl(log);
+        impl.run(null);
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestProcessor.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestProcessor.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestProcessor.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,51 @@
+package com.tyndalehouse.step.web.server.db.helper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+
+/**
+ * Test processor, to test the retrieval of data from the database
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TestProcessor implements ResultSetProcessor<String> {
+    /**
+     * simple constructor
+     */
+    public TestProcessor() {
+
+    }
+
+    public Map<String, Object> getParameters() {
+        final Map<String, Object> params = new HashMap<String, Object>();
+        params.put("event_name", "Events in Africa");
+        params.put("event_id", 2);
+        final long l = -160321161544388L;
+        params.put("date_of_event", l);
+        return params;
+    }
+
+    public Query getQuery() {
+        return TestQueryImpl.TEST_QUERY_PARAMS_DIFFERENT_TYPES;
+    }
+
+    public List<String> process(final ResultSet rs) throws MalformedStepQueryException, ConfigNotLoadedException,
+            SQLException {
+        final List<String> events = new ArrayList<String>();
+
+        while (rs.next()) {
+            events.add(rs.getString("name"));
+        }
+        return events;
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestQueryImpl.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestQueryImpl.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/db/helper/TestQueryImpl.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,27 @@
+package com.tyndalehouse.step.web.server.db.helper;
+
+import com.tyndalehouse.step.web.server.db.framework.Query;
+
+public enum TestQueryImpl implements Query {
+    /** a test query */
+    TEST_QUERY_PARAMS_DIFFERENT_TYPES("tests");
+
+    /**
+     * component, directory of the test queries
+     */
+    private final String component;
+
+    /**
+     * creates the enum
+     * 
+     * @param component
+     *            given a component/directory where the test sql script lives
+     */
+    TestQueryImpl(final String component) {
+        this.component = component;
+    }
+
+    public String getComponent() {
+        return component;
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetCurrentBibleTextHandlerTest.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetCurrentBibleTextHandlerTest.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetCurrentBibleTextHandlerTest.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,140 @@
+package com.tyndalehouse.step.web.server.handlers;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.tyndalehouse.step.web.server.handler.GetCurrentBibleTextHandler;
+import com.tyndalehouse.step.web.shared.command.GetCurrentBibleTextCommand;
+import com.tyndalehouse.step.web.shared.common.scripturelookup.BibleTextLookupType;
+import com.tyndalehouse.step.web.shared.result.GetCurrentBibleTextResult;
+
+/**
+ * Tests the handler that retrieves scripture from the server
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at RunWith(JMock.class)
+public class GetCurrentBibleTextHandlerTest {
+    /**
+     * The standard context for mocking objects
+     */
+    private final Mockery context = new Mockery();
+
+    /**
+     * tests a greek reverse interlinear
+     * 
+     * @throws ActionException
+     *             exception during test
+     **/
+    @Test
+    public void testGreekReverseInterlinear() throws ActionException {
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final GetCurrentBibleTextCommand cmd = new GetCurrentBibleTextCommand("KJV", "acts 1:1");
+        cmd.setTypeOfLookup(BibleTextLookupType.REVERSE_INTERLINEAR);
+
+        final GetCurrentBibleTextHandler handler = new GetCurrentBibleTextHandler();
+        final GetCurrentBibleTextResult result = handler.execute(cmd, null);
+
+        Assert.assertNotNull(result.getPassage());
+        Assert.assertNotNull(result.getPassage().getVerseContent());
+        Assert.assertTrue(result.getPassage().getVerseContent().size() != 0);
+
+        // TODO: add interlinear specific stuff
+
+    }
+
+    /**
+     * tests hebrew reverse interlinear
+     * 
+     * @throws ActionException
+     *             an exception during execution
+     */
+    @Test
+    public void testHebrewReverseInterlinear() throws ActionException {
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final GetCurrentBibleTextCommand cmd = new GetCurrentBibleTextCommand("KJV", "Gen 1:1");
+        cmd.setTypeOfLookup(BibleTextLookupType.REVERSE_INTERLINEAR);
+
+        final GetCurrentBibleTextHandler handler = new GetCurrentBibleTextHandler();
+        final GetCurrentBibleTextResult result = handler.execute(cmd, null);
+
+        Assert.assertNotNull(result.getPassage());
+        Assert.assertNotNull(result.getPassage().getVerseContent());
+        Assert.assertTrue(result.getPassage().getVerseContent().size() != 0);
+
+        // TODO: add interlinear specific stuff
+
+    }
+
+    /**
+     * tests a logical lookup of the passage, as opposed to plain text
+     * 
+     * @throws ActionException
+     *             exception during running
+     */
+    @Test
+    public void testLogicalPassage() throws ActionException {
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final GetCurrentBibleTextCommand cmd = new GetCurrentBibleTextCommand("ESV", "Gen 1:1");
+        cmd.setTypeOfLookup(BibleTextLookupType.LOGICAL);
+
+        final GetCurrentBibleTextHandler handler = new GetCurrentBibleTextHandler();
+        final GetCurrentBibleTextResult result = handler.execute(cmd, null);
+
+        Assert.assertEquals(result.getPassage().getText(), "In the beginning, God created the heavens and the earth.");
+    }
+
+    /**
+     * An lookup for plain text
+     * 
+     * @throws ActionException
+     *             exception during the retrieval of the text
+     */
+    @Test
+    public void testLookupText() throws ActionException {
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final GetCurrentBibleTextCommand cmd = new GetCurrentBibleTextCommand("ESV", "Gen 1:1");
+        cmd.setTypeOfLookup(BibleTextLookupType.PLAIN_TEXT);
+
+        final GetCurrentBibleTextHandler handler = new GetCurrentBibleTextHandler();
+        final GetCurrentBibleTextResult result = handler.execute(cmd, null);
+
+        Assert.assertEquals(result.getPassageText(), "In the beginning, God created the heavens and the earth.");
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetDictionaryDefinitionHandlerTest.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetDictionaryDefinitionHandlerTest.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetDictionaryDefinitionHandlerTest.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,70 @@
+package com.tyndalehouse.step.web.server.handlers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.tyndalehouse.step.web.server.handler.GetDictionaryDefinitionHandler;
+import com.tyndalehouse.step.web.shared.command.GetDictionaryDefinitionCommand;
+import com.tyndalehouse.step.web.shared.result.GetDictionaryDefinitionResult;
+
+/**
+ * Tests the retrieval of a dictionary definition from a dictionary module
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at RunWith(JMock.class)
+public class GetDictionaryDefinitionHandlerTest {
+
+    /**
+     * The standard context for mocking objects
+     */
+    private final Mockery context = new Mockery();
+
+    // TODO: add test to ensure that we have a negative,
+    // what happens when we lookup a reference that doesn't exist
+    // at the moment we get a false positive
+
+    /**
+     * looks up some text for two references, one greek, one hebrew
+     * 
+     * @throws ActionException
+     *             an exception during execution of the test
+     */
+    @Test
+    public void testLookupText() throws ActionException {
+        final List<String> lookupReferences = new ArrayList<String>();
+        lookupReferences.add("strong:G00051");
+        lookupReferences.add("strong:H00052");
+
+        final Log log = context.mock(Log.class);
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final GetDictionaryDefinitionCommand cmd = new GetDictionaryDefinitionCommand();
+        cmd.setLookupReference(lookupReferences);
+
+        final GetDictionaryDefinitionHandler handler = new GetDictionaryDefinitionHandler();
+        final GetDictionaryDefinitionResult result = handler.execute(cmd, null);
+
+        Assert.assertTrue(result.getXsltedDefinition().contains(">00051<"));
+        Assert.assertTrue(result.getXsltedDefinition().contains("Abshay"));
+
+        Assert.assertTrue(result.getXsltedDefinition().contains(">00052<"));
+        Assert.assertTrue(result.getXsltedDefinition().contains("a thing ignored"));
+
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetTimelineUISetupHandlerTest.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetTimelineUISetupHandlerTest.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/GetTimelineUISetupHandlerTest.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,61 @@
+package com.tyndalehouse.step.web.server.handlers;
+
+import java.util.ArrayList;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.handler.GetTimelineUISetupHandler;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+
+/**
+ * Testing the timeline setup handler
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at RunWith(JMock.class)
+public class GetTimelineUISetupHandlerTest {
+
+    /**
+     * The standard context for mocking objects
+     */
+    private final Mockery context = new Mockery();
+
+    /**
+     * looks up
+     * 
+     * @throws ActionException
+     *             an exception during the running
+     */
+    @Test
+    public void testTimelineUIHandler() throws ActionException {
+        final Log log = context.mock(Log.class);
+
+        context.checking(new Expectations() {
+            {
+                ignoring(log);
+            }
+        });
+
+        final StepQueryRunner runner = context.mock(StepQueryRunner.class);
+        context.checking(new Expectations() {
+            {
+                atMost(1).of(runner);
+                will(returnValue(new ArrayList<TimelineBean>()));
+            }
+        });
+
+        new GetTimelineUISetupHandler(runner).execute(null, null);
+
+        // this test is purely to check we are not calling the database more
+        // than is required.
+    }
+}

Added: trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/JSwordInstallTest.java
===================================================================
--- trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/JSwordInstallTest.java	                        (rev 0)
+++ trunk/step-web-server/src/test/java/com/tyndalehouse/step/web/server/handlers/JSwordInstallTest.java	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,40 @@
+package com.tyndalehouse.step.web.server.handlers;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.junit.Test;
+
+/**
+ * Tests JSword installation handler
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class JSwordInstallTest {
+    /**
+     * tests the installation of a bible version from JSword/crosswire.org
+     * 
+     * @throws ActionException
+     *             an exception during execution of the tests
+     */
+    @Test
+    public void testInstallESV() throws ActionException {
+        // TODO: change to a module that's tiny. Because this test is quite
+        // slow, also relies on outside world
+        //		
+        // final String initials = "ASV";
+        // final InstallJswordModuleCommand cmd = new
+        // InstallJswordModuleCommand();
+        // cmd.setInitials(initials);
+        //
+        //		
+        // final InstallJswordModuleHandler ijmh = new
+        // InstallJswordModuleHandler();
+        // final InstallJswordModuleResult result = ijmh.execute(cmd, null);
+        //
+        // Assert.assertTrue(result.isSuccessful());
+        // Assert.assertTrue(Books.installed().getBook(initials) != null);
+        // // check book is installed
+
+    }
+}

Added: trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/queries/tests/test_query_params_different_types.sql
===================================================================
--- trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/queries/tests/test_query_params_different_types.sql	                        (rev 0)
+++ trunk/step-web-server/src/test/resources/com/tyndalehouse/step/web/server/db/queries/tests/test_query_params_different_types.sql	2010-06-25 20:30:48 UTC (rev 141)
@@ -0,0 +1,30 @@
+--------------------------------------------------------
+-- Query test
+-- This looks up 3 events 
+--------------------------------------------------------
+define date_of_event as bigint
+define event_name as varchar
+define event_id as integer
+
+
+	select 
+		name 
+	from 
+		step.event 
+	where 
+		name = #event_name# -- 'Events in Africa'
+union
+	select 
+		name 
+	from 
+		step.event 
+	where 
+		event_id = #event_id# -- 2
+union
+	select 
+		name 
+	from 
+		step.event 
+	where 
+		from_date = #date_of_event# -- = -160321161544388
+order by name




More information about the Tynstep-svn mailing list