[Tynstep-svn] r226 - in trunk/step: step-core step-core/src/main/java/com/tyndalehouse/step/core/data step-core/src/main/java/com/tyndalehouse/step/core/data/caches step-core/src/main/java/com/tyndalehouse/step/core/data/entities step-core/src/main/java/com/tyndalehouse/step/core/guice step-core/src/main/java/com/tyndalehouse/step/core/guice/providers step-core/src/main/java/com/tyndalehouse/step/core/models 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/java/com/tyndalehouse/step/core/utils/cache step-core/src/main/resources step-core/src/test/java/com/tyndalehouse/step/core/data/create step-core/src/test/java/com/tyndalehouse/step/core/guice step-core/src/test/java/com/tyndalehouse/step/core/guice/providers step-core/src/test/java/com/tyndalehouse/step/core/service step-core/src/test/java/com/tyndalehouse/step/core/service/impl step-core/src/test/java/com/tyndalehouse/step/core/utils step-parent step-web 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/WEB-INF step-web/src/main/webapp/libs 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 Mar 29 14:43:38 MST 2011


Author: ChrisBurrell
Date: 2011-03-29 14:43:38 -0700 (Tue, 29 Mar 2011)
New Revision: 226

Added:
   trunk/step/step-core/db-create.sql
   trunk/step/step-core/db-drop.sql
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractCacheListener.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractDefaultCache.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCache.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCacheListener.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/cache/
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/cache/SimpleCache.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProviderTest.java
   trunk/step/step-web/db-create.sql
   trunk/step/step-web/db-drop.sql
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cacheable.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/EbeanServletContextListener.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java
   trunk/step/step-web/src/main/webapp/libs/jquery_include.js
Modified:
   trunk/step/step-core/pom.xml
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/Session.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.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/ServerSessionProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.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/JSwordServiceImpl.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/step.core.properties
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTestModule.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java
   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/utils/PassageReferenceUtilsTest.java
   trunk/step/step-parent/pom.xml
   trunk/step/step-web/pom.xml
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.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/ModuleController.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/StepRequest.java
   trunk/step/step-web/src/main/webapp/WEB-INF/web.xml
   trunk/step/step-web/src/main/webapp/index.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:
fixing poms and added a whole load of caching on request responses, as well as on server side sessions to reduce number of DB calls

Added: trunk/step/step-core/db-create.sql
===================================================================
--- trunk/step/step-core/db-create.sql	                        (rev 0)
+++ trunk/step/step-core/db-create.sql	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,106 @@
+create table bookmark (
+  id                        integer not null,
+  bookmark_reference        varchar(255) not null,
+  user_id                   integer,
+  constraint pk_bookmark primary key (id))
+;
+
+create table history (
+  id                        integer not null,
+  history_reference         varchar(255) not null,
+  user_id                   integer,
+  last_updated              timestamp not null,
+  constraint pk_history primary key (id))
+;
+
+create table hot_spot (
+  id                        integer not null,
+  description               varchar(255),
+  code                      varchar(255),
+  scale                     integer,
+  timeband_id               integer,
+  constraint ck_hot_spot_scale check (scale in (0,1,2,3,4,5,6)),
+  constraint pk_hot_spot primary key (id))
+;
+
+create table scripture_reference (
+  scripture_reference_id    integer not null,
+  target_id                 integer,
+  target_type               integer,
+  start_verse_id            integer,
+  end_verse_id              integer,
+  constraint ck_scripture_reference_target_type check (target_type in (0)),
+  constraint pk_scripture_reference primary key (scripture_reference_id))
+;
+
+create table scripture_target (
+  targetTypeId              integer(31) not null,
+  id                        integer not null,
+  summary                   varchar(255),
+  from_date                 bigint,
+  to_date                   bigint,
+  from_precision            integer,
+  to_precision              integer,
+  hot_spot_id               integer,
+  constraint ck_scripture_target_from_precision check (from_precision in (0,1,2,3)),
+  constraint ck_scripture_target_to_precision check (to_precision in (0,1,2,3)),
+  constraint pk_scripture_target primary key (id))
+;
+
+create table session (
+  id                        integer not null,
+  j_session_id              varchar(255),
+  user_id                   integer,
+  ip_address                varchar(255),
+  expires_on                timestamp,
+  constraint pk_session primary key (id))
+;
+
+create table timeband (
+  id                        integer not null,
+  code                      varchar(255),
+  scale                     integer,
+  description               varchar(255),
+  constraint ck_timeband_scale check (scale in (0,1,2,3,4,5,6)),
+  constraint pk_timeband primary key (id))
+;
+
+create table users (
+  id                        integer not null,
+  name                      varchar(255),
+  password                  varchar(255),
+  email_address             varchar(255),
+  country                   varchar(255),
+  constraint pk_users primary key (id))
+;
+
+create sequence bookmark_seq;
+
+create sequence history_seq;
+
+create sequence hot_spot_seq;
+
+create sequence scripture_reference_seq;
+
+create sequence scripture_target_seq;
+
+create sequence session_seq;
+
+create sequence timeband_seq;
+
+create sequence users_seq;
+
+alter table bookmark add constraint fk_bookmark_user_1 foreign key (user_id) references users (id) on delete restrict on update restrict;
+create index ix_bookmark_user_1 on bookmark (user_id);
+alter table history add constraint fk_history_user_2 foreign key (user_id) references users (id) on delete restrict on update restrict;
+create index ix_history_user_2 on history (user_id);
+alter table hot_spot add constraint fk_hot_spot_timeband_3 foreign key (timeband_id) references timeband (id) on delete restrict on update restrict;
+create index ix_hot_spot_timeband_3 on hot_spot (timeband_id);
+alter table scripture_reference add constraint fk_scripture_reference_target_4 foreign key (target_id) references scripture_target (id) on delete restrict on update restrict;
+create index ix_scripture_reference_target_4 on scripture_reference (target_id);
+alter table scripture_target add constraint fk_scripture_target_hotSpot_5 foreign key (hot_spot_id) references hot_spot (id) on delete restrict on update restrict;
+create index ix_scripture_target_hotSpot_5 on scripture_target (hot_spot_id);
+alter table session add constraint fk_session_user_6 foreign key (user_id) references users (id) on delete restrict on update restrict;
+create index ix_session_user_6 on session (user_id);
+
+

Added: trunk/step/step-core/db-drop.sql
===================================================================
--- trunk/step/step-core/db-drop.sql	                        (rev 0)
+++ trunk/step/step-core/db-drop.sql	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,36 @@
+SET REFERENTIAL_INTEGRITY FALSE;
+
+drop table if exists bookmark;
+
+drop table if exists history;
+
+drop table if exists hot_spot;
+
+drop table if exists scripture_reference;
+
+drop table if exists scripture_target;
+
+drop table if exists session;
+
+drop table if exists timeband;
+
+drop table if exists users;
+
+SET REFERENTIAL_INTEGRITY TRUE;
+
+drop sequence if exists bookmark_seq;
+
+drop sequence if exists history_seq;
+
+drop sequence if exists hot_spot_seq;
+
+drop sequence if exists scripture_reference_seq;
+
+drop sequence if exists scripture_target_seq;
+
+drop sequence if exists session_seq;
+
+drop sequence if exists timeband_seq;
+
+drop sequence if exists users_seq;
+

Modified: trunk/step/step-core/pom.xml
===================================================================
--- trunk/step/step-core/pom.xml	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/pom.xml	2011-03-29 21:43:38 UTC (rev 226)
@@ -136,6 +136,12 @@
 			<artifactId>h2</artifactId>
 		</dependency>
 		
+		<dependency>
+			<groupId>net.sf.ehcache</groupId>
+			<artifactId>ehcache</artifactId>
+			<type>pom</type>
+		</dependency>
+		
 		<!-- transitive dependencies not picked up by jsword -->
 		<dependency>
 			<groupId>javatar</groupId>

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractCacheListener.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractCacheListener.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractCacheListener.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,58 @@
+package com.tyndalehouse.step.core.data.caches;
+
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.event.CacheEventListener;
+
+/**
+ * This is a simple implementation where the listener does nothing. It is meant to be inherited to provide
+ * overiddes for just what is required.
+ * 
+ * @author Chris
+ * 
+ */
+ at SuppressWarnings("PMD.EmptyMethodInAbstractClassShouldBeAbstract")
+public abstract class AbstractCacheListener implements CacheEventListener {
+
+    @Override
+    public void notifyElementRemoved(final Ehcache cache, final Element element) {
+        // No implementation
+    }
+
+    @Override
+    public void notifyElementPut(final Ehcache cache, final Element element) {
+        // No implementation
+    }
+
+    @Override
+    public void notifyElementUpdated(final Ehcache cache, final Element element) {
+        // No implementation
+    }
+
+    @Override
+    public void notifyElementExpired(final Ehcache cache, final Element element) {
+        // No implementation
+    }
+
+    @Override
+    public void notifyElementEvicted(final Ehcache cache, final Element element) {
+        // No implementation
+    }
+
+    @Override
+    public void notifyRemoveAll(final Ehcache cache) {
+        // No implementation
+    }
+
+    @Override
+    public void dispose() {
+        // No implementation
+    }
+
+    // CHECKSTYLE:OFF We are forced to override here sadly
+    @Override
+    public Object clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+    // CHECKSTYLE:ON
+}


Property changes on: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractCacheListener.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractDefaultCache.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractDefaultCache.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractDefaultCache.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,57 @@
+package com.tyndalehouse.step.core.data.caches;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.config.CacheConfiguration;
+
+import com.tyndalehouse.step.core.utils.cache.SimpleCache;
+
+/**
+ * An abstract implementation of the cache
+ * 
+ * @author Chris
+ * @param <T> the type of element that will be stored in the cache
+ */
+public abstract class AbstractDefaultCache<T> implements SimpleCache<String, T> {
+    private final Cache cache;
+
+    /**
+     * creates a default cache
+     * 
+     * @param cacheManager the cache manager
+     * @param config the config to create it with
+     */
+    public AbstractDefaultCache(final CacheManager cacheManager, final CacheConfiguration config) {
+        this.cache = new Cache(config);
+        cacheManager.addCache(this.cache);
+    }
+
+    @Override
+    public void put(final String key, final T obj) {
+        final Element e = new Element(key, obj);
+        this.cache.put(e);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T get(final String key) {
+        if (key == null) {
+            return null;
+        }
+
+        final Element element = this.cache.get(key);
+        if (element == null) {
+            return null;
+        }
+
+        return (T) element.getObjectValue();
+    }
+
+    /**
+     * @return the cache
+     */
+    public Cache getCache() {
+        return this.cache;
+    }
+}


Property changes on: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/AbstractDefaultCache.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCache.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCache.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCache.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,44 @@
+package com.tyndalehouse.step.core.data.caches;
+
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import com.tyndalehouse.step.core.data.entities.Session;
+
+/**
+ * Session cache is configured to only contain elements for a certain while
+ * 
+ * The session cache automatically expires elements after a while and will clean up dead sessions on exit
+ * 
+ * @author Chris
+ * 
+ */
+public class SessionCache extends AbstractDefaultCache<Session> {
+
+    /**
+     * creates the session cache
+     * 
+     * @param cacheManager the cache manager
+     * @param cacheListener the listener that will expire or update elements in the database
+     * @param maxElementsInMemory the number of alive sessions
+     * @param timeToLiveSeconds the time in seconds for each element to live
+     * @param timeToIdleSeconds the number of seconds that after an element has been accessed for the last
+     *            time.
+     */
+    @Inject
+    public SessionCache(final CacheManager cacheManager, final SessionCacheListener cacheListener,
+            @Named("app.cache.session.maxElements") final int maxElementsInMemory,
+            @Named("app.cache.session.timeToLive") final int timeToLiveSeconds,
+            @Named("app.cache.session.timeToIdle") final int timeToIdleSeconds) {
+        super(cacheManager, new CacheConfiguration("sessionCache", maxElementsInMemory)
+                .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU).overflowToDisk(false)
+                .eternal(false).timeToLiveSeconds(timeToLiveSeconds).timeToIdleSeconds(timeToIdleSeconds)
+                .diskPersistent(false).diskExpiryThreadIntervalSeconds(0));
+
+        // add two listeners, one to expire sessions, one to maintain sessions:
+        getCache().getCacheEventNotificationService().registerListener(cacheListener);
+    }
+}


Property changes on: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCache.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCacheListener.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCacheListener.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCacheListener.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,65 @@
+package com.tyndalehouse.step.core.data.caches;
+
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+
+import com.avaje.ebean.EbeanServer;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import com.tyndalehouse.step.core.data.entities.Session;
+
+/**
+ * provides simple implementation for expiring and updating session
+ * 
+ * @author Chris
+ * 
+ */
+public class SessionCacheListener extends AbstractCacheListener {
+    private final EbeanServer ebean;
+    private final int expiryPeriod;
+
+    /**
+     * @param ebean ebean server
+     * @param expiryPeriod time to let go by before we expire the session after no activity
+     * 
+     */
+    @Inject
+    public SessionCacheListener(final EbeanServer ebean,
+            @Named("app.cache.session.timeToIdle") final int expiryPeriod) {
+        this.ebean = ebean;
+        this.expiryPeriod = expiryPeriod;
+    }
+
+    @Override
+    public void notifyElementUpdated(final Ehcache cache, final Element element) {
+        final Calendar expiryDate = Calendar.getInstance();
+        expiryDate.add(Calendar.DAY_OF_YEAR, this.expiryPeriod);
+
+        final Session session = getSessionFromElement(element);
+        session.setExpiresOn(new Timestamp(expiryDate.getTimeInMillis()));
+        this.ebean.update(session);
+    }
+
+    @Override
+    public void notifyElementEvicted(final Ehcache cache, final Element element) {
+        this.ebean.delete(getSessionFromElement(element));
+    }
+
+    /**
+     * Retrieves the session by casting the object value
+     * 
+     * @param element the cache element
+     * @return the value from the cache
+     */
+    private Session getSessionFromElement(final Element element) {
+        return (Session) element.getObjectValue();
+    }
+
+    @Override
+    public void notifyRemoveAll(final Ehcache cache) {
+        this.ebean.delete(Session.class);
+    }
+}


Property changes on: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/caches/SessionCacheListener.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/Session.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/Session.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/Session.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -1,7 +1,7 @@
 package com.tyndalehouse.step.core.data.entities;
 
 import java.io.Serializable;
-import java.util.Date;
+import java.sql.Timestamp;
 
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
@@ -13,8 +13,8 @@
 import javax.persistence.TemporalType;
 
 /**
- * TODO add job to clean up old sessions that have expired A session is associated with a user and may or may
- * not be active (expiresOn value) A user may be logged in multiple times and hence have several sessions.
+ * A session is associated with a user and may or may not be active (expiresOn value) A user may be logged in
+ * multiple times and hence have several sessions.
  * 
  * @author Chris
  * 
@@ -39,7 +39,7 @@
 
     @Temporal(TemporalType.TIMESTAMP)
     @Column
-    private Date expiresOn;
+    private Timestamp expiresOn;
 
     /**
      * @return the id
@@ -86,14 +86,14 @@
     /**
      * @return the expiresOn
      */
-    public Date getExpiresOn() {
+    public Timestamp getExpiresOn() {
         return this.expiresOn;
     }
 
     /**
      * @param expiresOn the expiresOn to set
      */
-    public void setExpiresOn(final Date expiresOn) {
+    public void setExpiresOn(final Timestamp expiresOn) {
         this.expiresOn = expiresOn;
     }
 

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -6,10 +6,15 @@
 import java.util.Map;
 import java.util.Properties;
 
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.config.Configuration;
+
 import org.crosswire.jsword.book.install.Installer;
 
 import com.avaje.ebean.EbeanServer;
 import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
 import com.google.inject.TypeLiteral;
 import com.google.inject.name.Names;
 import com.tyndalehouse.step.core.data.create.Loader;
@@ -48,6 +53,9 @@
         final Properties stepProperties = readProperties();
         bind(Properties.class).annotatedWith(Names.named("StepCoreProperties")).toInstance(stepProperties);
 
+        // for now just have a method that statically initialises the cache
+        initialiseCacheManager();
+
         bind(JSwordService.class).to(JSwordServiceImpl.class).asEagerSingleton();
         bind(BibleInformationService.class).to(BibleInformationServiceImpl.class).asEagerSingleton();
         bind(ModuleService.class).to(ModuleServiceImpl.class).asEagerSingleton();
@@ -67,6 +75,8 @@
 
         bind(EbeanServer.class).toProvider(DatabaseConfigProvider.class).asEagerSingleton();
 
+        // bind a cache
+
         bindDaos();
 
         // now bind the test data
@@ -76,6 +86,26 @@
     }
 
     /**
+     * we return the singleton instance here
+     * 
+     * @return the singleton cache manager
+     */
+    @Provides
+    public CacheManager getCacheManager() {
+        return CacheManager.getInstance();
+    }
+
+    /**
+     * initialises the cache manager. e.g. disables update checker
+     */
+    private void initialiseCacheManager() {
+        final Configuration config = new Configuration();
+        config.setUpdateCheck(false);
+        config.defaultCache(new CacheConfiguration());
+        CacheManager.create(config);
+    }
+
+    /**
      * helper method that binds the DAOs
      */
     private void bindDaos() {

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -63,7 +63,7 @@
         this.password = password;
         this.validationQuery = validationQuery;
 
-        // TODO add exception handling when i know how
+        // TODO: add exception handling when i know how
         this.maxActive = Integer.parseInt(maxActive);
         this.maxIdle = Integer.parseInt(maxIdle);
         this.maxOpenStatements = Integer.parseInt(maxOpenStatements);

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -57,7 +57,7 @@
                         final Integer p = Integer.parseInt(proxyPort);
                         installer.setProxyPort(p.intValue());
                     } catch (final NumberFormatException e) {
-                        // TODO work out how this should be thrown
+                        // 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/ServerSessionProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProvider.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProvider.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -1,16 +1,22 @@
 package com.tyndalehouse.step.core.guice.providers;
 
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.avaje.ebean.EbeanServer;
 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.caches.SessionCache;
 import com.tyndalehouse.step.core.data.entities.Session;
 import com.tyndalehouse.step.core.models.ClientSession;
-import com.tyndalehouse.step.core.service.UserDataService;
 
 /**
- * A server session provider TODO should use CACHE here since we query almost everytime there is a request for
- * bookmarks, etc.
+ * A server session provider
  * 
  * @author Chris
  * 
@@ -19,36 +25,99 @@
 public class ServerSessionProvider implements Provider<Session> {
     // we store the provider, since the provider is request-scoped and therefore
     // values vary
+    private static final Logger LOG = LoggerFactory.getLogger(ServerSessionProvider.class);
     private final Provider<ClientSession> clientSessionProvider;
     private final EbeanServer ebean;
-    private final UserDataService userDataService;
+    private final SessionCache sessionCache;
+    private final int expiryPeriod;
 
     /**
      * Sets up a singleton provider that relies upon a request-scoped clientSessionProvider.
      * 
      * @param ebean the ebean server used to retrieve data
      * @param clientSessionProvider the client session provider, giving us an id to reference
-     * @param userDataService a service for user and session management
+     * @param sessionCache which will hold in memory to avoid too many DB calls
+     * @param expiryPeriod the time a session will remain alive for the session
      */
     @Inject
     public ServerSessionProvider(final EbeanServer ebean,
-            final Provider<ClientSession> clientSessionProvider, final UserDataService userDataService) {
+            final Provider<ClientSession> clientSessionProvider, final SessionCache sessionCache,
+            @Named("app.cache.session.timeToIdle") final int expiryPeriod) {
         this.ebean = ebean;
         this.clientSessionProvider = clientSessionProvider;
-        this.userDataService = userDataService;
+        this.sessionCache = sessionCache;
+        this.expiryPeriod = expiryPeriod;
     }
 
     @Override
     public Session get() {
+        LOG.debug("Retrieving session");
         final String clientSessionId = this.clientSessionProvider.get().getSessionId();
+
+        Session session = this.sessionCache.get(clientSessionId);
+        if (session == null) {
+            LOG.debug("Session was not in cache, retrieving or creating from database");
+            // cache miss, or no session in server
+            session = getSessionFromDb(clientSessionId);
+            this.sessionCache.put(clientSessionId, session);
+        }
+        return session;
+    }
+
+    /**
+     * checks the database for the server session, and creates one if not present
+     * 
+     * @param clientSessionId the key identifying the session
+     * @return the sesion that was or has now been persisted
+     */
+    private Session getSessionFromDb(final String clientSessionId) {
         final Session serverSession = this.ebean.find(Session.class).fetch("user", "id, name").where()
                 .eq("jSessionId", clientSessionId).findUnique();
 
+        // we create a server session
         if (serverSession == null) {
-            // we create a server session
-            return this.userDataService.createSession();
+            LOG.debug("Server session was not present");
+            return createSession();
         }
 
+        // deal with expired sessions... This should never happen has a cache miss should have cleared out,
+        // but all the same
+        if (Calendar.getInstance().after(serverSession.getExpiresOn())) {
+            // session has expired, so we remove the reference to the user and update the expiry date
+            serverSession.setUser(null);
+            serverSession.setExpiresOn(getExpiryTime());
+            this.ebean.update(serverSession);
+        }
+
         return serverSession;
     }
+
+    /**
+     * Creates a session in the database
+     * 
+     * @return the session that was created
+     */
+    Session createSession() {
+        final Session session = new Session();
+        final ClientSession clientSession = this.clientSessionProvider.get();
+        session.setJSessionId(clientSession.getSessionId());
+        session.setIpAddress(clientSession.getIpAddress());
+        session.setExpiresOn(getExpiryTime());
+
+        LOG.debug("Persisting session (jSessionId=[{}],ip=[{}])", session.getJSessionId(),
+                session.getIpAddress());
+        this.ebean.save(session);
+        return session;
+    }
+
+    /**
+     * Simply add today to the expiry period and return
+     * 
+     * @return the time at which the session will expire
+     */
+    private Timestamp getExpiryTime() {
+        final Calendar expiryDate = Calendar.getInstance();
+        expiryDate.add(Calendar.DAY_OF_YEAR, this.expiryPeriod);
+        return new Timestamp(expiryDate.getTimeInMillis());
+    }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -11,7 +11,7 @@
  * 
  */
 public enum LookupOption {
-    // CHECKSTYLE:OFF TODO change the values in the XSL file
+    // CHECKSTYLE:OFF TODO: change the values in the XSL file
     /**
      * Showing headings
      */

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/UserDataService.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -1,6 +1,5 @@
 package com.tyndalehouse.step.core.service;
 
-import com.tyndalehouse.step.core.data.entities.Session;
 import com.tyndalehouse.step.core.data.entities.User;
 
 /**
@@ -34,14 +33,6 @@
     User register(String emailAddress, String name, String country, String password);
 
     /**
-     * TODO move this to session provider This method is called to create a session for the user. This will
-     * associate the jsession id with a new row in the Session table.
-     * 
-     * @return the server session that was created
-     */
-    Session createSession();
-
-    /**
      * Associates the current session with the username assuming password and username authenticates
      * 
      * @param emailAddress the email address is used as the login token

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -114,7 +114,7 @@
         return getOsisText(version, reference, options, null);
     }
 
-    // TODO remove synchronisation once book is fixed
+    // TODO: remove synchronisation once book is fixed
     @Override
     public synchronized String getOsisText(final String version, final String reference,
             final List<LookupOption> options, final String interlinearVersion) {
@@ -228,7 +228,7 @@
             if (isNotBlank(interlinearVersion)) {
                 tsep.setParameter("interlinearVersion", interlinearVersion);
             }
-            // TODO else depending on OT or NT, we select a default interlinear version
+            // TODO: else depending on OT or NT, we select a default interlinear version
         }
     }
 

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImpl.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -2,9 +2,6 @@
 
 import static com.avaje.ebean.Expr.eq;
 
-import java.util.Calendar;
-import java.util.Date;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -15,7 +12,6 @@
 import com.tyndalehouse.step.core.data.entities.Session;
 import com.tyndalehouse.step.core.data.entities.User;
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
-import com.tyndalehouse.step.core.models.ClientSession;
 import com.tyndalehouse.step.core.service.UserDataService;
 
 /**
@@ -28,41 +24,31 @@
  */
 @Singleton
 public class UserDataServiceImpl implements UserDataService {
-    private static final int EXPIRY_SESSION_INTERVAL = 30;
     private static final Logger LOG = LoggerFactory.getLogger(UserDataServiceImpl.class);
     private final Provider<Session> sessionProvider;
     private final EbeanServer ebean;
-    private final Provider<ClientSession> clientSessionProvider;
 
     /**
      * sessions change at runtime based on which request we are serving
      * 
      * @param ebean the ebean server to persist and load data
      * @param sessionProvider the session provider
-     * @param clientSessionProvider the client session (cookie information + ip address)
      */
     @Inject
-    public UserDataServiceImpl(final EbeanServer ebean, final Provider<Session> sessionProvider,
-            final Provider<ClientSession> clientSessionProvider) {
+    public UserDataServiceImpl(final EbeanServer ebean, final Provider<Session> sessionProvider) {
         this.ebean = ebean;
         this.sessionProvider = sessionProvider;
-        this.clientSessionProvider = clientSessionProvider;
     }
 
     @Override
     public User register(final String emailAddress, final String name, final String country,
             final String password) {
-        // first check that are we not logged in!
-        Session session = this.sessionProvider.get();
 
-        // check we have a session, otherwise create one for ourselves (this should be catered
-        if (session == null || Calendar.getInstance().after(session.getExpiresOn())) {
-            // the session is either non-existent or exists but has expired, so recreate one:
-            createSession();
-            session = this.sessionProvider.get();
-            assert session != null;
-        }
+        LOG.debug("Registering user [{}] with email address [{}]", name, emailAddress);
 
+        // first check that are we not logged in!
+        final Session session = this.sessionProvider.get();
+
         if (session.getUser() != null) {
             throw new IllegalArgumentException("You cannot register, as you are already logged in.");
         }
@@ -77,47 +63,26 @@
         this.ebean.save(u);
 
         // next, we just associate the current session with the user by logging in
-        return this.login(emailAddress, password);
+        return this.login(u);
     }
 
     @Override
-    public Session createSession() {
-        final Session session = new Session();
-        final ClientSession clientSession = this.clientSessionProvider.get();
-
-        // TODO we ensure that we expire the sessions after a while of inactivity
-        // so we will need to add a filter to ensure this actually happens.
-        // i.e. update the time of the session asynchronously if possible
-        // write a job that deletes expired sessions
-        // this also needs to match up with the value in the client session really
-        final Calendar expiryDate = Calendar.getInstance();
-        expiryDate.add(Calendar.DAY_OF_YEAR, EXPIRY_SESSION_INTERVAL);
-
-        session.setJSessionId(clientSession.getSessionId());
-        session.setIpAddress(clientSession.getIpAddress());
-        session.setExpiresOn(new Date(expiryDate.getTimeInMillis()));
-
-        LOG.debug("Persisting session (jSessionId=[{}],ip=[{}]", session.getJSessionId(),
-                session.getIpAddress());
-        this.ebean.save(session);
-        return session;
-    }
-
-    @Override
     public User getLoggedInUser() {
         final Session session = this.sessionProvider.get();
         if (session == null) {
+            LOG.debug("There was no user no logged in");
             return null;
         }
 
+        LOG.debug("Returning a user ");
         return session.getUser();
     }
 
     @Override
     public User login(final String emailAddress, final String password) {
-        // logging in basically means associating the user with the session
-        final Session serverSession = this.sessionProvider.get();
+        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();
 
@@ -126,11 +91,21 @@
             throw new StepInternalException("Unable to login with username/password provided");
         }
 
+        return login(user);
+    }
+
+    /**
+     * A way of logging in without authenticating
+     * 
+     * @param user the user that requires loggin in
+     * @return the user once logged in
+     */
+    private User login(final User user) {
+        final Session serverSession = this.sessionProvider.get();
         serverSession.setUser(user);
 
         // saving the session
         this.ebean.save(serverSession);
-
         return user;
     }
 

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/PassageReferenceUtils.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -63,7 +63,7 @@
                     LOG.trace("Found reference [{}] to [{}]", valueOf(startVerseId), valueOf(endVerseId));
                     final ScriptureReference sr = new ScriptureReference();
 
-                    // TODO fix this:
+                    // TODO: fix this:
                     sr.setTarget(target);
 
                     sr.setStartVerseId(startVerseId);

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/cache/SimpleCache.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/cache/SimpleCache.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/cache/SimpleCache.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,28 @@
+package com.tyndalehouse.step.core.utils.cache;
+
+
+/**
+ * a simple cache interface
+ * 
+ * @param <T> the key class
+ * @param <S> the item class
+ * @author Chris
+ * 
+ */
+public interface SimpleCache<T, S> {
+    /**
+     * puts an object in the cache
+     * 
+     * @param key the key of the object
+     * @param obj the object to be cached
+     */
+    void put(T key, S obj);
+
+    /**
+     * retrieves an object from the cache
+     * 
+     * @param key the key to the cache
+     * @return the object that was keyed
+     */
+    S get(T key);
+}


Property changes on: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/cache/SimpleCache.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/step/step-core/src/main/resources/step.core.properties
===================================================================
--- trunk/step/step-core/src/main/resources/step.core.properties	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/main/resources/step.core.properties	2011-03-29 21:43:38 UTC (rev 226)
@@ -1,5 +1,5 @@
 # Front controller properties
-cache.enabled=false
+cache.enabled=true
 
 #list of installers in the format: host,package,catalog
 installer.1=www.crosswire.org,/ftpmirror/pub/sword/packages/rawzip,/ftpmirror/pub/sword/raw
@@ -9,6 +9,8 @@
 app.proxy.host=
 app.proxy.port=
 
+
+
 #Test data related questions
 test.data.load=true
 
@@ -22,3 +24,14 @@
 app.db.maxOpenStatement=20
 app.db.poolableStatements=true 
 app.db.validationQuery=select 1
+
+#######################
+# cache settings
+#######################
+
+# session cache storing currently logged in people
+app.cache.session.maxElements=250
+app.cache.session.timeToLive=300
+app.cache.session.timeToIdle=300
+
+

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTest.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -41,7 +41,9 @@
     }
 
     /**
-     * testing the loading process TODO don't want to test the whole timeline component every build
+     * testing the loading process
+     * <p />
+     * TODO: don't want to test the whole timeline component every build
      */
     @Test
     public void tryLoadingProcess() {

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTestModule.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTestModule.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/data/create/DataTestModule.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -25,7 +25,7 @@
     }
 
     /**
-     * TODO share this code with main code reads the core properties from the file
+     * TODO: share this code with main code reads the core properties from the file
      * 
      * @return a list of properties read from file
      */

Added: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProviderTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProviderTest.java	                        (rev 0)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProviderTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,64 @@
+package com.tyndalehouse.step.core.guice.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import com.google.inject.Provider;
+import com.tyndalehouse.step.core.data.DataDrivenTestExtension;
+import com.tyndalehouse.step.core.data.caches.SessionCache;
+import com.tyndalehouse.step.core.data.entities.Session;
+import com.tyndalehouse.step.core.models.ClientSession;
+
+/**
+ * Testing various methods in the server-side session provider
+ * 
+ * @author Chris
+ * 
+ */
+ at RunWith(MockitoJUnitRunner.class)
+public class ServerSessionProviderTest extends DataDrivenTestExtension {
+    @Mock
+    private Provider<ClientSession> clientSessionProvider;
+    @Mock
+    private SessionCache sessionCache;
+    private ServerSessionProvider serverSessionProvider;
+
+    /**
+     * sets up the user service under test
+     */
+    @Before
+    public void setUp() {
+        // MockitoAnnotations.initMocks(this);
+        this.serverSessionProvider = new ServerSessionProvider(super.getEbean(), this.clientSessionProvider,
+                this.sessionCache, 10);
+    }
+
+    /**
+     * we check that we can create a session
+     */
+    @Test
+    public void testCreateSession() {
+        final String testClientSessionId = "999";
+        final String testIpAddress = "xx.xxx.xx.xx";
+        final ClientSession clientSession = mock(ClientSession.class);
+        when(this.clientSessionProvider.get()).thenReturn(clientSession);
+        when(clientSession.getSessionId()).thenReturn(testClientSessionId);
+        when(clientSession.getIpAddress()).thenReturn(testIpAddress);
+        this.serverSessionProvider.createSession();
+
+        final Session persistedSession = getEbean().find(Session.class).where()
+                .eq("jSessionId", testClientSessionId).findUnique();
+        assertEquals(persistedSession.getIpAddress(), testIpAddress);
+        assertTrue(persistedSession.getExpiresOn().after(new Date()));
+    }
+}


Property changes on: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/ServerSessionProviderTest.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -105,7 +105,7 @@
      * @throws BookException a book exception
      * @throws InterruptedException when the thread is interrupted
      */
-    // TODO currently disabled
+    // TODO: currently disabled
     @Test
     public void testConcurrencyIssueOnBookData() throws NoSuchKeyException, BookException,
             InterruptedException {

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/UserDataServiceImplTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -1,12 +1,9 @@
 package com.tyndalehouse.step.core.service.impl;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.Date;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -40,8 +37,7 @@
     @Before
     public void setUp() {
         // MockitoAnnotations.initMocks(this);
-        this.userService = new UserDataServiceImpl(super.getEbean(), this.serverSessionProvider,
-                this.clientSessionProvider);
+        this.userService = new UserDataServiceImpl(super.getEbean(), this.serverSessionProvider);
     }
 
     /**
@@ -127,23 +123,4 @@
         // check that the user is logged in
         assertEquals(currentServerSession.getUser().getName(), testName);
     }
-
-    /**
-     * we check that we can create a session
-     */
-    @Test
-    public void testCreateSession() {
-        final String testClientSessionId = "999";
-        final String testIpAddress = "xx.xxx.xx.xx";
-        final ClientSession clientSession = mock(ClientSession.class);
-        when(this.clientSessionProvider.get()).thenReturn(clientSession);
-        when(clientSession.getSessionId()).thenReturn(testClientSessionId);
-        when(clientSession.getIpAddress()).thenReturn(testIpAddress);
-        this.userService.createSession();
-
-        final Session persistedSession = getEbean().find(Session.class).where()
-                .eq("jSessionId", testClientSessionId).findUnique();
-        assertEquals(persistedSession.getIpAddress(), testIpAddress);
-        assertTrue(persistedSession.getExpiresOn().after(new Date()));
-    }
 }

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/PassageReferenceUtilsTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/PassageReferenceUtilsTest.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/PassageReferenceUtilsTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -8,8 +8,8 @@
 
 import org.junit.Test;
 
+import com.tyndalehouse.step.core.data.entities.ScriptureReference;
 import com.tyndalehouse.step.core.data.entities.ScriptureTarget;
-import com.tyndalehouse.step.core.data.entities.ScriptureReference;
 
 /**
  * testing the passage reference utils class

Modified: trunk/step/step-parent/pom.xml
===================================================================
--- trunk/step/step-parent/pom.xml	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-parent/pom.xml	2011-03-29 21:43:38 UTC (rev 226)
@@ -35,8 +35,9 @@
 		<guice-servlet.version>2.9.1</guice-servlet.version>
 		<opencsv.version>2.1</opencsv.version>
 		<jetty.version>6.1.26</jetty.version>
-		<!-- <ormlite.version>4.6</ormlite.version> -->
+
 		<ebean.version>2.7.2</ebean.version>
+		<ehcache.version>2.3.1</ehcache.version>
 		<lucene.version>3.0.3</lucene.version>
 
 		<!-- Commons -->
@@ -172,7 +173,7 @@
 				<version>${pjl-comp-filter.version}</version>
 			</dependency>
 
-			<!-- TODO build against google released artifacts -->
+			<!-- TODO: build against google released artifacts -->
 			<dependency>
 				<groupId>com.jolira</groupId>
 				<artifactId>guice</artifactId>
@@ -299,6 +300,12 @@
 				<artifactId>junit</artifactId>
 				<version>${junit.version}</version>
 			</dependency>
+			<dependency>
+				<groupId>net.sf.ehcache</groupId>
+				<artifactId>ehcache</artifactId>
+				<version>${ehcache.version}</version>
+				<type>pom</type>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>
 

Added: trunk/step/step-web/db-create.sql
===================================================================
--- trunk/step/step-web/db-create.sql	                        (rev 0)
+++ trunk/step/step-web/db-create.sql	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,106 @@
+create table bookmark (
+  id                        integer not null,
+  bookmark_reference        varchar(255) not null,
+  user_id                   integer,
+  constraint pk_bookmark primary key (id))
+;
+
+create table history (
+  id                        integer not null,
+  history_reference         varchar(255) not null,
+  user_id                   integer,
+  last_updated              timestamp not null,
+  constraint pk_history primary key (id))
+;
+
+create table hot_spot (
+  id                        integer not null,
+  description               varchar(255),
+  code                      varchar(255),
+  scale                     integer,
+  timeband_id               integer,
+  constraint ck_hot_spot_scale check (scale in (0,1,2,3,4,5,6)),
+  constraint pk_hot_spot primary key (id))
+;
+
+create table scripture_reference (
+  scripture_reference_id    integer not null,
+  target_id                 integer,
+  target_type               integer,
+  start_verse_id            integer,
+  end_verse_id              integer,
+  constraint ck_scripture_reference_target_type check (target_type in (0)),
+  constraint pk_scripture_reference primary key (scripture_reference_id))
+;
+
+create table scripture_target (
+  targetTypeId              integer(31) not null,
+  id                        integer not null,
+  summary                   varchar(255),
+  from_date                 bigint,
+  to_date                   bigint,
+  from_precision            integer,
+  to_precision              integer,
+  hot_spot_id               integer,
+  constraint ck_scripture_target_from_precision check (from_precision in (0,1,2,3)),
+  constraint ck_scripture_target_to_precision check (to_precision in (0,1,2,3)),
+  constraint pk_scripture_target primary key (id))
+;
+
+create table session (
+  id                        integer not null,
+  j_session_id              varchar(255),
+  user_id                   integer,
+  ip_address                varchar(255),
+  expires_on                timestamp,
+  constraint pk_session primary key (id))
+;
+
+create table timeband (
+  id                        integer not null,
+  code                      varchar(255),
+  scale                     integer,
+  description               varchar(255),
+  constraint ck_timeband_scale check (scale in (0,1,2,3,4,5,6)),
+  constraint pk_timeband primary key (id))
+;
+
+create table users (
+  id                        integer not null,
+  name                      varchar(255),
+  password                  varchar(255),
+  email_address             varchar(255),
+  country                   varchar(255),
+  constraint pk_users primary key (id))
+;
+
+create sequence bookmark_seq;
+
+create sequence history_seq;
+
+create sequence hot_spot_seq;
+
+create sequence scripture_reference_seq;
+
+create sequence scripture_target_seq;
+
+create sequence session_seq;
+
+create sequence timeband_seq;
+
+create sequence users_seq;
+
+alter table bookmark add constraint fk_bookmark_user_1 foreign key (user_id) references users (id) on delete restrict on update restrict;
+create index ix_bookmark_user_1 on bookmark (user_id);
+alter table history add constraint fk_history_user_2 foreign key (user_id) references users (id) on delete restrict on update restrict;
+create index ix_history_user_2 on history (user_id);
+alter table hot_spot add constraint fk_hot_spot_timeband_3 foreign key (timeband_id) references timeband (id) on delete restrict on update restrict;
+create index ix_hot_spot_timeband_3 on hot_spot (timeband_id);
+alter table scripture_reference add constraint fk_scripture_reference_target_4 foreign key (target_id) references scripture_target (id) on delete restrict on update restrict;
+create index ix_scripture_reference_target_4 on scripture_reference (target_id);
+alter table scripture_target add constraint fk_scripture_target_hotSpot_5 foreign key (hot_spot_id) references hot_spot (id) on delete restrict on update restrict;
+create index ix_scripture_target_hotSpot_5 on scripture_target (hot_spot_id);
+alter table session add constraint fk_session_user_6 foreign key (user_id) references users (id) on delete restrict on update restrict;
+create index ix_session_user_6 on session (user_id);
+
+

Added: trunk/step/step-web/db-drop.sql
===================================================================
--- trunk/step/step-web/db-drop.sql	                        (rev 0)
+++ trunk/step/step-web/db-drop.sql	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,36 @@
+SET REFERENTIAL_INTEGRITY FALSE;
+
+drop table if exists bookmark;
+
+drop table if exists history;
+
+drop table if exists hot_spot;
+
+drop table if exists scripture_reference;
+
+drop table if exists scripture_target;
+
+drop table if exists session;
+
+drop table if exists timeband;
+
+drop table if exists users;
+
+SET REFERENTIAL_INTEGRITY TRUE;
+
+drop sequence if exists bookmark_seq;
+
+drop sequence if exists history_seq;
+
+drop sequence if exists hot_spot_seq;
+
+drop sequence if exists scripture_reference_seq;
+
+drop sequence if exists scripture_target_seq;
+
+drop sequence if exists session_seq;
+
+drop sequence if exists timeband_seq;
+
+drop sequence if exists users_seq;
+

Modified: trunk/step/step-web/pom.xml
===================================================================
--- trunk/step/step-web/pom.xml	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/pom.xml	2011-03-29 21:43:38 UTC (rev 226)
@@ -102,5 +102,30 @@
 
 	<build>
 		<finalName>step-web</finalName>
+
+		<plugins>
+			<plugin>
+				<groupId>com.samaxes.maven</groupId>
+				<artifactId>maven-minify-plugin</artifactId>
+				<version>1.3.3</version>
+				<configuration>
+					<cssSourceDir>css</cssSourceDir>
+					<cssSourceIncludes>
+						<cssSourceInclude>ui-lightness/*.css</cssSourceInclude>
+						<cssSourceInclude>*.css</cssSourceInclude>
+						<cssSourceInclude>libs/menu/*.css</cssSourceInclude>
+					</cssSourceIncludes>
+					<cssFinalFile>step.css</cssFinalFile>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>process-resources</phase>
+						<goals>
+							<goal>minify</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
 	</build>
 </project>

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -16,6 +16,7 @@
 import com.tyndalehouse.step.core.models.EnrichedLookupOption;
 import com.tyndalehouse.step.core.models.LookupOption;
 import com.tyndalehouse.step.core.service.BibleInformationService;
+import com.tyndalehouse.step.rest.framework.Cacheable;
 import com.tyndalehouse.step.rest.wrappers.HtmlWrapper;
 
 /**
@@ -46,6 +47,7 @@
      * 
      * @return all versions of modules that are considered to be Bibles.
      */
+    @Cacheable(true)
     public List<BibleVersion> getBibleVersions() {
         return this.bibleInformation.getAvailableBibleVersions();
     }
@@ -57,6 +59,7 @@
      * @param reference the reference to lookup
      * @return the text to be displayed, formatted as HTML
      */
+    @Cacheable(true)
     public HtmlWrapper getBibleText(final String version, final String reference) {
         return getBibleText(version, reference, null, null);
     }
@@ -69,6 +72,7 @@
      * @param options the list of options to be passed through and affect the retrieval process
      * @return the text to be displayed, formatted as HTML
      */
+    @Cacheable(true)
     public HtmlWrapper getBibleText(final String version, final String reference, final String options) {
         return getBibleText(version, reference, options, null);
     }
@@ -82,6 +86,7 @@
      * @param interlinearVersion the interlinear version if provided adds lines under the text
      * @return the text to be displayed, formatted as HTML
      */
+    @Cacheable(true)
     public HtmlWrapper getBibleText(final String version, final String reference, final String options,
             final String interlinearVersion) {
         Validate.notEmpty(version, "You need to provide a version");
@@ -109,6 +114,7 @@
      * @param version the version initials or full version name to retrieve the versions for
      * @return all versions of modules that are considered to be Bibles.
      */
+    @Cacheable(true)
     public List<LookupOption> getFeatures(final String version) {
         return this.bibleInformation.getFeaturesForVersion(version);
     }
@@ -118,6 +124,7 @@
      * 
      * @return a list of features currently supported by the application
      */
+    @Cacheable(true)
     public List<EnrichedLookupOption> getAllFeatures() {
         return this.bibleInformation.getAllFeatures();
     }

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -26,9 +26,10 @@
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
+import com.tyndalehouse.step.rest.framework.Cacheable;
 import com.tyndalehouse.step.rest.framework.ClientErrorResolver;
 import com.tyndalehouse.step.rest.framework.ClientHandledIssue;
-import com.tyndalehouse.step.rest.framework.ControllerCacheKey;
+import com.tyndalehouse.step.rest.framework.ResponseCache;
 import com.tyndalehouse.step.rest.framework.StepRequest;
 
 /**
@@ -49,35 +50,38 @@
     private static final char PACKAGE_SEPARATOR = '.';
     private static final long serialVersionUID = 7898656504631346047L;
     private static final String CONTROLLER_SUFFIX = "Controller";
-    // TODO EH cache here too?
+    // TODO: EH cache here too?
     private final Map<String, String> contextPath = new HashMap<String, String>();
-    private final Map<String, byte[]> resultsCache = new HashMap<String, byte[]>();
     private final transient Injector guiceInjector;
-    // TODO but also check thread safety and whether we should share this object
+    // TODO: but also check thread safety and whether we should share this object
     private final transient ObjectMapper jsonMapper = new ObjectMapper();
-    // TODO check if this is thread safe, and if so, then make private field
+    // TODO: check if this is thread safe, and if so, then make private field
     private final transient JsonContext ebeanJson;
 
-    // TODO investigate EH cache here
+    // TODO: investigate EH cache here
     private final Map<String, Method> methodNames = new HashMap<String, Method>();
     private final Map<String, Object> controllers = new HashMap<String, Object>();
     private final boolean isCacheEnabled;
     private final transient ClientErrorResolver errorResolver;
+    private final transient ResponseCache responseCache;
 
     /**
      * 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 TODO rename all
-     *            ebeans to DB
+     * @param isCacheEnabled indicates whether responses should be cached for fast retrieval
      * @param ebean the db access/persisitence object
      * @param errorResolver the error resolver is the object that helps us translate errors for the client
+     * @param responseCache cache in which are put any number of responses to speed up processing
      */
     @Inject
     public FrontController(final Injector guiceInjector,
             @Named("cache.enabled") final Boolean isCacheEnabled, final EbeanServer ebean,
-            final ClientErrorResolver errorResolver) {
+            final ClientErrorResolver errorResolver, final ResponseCache responseCache) {
         this.guiceInjector = guiceInjector;
+        this.responseCache = responseCache;
         this.ebeanJson = ebean.createJsonContext();
 
         this.errorResolver = errorResolver;
@@ -86,31 +90,24 @@
 
     @Override
     protected void doGet(final HttpServletRequest request, final HttpServletResponse response) {
+        // first of all check cache against URI: (only cached responses go here)
+        byte[] jsonEncoded = this.responseCache.get(request.getRequestURI());
+
         StepRequest sr = null;
         try {
-            sr = parseRequest(request);
-            byte[] jsonEncoded = null;
-
-            // in here we want to retrieve from the cache.
-            final ControllerCacheKey cacheKey = sr.getCacheKey();
-
-            // check results cache here -- TODO - use servlet caching instead?
-            if (this.isCacheEnabled) {
-                LOGGER.debug("Checking cache...");
-                jsonEncoded = this.resultsCache.get(cacheKey.getResultsKey());
-            }
-
             // cache miss?
-            if (jsonEncoded == null) {
-                LOGGER.debug("The cache was missed so invoking method now...");
-                jsonEncoded = invokeMethod(sr);
+            if (jsonEncoded == null || jsonEncoded.length == 0) {
+                sr = parseRequest(request);
+                if (jsonEncoded == null) {
+                    LOGGER.debug("The cache was missed so invoking method now...");
+                    jsonEncoded = invokeMethod(sr);
+                }
+            } else {
+                LOGGER.debug("Returning answer from cache [{}]", request.getRequestURI());
             }
 
             setupHeaders(response, jsonEncoded.length);
             response.getOutputStream().write(jsonEncoded);
-
-            // TODO move cache down
-            cache(jsonEncoded, sr.getControllerName(), sr.getMethodName(), sr.getArgs());
             // CHECKSTYLE:OFF We allow catching errors here, since we are at the top of the structure
         } catch (final Exception e) {
             // CHECKSTYLE:ON
@@ -137,11 +134,14 @@
         Object returnVal;
         try {
             returnVal = controllerMethod.invoke(controllerInstance, (Object[]) sr.getArgs());
+
             // CHECKSTYLE:OFF
         } catch (final Exception e) {
             returnVal = convertExceptionToJson(e);
         }
-        return getEncodedJsonResponse(returnVal);
+        final byte[] encodedJsonResponse = getEncodedJsonResponse(returnVal);
+        cache(encodedJsonResponse, sr, controllerMethod);
+        return encodedJsonResponse;
         // CHECKSTYLE:ON
     }
 
@@ -225,20 +225,21 @@
         final int endOfMethodName = startOfMethodName + methodName.length();
 
         LOGGER.debug("Request parsed as controller: [{}], method [{}]", controllerName, methodName);
-        return new StepRequest(controllerName, methodName, getArgs(requestURI, endOfMethodName + 1));
+        return new StepRequest(requestURI, controllerName, methodName, getArgs(requestURI,
+                endOfMethodName + 1));
     }
 
     /**
-     * TODO caches the results for future use
+     * TODO: caches the results for future use
      * 
      * @param jsonEncoded json encoding of the response
-     * @param controllerName the name of the controller that was ino
-     * @param methodName the method name that was called
-     * @param args the arguments that were passed
+     * @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
      */
-    void cache(final byte[] jsonEncoded, final String controllerName, final String methodName,
-            final Object[] args) {
-        // TODO using EH Cache
+    void cache(final byte[] jsonEncoded, final StepRequest sr, final Method controllerMethod) {
+        if (this.isCacheEnabled && controllerMethod.isAnnotationPresent(Cacheable.class)) {
+            this.responseCache.put(sr.getCacheKey().getResultsKey(), jsonEncoded);
+        }
     }
 
     /**

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -8,6 +8,7 @@
 import com.google.inject.Inject;
 import com.tyndalehouse.step.core.models.BibleVersion;
 import com.tyndalehouse.step.core.service.ModuleService;
+import com.tyndalehouse.step.rest.framework.Cacheable;
 
 /**
  * The Module Controller servicing requests for module information
@@ -50,6 +51,7 @@
      * @param reference a reference for a module to lookup
      * @return the definition(s) that can be resolved from the reference provided
      */
+    @Cacheable(true)
     public String getDefinition(final String reference) {
         LOGGER.debug("Getting definition for {}", reference);
         return this.moduleDefintions.getDefinition(reference).getExplanation();

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -10,6 +10,7 @@
 import com.google.inject.Singleton;
 import com.tyndalehouse.step.core.data.entities.Timeband;
 import com.tyndalehouse.step.core.service.TimelineService;
+import com.tyndalehouse.step.rest.framework.Cacheable;
 
 /**
  * The timeline controller retrieves information about past events
@@ -40,8 +41,11 @@
      * @param timebandId the timeband ids
      * @param from the from dates
      * @param to the to dates
-     * @return all versions of modules that are considered to be Bibles. TODO work out UK date format mappings
+     * @return all versions of modules that are considered to be Bibles.
+     *         <p />
+     *         TODO: work out UK date format mappings
      */
+    @Cacheable(true)
     public String getEvents(final String[] timebandId, final Date from, final Date to) {
         LOGGER.debug("Retrieving events between [{}] and [{}]", from, to);
         return timebandId[0];
@@ -56,6 +60,7 @@
      * @return a list of events to be shown on a timeline, including the origin of the timeline and the scale
      *         of the timeline
      */
+    @Cacheable(true)
     public String getEventsFromReference(final String bibleReference) {
 
         return null;
@@ -66,6 +71,7 @@
      * 
      * @return the timebands
      */
+    @Cacheable(true)
     public List<Timeband> getTimelineConfiguration() {
         return this.timelineService.getTimelineConfiguration();
     }

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/UserController.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -32,7 +32,9 @@
      * @param name the name of the person [optional]
      * @param country his country [optional]
      * @param password the password he has chosen, which we should SHA-1 and salt
-     * @return the registered user TODO salt
+     * @return the registered user
+     * 
+     *         TODO: salt
      */
     public User register(final String emailAddress, final String name, final String country,
             final String password) {

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cacheable.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cacheable.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cacheable.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,21 @@
+package com.tyndalehouse.step.rest.framework;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that indicates the results of a particular method can be cached
+ * 
+ * @author Chris
+ * 
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+public @interface Cacheable {
+    /**
+     * true to indicate the results of a method can be cached
+     */
+    boolean value() default false;
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cacheable.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/EbeanServletContextListener.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/EbeanServletContextListener.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/EbeanServletContextListener.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.rest.framework;
+
+import javax.servlet.ServletContextEvent;
+
+import com.avaje.ebeaninternal.server.core.ServletContextListener;
+
+/**
+ * Overrides the creation to avoid creation of Ebean - this is handled by Guice
+ * 
+ * TODO: remove this in favour of context listener? if so refactor of tests required
+ * 
+ * @author Chris
+ * 
+ */
+public class EbeanServletContextListener extends ServletContextListener {
+    @Override
+    public void contextInitialized(final ServletContextEvent event) {
+        // DO NOTHING
+    }
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/EbeanServletContextListener.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: 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	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,30 @@
+package com.tyndalehouse.step.rest.framework;
+
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.core.data.caches.AbstractDefaultCache;
+
+/**
+ * This caches responses - should be varied for Android and mobiles since there would be less memory
+ * 
+ * @author Chris
+ * 
+ */
+public class ResponseCache extends AbstractDefaultCache<byte[]> {
+    /**
+     * A simple cache for the responses to be sent to the client..
+     * 
+     * @param cacheManager the cache manager with which to register the cache
+     */
+    @Inject
+    public ResponseCache(final CacheManager cacheManager) {
+        super(cacheManager, new CacheConfiguration("httpResponseCache", 500)
+                .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU).overflowToDisk(false)
+                .eternal(false).timeToLiveSeconds(3600).timeToIdleSeconds(3600).diskPersistent(false)
+                .diskExpiryThreadIntervalSeconds(0));
+    }
+
+}


Property changes on: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/ResponseCache.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/StepRequest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -2,25 +2,30 @@
 
 /**
  * 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 Object ARG_SEPARATOR = '-';
-
     private final String controllerName;
     private final String methodName;
     private final String[] args;
 
+    private final String requestURI;
+
     /**
      * Creates a request holder object containing the relevant information about a request
      * 
+     * @param requestURI the request URI that determines the controller, method name, etc.
      * @param controllerName the controller name
      * @param methodName the method name
      * @param args the arguments that should be passed to the method
      */
-    public StepRequest(final String controllerName, final String methodName, final String[] args) {
+    public StepRequest(final String requestURI, final String controllerName, final String methodName,
+            final String[] args) {
+        this.requestURI = requestURI;
         this.controllerName = controllerName;
         this.methodName = methodName;
         this.args = args == null ? new String[] {} : args;
@@ -33,7 +38,6 @@
      */
     public ControllerCacheKey getCacheKey() {
         final String methodKey;
-        final String resultsKey;
 
         // generate the shorter key
         final StringBuilder cacheKeyBuffer = new StringBuilder(this.controllerName.length()
@@ -44,14 +48,7 @@
 
         // get the shorter key now
         methodKey = cacheKeyBuffer.toString();
-
-        // now get a slightly longer key by extending it
-        for (int ii = 0; ii < this.args.length; ii++) {
-            cacheKeyBuffer.append(this.args[ii]);
-            cacheKeyBuffer.append(ARG_SEPARATOR);
-        }
-        resultsKey = cacheKeyBuffer.toString();
-        return new ControllerCacheKey(methodKey, resultsKey);
+        return new ControllerCacheKey(methodKey, this.requestURI);
     }
 
     /**

Modified: trunk/step/step-web/src/main/webapp/WEB-INF/web.xml
===================================================================
--- trunk/step/step-web/src/main/webapp/WEB-INF/web.xml	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/webapp/WEB-INF/web.xml	2011-03-29 21:43:38 UTC (rev 226)
@@ -29,6 +29,14 @@
 		<listener-class>com.tyndalehouse.step.guice.StepServletConfig</listener-class>
 	</listener>
 
+	<listener>
+		<listener-class>com.tyndalehouse.step.rest.framework.EbeanServletContextListener</listener-class>
+	</listener>
+
+	<listener>
+          <listener-class>net.sf.ehcache.constructs.web.ShutdownListener</listener-class>
+     </listener>
+
 	<welcome-file-list>
 		<welcome-file>index.html</welcome-file>
 	</welcome-file-list>

Modified: trunk/step/step-web/src/main/webapp/index.html
===================================================================
--- trunk/step/step-web/src/main/webapp/index.html	2011-03-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/main/webapp/index.html	2011-03-29 21:43:38 UTC (rev 226)
@@ -5,11 +5,12 @@
     <META http-equiv="Content-Type" content="text/html; charset=utf-8">
     <TITLE>STEP :: Scripture Tools for Every Pastor</TITLE>
 
+
+
     <link rel="stylesheet" type="text/css" href="css/ui-lightness/jquery-ui-1.8.5.custom.css" />
     <link rel="stylesheet" type="text/css" href="css/initial-layout.css" />
     <link rel="stylesheet" type="text/css" href="css/initial-fonts.css" />
     <link rel="stylesheet" type="text/css" href="css/passage.css" />
-
 	<link rel="stylesheet" type="text/css" href="libs/menu/ddsmoothmenu.css" />
 	<link rel="stylesheet" type="text/css" href="libs/menu/ddsmoothmenu-v.css" />
 
@@ -17,10 +18,11 @@
     <script src="libs/timeline_js/timeline-api.js?bundle=true" type="text/javascript"></script>
     <script src="libs/jquery-1.4.2.min.js" type="text/javascript"></script>
     <script src="libs/jquery-ui-1.8.5.custom.min.js" type="text/javascript"></script>
+    
+    
     <script src="libs/jquery-shout.js" type="text/javascript"></script>
 	<script src="libs/menu/ddsmoothmenu.js" type="text/javascript"></script>
     <script src="libs/cookies/jquery_cookie.js" type="text/javascript"></script>
-    
     <script src="js/util.js" type="text/javascript"></script>
     <script src="js/passage.js" type="text/javascript"></script>
     <script src="js/bookmark.js" type="text/javascript"></script>

Added: trunk/step/step-web/src/main/webapp/libs/jquery_include.js
===================================================================
--- trunk/step/step-web/src/main/webapp/libs/jquery_include.js	                        (rev 0)
+++ trunk/step/step-web/src/main/webapp/libs/jquery_include.js	2011-03-29 21:43:38 UTC (rev 226)
@@ -0,0 +1,199 @@
+/*!*
+ * @filename include.jquery.js
+ * @name jQuery Include File
+ * @type jQuery
+ * @projectDescription Include a file (css and js) in a head of the document and execute
+ * @date 08/07/2008
+ * @version 1.0
+ * @cat Ajax
+ * @require
+ * @author Alex
+ * @param required none url String|Array The address of the plugin that will be inserted.
+ * You can pass a indexed array of url
+ * @param optional none callback Function The function to be executed after the file has loaded
+ * @example
+ * $.include('/foo/test/file.js');
+ * @desc load the current script
+ * @example
+ * var files = ['test.js','another.js','onemore.js'];
+ * $.include(files,function(){
+ * 		//execute some code after all scripts are completed
+ * });
+ * @desc load all the script inside the array
+ * @return false | Element (object)
+ */
+
+(function($) {
+	$.extend({
+		// You can change the base path to be applied in all imports
+		ImportBasePath: '',
+		// Associative array storing wating tasks and their callback
+		__WaitingTasks: new Object(),
+		// Called when a single file is loaded successfully - update and check WaitingTasks to see if it's ok to load callback
+		__loadedSuccessfully: function(taskId){
+			if (taskId in $.__WaitingTasks){
+				if (($.__WaitingTasks[taskId].loading -= 1) < 1){
+					var callback = $.__WaitingTasks[taskId].task;
+					if (typeof callback == 'function') {
+						callback();
+					}
+					delete $.__WaitingTasks[taskId];
+				}
+			}
+		},
+		//pass a file name and return a array with file name and extension
+		fileinfo:	function(data){
+            data = data.replace(/^\s|\s$/g, "");
+			var m;
+            if (/\.\w+$/.test(data)) {
+                m = data.match(/([^\/\\]+)\.(\w+)$/);
+                if (m) {
+					if (m[2] == 'js') {
+						return {
+							filename: m[1],
+							ext: m[2],
+							tag: 'script'
+						};
+					}
+					else 
+						if (m[2] == 'css') {
+							return {
+								filename: m[1],
+								ext: m[2],
+								tag: 'link'
+							};
+						}
+						else {
+							return {
+								filename: m[1],
+								ext: m[2],
+								tag: null
+							};
+						}
+				}
+				else {
+					return {
+						filename: null,
+						ext: null
+					};
+				}
+            } else {
+                m = data.match(/([^\/\\]+)$/);
+                if (m) {
+					return {
+						filename: m[1],
+						ext: null,
+						tag: null
+					};
+				}
+				else {
+					return {
+						filename: null,
+						ext: null,
+						tag: null
+					};
+				}	
+            }
+        },
+		//Check if the file that is been included already exist and return a Boolean value
+		fileExist: function(filename,filetype,attrCheck) {
+			var elementsArray = document.getElementsByTagName(filetype);
+			for(var i=0;i<elementsArray.length;i++) {
+				if(elementsArray[i].getAttribute(attrCheck)==$.ImportBasePath+filename) {
+					return true;
+				}
+			}
+			return false;
+		},
+		//Create the element depending of the file type and return the element (Object)
+		createElement: function(filename,filetype) {
+			switch(filetype) {
+				case 'script' :
+				if (!$.fileExist(filename, filetype, 'src')) {
+					var scriptTag = document.createElement(filetype);
+					scriptTag.setAttribute('language', 'javascript');
+					scriptTag.setAttribute('type', 'text/javascript');
+					scriptTag.setAttribute('src', $.ImportBasePath + filename);
+					return scriptTag;
+				} else {
+					return false;
+				}
+				break;
+				case 'link' :
+				if (!$.fileExist(filename, filetype, 'href')) {
+					var styleTag = document.createElement(filetype);
+					styleTag.setAttribute('type', 'text/css');
+					styleTag.setAttribute('rel', 'stylesheet');
+					styleTag.setAttribute('href', $.ImportBasePath + filename);
+					return styleTag;
+				} else {
+					return false;
+				}
+				break;
+
+				default :
+					return false;
+				break;
+			}
+		},
+		cssReady: function(index, taskId) {
+			function check() {
+				if(document.styleSheets[index]){
+					window.clearInterval(checkInterval);
+					$.__loadedSuccessfully(taskId);
+				}
+			}
+			var checkInterval = window.setInterval(check,200);
+		},
+		//The main function to insert the file
+		include: function(file,callback) {
+			var headerTag = document.getElementsByTagName('head')[0];
+			var fileArray = [];
+			//if file is string, give a single index element
+			typeof file=='string' ? fileArray[0] = file : fileArray = file;
+			// Create a unique id using the current time
+			var taskId = new Date().getTime().toString();
+			$.__WaitingTasks[taskId] = {'loading': fileArray.length, 'task': callback};
+			//go through all the files
+			for (var i = 0; i < fileArray.length; i++) {
+				var elementTag = $.fileinfo(fileArray[i]).tag;
+				var el = [];
+				if (elementTag !== null) {
+					el[i] = $.createElement(fileArray[i], elementTag);
+					if (el[i]) {
+						headerTag.appendChild(el[i]);
+						if ($.browser.msie) {
+							el[i].onreadystatechange = function(){
+								if (this.readyState === 'loaded' || this.readyState === 'complete') {
+									$.__loadedSuccessfully(taskId);
+								}
+							};
+						}
+						else {
+							if (elementTag == 'link') {
+								$.cssReady(i, taskId);
+							}
+							else {
+                                if (/WebKit/i.test(navigator.userAgent)) {
+                                    var _timer = setInterval(function(){
+                                        if (/loaded|complete/.test(document.readyState)) {
+                                            $.__loadedSuccessfully(taskId); // call of the call
+                                        }
+                                    }, 100);
+                                }
+								el[i].onload = function(){
+									$.__loadedSuccessfully(taskId);
+								};
+							}
+						}
+					}else{
+						$.__loadedSuccessfully(taskId);
+					}
+				} else {
+					return false;
+				}
+			}
+		}
+	});
+
+})(jQuery);


Property changes on: trunk/step/step-web/src/main/webapp/libs/jquery_include.js
___________________________________________________________________
Added: svn:mime-type
   + text/plain

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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -24,12 +24,18 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
 
 import com.avaje.ebean.EbeanServer;
 import com.google.inject.Injector;
 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.ResponseCache;
 import com.tyndalehouse.step.rest.framework.StepRequest;
 
 /**
@@ -39,9 +45,31 @@
  * 
  */
 @SuppressWarnings("PMD.TooManyMethods")
+ at RunWith(MockitoJUnitRunner.class)
 public class FrontControllerTest {
+    private FrontController fcUnderTest;
+    @Mock
+    private Injector guiceInjector;
 
+    private final Boolean isCacheEnabled = Boolean.FALSE;
+
+    @Mock
+    private EbeanServer ebean;
+    @Mock
+    private ClientErrorResolver errorResolver;
+    @Mock
+    private ResponseCache responseCache;
+
     /**
+     * Simply setting up the FrontController under test
+     */
+    @Before
+    public void setUp() {
+        this.fcUnderTest = new FrontController(this.guiceInjector, this.isCacheEnabled, this.ebean,
+                this.errorResolver, this.responseCache);
+    }
+
+    /**
      * Tests normal operation of a GET method
      * 
      * @throws IOException uncaught exception
@@ -51,9 +79,9 @@
         final HttpServletRequest request = mock(HttpServletRequest.class);
         final HttpServletResponse response = mock(HttpServletResponse.class);
 
-        final FrontController fc = spy(new FrontController(null, false, mock(EbeanServer.class), null));
-        final StepRequest parsedRequest = new StepRequest("SomeController", "someMethod", new String[] {
-                "arg1", "arg2" });
+        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);
@@ -75,9 +103,9 @@
         final HttpServletResponse response = mock(HttpServletResponse.class);
         final StepInternalException testException = new StepInternalException("A test exception");
 
-        final FrontController fc = spy(new FrontController(null, false, mock(EbeanServer.class), null));
-        final StepRequest parsedRequest = new StepRequest("SomeController", "someMethod", new String[] {
-                "arg1", "arg2" });
+        final FrontController fc = spy(this.fcUnderTest);
+        final StepRequest parsedRequest = new StepRequest("blah", "SomeController", "someMethod",
+                new String[] { "arg1", "arg2" });
 
         doThrow(testException).when(fc).parseRequest(request);
         doNothing().when(fc).handleError(response, testException, parsedRequest);
@@ -95,11 +123,8 @@
         // index starts at ...........0123456789-123456789-123456
         final String sampleRequest = "step-web/rest/bible/get/1K2/2K2";
 
-        final FrontController fc = new FrontController(mock(Injector.class), Boolean.FALSE,
-                mock(EbeanServer.class), null);
-
         // when
-        final Object[] args = fc.getArgs(sampleRequest, 24);
+        final Object[] args = this.fcUnderTest.getArgs(sampleRequest, 24);
 
         // then
         assertEquals(2, args.length);
@@ -115,11 +140,8 @@
         // index starts at ...........0123456789-123456789-123456
         final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
 
-        final FrontController fc = new FrontController(mock(Injector.class), Boolean.FALSE,
-                mock(EbeanServer.class), null);
-
         // when
-        final Object[] args = fc.getArgs(sampleRequest, 24);
+        final Object[] args = this.fcUnderTest.getArgs(sampleRequest, 24);
 
         // then
         assertEquals(2, args.length);
@@ -134,8 +156,7 @@
      */
     @Test
     public void testGetPath() throws ServletException {
-        final FrontController fc = new FrontController(null, null, mock(EbeanServer.class), null);
-        final FrontController spy = spy(fc);
+        final FrontController spy = spy(this.fcUnderTest);
 
         final ServletContext mockServletContext = mock(ServletContext.class);
         final HttpServletRequest mockRequest = mock(HttpServletRequest.class);
@@ -161,8 +182,7 @@
         final HttpServletResponse response = mock(HttpServletResponse.class);
 
         final int sampleRequestLength = 10;
-        new FrontController(null, null, mock(EbeanServer.class), null).setupHeaders(response,
-                sampleRequestLength);
+        this.fcUnderTest.setupHeaders(response, sampleRequestLength);
 
         verify(response).addDateHeader(eq("Date"), anyLong());
         verify(response).setCharacterEncoding("UTF-8");
@@ -179,13 +199,11 @@
      */
     @Test
     public void testGetControllerMethod() throws IllegalAccessException, InvocationTargetException {
-        final FrontController frontController = new FrontController(mock(Injector.class), Boolean.FALSE,
-                mock(EbeanServer.class), null);
         final BibleInformationService bibleInfo = mock(BibleInformationService.class);
         final BibleController controllerInstance = new BibleController(bibleInfo);
 
         // when
-        final Method controllerMethod = frontController.getControllerMethod("getBibleVersions",
+        final Method controllerMethod = this.fcUnderTest.getControllerMethod("getBibleVersions",
                 controllerInstance, null, null);
 
         // then
@@ -199,15 +217,11 @@
     @Test
     public void testGetController() {
         final String controllerName = "Bible";
-        final Injector mockInjector = mock(Injector.class);
-        final FrontController frontController = new FrontController(mockInjector, Boolean.FALSE,
-                mock(EbeanServer.class), null);
-
         final BibleController mockController = mock(BibleController.class);
-        when(mockInjector.getInstance(BibleController.class)).thenReturn(mockController);
+        when(this.guiceInjector.getInstance(BibleController.class)).thenReturn(mockController);
 
         // when
-        final Object controller = frontController.getController(controllerName);
+        final Object controller = this.fcUnderTest.getController(controllerName);
 
         // then
         assertEquals(controller.getClass(), mockController.getClass());
@@ -218,12 +232,10 @@
      */
     @Test
     public void testGetClasses() {
-        final FrontController fc = new FrontController(null, Boolean.FALSE, mock(EbeanServer.class), null);
-
-        assertEquals(0, fc.getClasses(null).length);
-        assertEquals(0, fc.getClasses(new Object[0]).length);
+        assertEquals(0, this.fcUnderTest.getClasses(null).length);
+        assertEquals(0, this.fcUnderTest.getClasses(new Object[0]).length);
         assertArrayEquals(new Class<?>[] { String.class, Integer.class },
-                fc.getClasses(new Object[] { "hello", Integer.valueOf(1) }));
+                this.fcUnderTest.getClasses(new Object[] { "hello", Integer.valueOf(1) }));
 
     }
 
@@ -232,8 +244,7 @@
      */
     @Test
     public void testJsonEncoding() {
-        final byte[] encodedJsonResponse = new FrontController(null, null, mock(EbeanServer.class), null)
-                .getEncodedJsonResponse("abc");
+        final byte[] encodedJsonResponse = this.fcUnderTest.getEncodedJsonResponse("abc");
 
         // this reprensents the string "{abc}"
         final byte[] expectedValues = new byte[] { 34, 97, 98, 99, 34 };
@@ -248,15 +259,14 @@
      */
     @Test
     public void testDoErrorHandlesCorrectly() throws IOException {
-        final FrontController fc = new FrontController(null, null, mock(EbeanServer.class), null);
         final HttpServletResponse response = mock(HttpServletResponse.class);
-        final StepRequest stepRequest = new StepRequest("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);
 
         // do test
-        fc.handleError(response, exception, stepRequest);
+        this.fcUnderTest.handleError(response, exception, stepRequest);
 
         // check
         verify(outputStream).write(any(byte[].class));
@@ -283,17 +293,16 @@
                 contextName + requestSeparator + servletName + requestSeparator + controllerName
                         + requestSeparator + methodName + requestSeparator + arg1 + requestSeparator + arg2);
 
-        final FrontController frontController = new FrontController(null, null, mock(EbeanServer.class), null);
-        frontController.init(mock(ServletConfig.class));
+        this.fcUnderTest.init(mock(ServletConfig.class));
 
-        final FrontController spy = spy(frontController);
+        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 = frontController.parseRequest(request);
+        final StepRequest parseRequest = this.fcUnderTest.parseRequest(request);
 
         // check controller name, method name and arguments
         assertEquals(controllerName, parseRequest.getControllerName());
@@ -305,10 +314,10 @@
      */
     @Test
     public void testInvokeMethod() {
-        final StepRequest sr = new StepRequest("bible", "getAllFeatures", new String[] {});
+        final StepRequest sr = new StepRequest("blah", "bible", "getAllFeatures", new String[] {});
         final BibleController testController = mock(BibleController.class);
 
-        final FrontController fc = spy(new FrontController(null, null, mock(EbeanServer.class), null));
+        final FrontController fc = spy(this.fcUnderTest);
         doReturn(testController).when(fc).getController("bible");
 
         // do 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-26 17:01:58 UTC (rev 225)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/StepRequestTest.java	2011-03-29 21:43:38 UTC (rev 226)
@@ -15,6 +15,7 @@
     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";
+    private static final String TEST_URI = "uri/ControllerController/method/arg1/arg2/arg3";
 
     /**
      * a method key should not contain arguments, but contain controller name and method name
@@ -51,6 +52,6 @@
      * @return a step request
      */
     private StepRequest getTestStepRequest() {
-        return new StepRequest(TEST_CONTROLLER_NAME, TEST_METHOD_NAME, TEST_ARGS);
+        return new StepRequest(TEST_URI, TEST_CONTROLLER_NAME, TEST_METHOD_NAME, TEST_ARGS);
     }
 }




More information about the Tynstep-svn mailing list