[Tynstep-svn] r227 - in trunk/step: step-core step-core/src/main/java/com/tyndalehouse/step/core/data/common step-core/src/main/java/com/tyndalehouse/step/core/data/create step-core/src/main/java/com/tyndalehouse/step/core/data/entities step-core/src/main/java/com/tyndalehouse/step/core/guice/providers step-core/src/main/java/com/tyndalehouse/step/core/service step-core/src/main/java/com/tyndalehouse/step/core/service/impl step-core/src/main/java/com/tyndalehouse/step/core/utils step-core/src/main/resources step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline step-core/src/test/java/com/tyndalehouse/step/core/data/common step-core/src/test/java/com/tyndalehouse/step/core/data/entities step-core/src/test/java/com/tyndalehouse/step/core/service/impl step-parent step-web/src/main/java/com/tyndalehouse/step/guice step-web/src/main/java/com/tyndalehouse/step/models step-web/src/main/java/com/tyndalehouse/step/models/timeline step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl step-web/src/main/java/com/tyndalehouse/step/rest/controllers step-web/src/main/java/com/tyndalehouse/step/rest/framework step-web/src/main/webapp step-web/src/main/webapp/css step-web/src/main/webapp/js step-web/src/main/webapp/tempdev step-web/src/test/java/com/tyndalehouse/step/rest/controllers step-web/src/test/java/com/tyndalehouse/step/rest/framework

ChrisBurrell at crosswire.org ChrisBurrell at crosswire.org
Tue May 10 00:02:46 MST 2011


Author: ChrisBurrell
Date: 2011-05-10 00:02:46 -0700 (Tue, 10 May 2011)
New Revision: 227

Added:
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/DigestableTimeline.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/TimelineTranslator.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileEvent.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineImpl.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineTranslatorImpl.java
   trunk/step/step-web/src/main/webapp/tempdev/
   trunk/step/step-web/src/main/webapp/tempdev/events.json
Modified:
   trunk/step/step-core/pom.xml
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/common/PartialDate.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/TimelineEvent.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/User.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/TestData.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/UserDataService.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImpl.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/PassageReferenceUtils.java
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_ExileAndReturn.csv
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Global.csv
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Monarchy.csv
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_PatriarchsToJudges.csv
   trunk/step/step-core/src/main/resources/step.core.properties
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/common/PartialDateTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/entities/UserTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/FavouritesServiceImplTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImplTest.java
   trunk/step/step-parent/pom.xml
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/WebContextModule.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/UserController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/StepRequest.java
   trunk/step/step-web/src/main/webapp/css/initial-layout.css
   trunk/step/step-web/src/main/webapp/index.html
   trunk/step/step-web/src/main/webapp/js/init.js
   trunk/step/step-web/src/main/webapp/js/timeline.js
   trunk/step/step-web/src/main/webapp/js/ui_hooks.js
   trunk/step/step-web/src/main/webapp/panemenu.html
   trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java
   trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/StepRequestTest.java
Log:
initial timeline sketches

Modified: trunk/step/step-core/pom.xml
===================================================================
--- trunk/step/step-core/pom.xml	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/pom.xml	2011-05-10 07:02:46 UTC (rev 227)
@@ -100,10 +100,10 @@
 			<artifactId>commons-collections</artifactId>
 		</dependency>
 
-		<dependency>
-			<groupId>commons-codec</groupId>
-			<artifactId>commons-codec</artifactId>
-		</dependency>
+<!--		<dependency>-->
+<!--			<groupId>commons-codec</groupId>-->
+<!--			<artifactId>commons-codec</artifactId>-->
+<!--		</dependency>-->
 		
 		<!--  we don't always need this - depends on what version -->
 		<dependency>
@@ -142,6 +142,12 @@
 			<type>pom</type>
 		</dependency>
 		
+		<dependency>
+		    <groupId>joda-time</groupId>
+		    <artifactId>joda-time</artifactId>
+		</dependency>
+		
+		
 		<!-- transitive dependencies not picked up by jsword -->
 		<dependency>
 			<groupId>javatar</groupId>

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/common/PartialDate.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/common/PartialDate.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/common/PartialDate.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -5,9 +5,9 @@
 import static org.apache.commons.lang.StringUtils.split;
 
 import java.util.Calendar;
-import java.util.GregorianCalendar;
 
 import org.apache.commons.lang.StringUtils;
+import org.joda.time.LocalDateTime;
 
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
 
@@ -32,7 +32,7 @@
     /**
      * The date to be represented (whether fully accurate or not)
      */
-    private final Calendar c;
+    private final LocalDateTime localDateTime;
 
     /**
      * The precision specifier which tells us just quite how accurate the date is (year, month, day)
@@ -44,12 +44,12 @@
     /**
      * Public constructor to give us a partial date.
      * 
-     * @param c date partial reprentation of a date
+     * @param ldt date partial representation of a date
      * @param precision precision indicating how much of the date can be trusted day/month/year or month/year
      *            or just year
      */
-    public PartialDate(final Calendar c, final PrecisionType precision) {
-        this.c = c;
+    public PartialDate(final LocalDateTime ldt, final PrecisionType precision) {
+        this.localDateTime = ldt;
         this.precision = precision;
     }
 
@@ -86,7 +86,9 @@
      */
     private static PartialDate getPartialDateFromArray(final String[] parts, final boolean negativeDate) {
         final Calendar c = Calendar.getInstance();
+        final LocalDateTime translatedTime;
         PrecisionType p;
+        final int multiplier = negativeDate ? -1 : 1;
 
         try {
             // length of field determines how much of the date has been specified
@@ -95,15 +97,17 @@
                     throw new StepInternalException("There weren't enough parts to this date");
                 case YEAR:
                     // only the year is specified, so use 1st of Jan Year
-                    c.set(parseInt(parts[0]), 1, 1);
+                    translatedTime = new LocalDateTime(multiplier * parseInt(parts[0]), 1, 1, 0, 0);
                     p = PrecisionType.YEAR;
                     break;
                 case YEAR_AND_MONTH:
-                    c.set(parseInt(parts[0]), parseInt(parts[1]), 1);
+                    translatedTime = new LocalDateTime(multiplier * parseInt(parts[0]), parseInt(parts[1]),
+                            1, 0, 0);
                     p = PrecisionType.MONTH;
                     break;
                 case YEAR_MONTH_AND_DAY:
-                    c.set(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]));
+                    translatedTime = new LocalDateTime(multiplier * parseInt(parts[0]), parseInt(parts[1]),
+                            parseInt(parts[2]), 0, 0);
                     p = PrecisionType.DAY;
                     break;
                 default:
@@ -113,19 +117,14 @@
             throw new StepInternalException("Could not parse date into year, month or day.", nfe);
         }
 
-        c.set(Calendar.HOUR_OF_DAY, 0);
-        c.set(Calendar.MINUTE, 0);
-        if (negativeDate) {
-            c.set(Calendar.ERA, GregorianCalendar.BC);
-        }
-        return new PartialDate(c, p);
+        return new PartialDate(translatedTime, p);
     }
 
     /**
      * @return gets the internal date
      */
-    public Calendar getDate() {
-        return this.c;
+    public LocalDateTime getDate() {
+        return this.localDateTime;
     }
 
     /**

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -153,12 +153,12 @@
                 event.setHotSpot(hotspots.get(data.getData(ii, HOTSPOT_COLUMN_NAME)));
                 event.setSummary(data.getData(ii, "Name"));
                 if (from.getPrecision() != PrecisionType.NONE) {
-                    event.setFromDate(from.getDate().getTimeInMillis());
+                    event.setFromDate(from.getDate());
                     event.setFromPrecision(from.getPrecision());
                 }
 
                 if (to.getPrecision() != PrecisionType.NONE) {
-                    event.setToDate(to.getDate().getTimeInMillis());
+                    event.setToDate(to.getDate());
                     event.setToPrecision(to.getPrecision());
 
                 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/TimelineEvent.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/TimelineEvent.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/TimelineEvent.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -8,6 +8,8 @@
 import javax.persistence.Entity;
 import javax.persistence.ManyToOne;
 
+import org.joda.time.LocalDateTime;
+
 import com.avaje.ebean.annotation.CacheStrategy;
 import com.tyndalehouse.step.core.data.common.PrecisionType;
 
@@ -26,10 +28,10 @@
     private String summary;
 
     @Column(nullable = true)
-    private long fromDate;
+    private LocalDateTime fromDate;
 
     @Column(nullable = true)
-    private long toDate;
+    private LocalDateTime toDate;
 
     @Column(nullable = true)
     private PrecisionType fromPrecision;
@@ -57,28 +59,28 @@
     /**
      * @return the fromDate
      */
-    public long getFromDate() {
+    public LocalDateTime getFromDate() {
         return this.fromDate;
     }
 
     /**
      * @param fromDate the fromDate to set
      */
-    public void setFromDate(final long fromDate) {
+    public void setFromDate(final LocalDateTime fromDate) {
         this.fromDate = fromDate;
     }
 
     /**
      * @return the toDate
      */
-    public long getToDate() {
+    public LocalDateTime getToDate() {
         return this.toDate;
     }
 
     /**
      * @param toDate the toDate to set
      */
-    public void setToDate(final long toDate) {
+    public void setToDate(final LocalDateTime toDate) {
         this.toDate = toDate;
     }
 

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/User.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/User.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/User.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -26,10 +26,13 @@
     @Column
     private String name;
 
-    @Column
-    private String password;
+    @Column(nullable = false)
+    private byte[] password;
 
-    @Column
+    @Column(nullable = false)
+    private byte[] salt;
+
+    @Column(nullable = false)
     private String emailAddress;
 
     @Column
@@ -52,15 +55,15 @@
     /**
      * @return the password
      */
-    public String getPassword() {
+    public byte[] getPassword() {
         return this.password;
     }
 
     /**
      * @param password the password to set
      */
-    public void setPassword(final String password) {
-        this.password = password;
+    public void setPassword(final byte[] password) {
+        this.password = password.clone();
     }
 
     /**
@@ -104,4 +107,18 @@
     public void setCountry(final String country) {
         this.country = country;
     }
+
+    /**
+     * @return the salt
+     */
+    public byte[] getSalt() {
+        return this.salt;
+    }
+
+    /**
+     * @param salt the salt to set
+     */
+    public void setSalt(final byte[] salt) {
+        this.salt = salt.clone();
+    }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -52,10 +52,10 @@
     @Inject
     public DatabaseConfigProvider(@Named("app.db.driver") final String driverClassName,
             @Named("app.db.url") final String url, @Named("app.db.username") final String username,
-            @Named("app.db.password") final String password,
-            @Named("app.db.maxActive") final String maxActive, @Named("app.db.maxIdle") final String maxIdle,
-            @Named("app.db.maxOpenStatement") final String maxOpenStatements,
-            @Named("app.db.poolableStatements") final String poolableStatements,
+            @Named("app.db.password") final String password, @Named("app.db.maxActive") final int maxActive,
+            @Named("app.db.maxIdle") final int maxIdle,
+            @Named("app.db.maxOpenStatement") final int maxOpenStatements,
+            @Named("app.db.poolableStatements") final boolean poolableStatements,
             @Named("app.db.validationQuery") final String validationQuery) {
         this.driverClassName = driverClassName;
         this.url = url;
@@ -63,11 +63,10 @@
         this.password = password;
         this.validationQuery = validationQuery;
 
-        // TODO: add exception handling when i know how
-        this.maxActive = Integer.parseInt(maxActive);
-        this.maxIdle = Integer.parseInt(maxIdle);
-        this.maxOpenStatements = Integer.parseInt(maxOpenStatements);
-        this.poolStatements = Boolean.parseBoolean(poolableStatements);
+        this.maxActive = maxActive;
+        this.maxIdle = maxIdle;
+        this.maxOpenStatements = maxOpenStatements;
+        this.poolStatements = poolableStatements;
     }
 
     // CHECKSTYLE:ON

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -57,7 +57,6 @@
                         final Integer p = Integer.parseInt(proxyPort);
                         installer.setProxyPort(p.intValue());
                     } catch (final NumberFormatException e) {
-                        // TODO: work out how this should be thrown
                         throw new StepInternalException("Unable to parse port number " + proxyPort, e);
                     }
                 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/TestData.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/TestData.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/TestData.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -4,15 +4,16 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.codec.digest.DigestUtils;
-
 import com.avaje.ebean.EbeanServer;
 import com.avaje.ebean.Transaction;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.tyndalehouse.step.core.data.create.Loader;
 import com.tyndalehouse.step.core.data.entities.Bookmark;
 import com.tyndalehouse.step.core.data.entities.History;
 import com.tyndalehouse.step.core.data.entities.User;
+import com.tyndalehouse.step.core.service.UserDataService;
 
 /**
  * Provides test data if necessary
@@ -23,16 +24,26 @@
 @Singleton
 public class TestData {
     private final EbeanServer ebean;
+    private final UserDataService userService;
+    private final int numCryptoIterations;
 
     /**
      * @param ebean the ebean server to persist objects with
+     * @param userService the user service to create a user
+     * @param numCryptoIterations the number of iterations to perform - we need since we hook in to the user
+     *            data service from a different viewpoint
+     * @param loader the loader that should be called upon installation mainly
      */
     @Inject
-    public TestData(final EbeanServer ebean) {
+    public TestData(final EbeanServer ebean, final UserDataService userService,
+            @Named("app.security.numIterations") final int numCryptoIterations, final Loader loader) {
         this.ebean = ebean;
+        this.userService = userService;
+        this.numCryptoIterations = numCryptoIterations;
         final User u = getUser();
         createBookmarks(u);
         createHistory(u);
+        loader.init();
     }
 
     /**
@@ -75,15 +86,17 @@
     }
 
     /**
-     * creates a user
-     * 
-     * @return the user to be created
+     * @return a test user
      */
     private User getUser() {
         final User u = new User();
         u.setEmailAddress("t at t.c");
         u.setName("Mr Test");
-        u.setPassword(new String(DigestUtils.sha512("password")));
+        final byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+        u.setPassword(this.userService.getHash(this.numCryptoIterations, "password", salt));
+        u.setSalt(salt);
+
+        // this.ebean.save(u);
         return u;
     }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -2,7 +2,10 @@
 
 import java.util.List;
 
+import org.joda.time.LocalDateTime;
+
 import com.tyndalehouse.step.core.data.entities.Timeband;
+import com.tyndalehouse.step.core.data.entities.TimelineEvent;
 
 /**
  * The timeline service gives access to all the data relating to the timeline the events, the configuration,
@@ -23,4 +26,12 @@
      */
     List<Timeband> getTimelineConfiguration();
 
+    /**
+     * Returns events that fall within a certain time period
+     * 
+     * @param from from date
+     * @param to to date
+     * @return a list of timeline events contained between the two dates
+     */
+    List<TimelineEvent> getTimelineEvents(LocalDateTime from, LocalDateTime to);
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/UserDataService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/UserDataService.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/UserDataService.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -50,4 +50,14 @@
      * @return the logged in user if the user is logged in
      */
     User getLoggedInUser();
+
+    /**
+     * From a password, a number of iterations and a salt, returns the corresponding digest
+     * 
+     * @param iterationNb int The number of iterations of the algorithm
+     * @param password String The password to encrypt
+     * @param salt byte[] The salt
+     * @return The digested password
+     */
+    byte[] getHash(int iterationNb, String password, byte[] salt);
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -2,10 +2,14 @@
 
 import java.util.List;
 
+import org.joda.time.LocalDateTime;
+
 import com.avaje.ebean.EbeanServer;
+import com.avaje.ebean.Query;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.tyndalehouse.step.core.data.entities.Timeband;
+import com.tyndalehouse.step.core.data.entities.TimelineEvent;
 import com.tyndalehouse.step.core.service.TimelineService;
 
 /**
@@ -25,23 +29,28 @@
         this.ebean = ebean;
     }
 
-    // private final Loader loader;
-
-    // /**
-    // * Constructing a timeband dao
-    // *
-    // * @param timebandDao the data access object that can be used to access the timeband
-    // */
-    // @Inject
-    // public TimelineServiceImpl(final TimebandDao timebandDao, final HotSpotDao hotSpotDao, final Loader
-    // loader) {
-    // // this.timebandDao = timebandDao;
-    // // this.hotSpotDao = hotSpotDao;
-    // this.loader = loader;
-    // }
-
     @Override
     public List<Timeband> getTimelineConfiguration() {
         return this.ebean.createQuery(Timeband.class).fetch("hotspots").findList();
     }
+
+    @Override
+    public List<TimelineEvent> getTimelineEvents(final LocalDateTime from, final LocalDateTime to) {
+        // fromDate < to and toDate > from is the standard coverage method where we find the overlapping
+        // events
+        // however "toDate" can be null, therefore we need to cater for that
+
+        // which gives us
+        // fromDate < to and ((toDate != null and toDate > from) or (toDate == null and fromDate > from ))
+
+        // in other words the event starts before the requested period ends, but finishes after the end
+
+        final String eventsQuery = "find timelineEvent where fromDate <= :to and "
+                + "((toDate is not null and toDate >= :from) or (toDate is null and fromDate >= :from))";
+
+        final Query<TimelineEvent> query = this.ebean.createQuery(TimelineEvent.class, eventsQuery);
+        query.setParameter("from", from);
+        query.setParameter("to", to);
+        return query.findList();
+    }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImpl.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImpl.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -2,6 +2,11 @@
 
 import static com.avaje.ebean.Expr.eq;
 
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -9,6 +14,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 import com.tyndalehouse.step.core.data.entities.Session;
 import com.tyndalehouse.step.core.data.entities.User;
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
@@ -24,7 +30,14 @@
  */
 @Singleton
 public class UserDataServiceImpl implements UserDataService {
+    private static final String USER_ID_FIELD = "id";
+    private static final String UNABLE_TO_LOGIN_MESSAGE = "Unable to login with username/password provided";
     private static final Logger LOG = LoggerFactory.getLogger(UserDataServiceImpl.class);
+    private final int numCryptoIterations;
+    private final int saltLength;
+    private final String inputEncoding;
+    private final String hashingAlgorithm;
+    private final String saltingRandomAlgorithm;
     private final Provider<Session> sessionProvider;
     private final EbeanServer ebean;
 
@@ -33,11 +46,27 @@
      * 
      * @param ebean the ebean server to persist and load data
      * @param sessionProvider the session provider
+     * @param numCryptoIterations the number of iterations that should be performed when encrypting
+     * @param inputEncoding the encoding of the input password
+     * @param hashingAlgorithm what algorithm to use for hashing the password
+     * @param saltingRandomAlgorithm what algorithm to use for salting
+     * @param saltLength the length of the salt that should be obtained in bytes (e.g 8 for 64-bit)
      */
     @Inject
-    public UserDataServiceImpl(final EbeanServer ebean, final Provider<Session> sessionProvider) {
+    public UserDataServiceImpl(final EbeanServer ebean, final Provider<Session> sessionProvider,
+            @Named("app.security.numIterations") final int numCryptoIterations,
+            @Named("app.security.inputEncoding") final String inputEncoding,
+            @Named("app.security.hashingAlgorithm") final String hashingAlgorithm,
+            @Named("app.security.saltingAlgorithm") final String saltingRandomAlgorithm,
+            @Named("app.security.saltLength") final int saltLength) {
         this.ebean = ebean;
         this.sessionProvider = sessionProvider;
+        this.numCryptoIterations = numCryptoIterations;
+        this.inputEncoding = inputEncoding;
+        this.hashingAlgorithm = hashingAlgorithm;
+        this.saltingRandomAlgorithm = saltingRandomAlgorithm;
+        this.saltLength = saltLength;
+
     }
 
     @Override
@@ -54,11 +83,15 @@
         }
 
         // it is easy enough to register, just create a user and save to the database
+        // however we salt the password as we do...
+        final byte[] salt = getRandomSalt();
+
         final User u = new User();
         u.setEmailAddress(emailAddress);
         u.setName(name);
         u.setCountry(country);
-        u.setPassword(password);
+        u.setPassword(getHash(this.numCryptoIterations, password, salt));
+        u.setSalt(salt);
 
         this.ebean.save(u);
 
@@ -83,15 +116,32 @@
         LOG.debug("Logging [{}] in to the system", emailAddress);
 
         // logging in basically means associating the user with the session
-        final User user = this.ebean.find(User.class).select("id, name").where()
-                .and(eq("emailAddress", emailAddress), eq("password", password)).findUnique();
+        final User user = this.ebean.find(User.class).select("id, name, salt").where()
+                .eq("emailAddress", emailAddress).findUnique();
 
-        // couldn't authenticate?
         if (user == null) {
-            throw new StepInternalException("Unable to login with username/password provided");
+            throw new StepInternalException(UNABLE_TO_LOGIN_MESSAGE);
         }
 
-        return login(user);
+        // compute salt and check password leaving password in DB (we could optimise, but
+        // that would require removing the encrypted password from the database (?)
+        final byte[] salt = user.getSalt();
+
+        final int matchingPasswords = this.ebean
+                .find(User.class)
+                .select(USER_ID_FIELD)
+                .where()
+                .and(eq(USER_ID_FIELD, user.getId()),
+                        eq("password", getHash(this.numCryptoIterations, password, salt))).findRowCount();
+
+        // couldn't authenticate?
+        if (matchingPasswords != 1) {
+            throw new StepInternalException(UNABLE_TO_LOGIN_MESSAGE);
+        }
+
+        // WORKAROUND: ideally we want to be able to specify/annotate fields that should not be serialised
+        return login(this.ebean.find(User.class).select("id, name").where().eq(USER_ID_FIELD, user.getId())
+                .findUnique());
     }
 
     /**
@@ -114,4 +164,41 @@
         // simply delete the session from the db
         this.ebean.delete(this.sessionProvider.get());
     }
+
+    /**
+     * @return a securely generated random salt
+     */
+    private byte[] getRandomSalt() {
+        SecureRandom random;
+        try {
+            random = SecureRandom.getInstance(this.saltingRandomAlgorithm);
+            final byte[] bSalt = new byte[this.saltLength];
+            random.nextBytes(bSalt);
+            return bSalt;
+        } catch (final NoSuchAlgorithmException e) {
+            throw new StepInternalException("Can't generate salt", e);
+        }
+    }
+
+    @Override
+    public byte[] getHash(final int iterationNb, final String password, final byte[] salt) {
+        MessageDigest digest;
+        byte[] input = null;
+        try {
+            digest = MessageDigest.getInstance(this.hashingAlgorithm);
+            digest.reset();
+            digest.update(salt);
+            input = digest.digest(password.getBytes(this.inputEncoding));
+            for (int i = 0; i < iterationNb; i++) {
+                digest.reset();
+                input = digest.digest(input);
+            }
+        } catch (final NoSuchAlgorithmException e) {
+            throw new StepInternalException("Unable to find encryption algorithm", e);
+        } catch (final UnsupportedEncodingException e) {
+            throw new StepInternalException("Unable carry out encryption", e);
+        }
+
+        return input;
+    }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/PassageReferenceUtils.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/PassageReferenceUtils.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/PassageReferenceUtils.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -63,7 +63,7 @@
                     LOG.trace("Found reference [{}] to [{}]", valueOf(startVerseId), valueOf(endVerseId));
                     final ScriptureReference sr = new ScriptureReference();
 
-                    // TODO: fix this:
+                    // TODO: fix the broken references in csv files
                     sr.setTarget(target);
 
                     sr.setStartVerseId(startVerseId);

Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_ExileAndReturn.csv
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_ExileAndReturn.csv	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_ExileAndReturn.csv	2011-05-10 07:02:46 UTC (rev 227)
@@ -22,7 +22,7 @@
 "E_EzNe20","Nehemiah arrives in Jerusalem","-445-04-28",,,,"T_Return",,,"T_Return","Event","Aug 7","Neh.2.11",
 "E_EzNe21","Nehemiah inspects the walls","-445-05-02",,,,"T_Return",,,"T_Return","Event","night of Aug 10","Neh.2.12-16",
 "E_EzNe22","Rebuilding of the walls of Jerusalem","-445-05-03","-445-06-25",,,"T_Return",,,"T_Return","Event","Aug 11-Oct 2","Neh.2.17-6.19","End date given, plus length of 52 days. (Not sure which months were 30 days, which 29, so may be one or two days off.)"
-"E_EzNe23","Appointing of gatekeepers, singers and Levites","-445-06-26","-445-06-29",,,"T_Return",,,"T_Return","Event","Oct 3-Oct 6","Neh.6.20-7.72",
+"E_EzNe23","Appointing of gatekeepers, singers and Levites","-445-06-26","-445-06-29",,,"T_Return",,,"T_Return","Event","Oct 3-Oct 6","Neh.7.1-73",
 "E_EzNe24","Ezra reads the Law","-445-07-01","-445-07-08",,,"T_Return",,,"T_Return","Event","Oct 7-Oct 14","Neh.7.73-8.18",
 "E_EzNe25","The Israelites confess their sins","-445-07-24",,,,"T_Return",,,"T_Return","Event",,"Neh.9-10",
 "E_EzNe26","Resettlement in Jerusalem","-445","-444",,,"T_Return",,,"T_Return","Event",,"Neh.11-12.26","No end time. Months seem reasonable"

Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Global.csv
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Global.csv	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Global.csv	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,5 +1,5 @@
 "ID","Name","From","To","From2","To2","Importance","Certainty","Flags","Timeline","Type","Description","Refs","Notes"
-"T_All","All","-3800","2000","-4112","2000",,,,"T_All","Timeline","Container for everything",,"All refs very approximate"
+"T_All","All","-3800","2000","-4112","2000",,,,"-","Timeline","Container for everything",,"All refs very approximate"
 "T_Bible","Bible ","-3800","400","-4112","400","T_All",,,"T_All","Timeline","All OT dates need sorting out",,
 "T_Patriarchs","Patriarchs","-4000","-1547","-4112","-1859","T_All",,,"T_Bible","Timeline",,"Gen.*",
 "T_AdamToAbraham","Adam to Abraham","-4000","-1854","-4000","-1854","T_Patriarchs",,,"T_Patriarchs","Timeline",,"Gen.1-11",

Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Monarchy.csv
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Monarchy.csv	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_Monarchy.csv	2011-05-10 07:02:46 UTC (rev 227)
@@ -109,7 +109,7 @@
 "E_MON105","Amaziah","-796","-767",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Event",,"2Kgs.14.1-22;2Chr.25.1-28",
 "E_MON106","Azariah","-767","-739",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Reign","Also Uzziah. Co-regent 790-767","2Kgs.15.1-7;2Chr.26.1-23",
 "E_MON107","Jotham","-739","-732",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Reign","Co-regent 750-739","2Kgs.15.32-38;2Chr.27.1-9",
-"E_MON108","Ahaz","-732","-715-01",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Reign","Co-regent 736-732","2Kgs.16.1-20;2Chr.28-1.27",
+"E_MON108","Ahaz","-732","-715-01",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Reign","Co-regent 736-732","2Kgs.16.1-20;2Chr.28.1-27",
 "E_MON109","Hezekiah","-715-01","-687",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Reign",,"2Kgs.18.1-20.21;2Chr.29.1-32.33",
 "E_MON110","Hezekiah reconsecrates the Temple and re-establishes Passover","-715-01","-715-03",,,"T_JudahMonarchy",,,"T_JudahMonarchy","Event",,"2Chr.29.3-31.20",
 "E_MON111","Sennacherib attacks Judah","-701-06",,,,"T_JudahMonarchy","EM",,"T_JudahMonarchy","Event",,"2Kgs.18.13-19.37;2Chr.32.1-23",

Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_PatriarchsToJudges.csv
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_PatriarchsToJudges.csv	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/TL_PatriarchsToJudges.csv	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,7 +1,7 @@
 "ID","Name","From","To","From2","To2","Importance","Certainty","Flags","Timeline","Type","Description","Refs","Notes"
 "E_PAT1","Birth of Abraham","-1854",,"-2166",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.11.27",
 "E_PAT2","Call of Abraham; Abraham goes from Haran to Canaan","-1779",,"-2091",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.12.1-9",
-"E_PAT3","Birth of Ishmael","-1768",,"-2080",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.16.15-17",
+"E_PAT3","Birth of Ishmael","-1768",,"-2080",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.16.15-16",
 "E_PAT4","Birth of Isaac","-1754",,"-2066",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.21.1-5",
 "E_PAT5","Mount Moriah","-1739",,"-2051",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.22",
 "E_PAT6","Isaac marries Rebekah","-1714",,"-2026",,"T_Abraham","20",,"T_Abraham","Event",,"Gen.24",
@@ -54,7 +54,7 @@
 "E_PAT53","Joseph, the cupbearer and the baker","-1576",,"-1888",,"T_Jacob","20","EY","T_Jacob","Event",,"Gen.40",
 "E_PAT54","Joseph's brothers visit Egypt","-1566",,"-1878",,"T_Jacob","20",,"T_Jacob","Event",,"Gen.42",
 "E_PAT55","Joseph's brothers visit Egypt a second time ","-1565",,"-1877",,"T_Jacob","20",,"T_Jacob","Event",,"Gen.43-45",
-"E_PAT56","Joseph buries Jacob","-1547-07",,"-1859-07",,"T_Jacob","20Y",,"T_Jacob","Event",,"Gen.50-1-21",
+"E_PAT56","Joseph buries Jacob","-1547-07",,"-1859-07",,"T_Jacob","20Y",,"T_Jacob","Event",,"Gen.50.1-21",
 "E_PAT57","Adam","-3800","-2870","-4112","-3182","T_AdamToAbraham","100",,"T_AdamToAbraham","Event",,"Gen.1.26-28; Gen.2.15-3.24; Gen.5.1-5",
 "E_PAT58","Seth","-3670","-2758","-3982","-3070","T_AdamToAbraham","100",,"T_AdamToAbraham","Event",,"Gen.5.6-8",
 "E_PAT59","Enosh","-3565","-2660","-3877","-2972","T_AdamToAbraham","100",,"T_AdamToAbraham","Event",,"Gen.5.9-11",
@@ -124,10 +124,10 @@
 "E_PAT125","At Elim","-1250-02-01","-1250-02-08","-1446-02-01","-1446-02-08","T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.15.27",
 "E_PAT126","Giving of Manna","-1250-02-15","-1250-02-21","-1446-02-15","-1446-02-21","T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.16",
 "E_PAT127","Water from the Rock at Rephidim","-1250-02-22",,"-1446-02-22",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.17.1-7",
-"E_PAT128","Israel defeats Amalek","-1250-02-24",,"-1446-02-24",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.17-8-16",
+"E_PAT128","Israel defeats Amalek","-1250-02-24",,"-1446-02-24",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.17.8-16",
 "E_PAT129","Jethro visits Moses","-1250-02-25","-1250-02-28","-1446-02-25","-1446-02-28","T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.18",
 "E_PAT130","Israel arrive at Mount Sinai","-1250-03-01",,"-1446-03-01",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.19.1-15",
-"E_PAT131","Giving of the Ten Commandments","-1250-03-03",,"-1446-03-03",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.19-16-20.21",
+"E_PAT131","Giving of the Ten Commandments","-1250-03-03",,"-1446-03-03",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.19.16-20.21",
 "E_PAT132","Moses given the Law","-1250-03-04",,"-1446-03-04",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.20.22-23.33",
 "E_PAT133","The seventy elders worship God","-1250-03-05",,"-1446-03-05",,"T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.24.1-14",
 "E_PAT134","Moses on the mountain for 40 days","-1250-03-06","-1250-04-15","-1446-03-06","-1446-04-15","T_Wilderness","10Y",,"T_Wilderness","Event",,"Exod.24.15-31.18",

Modified: trunk/step/step-core/src/main/resources/step.core.properties
===================================================================
--- trunk/step/step-core/src/main/resources/step.core.properties	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/main/resources/step.core.properties	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,5 +1,5 @@
 # Front controller properties
-cache.enabled=true
+frontcontroller.cache.enabled=false
 
 #list of installers in the format: host,package,catalog
 installer.1=www.crosswire.org,/ftpmirror/pub/sword/packages/rawzip,/ftpmirror/pub/sword/raw
@@ -34,4 +34,15 @@
 app.cache.session.timeToLive=300
 app.cache.session.timeToIdle=300
 
+#caches entire responses
+app.cache.responses.maxElements=500
+app.cache.timeBeforeExpiration=3600
 
+#####################
+# Security settings
+#####################
+app.security.numIterations=1500
+app.security.inputEncoding=UTF-8
+app.security.hashingAlgorithm=SHA-1
+app.security.saltingAlgorithm=SHA1PRNG
+app.security.saltLength=8

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/common/PartialDateTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/common/PartialDateTest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/common/PartialDateTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -2,7 +2,6 @@
 
 import static org.junit.Assert.assertEquals;
 
-import java.util.Calendar;
 import java.util.GregorianCalendar;
 
 import org.junit.Test;
@@ -36,8 +35,8 @@
     @Test
     public void testYearAD() {
         final PartialDate pd = PartialDate.parseDate("1");
-        assertEquals(pd.getDate().get(Calendar.YEAR), 1);
-        assertEquals(pd.getDate().get(Calendar.ERA), GregorianCalendar.AD);
+        assertEquals(pd.getDate().getYear(), 1);
+        assertEquals(pd.getDate().getEra(), GregorianCalendar.AD);
         assertEquals(pd.getPrecision(), PrecisionType.YEAR);
     }
 
@@ -45,8 +44,8 @@
     @Test
     public void testYearBC() {
         final PartialDate pd = PartialDate.parseDate("-1");
-        assertEquals(pd.getDate().get(Calendar.YEAR), 1);
-        assertEquals(pd.getDate().get(Calendar.ERA), GregorianCalendar.BC);
+        assertEquals(pd.getDate().getYear(), -1);
+        assertEquals(pd.getDate().getEra(), GregorianCalendar.BC);
         assertEquals(pd.getPrecision(), PrecisionType.YEAR);
     }
 
@@ -54,9 +53,9 @@
     @Test
     public void testYearMonthBC() {
         final PartialDate pd = PartialDate.parseDate("-3-7");
-        assertEquals(pd.getDate().get(Calendar.YEAR), 3);
-        assertEquals(pd.getDate().get(Calendar.MONTH), 7);
-        assertEquals(pd.getDate().get(Calendar.ERA), GregorianCalendar.BC);
+        assertEquals(pd.getDate().getYear(), -3);
+        assertEquals(pd.getDate().getMonthOfYear(), 7);
+        assertEquals(pd.getDate().getEra(), GregorianCalendar.BC);
         assertEquals(pd.getPrecision(), PrecisionType.MONTH);
     }
 
@@ -64,11 +63,11 @@
     @Test
     public void testYearMonthDay() {
         final PartialDate pd = PartialDate.parseDate("3-07-25");
-        assertEquals(pd.getDate().get(Calendar.YEAR), 3);
-        assertEquals(pd.getDate().get(Calendar.MONTH), 7);
-        assertEquals(pd.getDate().get(Calendar.DAY_OF_MONTH), 25);
+        assertEquals(pd.getDate().getYear(), 3);
+        assertEquals(pd.getDate().getMonthOfYear(), 7);
+        assertEquals(pd.getDate().getDayOfMonth(), 25);
 
-        assertEquals(pd.getDate().get(Calendar.ERA), GregorianCalendar.AD);
+        assertEquals(pd.getDate().getEra(), GregorianCalendar.AD);
         assertEquals(pd.getPrecision(), PrecisionType.DAY);
     }
 

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/entities/UserTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/entities/UserTest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/entities/UserTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -22,8 +22,8 @@
         final User u = new User();
         u.setEmailAddress("chrisburrell at test.com");
         u.setName("Chris");
-        u.setPassword("password");
-
+        u.setPassword("password".getBytes());
+        u.setSalt(new byte[0]);
         getEbean().save(u);
         final User r = Ebean.find(User.class, u.getId());
         assertEquals(u.getEmailAddress(), r.getEmailAddress());

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/FavouritesServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/FavouritesServiceImplTest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/FavouritesServiceImplTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -48,6 +48,8 @@
         this.favouritesService = new FavouritesServiceImpl(getEbean(), this.serverSession);
         this.u = new User();
         this.u.setEmailAddress("b at b.com");
+        this.u.setSalt(new byte[0]);
+        this.u.setPassword(new byte[0]);
         final Session s = new Session();
         s.setUser(this.u);
 

Added: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java	                        (rev 0)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,173 @@
+package com.tyndalehouse.step.core.service.impl;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.tyndalehouse.step.core.data.DataDrivenTestExtension;
+import com.tyndalehouse.step.core.service.TimelineService;
+
+/**
+ * tests the timeline service
+ * 
+ * @author Chris
+ * 
+ */
+ at RunWith(MockitoJUnitRunner.class)
+public class TimelineServiceImplTest extends DataDrivenTestExtension {
+    private static final Logger LOG = LoggerFactory.getLogger(FavouritesServiceImpl.class);
+    private TimelineService ts;
+
+    /**
+     * sets up a few things to be able to test properly
+     */
+    @Before
+    public void setUp() {
+        this.ts = new TimelineServiceImpl(getEbean());
+    }
+
+    // /**
+    // * tests that the syntax of the query is correct
+    // */
+    // @Test
+    // public void testGetEventsInPeriodInRangePointInTime() {
+    // final TimelineEvent inRange = createEventAndPersist(1000, "A");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(0),
+    // new LocalDateTime(2000));
+    //
+    // LOG.debug("Event 1: [{}]", timelineEvents.get(0).getSummary());
+    // LOG.debug("Event 2: [{}]", timelineEvents.get(1).getSummary());
+    //
+    // assertEquals(timelineEvents.size(), 1);
+    // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+    // }
+    //
+    // /**
+    // * tests that out of range events before/after do not get retrieved
+    // */
+    // @Test
+    // public void testGetEventsInPeriodOutOfRangePointInTime() {
+    // createEventAndPersist(1000, "A");
+    // createEventAndPersist(2001, "B");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1001),
+    // new LocalDateTime(2000));
+    //
+    // assertEquals(timelineEvents.size(), 0);
+    // }
+    //
+    // /**
+    // * tests that out of range events before/after do not get retrieved
+    // */
+    // @Test
+    // public void testGetEventsInPeriodOverlapStartDuration() {
+    // final TimelineEvent inRange = createEvent(500, 1100, "A");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+    // new LocalDateTime(2000));
+    //
+    // assertEquals(timelineEvents.size(), 1);
+    // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+    // }
+    //
+    // /**
+    // * tests that out of range events before/after do not get retrieved
+    // */
+    // @Test
+    // public void testGetEventsInPeriodOverlapEndDuration() {
+    // final TimelineEvent inRange = createEvent(1500, 2100, "A");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+    // new LocalDateTime(2000));
+    //
+    // assertEquals(timelineEvents.size(), 1);
+    // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+    // }
+    //
+    // /**
+    // * tests that out of range events before/after do not get retrieved
+    // */
+    // @Test
+    // public void testGetEventsInPeriodContainedDuration() {
+    // final TimelineEvent inRange = createEvent(1500, 1700, "A");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+    // new LocalDateTime(2000));
+    //
+    // assertEquals(timelineEvents.size(), 1);
+    // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+    // }
+    //
+    // /**
+    // * tests that out of range events before/after do not get retrieved
+    // */
+    // @Test
+    // public void testGetEventsInPeriodOverflowDuration() {
+    // final TimelineEvent inRange = createEvent(200, 2100, "A");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+    // new LocalDateTime(2000));
+    //
+    // assertEquals(timelineEvents.size(), 1);
+    // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+    // }
+    //
+    // /**
+    // * tests that out of range events before/after do not get retrieved
+    // */
+    // @Test
+    // public void testGetEventsOutOfRangeDuration() {
+    // createEvent(200, 700, "A");
+    // createEvent(2200, 2700, "B");
+    // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+    // new LocalDateTime(2000));
+    //
+    // assertEquals(timelineEvents.size(), 0);
+    //
+    // }
+    //
+    // /**
+    // * creates a duration event
+    // *
+    // * @param startTime start of event
+    // * @param endTime end of event
+    // * @param summary summary of event
+    // * @return a single timeline event
+    // */
+    // private TimelineEvent createEvent(final int startTime, final int endTime, final String summary) {
+    // final TimelineEvent te = createEvent(startTime, summary);
+    // te.setToDate(new LocalDateTime(endTime));
+    // getEbean().save(te);
+    // return te;
+    // }
+    //
+    // /**
+    // * a helper method to create an event
+    // *
+    // * @param startTime the time of creation
+    // * @param summary the summary
+    // * @return the event that was creates and persisted
+    // */
+    // private TimelineEvent createEventAndPersist(final int startTime, final String summary) {
+    // final TimelineEvent te = createEvent(startTime, summary);
+    // getEbean().save(te);
+    // return te;
+    // }
+    //
+    // /**
+    // * creates the event without persisting
+    // *
+    // * @param startTime the start time of the event
+    // * @param summary the summary
+    // * @return the event created
+    // */
+    // private TimelineEvent createEvent(final int startTime, final String summary) {
+    // final TimelineEvent te = new TimelineEvent();
+    // te.setFromDate(new LocalDateTime(startTime));
+    // te.setSummary(summary);
+    // return te;
+    // }
+
+    @Test
+    public void temporaryTest() {
+
+    }
+}


Property changes on: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImplTest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImplTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -25,6 +25,7 @@
  */
 @RunWith(MockitoJUnitRunner.class)
 public class UserDataServiceImplTest extends DataDrivenTestExtension {
+    private static final int TEST_NUM_ENCRYPT_ITERATIONS = 1;
     @Mock
     private Provider<Session> serverSessionProvider;
     @Mock
@@ -37,7 +38,8 @@
     @Before
     public void setUp() {
         // MockitoAnnotations.initMocks(this);
-        this.userService = new UserDataServiceImpl(super.getEbean(), this.serverSessionProvider);
+        this.userService = new UserDataServiceImpl(super.getEbean(), this.serverSessionProvider,
+                TEST_NUM_ENCRYPT_ITERATIONS, "UTF-8", "SHA-1", "SHA1PRNG", 8);
     }
 
     /**
@@ -64,7 +66,6 @@
         assertEquals(user.getEmailAddress(), testEmail);
         assertEquals(user.getName(), testName);
         assertEquals(user.getCountry(), testCountry);
-        assertEquals(user.getPassword(), testPassword);
     }
 
     /**
@@ -97,8 +98,8 @@
     }
 
     /**
-     * we check that login in creates a row in the session table mapped to a user
-     * 
+     * we check that login in creates a row in the session table mapped to a user we also check that the hash
+     * creating the user is used on retrieval of the user
      */
     @Test
     public void testLoginPass() {
@@ -114,7 +115,9 @@
         // save the user in a database
         final User u = new User();
         u.setEmailAddress(email);
-        u.setPassword(password);
+        final byte[] salt = "abcdefg".getBytes();
+        u.setSalt(salt);
+        u.setPassword(this.userService.getHash(TEST_NUM_ENCRYPT_ITERATIONS, password, salt));
         u.setName(testName);
         getEbean().save(u);
 

Modified: trunk/step/step-parent/pom.xml
===================================================================
--- trunk/step/step-parent/pom.xml	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-parent/pom.xml	2011-05-10 07:02:46 UTC (rev 227)
@@ -306,6 +306,12 @@
 				<version>${ehcache.version}</version>
 				<type>pom</type>
 			</dependency>
+			
+			<dependency>
+			    <groupId>joda-time</groupId>
+			    <artifactId>joda-time</artifactId>
+			    <version>1.6.2</version>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>
 

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/WebContextModule.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/WebContextModule.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/WebContextModule.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -3,6 +3,8 @@
 import com.google.inject.AbstractModule;
 import com.tyndalehouse.step.core.models.ClientSession;
 import com.tyndalehouse.step.guice.providers.ClientSessionProvider;
+import com.tyndalehouse.step.models.timeline.TimelineTranslator;
+import com.tyndalehouse.step.models.timeline.impl.SimileTimelineTranslatorImpl;
 
 /**
  * This module serves to inject data that is specific to the servlet layer. The purpose of it is therefore to
@@ -17,5 +19,6 @@
     protected void configure() {
         // this provider is helpful for getting the request at runtime
         bind(ClientSession.class).toProvider(ClientSessionProvider.class);
+        bind(TimelineTranslator.class).to(SimileTimelineTranslatorImpl.class);
     }
 }

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/DigestableTimeline.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/DigestableTimeline.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/DigestableTimeline.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,11 @@
+package com.tyndalehouse.step.models.timeline;
+
+/**
+ * Marks a structure that a UI can understand
+ * 
+ * @author Chris
+ * 
+ */
+public interface DigestableTimeline {
+
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/DigestableTimeline.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/TimelineTranslator.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/TimelineTranslator.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/TimelineTranslator.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,23 @@
+package com.tyndalehouse.step.models.timeline;
+
+import java.util.List;
+
+import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+
+/**
+ * A translator is able to convert timeline data into a form that is acceptable by the client
+ * 
+ * @author Chris
+ * 
+ */
+public interface TimelineTranslator {
+
+    /**
+     * translates a list of events to a digestable form of a timeline
+     * 
+     * @param events a list of events
+     * @return the wrapped up form of the timeline
+     */
+    DigestableTimeline toDigestableTimeline(final List<TimelineEvent> events);
+
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/TimelineTranslator.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileEvent.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileEvent.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileEvent.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,124 @@
+package com.tyndalehouse.step.models.timeline.impl;
+
+/**
+ * This represents the following fragment:
+ * 
+ * <pre>
+ *      {'start': '-1262',
+ *       'title': 'Barfusserkirche',
+ *         'description': 'by Lyonel Feininger, American/German Painter, 1871-1956',
+ *         'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
+ *         'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
+ *         },
+ * </pre>
+ * 
+ * @author Chris
+ * 
+ */
+public class SimileEvent {
+    private String start;
+    private String end;
+    private boolean duration;
+    private String title;
+    private String description;
+    private String image; // ? should be url? TODO
+    private String link; // ? should be url
+
+    /**
+     * @return the start
+     */
+    public String getStart() {
+        return this.start;
+    }
+
+    /**
+     * @param start the start to set
+     */
+    public void setStart(final String start) {
+        this.start = start;
+    }
+
+    /**
+     * @return the title
+     */
+    public String getTitle() {
+        return this.title;
+    }
+
+    /**
+     * @param title the title to set
+     */
+    public void setTitle(final String title) {
+        this.title = title;
+    }
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return this.description;
+    }
+
+    /**
+     * @param description the description to set
+     */
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    /**
+     * @return the image
+     */
+    public String getImage() {
+        return this.image;
+    }
+
+    /**
+     * @param image the image to set
+     */
+    public void setImage(final String image) {
+        this.image = image;
+    }
+
+    /**
+     * @return the link
+     */
+    public String getLink() {
+        return this.link;
+    }
+
+    /**
+     * @param link the link to set
+     */
+    public void setLink(final String link) {
+        this.link = link;
+    }
+
+    /**
+     * @return the end
+     */
+    public String getEnd() {
+        return this.end;
+    }
+
+    /**
+     * @param end the end to set
+     */
+    public void setEnd(final String end) {
+        this.end = end;
+    }
+
+    /**
+     * @return the duration
+     */
+    public boolean isDuration() {
+        return this.duration;
+    }
+
+    /**
+     * @param duration the duration to set
+     */
+    public void setDuration(final boolean duration) {
+        this.duration = duration;
+    }
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileEvent.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineImpl.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineImpl.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineImpl.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,62 @@
+package com.tyndalehouse.step.models.timeline.impl;
+
+import java.util.List;
+
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.models.timeline.DigestableTimeline;
+
+/**
+ * This is a wrapper around the input expected by the simile timeline
+ * 
+ * <pre>
+ *     'dateTimeFormat': 'iso8601',
+ *     'wikiURL': "http://simile.mit.edu/shelf/",
+ *     'wikiSection': "Simile Cubism Timeline",
+ * 
+ *     'events' : [
+ *             {'start': '-1262',
+ *             'title': 'Barfusserkirche',
+ *             'description': 'by Lyonel Feininger, American/German Painter, 1871-1956',
+ *             'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
+ *             'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
+ *             },
+ *     ]
+ *     }
+ * </pre>
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class SimileTimelineImpl implements DigestableTimeline {
+    private String dateTimeFormat;
+    private List<SimileEvent> events;
+
+    /**
+     * @return the dateTimeFormat
+     */
+    public String getDateTimeFormat() {
+        return this.dateTimeFormat;
+    }
+
+    /**
+     * @param dateTimeFormat the dateTimeFormat to set
+     */
+    public void setDateTimeFormat(final String dateTimeFormat) {
+        this.dateTimeFormat = dateTimeFormat;
+    }
+
+    /**
+     * @return the events
+     */
+    public List<SimileEvent> getEvents() {
+        return this.events;
+    }
+
+    /**
+     * @param events the events to set
+     */
+    public void setEvents(final List<SimileEvent> events) {
+        this.events = events;
+    }
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineImpl.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineTranslatorImpl.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineTranslatorImpl.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineTranslatorImpl.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,48 @@
+package com.tyndalehouse.step.models.timeline.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.joda.time.LocalDateTime;
+
+import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+import com.tyndalehouse.step.models.timeline.DigestableTimeline;
+import com.tyndalehouse.step.models.timeline.TimelineTranslator;
+
+/**
+ * provides a way of
+ * 
+ * @author Chris
+ * 
+ */
+public class SimileTimelineTranslatorImpl implements TimelineTranslator {
+    private static final String SIMILE_DEFAULT_TIME_FORMAT = "iso8601";
+
+    @Override
+    public DigestableTimeline toDigestableTimeline(final List<TimelineEvent> events) {
+        final SimileTimelineImpl timeline = new SimileTimelineImpl();
+
+        timeline.setDateTimeFormat(SIMILE_DEFAULT_TIME_FORMAT);
+
+        final List<SimileEvent> eventList = new ArrayList<SimileEvent>();
+        for (final TimelineEvent te : events) {
+            final SimileEvent e = new SimileEvent();
+            e.setTitle(te.getSummary());
+            e.setDescription(te.getSummary());
+            e.setStart(te.getFromDate().toString());
+
+            final LocalDateTime toDate = te.getToDate();
+            if (toDate != null) {
+                e.setEnd(te.getToDate().toString());
+                e.setDuration(true);
+            } else {
+                e.setDuration(false);
+            }
+
+            eventList.add(e);
+        }
+
+        timeline.setEvents(eventList);
+        return timeline;
+    }
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/impl/SimileTimelineTranslatorImpl.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,12 +1,8 @@
 package com.tyndalehouse.step.rest.controllers;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Method;
-import java.net.URLDecoder;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.servlet.http.HttpServlet;
@@ -42,16 +38,13 @@
  */
 @Singleton
 public class FrontController extends HttpServlet {
+    private static final Logger LOGGER = LoggerFactory.getLogger(FrontController.class);
     private static final String ENTITIES_PACKAGE = "com.tyndalehouse.step.core.data.entities";
     private static final String AVAJE_PACKAGE = "com.avaje";
-
     private static final String UTF_8_ENCODING = "UTF-8";
-    private static final Logger LOGGER = LoggerFactory.getLogger(FrontController.class);
     private static final char PACKAGE_SEPARATOR = '.';
     private static final long serialVersionUID = 7898656504631346047L;
     private static final String CONTROLLER_SUFFIX = "Controller";
-    // TODO: EH cache here too?
-    private final Map<String, String> contextPath = new HashMap<String, String>();
     private final transient Injector guiceInjector;
     // TODO: but also check thread safety and whether we should share this object
     private final transient ObjectMapper jsonMapper = new ObjectMapper();
@@ -68,7 +61,6 @@
     /**
      * creates the front controller which will dispatch all the requests
      * <p />
-     * TODO: rename all ebeans to DB
      * 
      * @param guiceInjector the injector used to call the relevant controllers
      * @param isCacheEnabled indicates whether responses should be cached for fast retrieval
@@ -78,7 +70,7 @@
      */
     @Inject
     public FrontController(final Injector guiceInjector,
-            @Named("cache.enabled") final Boolean isCacheEnabled, final EbeanServer ebean,
+            @Named("frontcontroller.cache.enabled") final Boolean isCacheEnabled, final EbeanServer ebean,
             final ClientErrorResolver errorResolver, final ResponseCache responseCache) {
         this.guiceInjector = guiceInjector;
         this.responseCache = responseCache;
@@ -97,7 +89,7 @@
         try {
             // cache miss?
             if (jsonEncoded == null || jsonEncoded.length == 0) {
-                sr = parseRequest(request);
+                sr = new StepRequest(request, UTF_8_ENCODING);
                 if (jsonEncoded == null) {
                     LOGGER.debug("The cache was missed so invoking method now...");
                     jsonEncoded = invokeMethod(sr);
@@ -176,6 +168,8 @@
      * @return the encoded form of the JSON response
      */
     byte[] getEncodedJsonResponse(final Object responseValue) {
+        LOGGER.debug("Encoding the following response [{}]", responseValue);
+
         try {
             String response;
             // we have normal objects and avaje ebean objects which have been intercepted
@@ -205,33 +199,8 @@
     }
 
     /**
-     * Returns the step request object containing the relevant information about the STEP Request
+     * caches the results for future use
      * 
-     * @param request the HTTP request
-     * @return the StepRequest encapsulating key data
-     */
-    StepRequest parseRequest(final HttpServletRequest request) {
-        final String requestURI = request.getRequestURI();
-
-        LOGGER.debug("Parsing {}", requestURI);
-
-        final int requestStart = getPath(request).length() + 1;
-        final int endOfControllerName = requestURI.indexOf('/', requestStart);
-        final int startOfMethodName = endOfControllerName + 1;
-        final String controllerName = requestURI.substring(requestStart, endOfControllerName);
-        final int endOfMethodNameSlash = requestURI.indexOf('/', startOfMethodName);
-        final String methodName = requestURI.substring(startOfMethodName,
-                endOfMethodNameSlash == -1 ? requestURI.length() : endOfMethodNameSlash);
-        final int endOfMethodName = startOfMethodName + methodName.length();
-
-        LOGGER.debug("Request parsed as controller: [{}], method [{}]", controllerName, methodName);
-        return new StepRequest(requestURI, controllerName, methodName, getArgs(requestURI,
-                endOfMethodName + 1));
-    }
-
-    /**
-     * TODO: caches the results for future use
-     * 
      * @param jsonEncoded json encoding of the response
      * @param sr the processed request URI containg the the cache key
      * @param controllerMethod the method so that we can inspect whether an annotation is present
@@ -266,6 +235,7 @@
      */
     void handleError(final HttpServletResponse response, final Throwable e, final StepRequest sr) {
         String requestId = null;
+        LOGGER.debug("Handling error...");
         try {
             requestId = sr == null ? "Failed to parse request?" : sr.getCacheKey().getResultsKey();
             if (e != null) {
@@ -364,54 +334,4 @@
 
         return classes;
     }
-
-    /**
-     * gets the arguments out of the requestURI String
-     * 
-     * @param requestURI the request URI string
-     * @param parameterStart the location at which the parameters start
-     * @return a list of arguments
-     */
-    String[] getArgs(final String requestURI, final int parameterStart) {
-        final List<String> arguments = new ArrayList<String>();
-        int argStart = parameterStart;
-        int nextArgStop = requestURI.indexOf('/', argStart);
-        try {
-            while (nextArgStop != -1) {
-                arguments.add(URLDecoder.decode(requestURI.substring(argStart, nextArgStop), UTF_8_ENCODING));
-                argStart = nextArgStop + 1;
-                nextArgStop = requestURI.indexOf('/', argStart);
-            }
-        } catch (final UnsupportedEncodingException e) {
-            throw new StepInternalException(e.getMessage(), e);
-        }
-
-        // add the last argument
-        if (argStart < requestURI.length()) {
-            try {
-                arguments.add(URLDecoder.decode(requestURI.substring(argStart), UTF_8_ENCODING));
-            } catch (final UnsupportedEncodingException e) {
-                throw new StepInternalException("Unable to decode last argument", e);
-            }
-        }
-        return arguments.toArray(new String[arguments.size()]);
-    }
-
-    /**
-     * Retrieves the path from the request
-     * 
-     * @param req the request
-     * @return the concatenated request
-     */
-    String getPath(final HttpServletRequest req) {
-        final String servletPath = req.getServletPath();
-        String path = this.contextPath.get(servletPath);
-
-        if (path == null) {
-            path = super.getServletContext().getContextPath() + servletPath;
-            this.contextPath.put(servletPath, path);
-        }
-        return path;
-    }
-
 }

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -3,6 +3,7 @@
 import java.util.Date;
 import java.util.List;
 
+import org.joda.time.LocalDateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -10,6 +11,8 @@
 import com.google.inject.Singleton;
 import com.tyndalehouse.step.core.data.entities.Timeband;
 import com.tyndalehouse.step.core.service.TimelineService;
+import com.tyndalehouse.step.models.timeline.DigestableTimeline;
+import com.tyndalehouse.step.models.timeline.TimelineTranslator;
 import com.tyndalehouse.step.rest.framework.Cacheable;
 
 /**
@@ -22,16 +25,18 @@
 public class TimelineController {
     private static final Logger LOGGER = LoggerFactory.getLogger(TimelineController.class);
     private final TimelineService timelineService;
+    private final TimelineTranslator translator;
 
     /**
      * The timeline controller relies on the timeline service to retrieve the data
      * 
      * @param timelineService the service
+     * @param translator a service enabling the translation of the model into a chewable version for the UI
      */
     @Inject
-    public TimelineController(final TimelineService timelineService) {
+    public TimelineController(final TimelineService timelineService, final TimelineTranslator translator) {
         this.timelineService = timelineService;
-
+        this.translator = translator;
     }
 
     /**
@@ -67,6 +72,23 @@
     }
 
     /**
+     * returns a list of events that fall within the time period
+     * 
+     * @param from the from date, left-bound
+     * @param to the to date, right-bound
+     * @return a list of timeline events in format digestable by the UI
+     */
+    @Cacheable(true)
+    public DigestableTimeline getEventsInPeriod(final String from, final String to) {
+        // TODO enhance FrontController to accept basic types such as long
+        final long f = Long.parseLong(from);
+        final long t = Long.parseLong(to);
+
+        return this.translator.toDigestableTimeline(this.timelineService.getTimelineEvents(new LocalDateTime(
+                f), new LocalDateTime(t)));
+    }
+
+    /**
      * Retrieves the timebands that will be used to configure the timeline component
      * 
      * @return the timebands

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/UserController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/UserController.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/UserController.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,7 +1,5 @@
 package com.tyndalehouse.step.rest.controllers;
 
-import org.apache.commons.codec.digest.DigestUtils;
-
 import com.google.inject.Inject;
 import com.tyndalehouse.step.core.data.entities.User;
 import com.tyndalehouse.step.core.service.UserDataService;
@@ -34,13 +32,12 @@
      * @param password the password he has chosen, which we should SHA-1 and salt
      * @return the registered user
      * 
-     *         TODO: salt
      */
     public User register(final String emailAddress, final String name, final String country,
             final String password) {
+
         // do sha1 encoding here to avoid sending unencrypted string singletons all over the place...
-        return this.userDataService.register(emailAddress, name, country,
-                new String(DigestUtils.sha512(password)));
+        return this.userDataService.register(emailAddress, name, country, password);
     }
 
     /**
@@ -51,7 +48,7 @@
      * @return the user that has logged in
      */
     public User login(final String emailAddress, final String password) {
-        return this.userDataService.login(emailAddress, new String(DigestUtils.sha512(password)));
+        return this.userDataService.login(emailAddress, password);
     }
 
     /**

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -5,6 +5,7 @@
 import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
 
 import com.google.inject.Inject;
+import com.google.inject.name.Named;
 import com.tyndalehouse.step.core.data.caches.AbstractDefaultCache;
 
 /**
@@ -18,12 +19,17 @@
      * A simple cache for the responses to be sent to the client..
      * 
      * @param cacheManager the cache manager with which to register the cache
+     * @param maxElements the maximum number of elements to store in the cache
+     * @param timeBeforeExpiration the amount of time before the cache expires
      */
     @Inject
-    public ResponseCache(final CacheManager cacheManager) {
-        super(cacheManager, new CacheConfiguration("httpResponseCache", 500)
+    public ResponseCache(final CacheManager cacheManager,
+            @Named("app.cache.responses.maxElements") final int maxElements,
+            @Named("app.cache.timeBeforeExpiration") final int timeBeforeExpiration) {
+        super(cacheManager, new CacheConfiguration("httpResponseCache", maxElements)
                 .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU).overflowToDisk(false)
-                .eternal(false).timeToLiveSeconds(3600).timeToIdleSeconds(3600).diskPersistent(false)
+                .eternal(false).timeToLiveSeconds(timeBeforeExpiration)
+                .timeToIdleSeconds(timeBeforeExpiration).diskPersistent(false)
                 .diskExpiryThreadIntervalSeconds(0));
     }
 

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/StepRequest.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/StepRequest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/StepRequest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,14 +1,27 @@
 package com.tyndalehouse.step.rest.framework;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.tyndalehouse.step.core.exceptions.StepInternalException;
+
 /**
  * A simple class that hold request information, provides various cache keys
  * <p />
- * TODO: move parse method from FrontController to here.
  * 
  * @author Chris
  * 
  */
 public class StepRequest {
+    private static final Logger LOGGER = LoggerFactory.getLogger(StepRequest.class);
+
     private final String controllerName;
     private final String methodName;
     private final String[] args;
@@ -16,7 +29,8 @@
     private final String requestURI;
 
     /**
-     * Creates a request holder object containing the relevant information about a request
+     * Creates a request holder object containing the relevant information about a request. This constructor
+     * is used more for testing and could possibly be removed later
      * 
      * @param requestURI the request URI that determines the controller, method name, etc.
      * @param controllerName the controller name
@@ -32,6 +46,75 @@
     }
 
     /**
+     * Returns the step request object containing the relevant information about the STEP Request
+     * 
+     * @param request the HTTP request
+     * @param encoding the encoding with which to decode the request
+     */
+    public StepRequest(final HttpServletRequest request, final String encoding) {
+        this.requestURI = request.getRequestURI();
+
+        LOGGER.debug("Parsing {}", this.requestURI);
+
+        final int requestStart = getPathLength(request) + 1;
+        final int endOfControllerName = this.requestURI.indexOf('/', requestStart);
+        final int startOfMethodName = endOfControllerName + 1;
+        final int endOfMethodNameSlash = this.requestURI.indexOf('/', startOfMethodName);
+
+        // now we can set the controllerName and methodNme
+        this.controllerName = this.requestURI.substring(requestStart, endOfControllerName);
+        this.methodName = this.requestURI.substring(startOfMethodName,
+                endOfMethodNameSlash == -1 ? this.requestURI.length() : endOfMethodNameSlash);
+
+        LOGGER.debug("Request parsed as controller: [{}], method [{}]", this.controllerName, this.methodName);
+        final int endOfMethodName = startOfMethodName + this.methodName.length();
+        final String[] calculatedArguments = parseArguments(endOfMethodName + 1, encoding);
+        this.args = calculatedArguments == null ? new String[] {} : calculatedArguments;
+    }
+
+    /**
+     * gets the arguments out of the requestURI String
+     * 
+     * @param parameterStart the location at which the parameters start
+     * @param encoding the encoding with which to decode the arguments
+     * @return a list of arguments
+     */
+    private String[] parseArguments(final int parameterStart, final String encoding) {
+        final List<String> arguments = new ArrayList<String>();
+        int argStart = parameterStart;
+        int nextArgStop = this.requestURI.indexOf('/', argStart);
+        try {
+            while (nextArgStop != -1) {
+                arguments.add(URLDecoder.decode(this.requestURI.substring(argStart, nextArgStop), encoding));
+                argStart = nextArgStop + 1;
+                nextArgStop = this.requestURI.indexOf('/', argStart);
+            }
+        } catch (final UnsupportedEncodingException e) {
+            throw new StepInternalException(e.getMessage(), e);
+        }
+
+        // add the last argument
+        if (argStart < this.requestURI.length()) {
+            try {
+                arguments.add(URLDecoder.decode(this.requestURI.substring(argStart), encoding));
+            } catch (final UnsupportedEncodingException e) {
+                throw new StepInternalException("Unable to decode last argument", e);
+            }
+        }
+        return arguments.toArray(new String[arguments.size()]);
+    }
+
+    /**
+     * Retrieves the path from the request
+     * 
+     * @param req the request
+     * @return the concatenated request
+     */
+    private int getPathLength(final HttpServletRequest req) {
+        return req.getServletPath().length() + req.getContextPath().length();
+    }
+
+    /**
      * returns the cache key to resolve from the cache
      * 
      * @return the key to the method as expected in the cache.

Modified: trunk/step/step-web/src/main/webapp/css/initial-layout.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/initial-layout.css	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/webapp/css/initial-layout.css	2011-05-10 07:02:46 UTC (rev 227)
@@ -166,10 +166,22 @@
 
 .passageContent {
 	position: absolute;
-	top: 45px;
+	/* top: 45px; */ 
 	overflow: auto;
 }
 
+/*********************************************/
+/** BOTTOM COMPONENT
+/*********************************************/
+#bottomSection { 
+	height: 0px;
+	position: absolute;
+	bottom: 0px;
+	left: 0px;
+	width: 100%;
+}
+
+
 .no-left-border {
 	/* border-left: none; */
 	margin-left: -1px; 

Modified: trunk/step/step-web/src/main/webapp/index.html
===================================================================
--- trunk/step/step-web/src/main/webapp/index.html	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/webapp/index.html	2011-05-10 07:02:46 UTC (rev 227)
@@ -37,55 +37,60 @@
 </HEAD>
 <body>
 
-<div id="topMenu" class="ddsmoothmenu">
-</div>
-<div class="column">
-	<div class="passageContainer">
-		<div id="leftPaneMenu" class="innerMenus"></div>
-	    <div class="passageText ui-widget">
-	    	<div class="headingContainer">
-				<a class="bookmarkPassageLink">Add a bookmark</a>
-		    	<input id="leftPassageReference" class="heading editable passageReference" size="30" value="Rom 1:1-7" />
-		    	<input id="leftPassageBook" class="heading editable passageVersion" size="5" value="KJV" />
-	    	</div>
-	    	<div class="passageContent"></div>
-	    </div>
+<div id="topMenu" class="ddsmoothmenu"> </div>
+<div style="height: 100%">
+	<div id="middleSection">
+		<div class="column">
+			<div class="passageContainer">
+				<div id="leftPaneMenu" class="innerMenus"></div>
+			    <div class="passageText ui-widget">
+			    	<div class="headingContainer">
+						<a class="bookmarkPassageLink">Add a bookmark</a>
+				    	<input id="leftPassageReference" class="heading editable passageReference" size="30" value="Rom 1:1-7" />
+				    	<input id="leftPassageBook" class="heading editable passageVersion" size="5" value="KJV" />
+			    	</div>
+			    	<div class="passageContent"></div>
+			    </div>
+			</div>
+		</div>
+		
+		<div class="bookmarks" id="centerPane">
+			<div class="northBookmark">
+				<img id="topLogo" src="images/step-logo.png" alt="STEP :: Scripture Tools for Every Pastor" />
+			</div>
+			<div id="bookmarkPane" class="bookmarkPane ui-corner-all">
+				<h3 class="ui-helper-reset ui-state-default ui-corner-all">
+					<span class="leftBookmarkArrow ui-icon ui-icon-triangle-1-e"></span>History
+				</h3>
+				<div id="historyDisplayPane" class="bookmarkContents"><br /></div>
+				<h3 id="bookmarkHeader" class="ui-helper-reset ui-state-default ui-corner-all">
+					<span class="leftBookmarkArrow ui-icon ui-icon-triangle-1-e"></span>Bookmarks
+				</h3>
+				<div id="bookmarkDisplayPane" class="bookmarkContents"><br /></div>
+			</div>
+			<div class="logo">
+				<span class="copyright">&copy; Tyndale House</span>
+			</div>
+		</div>
+			
+			
+		<div class="column">
+			<div class="passageContainer">
+				<div id="rightPaneMenu" class="innerMenus"></div>
+			    <div class="passageText ui-widget">
+			    	<div class="headingContainer">
+						<a class="bookmarkPassageLink">Add a bookmark</a>
+				    	<input id="leftPassageReference" class="heading editable passageReference" size="30" value="Jhn 1:1" />
+				    	<input id="leftPassageBook" class="heading editable passageVersion" size="5" value="ESV" />
+			    	</div>
+			    	<div class="passageContent"></div>
+				</div>
+			</div>
+		</div>
 	</div>
-</div>
 	
-<div class="bookmarks" id="centerPane">
-	<div class="northBookmark">
-		<img id="topLogo" src="images/step-logo.png" alt="STEP :: Scripture Tools for Every Pastor" />
-	</div>
-	<div id="bookmarkPane" class="bookmarkPane ui-corner-all">
-		<h3 class="ui-helper-reset ui-state-default ui-corner-all">
-			<span class="leftBookmarkArrow ui-icon ui-icon-triangle-1-e"></span>History
-		</h3>
-		<div id="historyDisplayPane" class="bookmarkContents"><br /></div>
-		<h3 id="bookmarkHeader" class="ui-helper-reset ui-state-default ui-corner-all">
-			<span class="leftBookmarkArrow ui-icon ui-icon-triangle-1-e"></span>Bookmarks
-		</h3>
-		<div id="bookmarkDisplayPane" class="bookmarkContents"><br /></div>
-	</div>
-	<div class="logo">
-		<span class="copyright">&copy; Tyndale House</span>
-	</div>
+	<div id="bottomSection" class="bottomModule timeline">No modules have yet been loaded.</div>
 </div>
-	
-	
-<div class="column">
-	<div class="passageContainer">
-		<div id="rightPaneMenu" class="innerMenus"></div>
-	    <div class="passageText ui-widget">
-	    	<div class="headingContainer">
-				<a class="bookmarkPassageLink">Add a bookmark</a>
-		    	<input id="leftPassageReference" class="heading editable passageReference" size="30" value="Jhn 1:1" />
-		    	<input id="leftPassageBook" class="heading editable passageVersion" size="5" value="ESV" />
-	    	</div>
-	    	<div class="passageContent"></div>
-		</div>
-	</div>
-</div>
 
 <div class="interlinearPopup">
 	<input type="text" class="interlinearVersions"/>
@@ -97,9 +102,6 @@
 </div>
 
 
-
-<!--<div id="bottomSection" class="timeline">No modules have yet been loaded.</div>-->
-<!---->
 <!--<div id="loading"><img alt="Loading..." src="images/wait16.gif" />Loading...</div>-->
 <div id="error">A placeholder for error messages</div>
 

Modified: trunk/step/step-web/src/main/webapp/js/init.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/init.js	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/webapp/js/init.js	2011-05-10 07:02:46 UTC (rev 227)
@@ -13,7 +13,7 @@
 		initLayout();
 		initDefaultValues();
 		initLexicon();
-//		initTimeline(mainAppLayout);
+		initTimeline();
 		initBookmarks();
 		initData();
 		initInitialEvents();
@@ -26,11 +26,37 @@
 	var windowHeight = $(window).height();
 	var innerMenuHeight = $("#leftPaneMenu").height();
 	var topMenuHeight = $("#topMenu").height();
+	var headingContainerHeight = $(".headingContainer").height();
 	var imageAndFooterHeight = $(".northBookmark").height() + $(".logo").height();
-	$(".column").height(windowHeight - topMenuHeight);
-	$(".bookmarkPane").height(windowHeight - topMenuHeight - imageAndFooterHeight);
-	$(".passageText").height(windowHeight - topMenuHeight - innerMenuHeight);
-	$(".passageContent").height($(".passageText").height() - $(".headingContainer").height());	
+	var bottomSectionHeight = $("#bottomSection").height();
+	var windowWithoutMenuNorModule = windowHeight - topMenuHeight - bottomSectionHeight; 
+	var columnHeight = windowWithoutMenuNorModule;
+	var bookmarkHeight = windowWithoutMenuNorModule - imageAndFooterHeight ;
+	var passageTextHeight = windowWithoutMenuNorModule - innerMenuHeight;
+	var passageContentHeight = passageTextHeight - headingContainerHeight;
+	
+	$(".column").height(columnHeight);
+	$(".bookmarkPane").height(bookmarkHeight);
+	$(".passageText").height(passageTextHeight);
+	$(".passageContent").css("top", headingContainerHeight);
+	$(".passageContent").height(passageContentHeight);	
+
+//	alert(headingContainerHeight);
+//	if($("#debug").text() == "") {
+//		$("#bookmarkPane").append("<span id=\"debug\" />");		
+//	}
+//	
+//	var heights = 
+//		"window = " + windowHeight + "\n" + 
+//		"paneMenu = " + innerMenuHeight + "\n" +
+//		"topMenu = " + topMenuHeight + "\n" + 
+//		"imageAndFooter = " + imageAndFooterHeight + "\n" +
+//		"passageText = " + $(".passageText").height() + "\n" +
+//		"heading = " + $(".headingContainer").height() + "\n" +
+//		"passageContent = " + $(".passageContent").height() + "\n" ;
+//		
+//	$("#debug").text(heights);
+//	
 }
 
 /**
@@ -228,7 +254,7 @@
 }
 
 function initTimeline(mainAppLayout) {
-	new TimelineWidget($("#bottomSection"), mainAppLayout);
+	new TimelineWidget($("#bottomSection"));
 }
 
 function raiseError(error) {

Modified: trunk/step/step-web/src/main/webapp/js/timeline.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/timeline.js	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/webapp/js/timeline.js	2011-05-10 07:02:46 UTC (rev 227)
@@ -2,135 +2,163 @@
  * Code for showing and interacting with the timeline
  */
 
-function TimelineWidget(rootElement, mainAppLayout) {
+function TimelineWidget(rootElement) {
 	this.rootElement = rootElement;
 	var self = this;
 	$(rootElement).hear("show-timeline", function(selfElement) {
 		//first show the bottom pane...
-		mainAppLayout.open("south");
-		
 		self.onLoad();
 		$(window).resize(self.onResize);
 	});
 	
 	$(rootElement).hear("hide-timeline", function(selfElement) {
 		//first show the bottom pane...
-		mainAppLayout.close("south");
+//		mainAppLayout.close("south");
 	});
 }
 
 var tl;
 TimelineWidget.prototype.onLoad = function() {
     var eventSource = new Timeline.DefaultEventSource();
+    var zones = [];
+
+	zones[0] = {   start:    "-1252",
+            end:     		 "-1249",
+//            magnify:  1,
+            unit:     Timeline.DateTime.YEAR
+        };
+
+	
     
-    var zones = [
-        {   start:    "Fri Nov 22 1963 00:00:00 GMT-0600",
-            end:      "Mon Nov 25 1963 00:00:00 GMT-0600",
-            magnify:  10,
-            unit:     Timeline.DateTime.DAY
-        },
-        {   start:    "Fri Nov 22 1963 09:00:00 GMT-0600",
-            end:      "Sun Nov 24 1963 00:00:00 GMT-0600",
-            magnify:  5,
-            unit:     Timeline.DateTime.HOUR
-        },
-        {   start:    "Fri Nov 22 1963 11:00:00 GMT-0600",
-            end:      "Sat Nov 23 1963 00:00:00 GMT-0600",
-            magnify:  5,
-            unit:     Timeline.DateTime.MINUTE,
-            multiple: 10
-        },
-        {   start:    "Fri Nov 22 1963 12:00:00 GMT-0600",
-            end:      "Fri Nov 22 1963 14:00:00 GMT-0600",
-            magnify:  3,
-            unit:     Timeline.DateTime.MINUTE,
-            multiple: 5
-        }
-    ];
-    var zones2 = [
-        {   start:    "Fri Nov 22 1963 00:00:00 GMT-0600",
-            end:      "Mon Nov 25 1963 00:00:00 GMT-0600",
-            magnify:  10,
-            unit:     Timeline.DateTime.WEEK
-        },
-        {   start:    "Fri Nov 22 1963 09:00:00 GMT-0600",
-            end:      "Sun Nov 24 1963 00:00:00 GMT-0600",
-            magnify:  5,
-            unit:     Timeline.DateTime.DAY
-        },
-        {   start:    "Fri Nov 22 1963 11:00:00 GMT-0600",
-            end:      "Sat Nov 23 1963 00:00:00 GMT-0600",
-            magnify:  5,
-            unit:     Timeline.DateTime.MINUTE,
-            multiple: 60
-        },
-        {   start:    "Fri Nov 22 1963 12:00:00 GMT-0600",
-            end:      "Fri Nov 22 1963 14:00:00 GMT-0600",
-            magnify:  3,
-            unit:     Timeline.DateTime.MINUTE,
-            multiple: 15
-        }
-    ];
+    if(this.config == null) {
+    	$.getSafe(TIMELINE_GET_CONFIG, function(data) {
+    		
+//    		$.each(data, function(index, item) {
+//    			//set up the bands
+//    			//set up the hotspots
+//    		});
+    	});
+    }
     
+//    
+//    
+//    
+//    var zones = [
+//        {   start:    "Fri Nov 22 1963 00:00:00 GMT-0600",
+//            end:      "Mon Nov 25 1963 00:00:00 GMT-0600",
+//            magnify:  10,
+//            unit:     Timeline.DateTime.DAY
+//        },
+//        {   start:    "Fri Nov 22 1963 09:00:00 GMT-0600",
+//            end:      "Sun Nov 24 1963 00:00:00 GMT-0600",
+//            magnify:  5,
+//            unit:     Timeline.DateTime.HOUR
+//        },
+//        {   start:    "Fri Nov 22 1963 11:00:00 GMT-0600",
+//            end:      "Sat Nov 23 1963 00:00:00 GMT-0600",
+//            magnify:  5,
+//            unit:     Timeline.DateTime.MINUTE,
+//            multiple: 10
+//        },
+//        {   start:    "Fri Nov 22 1963 12:00:00 GMT-0600",
+//            end:      "Fri Nov 22 1963 14:00:00 GMT-0600",
+//            magnify:  3,
+//            unit:     Timeline.DateTime.MINUTE,
+//            multiple: 5
+//        }
+//    ];
+//    var zones2 = [
+//        {   start:    "Fri Nov 22 1963 00:00:00 GMT-0600",
+//            end:      "Mon Nov 25 1963 00:00:00 GMT-0600",
+//            magnify:  10,
+//            unit:     Timeline.DateTime.WEEK
+//        },
+//        {   start:    "Fri Nov 22 1963 09:00:00 GMT-0600",
+//            end:      "Sun Nov 24 1963 00:00:00 GMT-0600",
+//            magnify:  5,
+//            unit:     Timeline.DateTime.DAY
+//        },
+//        {   start:    "Fri Nov 22 1963 11:00:00 GMT-0600",
+//            end:      "Sat Nov 23 1963 00:00:00 GMT-0600",
+//            magnify:  5,
+//            unit:     Timeline.DateTime.MINUTE,
+//            multiple: 60
+//        },
+//        {   start:    "Fri Nov 22 1963 12:00:00 GMT-0600",
+//            end:      "Fri Nov 22 1963 14:00:00 GMT-0600",
+//            magnify:  3,
+//            unit:     Timeline.DateTime.MINUTE,
+//            multiple: 15
+//        }
+//    ];
+//    
     var theme = Timeline.ClassicTheme.create();
     theme.event.bubble.width = 250;
     
-    var date = "Fri Nov 22 1963 13:00:00 GMT-0600"
+    var date = "-1250";
     var bandInfos = [
-        Timeline.createHotZoneBandInfo({
-            width:          "80%", 
-            intervalUnit:   Timeline.DateTime.WEEK, 
-            intervalPixels: 220,
+        Timeline.createBandInfo({
+            width:          "100%", 
+            intervalUnit:   Timeline.DateTime.MONTH, 
+            intervalPixels: 150,
             zones:          zones,
             eventSource:    eventSource,
             date:           date,
-            timeZone:       -6,
+//            timeZone:       -6,
             theme:          theme
-        }),
-        Timeline.createHotZoneBandInfo({
-            width:          "20%", 
-            intervalUnit:   Timeline.DateTime.MONTH, 
-            intervalPixels: 200,
-            zones:          zones2, 
-            eventSource:    eventSource,
-            date:           date, 
-            timeZone:       -6,
-            overview:       true,
-            theme:          theme
         })
+//        ,
+//        Timeline.createHotZoneBandInfo({
+//            width:          "20%", 
+//            intervalUnit:   Timeline.DateTime.MONTH, 
+//            intervalPixels: 200,
+//            zones:          zones2, 
+//            eventSource:    eventSource,
+//            date:           date, 
+//            timeZone:       -6,
+//            overview:       true,
+//            theme:          theme
+//        })
     ];
-    bandInfos[1].syncWith = 0;
-    bandInfos[1].highlight = true;
+//    bandInfos[1].syncWith = 0;
+//    bandInfos[1].highlight = true;
     
-    for (var i = 0; i < bandInfos.length; i++) {
-        bandInfos[i].decorators = [
-            new Timeline.SpanHighlightDecorator({
-                startDate:  "Fri Nov 22 1963 12:30:00 GMT-0600",
-                endDate:    "Fri Nov 22 1963 13:00:00 GMT-0600",
-                color:      "#FFC080", // set color explicitly
-                opacity:    50,
-                startLabel: "shot",
-                endLabel:   "t.o.d.",
-                theme:      theme
-            }),
-            new Timeline.PointHighlightDecorator({
-                date:       "Fri Nov 22 1963 14:38:00 GMT-0600",
-                opacity:    50,
-                theme:      theme
-                // use the color from the css file
-            }),
-            new Timeline.PointHighlightDecorator({
-                date:       "Sun Nov 24 1963 13:00:00 GMT-0600",
-                opacity:    50,
-                theme:      theme
-                // use the color from the css file
-            })
-        ];
-    }
+//    for (var i = 0; i < bandInfos.length; i++) {
+//        bandInfos[i].decorators = [
+//            new Timeline.SpanHighlightDecorator({
+//                startDate:  "Fri Nov 22 1963 12:30:00 GMT-0600",
+//                endDate:    "Fri Nov 22 1963 13:00:00 GMT-0600",
+//                color:      "#FFC080", // set color explicitly
+//                opacity:    50,
+//                startLabel: "shot",
+//                endLabel:   "t.o.d.",
+//                theme:      theme
+//            }),
+//            new Timeline.PointHighlightDecorator({
+//                date:       "Fri Nov 22 1963 14:38:00 GMT-0600",
+//                opacity:    50,
+//                theme:      theme
+//                // use the color from the css file
+//            }),
+//            new Timeline.PointHighlightDecorator({
+//                date:       "Sun Nov 24 1963 13:00:00 GMT-0600",
+//                opacity:    50,
+//                theme:      theme
+//                // use the color from the css file
+//            })
+//        ];
+//    }
     
     if(!tl) {
     	tl = Timeline.create(this.rootElement[0], bandInfos, Timeline.HORIZONTAL);    	
     }
+    
+    tl.loadJSON("rest/timeline/getEventsInPeriod/-101690000000000/-101580000000000", function(json, url) {
+        eventSource.loadJSON(json, url);
+    });    
+   
+    
+    
 //    tl.loadXML("jfk.xml", function(xml, url) { eventSource.loadXML(xml, url); });
 //    setupFilterHighlightControls(document.getElementById("controls"), tl, [0,1], theme);
 }

Modified: trunk/step/step-web/src/main/webapp/js/ui_hooks.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/ui_hooks.js	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/webapp/js/ui_hooks.js	2011-05-10 07:02:46 UTC (rev 227)
@@ -30,6 +30,7 @@
 
 TIMELINE_GET_EVENTS = "rest/timeline/getEvents/";
 TIMELINE_GET_EVENTS_FROM_REFERENCE = "rest/timeline/getEventsFromReference/";
+TIMELINE_GET_CONFIG = "rest/timeline/getTimelineConfiguration";
 
 USER_LOGIN = "rest/user/login/";
 USER_LOGOUT = "rest/user/logout/";
@@ -45,14 +46,14 @@
 function toggleMenuItem(menuItem) {
 	//the hook needs to find the passage id
 	$.shout("pane-menu-toggle-item-" + $(menuItem).closest(".passageContainer").attr("passage-id"), menuItem.name);
-}
+};
 
 /**
  * shows the login popup
  */
 function login() {
 	$.shout("show-login-popup");
-}
+};
 
 /**
  * shows the interlinear options as a popup
@@ -61,7 +62,7 @@
 function showInterlinearChoices(menuItem) {
 	//get passage id from menu parent
 	$.shout("interlinear-menu-option-triggered-" + $(menuItem).closest(".passageContainer").attr("passage-id")); 
-}
+};
 
 /**
  * called when click on a piece of text.
@@ -69,7 +70,7 @@
  */
 function showAllStrongMorphs(strongMorphs) {
 	$.shout("show-all-strong-morphs", strongMorphs);
-}
+};
 
 /**
  * Called when clicking on a strong link
@@ -77,7 +78,7 @@
  */
 function showStrong(strong, sourceElement) {
 	showMorphOrStrong(strong, sourceElement);
-}
+};
 
 /**
  * called when clicking on a morph
@@ -85,7 +86,7 @@
  */
 function showMorph(morph, sourceElement) {
 	showMorphOrStrong(morph, sourceElement);
-}
+};
 
 /** TODO: move this out of here to utils.js if we have more utility classes/functions 
  * helper function for morph and strongs 
@@ -96,7 +97,7 @@
 	
 	//need to find what event is coming in, to get the clicked element and pass that down
 	$("#lexiconDefinition span:contains(" + tag + ")").parent().click();	
-}
+};
 
 function showAbout() {
 	//show popup for About box
@@ -105,4 +106,21 @@
 		width: DEFAULT_POPUP_WIDTH,
 		title: "STEP :: Scripture Tools for Every Pastor",
 	});
-}
\ No newline at end of file
+};
+
+/**
+ * Shows the timeline module
+ */
+function showTimelineModule() {
+	showBottomSection();
+	$.shout("show-timeline");
+};
+
+/**
+ * shows the bottom section
+ */
+function showBottomSection() {
+	var bottomSection = $("#bottomSection");
+	bottomSection.height(bottomSection.parent().parent().height() / 2);
+	refreshLayout();
+}

Modified: trunk/step/step-web/src/main/webapp/panemenu.html
===================================================================
--- trunk/step/step-web/src/main/webapp/panemenu.html	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/main/webapp/panemenu.html	2011-05-10 07:02:46 UTC (rev 227)
@@ -10,7 +10,7 @@
 	</li>
 	<li><a href="#">Context</a>
 	<ul>
-		<li><a href="#" class="notYetImplemented">Timeline</a></li>
+		<li><a href="#" onclick="showTimelineModule();">Timeline</a></li>
 	</ul>
 	</li>
 	<li><a href="#">Tools</a>

Added: trunk/step/step-web/src/main/webapp/tempdev/events.json
===================================================================
--- trunk/step/step-web/src/main/webapp/tempdev/events.json	                        (rev 0)
+++ trunk/step/step-web/src/main/webapp/tempdev/events.json	2011-05-10 07:02:46 UTC (rev 227)
@@ -0,0 +1,14 @@
+{
+'dateTimeFormat': 'iso8601',
+'wikiURL': "http://simile.mit.edu/shelf/",
+'wikiSection': "Simile Cubism Timeline",
+
+'events' : [
+        {'start': '-1262',
+        'title': 'Barfusserkirche',
+        'description': 'by Lyonel Feininger, American/German Painter, 1871-1956',
+        'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
+        'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
+        },
+]
+}
\ No newline at end of file

Modified: trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java
===================================================================
--- trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -7,7 +7,6 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -17,9 +16,6 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -35,6 +31,7 @@
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
 import com.tyndalehouse.step.core.service.BibleInformationService;
 import com.tyndalehouse.step.rest.framework.ClientErrorResolver;
+import com.tyndalehouse.step.rest.framework.ControllerCacheKey;
 import com.tyndalehouse.step.rest.framework.ResponseCache;
 import com.tyndalehouse.step.rest.framework.StepRequest;
 
@@ -59,6 +56,8 @@
     private ClientErrorResolver errorResolver;
     @Mock
     private ResponseCache responseCache;
+    @Mock
+    private StepRequest stepRequest;
 
     /**
      * Simply setting up the FrontController under test
@@ -76,21 +75,24 @@
      */
     @Test
     public void testDoGet() throws IOException {
-        final HttpServletRequest request = mock(HttpServletRequest.class);
+        final HttpServletRequest req = mock(HttpServletRequest.class);
         final HttpServletResponse response = mock(HttpServletResponse.class);
+        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
 
+        when(req.getRequestURI()).thenReturn(sampleRequest);
+        when(req.getServletPath()).thenReturn("step-web/");
+        when(req.getContextPath()).thenReturn("rest/");
+
         final FrontController fc = spy(this.fcUnderTest);
-        final StepRequest parsedRequest = new StepRequest("blah", "SomeController", "someMethod",
-                new String[] { "arg1", "arg2" });
+
         final ServletOutputStream mockOutputStream = mock(ServletOutputStream.class);
 
-        doReturn(parsedRequest).when(fc).parseRequest(request);
         doReturn(mockOutputStream).when(response).getOutputStream();
         final byte[] sampleResponse = new byte[] { 1, 2, 3 };
-        doReturn(sampleResponse).when(fc).invokeMethod(parsedRequest);
+        doReturn(sampleResponse).when(fc).invokeMethod(any(StepRequest.class));
 
         // do the test
-        fc.doGet(request, response);
+        fc.doGet(req, response);
         verify(mockOutputStream).write(sampleResponse);
     }
 
@@ -107,7 +109,8 @@
         final StepRequest parsedRequest = new StepRequest("blah", "SomeController", "someMethod",
                 new String[] { "arg1", "arg2" });
 
-        doThrow(testException).when(fc).parseRequest(request);
+        // TODO remove this/
+        // doThrow(testException).when(fc).parseRequest(request);
         doNothing().when(fc).handleError(response, testException, parsedRequest);
 
         // do the test
@@ -116,65 +119,6 @@
     }
 
     /**
-     * tests that arguments are parsed correctly given the correct start
-     */
-    @Test
-    public void testGetArgs() {
-        // index starts at ...........0123456789-123456789-123456
-        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2";
-
-        // when
-        final Object[] args = this.fcUnderTest.getArgs(sampleRequest, 24);
-
-        // then
-        assertEquals(2, args.length);
-        assertEquals("1K2", args[0]);
-        assertEquals("2K2", args[1]);
-    }
-
-    /**
-     * tests that parsing of request works if request finishes with a slash
-     */
-    @Test
-    public void testGetArgsFinishingWithSlash() {
-        // index starts at ...........0123456789-123456789-123456
-        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
-
-        // when
-        final Object[] args = this.fcUnderTest.getArgs(sampleRequest, 24);
-
-        // then
-        assertEquals(2, args.length);
-        assertEquals("1K2", args[0]);
-        assertEquals("2K2", args[1]);
-    }
-
-    /**
-     * we check that the path is concatenated with the servlet path
-     * 
-     * @throws ServletException an uncaught exception
-     */
-    @Test
-    public void testGetPath() throws ServletException {
-        final FrontController spy = spy(this.fcUnderTest);
-
-        final ServletContext mockServletContext = mock(ServletContext.class);
-        final HttpServletRequest mockRequest = mock(HttpServletRequest.class);
-
-        spy.init(mock(ServletConfig.class));
-
-        when(spy.getServletContext()).thenReturn(mockServletContext);
-        when(mockServletContext.getContextPath()).thenReturn("context/");
-        when(mockRequest.getServletPath()).thenReturn("servletPath");
-
-        // when
-        final String path = spy.getPath(mockRequest);
-
-        // then
-        assertEquals(path, "context/servletPath");
-    }
-
-    /**
      * tests that the headers are setup correctly
      */
     @Test
@@ -260,56 +204,20 @@
     @Test
     public void testDoErrorHandlesCorrectly() throws IOException {
         final HttpServletResponse response = mock(HttpServletResponse.class);
-        final StepRequest stepRequest = new StepRequest("blah", "controller", "method", null);
+        // final StepRequest stepRequest = new StepRequest("blah", "controller", "method", null);
         final ServletOutputStream outputStream = mock(ServletOutputStream.class);
         final Throwable exception = new Exception();
         when(response.getOutputStream()).thenReturn(outputStream);
+        when(this.stepRequest.getCacheKey()).thenReturn(new ControllerCacheKey("method", "results"));
 
         // do test
-        this.fcUnderTest.handleError(response, exception, stepRequest);
+        this.fcUnderTest.handleError(response, exception, this.stepRequest);
 
         // check
         verify(outputStream).write(any(byte[].class));
     }
 
     /**
-     * checks that parsing is working correctly
-     * 
-     * @throws ServletException uncaught exception
-     */
-    @Test
-    public void testParseRequest() throws ServletException {
-        final HttpServletRequest request = mock(HttpServletRequest.class);
-        final String requestSeparator = "/";
-        final String contextName = "step-web";
-        final String servletName = "servletName";
-        final String controllerName = "controllerName";
-        final String methodName = "methodName";
-        final String arg1 = "argument1";
-        final String arg2 = "argument2";
-
-        when(request.getServletPath()).thenReturn(servletName);
-        when(request.getRequestURI()).thenReturn(
-                contextName + requestSeparator + servletName + requestSeparator + controllerName
-                        + requestSeparator + methodName + requestSeparator + arg1 + requestSeparator + arg2);
-
-        this.fcUnderTest.init(mock(ServletConfig.class));
-
-        final FrontController spy = spy(this.fcUnderTest);
-
-        final ServletContext mockServletContext = mock(ServletContext.class);
-        when(spy.getServletContext()).thenReturn(mockServletContext);
-        when(mockServletContext.getContextPath()).thenReturn(contextName + "/");
-
-        // do test
-        final StepRequest parseRequest = this.fcUnderTest.parseRequest(request);
-
-        // check controller name, method name and arguments
-        assertEquals(controllerName, parseRequest.getControllerName());
-        assertEquals(methodName, parseRequest.getMethodName());
-    }
-
-    /**
      * We check that invoke method calls the correct controller and method with the right arguments
      */
     @Test

Modified: trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/StepRequestTest.java
===================================================================
--- trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/StepRequestTest.java	2011-03-29 21:43:38 UTC (rev 226)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/StepRequestTest.java	2011-05-10 07:02:46 UTC (rev 227)
@@ -1,8 +1,17 @@
 package com.tyndalehouse.step.rest.framework;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
 import org.junit.Test;
 
 /**
@@ -12,6 +21,7 @@
  * 
  */
 public class StepRequestTest {
+    private static final String UTF_8_ENCODING = "UTF-8";
     private static final String[] TEST_ARGS = new String[] { "arg1", "arg2", "arg3" };
     private static final String TEST_CONTROLLER_NAME = "Controller";
     private static final String TEST_METHOD_NAME = "method";
@@ -47,6 +57,76 @@
     }
 
     /**
+     * testing simple parsing of arguments
+     */
+    @Test
+    public void testParseArguments() {
+        // index starts at ...........0123456789-123456789-123456
+        final String stepRequest = "step-web/rest/bible/get/1K2/2K2/";
+        final HttpServletRequest req = mock(HttpServletRequest.class);
+
+        when(req.getRequestURI()).thenReturn(stepRequest);
+        when(req.getServletPath()).thenReturn("step-web/");
+        when(req.getContextPath()).thenReturn("rest/");
+
+        // index starts at ...........0123456789-123456789-123456
+        final StepRequest sr = new StepRequest(req, UTF_8_ENCODING);
+        assertEquals(2, sr.getArgs().length);
+        assertEquals("1K2", sr.getArgs()[0]);
+        assertEquals("2K2", sr.getArgs()[1]);
+    }
+
+    /**
+     * tests that parsing of request works if request finishes with a slash
+     */
+    @Test
+    public void testGetArgsFinishingWithSlash() {
+        // index starts at ...........0123456789-123456789-123456
+        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
+        final HttpServletRequest req = mock(HttpServletRequest.class);
+
+        when(req.getRequestURI()).thenReturn(sampleRequest);
+        when(req.getServletPath()).thenReturn("step-web/");
+        when(req.getContextPath()).thenReturn("rest/");
+
+        final StepRequest sr = new StepRequest(req, UTF_8_ENCODING);
+
+        // then
+        assertEquals(2, sr.getArgs().length);
+        assertEquals("1K2", sr.getArgs()[0]);
+        assertEquals("2K2", sr.getArgs()[1]);
+    }
+
+    /**
+     * we check that the path is concatenated with the servlet path
+     * 
+     * @throws ServletException an uncaught exception
+     * @throws InvocationTargetException an uncaught exception
+     * @throws IllegalAccessException an uncaught exception
+     * @throws NoSuchMethodException an uncaught exception
+     */
+    @Test
+    public void testGetPath() throws ServletException, IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        // length is: 1234567890123456789012345
+        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
+        final HttpServletRequest req = mock(HttpServletRequest.class);
+
+        when(req.getRequestURI()).thenReturn(sampleRequest);
+        when(req.getServletPath()).thenReturn("letters");
+        when(req.getContextPath()).thenReturn("more");
+
+        // then
+        final StepRequest sr = new StepRequest(req, "UTF-8");
+        final Method declaredMethod = sr.getClass().getDeclaredMethod("getPathLength",
+                HttpServletRequest.class);
+        declaredMethod.setAccessible(true);
+
+        assertEquals(11, declaredMethod.invoke(sr, req));
+    }
+
+    /**
      * helper factory method
      * 
      * @return a step request




More information about the Tynstep-svn mailing list