[Tynstep-svn] r253 - in trunk/step: step-build/src/main/resources step-core step-core/src/main/java/com/tyndalehouse/step/core/models step-core/src/main/java/com/tyndalehouse/step/core/service/impl step-core/src/main/resources/com/tyndalehouse/step/core/data/create step-core/src/main/resources/com/tyndalehouse/step/core/service/impl step-core/src/test/java/com/tyndalehouse/step/core/guice/providers step-core/src/test/java/com/tyndalehouse/step/core/service/impl step-parent step-web/src/main/java/com/tyndalehouse/step/guice step-web/src/main/java/com/tyndalehouse/step/rest/controllers step-web/src/main/java/com/tyndalehouse/step/rest/framework step-web/src/main/webapp step-web/src/main/webapp/css step-web/src/main/webapp/js step-web/src/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
Mon Apr 23 04:52:53 MST 2012
Author: ChrisBurrell
Date: 2012-04-23 04:52:53 -0700 (Mon, 23 Apr 2012)
New Revision: 253
Added:
trunk/step/step-build/src/main/resources/js/
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProviderTest.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/FrontController.java
trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/FrontControllerTest.java
Removed:
trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeband/
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/PeopleController.java
trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java
Modified:
trunk/step/step-core/pom.xml
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/impl/JSwordServiceImpl.java
trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java
trunk/step/step-parent/pom.xml
trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java
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/GeographyController.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/SetupController.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
trunk/step/step-web/src/main/webapp/css/passage.css
trunk/step/step-web/src/main/webapp/index.html
trunk/step/step-web/src/main/webapp/js/bookmark.js
trunk/step/step-web/src/main/webapp/js/passage.js
trunk/step/step-web/src/main/webapp/js/timeline.js
trunk/step/step-web/src/main/webapp/js/toolbar_menu.js
trunk/step/step-web/src/main/webapp/js/ui_hooks.js
trunk/step/step-web/src/main/webapp/panemenu.html
Log:
Modified: trunk/step/step-core/pom.xml
===================================================================
--- trunk/step/step-core/pom.xml 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-core/pom.xml 2012-04-23 11:52:53 UTC (rev 253)
@@ -61,6 +61,22 @@
</execution>
</executions>
</plugin>
+
+<!-- <plugin> -->
+<!-- <groupId>org.codehaus.mojo</groupId> -->
+<!-- <artifactId>cobertura-maven-plugin</artifactId> -->
+<!-- <configuration> -->
+<!-- <instrumentation> -->
+<!-- <excludes> -->
+<!-- Controllers are generally empty and provide validation only -->
+<!-- <exclude>com/tyndalehouse/step/rest/controllers/*.class</exclude> -->
+<!-- <exclude>com/tyndalehouse/step/core/data/entities/*.class</exclude> -->
+<!-- <exclude>com/tyndalehouse/step/core/models/*.class</exclude> -->
+<!-- </excludes> -->
+<!-- </instrumentation> -->
+<!-- </configuration> -->
+<!-- </plugin> -->
+
</plugins>
</build>
@@ -100,11 +116,6 @@
<artifactId>commons-collections</artifactId>
</dependency>
-<!-- <dependency>-->
-<!-- <groupId>commons-codec</groupId>-->
-<!-- <artifactId>commons-codec</artifactId>-->
-<!-- </dependency>-->
-
<!-- we don't always need this - depends on what version -->
<dependency>
<groupId>commons-dbcp</groupId>
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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -15,22 +15,26 @@
/**
* Showing headings
*/
- HEADINGS("Headings", "Headings", XslConversionType.DEFAULT, true),
+ HEADINGS("Headings", XslConversionType.DEFAULT, true),
// CHECKSTYLE:ON
/**
- * Showing headings
+ * Showing verse numbers
*/
- VERSE_NUMBERS("VNum", "Verse Nums.", XslConversionType.DEFAULT, true),
+ VERSE_NUMBERS("VNum", XslConversionType.DEFAULT, true),
+ /**
+ * Showing cross references
+ */
+ NOTES("Notes", XslConversionType.DEFAULT, true),
/** Strong numbers */
- STRONG_NUMBERS("StrongsNumbers", "Strongs", XslConversionType.INTERLINEAR),
+ STRONG_NUMBERS("StrongsNumbers", XslConversionType.INTERLINEAR),
/** Morphology */
- MORPHOLOGY("Morph", "Morphology", XslConversionType.INTERLINEAR),
+ MORPHOLOGY("Morph", XslConversionType.INTERLINEAR),
// CHECKSTYLE:OFF
/**
* Interlinears are available when Strongs are available.
*/
- INTERLINEAR("Interlinear", "Interlinear", XslConversionType.INTERLINEAR),
+ INTERLINEAR("Interlinear", XslConversionType.INTERLINEAR),
// CHECKSTYLE:ON
/**
* Showing headings
@@ -38,7 +42,6 @@
TINY_VERSE_NUMBERS("TinyVNum", XslConversionType.DEFAULT);
private final String xsltParameterName;
- // private final String displayName;
private final XslConversionType stylesheet;
private final boolean enabledByDefault;
@@ -48,7 +51,7 @@
* @param xsltParameterName the corresponding parameter name in the XSLT stylesheet
*/
private LookupOption(final String xsltParameterName) {
- this(xsltParameterName, xsltParameterName, DEFAULT);
+ this(xsltParameterName, DEFAULT, false);
}
/**
@@ -56,29 +59,17 @@
* @param stylesheet the stylesheet to use
*/
private LookupOption(final String xsltParameterName, final XslConversionType stylesheet) {
- this(xsltParameterName, null, stylesheet);
+ this(xsltParameterName, stylesheet, false);
}
/**
* @param xsltParameterName the name of the parameter in the stylesheet
* @param stylesheet the stylesheet to use
- * @param displayName the name to display on the user interface
- */
- private LookupOption(final String xsltParameterName, final String displayName,
- final XslConversionType stylesheet) {
- this(xsltParameterName, displayName, stylesheet, false);
- }
-
- /**
- * @param xsltParameterName the name of the parameter in the stylesheet
- * @param stylesheet the stylesheet to use
- * @param displayName the name to display on the user interface
* @param enabledByDefault true to have the UI display the option by default
*/
- private LookupOption(final String xsltParameterName, final String displayName,
- final XslConversionType stylesheet, final boolean enabledByDefault) {
+ private LookupOption(final String xsltParameterName, final XslConversionType stylesheet,
+ final boolean enabledByDefault) {
this.xsltParameterName = xsltParameterName;
- // this.displayName = displayName;
this.stylesheet = stylesheet;
this.enabledByDefault = enabledByDefault;
}
@@ -90,13 +81,6 @@
return this.xsltParameterName;
}
- // /**
- // * @return the display name of the lookup option
- // */
- // public String getUiKey() {
- // return this.displayName;
- // }
-
/**
* @return the stylesheet that should be used
*/
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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -216,6 +216,11 @@
options.add(LookupOption.VERSE_NUMBERS);
}
+ if (book.getBookMetaData().hasFeature(FeatureType.FOOTNOTES)
+ || book.getBookMetaData().hasFeature(FeatureType.SCRIPTURE_REFERENCES)) {
+ options.add(LookupOption.NOTES);
+ }
+
// cycle through each option
for (final LookupOption lo : LookupOption.values()) {
final FeatureType ft = FeatureType.fromString(lo.getXsltParameterName());
Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl 2012-04-23 11:52:53 UTC (rev 253)
@@ -668,25 +668,17 @@
<!--=======================================================================-->
<xsl:template match="reference">
- <xsl:choose>
- <xsl:when test="$XRef = 'true'">
- <a href="bible://{@osisRef}"><xsl:apply-templates/></a>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates/>
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:variable name="versification" select="jsword:getVersification($v11nf, $v11n)"/>
+ <xsl:variable name="passage" select="jsword:getValidKey($keyf, $versification, @osisRef)"/>
+ <xsl:variable name="passageKey" select="jsword:getName($passage)"/>
+ <a href="#" class="linkRef" onclick="javascript:changePassage(this, "{$passageKey}");"><xsl:apply-templates/></a>
</xsl:template>
<xsl:template match="reference" mode="jesus">
- <xsl:choose>
- <xsl:when test="$XRef = 'true'">
- <a href="bible://{@osisRef}"><xsl:apply-templates mode="jesus"/></a>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates mode="jesus"/>
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:variable name="versification" select="jsword:getVersification($v11nf, $v11n)"/>
+ <xsl:variable name="passage" select="jsword:getValidKey($keyf, $versification, @osisRef)"/>
+ <xsl:variable name="passageKey" select="jsword:getName($passage)"/>
+ <a href="#" onclick="javascript:changePassage(this, "{$passageKey}");"><xsl:apply-templates/></a>
</xsl:template>
<!--=======================================================================-->
Added: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProviderTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProviderTest.java (rev 0)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProviderTest.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -0,0 +1,34 @@
+package com.tyndalehouse.step.core.guice.providers;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Properties;
+
+import org.junit.Test;
+
+/**
+ * Test properties are loaded properly and construct a installer capable of downloading books off the internet
+ *
+ * @author Chris
+ *
+ */
+public class DefaultInstallersProviderTest {
+ /**
+ * tests the main flows
+ */
+ @Test
+ public void testDefaultInstaller() {
+ // DefaultInstallersProvider p = new DefaultInstallersProvider(
+ final String i = "www.crosswire.org,/ftpmirror/pub/sword/packages/rawzip,/ftpmirror/pub/sword/raw";
+ final Properties p = new Properties();
+ p.put("installer.1", i);
+
+ final DefaultInstallersProvider defaultInstallersProvider = new DefaultInstallersProvider(p,
+ "localhost", "8080");
+
+ final String def = defaultInstallersProvider.get().get(0).getInstallerDefinition();
+
+ assertEquals("www.crosswire.org,/ftpmirror/pub/sword/packages/rawzip,"
+ + "/ftpmirror/pub/sword/raw,,localhost,8080", def);
+ }
+}
Property changes on: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProviderTest.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -266,4 +266,14 @@
// t2.join();
// }
}
+
+ @Test
+ public void testPrettyXml() throws BookException, NoSuchKeyException, JDOMException, IOException {
+ final Book currentBook = Books.installed().getBook("ESV");
+ final BookData bookData = new BookData(currentBook, currentBook.getKey("Exodus 3:14"));
+ final Element osisFragment = bookData.getOsisFragment();
+
+ final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
+ LOGGER.debug(xmlOutputter.outputString(osisFragment));
+ }
}
Modified: trunk/step/step-parent/pom.xml
===================================================================
--- trunk/step/step-parent/pom.xml 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-parent/pom.xml 2012-04-23 11:52:53 UTC (rev 253)
@@ -333,7 +333,6 @@
<url>http://http://www.tyndale.cam.ac.uk/</url>
</organization>
-
<build>
<pluginManagement>
<plugins>
@@ -454,19 +453,31 @@
<version>2.4</version>
<configuration>
<check>
- <branchRate>70</branchRate>
- <lineRate>70</lineRate>
- <haltOnFailure>false</haltOnFailure>
- <totalBranchRate>60</totalBranchRate>
- <totalLineRate>60</totalLineRate>
- <packageLineRate>60</packageLineRate>
- <packageBranchRate>60</packageBranchRate>
+ <branchRate>20</branchRate>
+ <lineRate>20</lineRate>
+ <haltOnFailure>true</haltOnFailure>
+ <totalBranchRate>20</totalBranchRate>
+ <totalLineRate>20</totalLineRate>
</check>
</configuration>
</plugin>
</plugins>
</pluginManagement>
+ <plugins>
+<!-- <plugin> -->
+<!-- <groupId>org.codehaus.mojo</groupId> -->
+<!-- <artifactId>cobertura-maven-plugin</artifactId> -->
+<!-- <executions> -->
+<!-- <execution> -->
+<!-- <goals> -->
+<!-- <goal>clean</goal> -->
+<!-- <goal>check</goal> -->
+<!-- </goals> -->
+<!-- </execution> -->
+<!-- </executions> -->
+<!-- </plugin> -->
+ </plugins>
</build>
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -5,7 +5,7 @@
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.ServletModule;
import com.tyndalehouse.step.core.guice.StepCoreModule;
-import com.tyndalehouse.step.rest.controllers.FrontController;
+import com.tyndalehouse.step.rest.framework.FrontController;
/**
* Configures the listener for the web app to return the injector used to configure the whole of the
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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,12 +1,12 @@
package com.tyndalehouse.step.rest.controllers;
import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang.Validate.notEmpty;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,6 +38,7 @@
*/
@Inject
public BibleController(final BibleInformationService bibleInformation) {
+
this.bibleInformation = bibleInformation;
LOGGER.debug("Created Bible Controller");
}
@@ -89,8 +90,8 @@
@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");
- Validate.notEmpty(reference, "You need to provide a reference");
+ notEmpty(version, "You need to provide a version");
+ notEmpty(reference, "You need to provide a reference");
String[] userOptions = null;
if (isNotBlank(options)) {
Deleted: 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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,355 +0,0 @@
-package com.tyndalehouse.step.rest.controllers;
-
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.avaje.ebean.EbeanServer;
-import com.avaje.ebean.text.json.JsonContext;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-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.ResponseCache;
-import com.tyndalehouse.step.rest.framework.StepRequest;
-
-/**
- * The FrontController acts like a minimal REST server. The paths are resolved as follows:
- *
- * /step-web/rest/controllerName/methodName/arg1/arg2/arg3
- *
- * @author Chris
- *
- */
- at Singleton
-public class FrontController extends HttpServlet {
- private static final Logger LOGGER = LoggerFactory.getLogger(FrontController.class);
- private static final String ENTITIES_PACKAGE = "com.tyndalehouse.step.core.data.entities";
- private static final String AVAJE_PACKAGE = "com.avaje";
- private static final String UTF_8_ENCODING = "UTF-8";
- private static final char PACKAGE_SEPARATOR = '.';
- private static final long serialVersionUID = 7898656504631346047L;
- private static final String CONTROLLER_SUFFIX = "Controller";
- private final transient Injector guiceInjector;
- // TODO: but also check thread safety and whether we should share this object
- private final transient ObjectMapper jsonMapper = new ObjectMapper();
- // TODO: check if this is thread safe, and if so, then make private field
- private final transient JsonContext ebeanJson;
-
- // 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 />
- *
- * @param guiceInjector the injector used to call the relevant controllers
- * @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("frontcontroller.cache.enabled") final Boolean isCacheEnabled, final EbeanServer ebean,
- final ClientErrorResolver errorResolver, final ResponseCache responseCache) {
- this.guiceInjector = guiceInjector;
- this.responseCache = responseCache;
- this.ebeanJson = ebean.createJsonContext();
-
- this.errorResolver = errorResolver;
- this.isCacheEnabled = Boolean.TRUE.equals(isCacheEnabled);
- }
-
- @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 {
- // cache miss?
- if (jsonEncoded == null || jsonEncoded.length == 0) {
- sr = new StepRequest(request, UTF_8_ENCODING);
- 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);
- // CHECKSTYLE:OFF We allow catching errors here, since we are at the top of the structure
- } catch (final Exception e) {
- // CHECKSTYLE:ON
- handleError(response, e, sr);
- }
- }
-
- /**
- * Invokes the method on the controller instance and returns JSON-ed results
- *
- * @param sr the STEP Request containing all pertinent information
- * @return byte array representation of the return value
- */
- byte[] invokeMethod(final StepRequest sr) {
-
- // controller instance on which to call a method
- final Object controllerInstance = getController(sr.getControllerName());
-
- // resolve method
- final Method controllerMethod = getControllerMethod(sr.getMethodName(), controllerInstance,
- sr.getArgs(), sr.getCacheKey().getMethodKey());
-
- // invoke the three together
- Object returnVal;
- try {
- returnVal = controllerMethod.invoke(controllerInstance, (Object[]) sr.getArgs());
-
- // CHECKSTYLE:OFF
- } catch (final Exception e) {
- returnVal = convertExceptionToJson(e);
- }
- final byte[] encodedJsonResponse = getEncodedJsonResponse(returnVal);
- cache(encodedJsonResponse, sr, controllerMethod);
- return encodedJsonResponse;
- // CHECKSTYLE:ON
- }
-
- /**
- * We attempt here to rethrow the exception that caused the invocation target exception, so that we can
- * handle it nicely for the user
- *
- * @param e the wrapped exception that happened during the reflective call
- * @return a client handled issue which wraps the exception that was raised
- */
- private ClientHandledIssue convertExceptionToJson(final Exception e) {
- // first we check to see if it's a step exception, or an illegal argument exception
-
- final Throwable cause = e.getCause();
- if (cause instanceof StepInternalException) {
- LOGGER.trace(e.getMessage(), e);
- return new ClientHandledIssue(cause.getMessage(), this.errorResolver.resolve(cause.getClass()));
- } else if (cause instanceof IllegalArgumentException) {
- // a validation exception occurred
- LOGGER.warn(e.getMessage(), e);
- return new ClientHandledIssue(cause.getMessage());
- }
-
- LOGGER.error(e.getMessage(), e);
- return new ClientHandledIssue("An internal error has occurred");
- }
-
- /**
- * Returns a json response that is encoded
- *
- * @param responseValue the value that should be encoded
- * @return the encoded form of the JSON response
- */
- byte[] getEncodedJsonResponse(final Object responseValue) {
- LOGGER.debug("Encoding the following response [{}]", responseValue);
-
- try {
- String response;
- // we have normal objects and avaje ebean objects which have been intercepted
- // therefore we can't just use simple jackson mapper
- if (responseValue == null) {
- return new byte[0];
- } else {
- if (isPojo(responseValue)) {
- response = this.jsonMapper.writeValueAsString(responseValue);
- } else {
- response = this.ebeanJson.toJsonString(responseValue);
- }
- }
-
- return response.getBytes(UTF_8_ENCODING);
- } catch (final JsonGenerationException e) {
- throw new StepInternalException(e.getMessage(), e);
- } catch (final JsonMappingException e) {
- throw new StepInternalException(e.getMessage(), e);
- } catch (final IOException e) {
- throw new StepInternalException(e.getMessage(), e);
- }
- }
-
- /**
- * inspects the response value to determine the correct serialiser
- *
- * @param responseValue the response value
- * @return true if normal serialisation should be used
- */
- private boolean isPojo(final Object responseValue) {
- if (responseValue instanceof java.util.Collection<?>) {
- // inspect what the collection contains...
- final Collection<?> c = (Collection<?>) responseValue;
- if (((java.util.Collection<?>) responseValue).size() != 0) {
- final Object o = c.iterator().next();
- return isPojo(o);
- }
- }
-
- final String responsePackage = responseValue.getClass().getPackage().getName();
- return !responsePackage.startsWith(ENTITIES_PACKAGE) && !responsePackage.startsWith(AVAJE_PACKAGE);
-
- }
-
- /**
- * caches the results for future use
- *
- * @param jsonEncoded json encoding of the response
- * @param sr the processed request URI containg the the cache key
- * @param controllerMethod the method so that we can inspect whether an annotation is present
- */
- 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);
- }
- }
-
- /**
- * sets up the headers and the length of the message
- *
- * @param response the response
- * @param length the length of the message
- */
- void setupHeaders(final HttpServletResponse response, final int length) {
- // we ensure that headers are set up appropriately
- response.addDateHeader("Date", System.currentTimeMillis());
- response.setCharacterEncoding(UTF_8_ENCODING);
- response.setContentType("application/json");
- response.setContentLength(length);
- }
-
- /**
- * deals with an error whilst executing the request
- *
- * @param response the response
- *
- * @param e the exception
- * @param sr the step request
- */
- void handleError(final HttpServletResponse response, final Throwable e, final StepRequest sr) {
- String requestId = null;
- LOGGER.debug("Handling error...");
- try {
- requestId = sr == null ? "Failed to parse request?" : sr.getCacheKey().getResultsKey();
- if (e != null) {
- final byte[] errorMessage = this.getEncodedJsonResponse(e);
- response.getOutputStream().write(errorMessage);
- setupHeaders(response, errorMessage.length);
-
- LOGGER.error("An internal error has occurred for [{}]", requestId, e);
- }
- // CHECKSTYLE:OFF We allow catching errors here, since we are at the top of the structure
- } catch (final Exception unableToSendError) {
- // CHECKSTYLE:ON
- LOGGER.error("Unable to output error for request" + requestId, unableToSendError);
- LOGGER.error("Due to original Throwable", e);
- }
- }
-
- /**
- * Retrieves a controller, either from the cache, or from Guice
- *
- * @param controllerName the name of the controller (used as the key for the cache)
- * @return the controller object
- */
- Object getController(final String controllerName) {
- Object controllerInstance = this.controllers.get(controllerName);
-
- // if retrieving yields null, get controller from Guice, and put in cache
- if (controllerInstance == null) {
- // make up the full class name
- final String packageName = getClass().getPackage().getName();
- final StringBuilder className = new StringBuilder(packageName.length() + controllerName.length()
- + CONTROLLER_SUFFIX.length() + 1);
-
- className.append(packageName);
- className.append(PACKAGE_SEPARATOR);
- className.append(Character.toUpperCase(controllerName.charAt(0)));
- className.append(controllerName.substring(1));
- className.append(CONTROLLER_SUFFIX);
-
- try {
- final Class<?> controllerClass = Class.forName(className.toString());
- controllerInstance = this.guiceInjector.getInstance(controllerClass);
-
- // we use the controller name as it came in to key the map
- this.controllers.put(controllerName, controllerInstance);
- } catch (final ClassNotFoundException e) {
- throw new StepInternalException("Unable to find a controller for " + className, e);
- }
- }
- return controllerInstance;
- }
-
- /**
- * Returns the method to be invoked upon the controller
- *
- * @param methodName the method name
- * @param controllerInstance the instance of the controller
- * @param args the list of arguments, required to resolve the correct method if they have arguments
- * @param cacheKey the key to retrieve in the cache
- * @return the method to be invoked
- */
- Method getControllerMethod(final String methodName, final Object controllerInstance, final Object[] args,
- final String cacheKey) {
- final Class<? extends Object> controllerClass = controllerInstance.getClass();
-
- // retrieve method from cache, or put in cache if not there
- Method controllerMethod = this.methodNames.get(cacheKey);
- if (controllerMethod == null) {
- // resolve method
- try {
- controllerMethod = controllerClass.getMethod(methodName, getClasses(args));
-
- // put method in cache
- this.methodNames.put(cacheKey, controllerMethod);
- } catch (final NoSuchMethodException e) {
- throw new StepInternalException(e.getMessage(), e);
- }
- }
- return controllerMethod;
- }
-
- /**
- * @param args a number of arguments
- * @return an array of classes matching the list of arguments passed in
- */
- Class<?>[] getClasses(final Object[] args) {
- if (args == null) {
- return new Class<?>[0];
- }
-
- final Class<?>[] classes = new Class<?>[args.length];
-
- for (int ii = 0; ii < classes.length; ii++) {
- classes[ii] = args[ii].getClass();
- }
-
- return classes;
- }
-}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/GeographyController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/GeographyController.java 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/GeographyController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,5 +1,8 @@
package com.tyndalehouse.step.rest.controllers;
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
+
import java.util.List;
import com.google.inject.Inject;
@@ -25,6 +28,7 @@
*/
@Inject
public GeographyController(final GeographyService geoService) {
+ notNull(geoService, "Failed to initialise Geography Controller");
this.geoService = geoService;
}
@@ -36,6 +40,7 @@
* @return the list of places (lat/long/precisions)
*/
public List<GeoPlace> getPlaces(final String reference) {
+ notEmpty("A reference is required for looking up geography modules");
return this.geoService.getPlaces(reference);
}
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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,5 +1,8 @@
package com.tyndalehouse.step.rest.controllers;
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
+
import java.util.List;
import org.slf4j.Logger;
@@ -24,6 +27,7 @@
*/
@Inject
public ModuleController(final ModuleService moduleDefintions) {
+ notNull(moduleDefintions, "Intialising the module administration controller failed");
this.moduleDefintions = moduleDefintions;
}
@@ -53,6 +57,7 @@
*/
@Cacheable(true)
public String getDefinition(final String reference) {
+ notEmpty(reference, "A reference must be provided to obtain a definition");
LOGGER.debug("Getting definition for {}", reference);
return this.moduleDefintions.getDefinition(reference).getExplanation();
}
Deleted: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/PeopleController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/PeopleController.java 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/PeopleController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,77 +0,0 @@
-package com.tyndalehouse.step.rest.controllers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.tyndalehouse.step.core.data.entities.RelationalPerson;
-import com.tyndalehouse.step.core.service.RelationalPeopleService;
-import com.tyndalehouse.step.models.genealogy.JitRelationalPerson;
-
-/**
- * Getting some geographical data to display
- *
- * @author Chris
- *
- */
- at Singleton
-public class PeopleController {
- private final RelationalPeopleService peopleService;
-
- /**
- * Constructs a simple geography service
- *
- * @param peopleService the people service
- */
- @Inject
- public PeopleController(final RelationalPeopleService peopleService) {
- this.peopleService = peopleService;
-
- }
-
- /**
- * returns all places that are within a passage reference
- *
- * @param personName the biblical name
- * @param degreeFromUser the number of generations to lookup
- * @return the list of places (lat/long/precisions)
- *
- */
- public JitRelationalPerson getGenealogy(final String personName, final String degreeFromUser) {
- final int degree = Integer.parseInt(degreeFromUser);
- final RelationalPerson genealogy = this.peopleService.getGenealogy(personName, degree);
- return collapseGenealogy(genealogy, degree);
- }
-
- /**
- *
- * @param sourcePerson the person we are trying to translate
- * @param degree the number of generations to ascend
- * @return the genealogy with the father/mother collapsed into a list
- */
- private JitRelationalPerson collapseGenealogy(final RelationalPerson sourcePerson, final int degree) {
- final JitRelationalPerson p = new JitRelationalPerson();
- p.setData(sourcePerson.getName());
- p.setId(sourcePerson.getCode());
- p.setName(sourcePerson.getName());
-
- final List<JitRelationalPerson> children = new ArrayList<JitRelationalPerson>();
-
- if (degree > 0) {
- final int newDegree = degree - 1;
- if (sourcePerson.getFather() != null) {
- children.add(collapseGenealogy(sourcePerson.getFather(), newDegree));
- }
-
- if (sourcePerson.getMother() != null) {
- children.add(collapseGenealogy(sourcePerson.getMother(), newDegree));
- }
- }
-
- p.setChildren(children);
-
- return p;
-
- }
-}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,5 +1,7 @@
package com.tyndalehouse.step.rest.controllers;
+import static org.apache.commons.lang.Validate.notNull;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,6 +30,9 @@
*/
@Inject
public SetupController(final BibleInformationService bibleInformationService, final Loader loader) {
+ notNull(bibleInformationService, "No bible information service was provided");
+ notNull(loader, "No loader module was provided");
+
this.bibleInformation = bibleInformationService;
this.loader = loader;
}
@@ -59,6 +64,7 @@
* @param reference the initials of the bible to install
*/
public void installBible(final String reference) {
+ notNull(reference, "A reference must be provided to install a bible");
LOGGER.debug("Installing module {}", reference);
this.bibleInformation.installModules(reference);
}
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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,6 +1,5 @@
package com.tyndalehouse.step.rest.controllers;
-import java.util.Date;
import java.util.List;
import org.joda.time.LocalDateTime;
@@ -43,23 +42,6 @@
}
/**
- * a REST method to retrieve events between two dates The arrays match in index, and go by three
- * (timebandId, from, to), (timebandId, from, to), ...
- *
- * @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.
- * <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];
- }
-
- /**
* Retrieves events based on a biblical reference. This method also needs to return an origin and a scale
* for the timeline to be displayed properly as it might well be that the UI has carried out a different
* search
Copied: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/FrontController.java (from rev 243, 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/framework/FrontController.java (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/FrontController.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -0,0 +1,354 @@
+package com.tyndalehouse.step.rest.framework;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.avaje.ebean.EbeanServer;
+import com.avaje.ebean.text.json.JsonContext;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.tyndalehouse.step.core.exceptions.StepInternalException;
+
+/**
+ * The FrontController acts like a minimal REST server. The paths are resolved as follows:
+ *
+ * /step-web/rest/controllerName/methodName/arg1/arg2/arg3
+ *
+ * @author Chris
+ *
+ */
+ at Singleton
+public class FrontController extends HttpServlet {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FrontController.class);
+ private static final String CONTROLLER_PACKAGE = "com.tyndalehouse.step.rest.controllers";
+ private static final String ENTITIES_PACKAGE = "com.tyndalehouse.step.core.data.entities";
+ private static final String AVAJE_PACKAGE = "com.avaje";
+ private static final String UTF_8_ENCODING = "UTF-8";
+ private static final char PACKAGE_SEPARATOR = '.';
+ private static final long serialVersionUID = 7898656504631346047L;
+ private static final String CONTROLLER_SUFFIX = "Controller";
+ private final transient Injector guiceInjector;
+ // TODO: but also check thread safety and whether we should share this object
+ private final transient ObjectMapper jsonMapper = new ObjectMapper();
+ // TODO: check if this is thread safe, and if so, then make private field
+ private final transient JsonContext ebeanJson;
+
+ // 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 />
+ *
+ * @param guiceInjector the injector used to call the relevant controllers
+ * @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("frontcontroller.cache.enabled") final Boolean isCacheEnabled, final EbeanServer ebean,
+ final ClientErrorResolver errorResolver, final ResponseCache responseCache) {
+ this.guiceInjector = guiceInjector;
+ this.responseCache = responseCache;
+ this.ebeanJson = ebean.createJsonContext();
+
+ this.errorResolver = errorResolver;
+ this.isCacheEnabled = Boolean.TRUE.equals(isCacheEnabled);
+ }
+
+ @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 {
+ // cache miss?
+ if (jsonEncoded == null || jsonEncoded.length == 0) {
+ sr = new StepRequest(request, UTF_8_ENCODING);
+ 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);
+ // CHECKSTYLE:OFF We allow catching errors here, since we are at the top of the structure
+ } catch (final Exception e) {
+ // CHECKSTYLE:ON
+ handleError(response, e, sr);
+ }
+ }
+
+ /**
+ * Invokes the method on the controller instance and returns JSON-ed results
+ *
+ * @param sr the STEP Request containing all pertinent information
+ * @return byte array representation of the return value
+ */
+ byte[] invokeMethod(final StepRequest sr) {
+
+ // controller instance on which to call a method
+ final Object controllerInstance = getController(sr.getControllerName());
+
+ // resolve method
+ final Method controllerMethod = getControllerMethod(sr.getMethodName(), controllerInstance,
+ sr.getArgs(), sr.getCacheKey().getMethodKey());
+
+ // invoke the three together
+ Object returnVal;
+ try {
+ returnVal = controllerMethod.invoke(controllerInstance, (Object[]) sr.getArgs());
+
+ // CHECKSTYLE:OFF
+ } catch (final Exception e) {
+ returnVal = convertExceptionToJson(e);
+ }
+ final byte[] encodedJsonResponse = getEncodedJsonResponse(returnVal);
+ cache(encodedJsonResponse, sr, controllerMethod);
+ return encodedJsonResponse;
+ // CHECKSTYLE:ON
+ }
+
+ /**
+ * We attempt here to rethrow the exception that caused the invocation target exception, so that we can
+ * handle it nicely for the user
+ *
+ * @param e the wrapped exception that happened during the reflective call
+ * @return a client handled issue which wraps the exception that was raised
+ */
+ private ClientHandledIssue convertExceptionToJson(final Exception e) {
+ // first we check to see if it's a step exception, or an illegal argument exception
+
+ final Throwable cause = e.getCause();
+ if (cause instanceof StepInternalException) {
+ LOGGER.trace(e.getMessage(), e);
+ return new ClientHandledIssue(cause.getMessage(), this.errorResolver.resolve(cause.getClass()));
+ } else if (cause instanceof IllegalArgumentException) {
+ // a validation exception occurred
+ LOGGER.warn(e.getMessage(), e);
+ return new ClientHandledIssue(cause.getMessage());
+ }
+
+ LOGGER.error(e.getMessage(), e);
+ return new ClientHandledIssue("An internal error has occurred");
+ }
+
+ /**
+ * Returns a json response that is encoded
+ *
+ * @param responseValue the value that should be encoded
+ * @return the encoded form of the JSON response
+ */
+ byte[] getEncodedJsonResponse(final Object responseValue) {
+ LOGGER.debug("Encoding the following response [{}]", responseValue);
+
+ try {
+ String response;
+ // we have normal objects and avaje ebean objects which have been intercepted
+ // therefore we can't just use simple jackson mapper
+ if (responseValue == null) {
+ return new byte[0];
+ } else {
+ if (isPojo(responseValue)) {
+ response = this.jsonMapper.writeValueAsString(responseValue);
+ } else {
+ response = this.ebeanJson.toJsonString(responseValue);
+ }
+ }
+
+ return response.getBytes(UTF_8_ENCODING);
+ } catch (final JsonGenerationException e) {
+ throw new StepInternalException(e.getMessage(), e);
+ } catch (final JsonMappingException e) {
+ throw new StepInternalException(e.getMessage(), e);
+ } catch (final IOException e) {
+ throw new StepInternalException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * inspects the response value to determine the correct serialiser
+ *
+ * @param responseValue the response value
+ * @return true if normal serialisation should be used
+ */
+ private boolean isPojo(final Object responseValue) {
+ if (responseValue instanceof java.util.Collection<?>) {
+ // inspect what the collection contains...
+ final Collection<?> c = (Collection<?>) responseValue;
+ if (((java.util.Collection<?>) responseValue).size() != 0) {
+ final Object o = c.iterator().next();
+ return isPojo(o);
+ }
+ }
+
+ final String responsePackage = responseValue.getClass().getPackage().getName();
+ return !responsePackage.startsWith(ENTITIES_PACKAGE) && !responsePackage.startsWith(AVAJE_PACKAGE);
+
+ }
+
+ /**
+ * caches the results for future use
+ *
+ * @param jsonEncoded json encoding of the response
+ * @param sr the processed request URI containg the the cache key
+ * @param controllerMethod the method so that we can inspect whether an annotation is present
+ */
+ 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);
+ }
+ }
+
+ /**
+ * sets up the headers and the length of the message
+ *
+ * @param response the response
+ * @param length the length of the message
+ */
+ void setupHeaders(final HttpServletResponse response, final int length) {
+ // we ensure that headers are set up appropriately
+ response.addDateHeader("Date", System.currentTimeMillis());
+ response.setCharacterEncoding(UTF_8_ENCODING);
+ response.setContentType("application/json");
+ response.setContentLength(length);
+ }
+
+ /**
+ * deals with an error whilst executing the request
+ *
+ * @param response the response
+ *
+ * @param e the exception
+ * @param sr the step request
+ */
+ void handleError(final HttpServletResponse response, final Throwable e, final StepRequest sr) {
+ String requestId = null;
+ LOGGER.debug("Handling error...");
+ try {
+ requestId = sr == null ? "Failed to parse request?" : sr.getCacheKey().getResultsKey();
+ if (e != null) {
+ final byte[] errorMessage = this.getEncodedJsonResponse(e);
+ response.getOutputStream().write(errorMessage);
+ setupHeaders(response, errorMessage.length);
+
+ LOGGER.error("An internal error has occurred for [{}]", requestId, e);
+ }
+ // CHECKSTYLE:OFF We allow catching errors here, since we are at the top of the structure
+ } catch (final Exception unableToSendError) {
+ // CHECKSTYLE:ON
+ LOGGER.error("Unable to output error for request" + requestId, unableToSendError);
+ LOGGER.error("Due to original Throwable", e);
+ }
+ }
+
+ /**
+ * Retrieves a controller, either from the cache, or from Guice
+ *
+ * @param controllerName the name of the controller (used as the key for the cache)
+ * @return the controller object
+ */
+ Object getController(final String controllerName) {
+ Object controllerInstance = this.controllers.get(controllerName);
+
+ // if retrieving yields null, get controller from Guice, and put in cache
+ if (controllerInstance == null) {
+ // make up the full class name
+ final String packageName = CONTROLLER_PACKAGE;
+ final StringBuilder className = new StringBuilder(packageName.length() + controllerName.length()
+ + CONTROLLER_SUFFIX.length() + 1);
+
+ className.append(packageName);
+ className.append(PACKAGE_SEPARATOR);
+ className.append(Character.toUpperCase(controllerName.charAt(0)));
+ className.append(controllerName.substring(1));
+ className.append(CONTROLLER_SUFFIX);
+
+ try {
+ final Class<?> controllerClass = Class.forName(className.toString());
+ controllerInstance = this.guiceInjector.getInstance(controllerClass);
+
+ // we use the controller name as it came in to key the map
+ this.controllers.put(controllerName, controllerInstance);
+ } catch (final ClassNotFoundException e) {
+ throw new StepInternalException("Unable to find a controller for " + className, e);
+ }
+ }
+ return controllerInstance;
+ }
+
+ /**
+ * Returns the method to be invoked upon the controller
+ *
+ * @param methodName the method name
+ * @param controllerInstance the instance of the controller
+ * @param args the list of arguments, required to resolve the correct method if they have arguments
+ * @param cacheKey the key to retrieve in the cache
+ * @return the method to be invoked
+ */
+ Method getControllerMethod(final String methodName, final Object controllerInstance, final Object[] args,
+ final String cacheKey) {
+ final Class<? extends Object> controllerClass = controllerInstance.getClass();
+
+ // retrieve method from cache, or put in cache if not there
+ Method controllerMethod = this.methodNames.get(cacheKey);
+ if (controllerMethod == null) {
+ // resolve method
+
+ try {
+ final Class<?>[] classes = getClasses(args);
+ controllerMethod = controllerClass.getMethod(methodName, classes);
+ this.methodNames.put(cacheKey, controllerMethod);
+
+ // put method in cache
+ } catch (final NoSuchMethodException e) {
+ throw new StepInternalException(e.getMessage(), e);
+ }
+ }
+
+ return controllerMethod;
+ }
+
+ /**
+ * @param args a number of arguments
+ * @return an array of classes matching the list of arguments passed in
+ */
+ Class<?>[] getClasses(final Object[] args) {
+ if (args == null) {
+ return new Class<?>[0];
+ }
+
+ final Class<?>[] classes = new Class<?>[args.length];
+
+ for (int ii = 0; ii < classes.length; ii++) {
+ classes[ii] = args[ii].getClass();
+ }
+
+ return classes;
+ }
+}
Modified: trunk/step/step-web/src/main/webapp/css/passage.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/passage.css 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/css/passage.css 2012-04-23 11:52:53 UTC (rev 253)
@@ -74,11 +74,18 @@
color: gray;
}
-SUP.note {
- font-size: 75%;
- color: green;
+SUP.note a {
+ font-size: 100%;
+ font-weight: bold;
+ color: #696;
}
+SUP.note a:visited {
+ font-size: 100%;
+ font-weight: bold;
+ color: #696;
+}
+
FONT.lex {
color: red;
}
@@ -151,14 +158,13 @@
-H3.heading {
+H3.heading {
font-size: 110%;
color: #666699;
font-weight: bold;
clear: both;
}
-
.editable {
border: 1px dashed black;
}
@@ -206,9 +212,31 @@
}
+.notes a {
+ color: #666699;
+ font-weight: bold;
+ front-size: xx-small;
+}
+
+
+
+a.linkRef {
+ color: #696;
+ font-weight: normal;
+ front-size: smaller;
+}
+
+a:hover.linkRef {
+ color: #696;
+ font-weight: normal;
+ front-size: smaller;
+}
+
+
/* the following are for dictionary entries */
FONT.orth {
font-weight: bold;
+
}
FONT.pron {
Modified: trunk/step/step-web/src/main/webapp/index.html
===================================================================
--- trunk/step/step-web/src/main/webapp/index.html 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/index.html 2012-04-23 11:52:53 UTC (rev 253)
@@ -32,6 +32,7 @@
<!-- load the maps - eventually this has to be dynamic, so that no all loading happens -->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></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>
Modified: trunk/step/step-web/src/main/webapp/js/bookmark.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/bookmark.js 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/js/bookmark.js 2012-04-23 11:52:53 UTC (rev 253)
@@ -210,9 +210,9 @@
if(passageReference && passageReference != "") {
var item = "<div class='bookmarkItem'>";
- item += "<a class='ui-icon ui-icon-arrowthick-1-w bookmarkArrow leftBookmarkArrow' href='#' onclick='$.shout(\"bookmark-triggered-0\", \""+ passageReference + "\");'>←</a>";
+ item += "<a class='ui-icon ui-icon-arrowthick-1-w bookmarkArrow leftBookmarkArrow' href='#' onclick='$.shout(\"new-passage-0\", \""+ passageReference + "\");'>←</a>";
item += passageReference;
- item += "<a class='ui-icon ui-icon-arrowthick-1-e bookmarkArrow rightBookmarkArrow' href='#' onclick='$.shout(\"bookmark-triggered-1\", \""+ passageReference + "\");'>→</a>";
+ item += "<a class='ui-icon ui-icon-arrowthick-1-e bookmarkArrow rightBookmarkArrow' href='#' onclick='$.shout(\"new-passage-1\", \""+ passageReference + "\");'>→</a>";
item += "</div>";
if(ascending) {
Modified: trunk/step/step-web/src/main/webapp/js/passage.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/passage.js 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/js/passage.js 2012-04-23 11:52:53 UTC (rev 253)
@@ -35,7 +35,7 @@
//register when we want to be alerted that a bookmark has changed
- this.passage.hear("bookmark-triggered-" + this.passageId, function(selfElement, data) {
+ this.passage.hear("new-passage-" + this.passageId, function(selfElement, data) {
self.reference.val(data);
self.changePassage();
});
Modified: trunk/step/step-web/src/main/webapp/js/timeline.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/timeline.js 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/js/timeline.js 2012-04-23 11:52:53 UTC (rev 253)
@@ -38,6 +38,7 @@
//set up the theme
this.theme = Timeline.ClassicTheme.create();
+
this.theme.event.bubble.width = 250;
this.eventSource = new Timeline.DefaultEventSource();
@@ -64,6 +65,20 @@
intervalPixels: 100,
zones: zones,
eventSource: self.eventSource,
+ zoomIndex: 10,
+ zoomSteps: new Array(
+ {pixelsPerInterval: 280, unit: Timeline.DateTime.HOUR},
+ {pixelsPerInterval: 140, unit: Timeline.DateTime.HOUR},
+ {pixelsPerInterval: 70, unit: Timeline.DateTime.HOUR},
+ {pixelsPerInterval: 35, unit: Timeline.DateTime.HOUR},
+ {pixelsPerInterval: 400, unit: Timeline.DateTime.DAY},
+ {pixelsPerInterval: 200, unit: Timeline.DateTime.DAY},
+ {pixelsPerInterval: 100, unit: Timeline.DateTime.DAY},
+ {pixelsPerInterval: 50, unit: Timeline.DateTime.DAY},
+ {pixelsPerInterval: 400, unit: Timeline.DateTime.MONTH},
+ {pixelsPerInterval: 200, unit: Timeline.DateTime.MONTH},
+ {pixelsPerInterval: 100, unit: Timeline.DateTime.MONTH}
+ )
}),
Timeline.createBandInfo({
@@ -244,6 +259,21 @@
mainBand.scrollToCenter(mainBand.getMaxVisibleDate());
});
+ $("#bottomModuleHeader #zoomInTimeline").click(function() {
+ var mainBand = self.tl.getBand(0);
+ mainBand.zoom(true);
+ self.tl.paint();
+ self.tl.layout();
+ });
+
+ $("#bottomModuleHeader #zoomOutTimeline").click(function() {
+ var mainBand = self.tl.getBand(0);
+ mainBand.zoom(false);
+ self.tl.paint();
+ self.tl.layout();
+ });
+
+
$("#bottomModuleHeader #linkToPassage").click(function() {
if($(this).text() === "Link to passage") {
$(this).button("option", {icons: { primary: "ui-icon-pin-s" }, label: "Unlink from passage"});
@@ -261,7 +291,8 @@
$("#bottomModuleHeader #scrollTimelineToDate").click(function() {
var datePopup = $("#goToDate");
$("#scrollToYear", datePopup).val(self.tl.getBand(0).getCenterVisibleDate().getFullYear());
- datePopup.dialog({ modal: true,
+ datePopup.dialog({ title: "Please enter a year:",
+ modal: true,
buttons : [{
text: "OK",
click: function() {
@@ -330,6 +361,7 @@
this.fillDescription(divBody);
theme.event.bubble.bodyStyler(divBody);
elmt.appendChild(divBody);
+
// This is where they define the times in the bubble
var divTime = doc.createElement("div");
divTime.innerHTML = start + " - " + end;
Modified: trunk/step/step-web/src/main/webapp/js/toolbar_menu.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/toolbar_menu.js 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/js/toolbar_menu.js 2012-04-23 11:52:53 UTC (rev 253)
@@ -126,6 +126,7 @@
ToolbarMenu.prototype.setDefaultOptions = function() {
this.toggleMenuItem("HEADINGS");
this.toggleMenuItem("VERSE_NUMBERS");
+ this.toggleMenuItem("NOTES");
}
/**
Modified: trunk/step/step-web/src/main/webapp/js/ui_hooks.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/ui_hooks.js 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/js/ui_hooks.js 2012-04-23 11:52:53 UTC (rev 253)
@@ -63,6 +63,10 @@
$.shout("pane-menu-toggle-item-" + getPassageId(menuItem), menuItem.name);
};
+function changePassage(element, passageReference) {
+ $.shout("new-passage-" + getPassageId(element), passageReference);
+}
+
/**
* shows the login popup
*/
Modified: trunk/step/step-web/src/main/webapp/panemenu.html
===================================================================
--- trunk/step/step-web/src/main/webapp/panemenu.html 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/main/webapp/panemenu.html 2012-04-23 11:52:53 UTC (rev 253)
@@ -3,6 +3,7 @@
<ul>
<li><a href="#" name="HEADINGS" onclick="toggleMenuItem(this);">Headings</a></li>
<li><a href="#" name="VERSE_NUMBERS" onclick="toggleMenuItem(this);">Verse Numbers</a></li>
+ <li><a href="#" name="NOTES" onclick="toggleMenuItem(this);">Notes and References</a></li>
<li><a href="#" name="STRONG_NUMBERS" onclick="toggleMenuItem(this);">Strong Numbers</a></li>
<li><a href="#" name="MORPHOLOGY" onclick="toggleMenuItem(this);">Morphology</a></li>
<li><a href="#" name="INTERLINEAR" onclick="showInterlinearChoices(this);" >Interlinear...</a></li>
Deleted: 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 2012-04-20 19:43:48 UTC (rev 252)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -1,237 +0,0 @@
-package com.tyndalehouse.step.rest.controllers;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import javax.servlet.ServletOutputStream;
-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.ControllerCacheKey;
-import com.tyndalehouse.step.rest.framework.ResponseCache;
-import com.tyndalehouse.step.rest.framework.StepRequest;
-
-/**
- * tests the front controller parsing process
- *
- * @author Chris
- *
- */
- at 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;
- @Mock
- private StepRequest stepRequest;
-
- /**
- * 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
- */
- @Test
- public void testDoGet() throws IOException {
- final HttpServletRequest req = mock(HttpServletRequest.class);
- final HttpServletResponse response = mock(HttpServletResponse.class);
- final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
-
- when(req.getRequestURI()).thenReturn(sampleRequest);
- when(req.getServletPath()).thenReturn("step-web/");
- when(req.getContextPath()).thenReturn("rest/");
-
- final FrontController fc = spy(this.fcUnderTest);
-
- final ServletOutputStream mockOutputStream = mock(ServletOutputStream.class);
-
- doReturn(mockOutputStream).when(response).getOutputStream();
- final byte[] sampleResponse = new byte[] { 1, 2, 3 };
- doReturn(sampleResponse).when(fc).invokeMethod(any(StepRequest.class));
-
- // do the test
- fc.doGet(req, response);
- verify(mockOutputStream).write(sampleResponse);
- }
-
- /**
- * tests what happens when doGet catches an exception
- */
- @Test
- public void testDoGetHasException() {
- final HttpServletRequest request = mock(HttpServletRequest.class);
- final HttpServletResponse response = mock(HttpServletResponse.class);
- final StepInternalException testException = new StepInternalException("A test exception");
-
- final FrontController fc = spy(this.fcUnderTest);
- final StepRequest parsedRequest = new StepRequest("blah", "SomeController", "someMethod",
- new String[] { "arg1", "arg2" });
-
- // TODO remove this/
- // doThrow(testException).when(fc).parseRequest(request);
- doNothing().when(fc).handleError(response, testException, parsedRequest);
-
- // do the test
- fc.doGet(request, response);
-
- }
-
- /**
- * tests that the headers are setup correctly
- */
- @Test
- public void testHeadersSetupCorrectly() {
- final HttpServletResponse response = mock(HttpServletResponse.class);
-
- final int sampleRequestLength = 10;
- this.fcUnderTest.setupHeaders(response, sampleRequestLength);
-
- verify(response).addDateHeader(eq("Date"), anyLong());
- verify(response).setCharacterEncoding("UTF-8");
- verify(response).setContentType("application/json");
- verify(response).setContentLength(sampleRequestLength);
-
- }
-
- /**
- * tests that resolving method works
- *
- * @throws IllegalAccessException uncaught exception
- * @throws InvocationTargetException uncaught exception
- */
- @Test
- public void testGetControllerMethod() throws IllegalAccessException, InvocationTargetException {
- final BibleInformationService bibleInfo = mock(BibleInformationService.class);
- final BibleController controllerInstance = new BibleController(bibleInfo);
-
- // when
- final Method controllerMethod = this.fcUnderTest.getControllerMethod("getBibleVersions",
- controllerInstance, null, null);
-
- // then
- controllerMethod.invoke(controllerInstance);
- verify(bibleInfo).getAvailableBibleVersions();
- }
-
- /**
- * tests the get controller method
- */
- @Test
- public void testGetController() {
- final String controllerName = "Bible";
- final BibleController mockController = mock(BibleController.class);
- when(this.guiceInjector.getInstance(BibleController.class)).thenReturn(mockController);
-
- // when
- final Object controller = this.fcUnderTest.getController(controllerName);
-
- // then
- assertEquals(controller.getClass(), mockController.getClass());
- }
-
- /**
- * tests various combinations for getClasses
- */
- @Test
- public void testGetClasses() {
- assertEquals(0, this.fcUnderTest.getClasses(null).length);
- assertEquals(0, this.fcUnderTest.getClasses(new Object[0]).length);
- assertArrayEquals(new Class<?>[] { String.class, Integer.class },
- this.fcUnderTest.getClasses(new Object[] { "hello", Integer.valueOf(1) }));
-
- }
-
- /**
- * tests that we encode using json mapper and set to UTF 8
- */
- @Test
- public void testJsonEncoding() {
- final byte[] encodedJsonResponse = this.fcUnderTest.getEncodedJsonResponse("abc");
-
- // this reprensents the string "{abc}"
- final byte[] expectedValues = new byte[] { 34, 97, 98, 99, 34 };
-
- assertArrayEquals(expectedValues, encodedJsonResponse);
- }
-
- /**
- * If an error was thrown, we should map it and output
- *
- * @throws IOException uncaught exception
- */
- @Test
- public void testDoErrorHandlesCorrectly() throws IOException {
- final HttpServletResponse response = mock(HttpServletResponse.class);
- // final StepRequest stepRequest = new StepRequest("blah", "controller", "method", null);
- final ServletOutputStream outputStream = mock(ServletOutputStream.class);
- final Throwable exception = new Exception();
- when(response.getOutputStream()).thenReturn(outputStream);
- when(this.stepRequest.getCacheKey()).thenReturn(new ControllerCacheKey("method", "results"));
-
- // do test
- this.fcUnderTest.handleError(response, exception, this.stepRequest);
-
- // check
- verify(outputStream).write(any(byte[].class));
- }
-
- /**
- * We check that invoke method calls the correct controller and method with the right arguments
- */
- @Test
- public void testInvokeMethod() {
- final StepRequest sr = new StepRequest("blah", "bible", "getAllFeatures", new String[] {});
- final BibleController testController = mock(BibleController.class);
-
- final FrontController fc = spy(this.fcUnderTest);
- doReturn(testController).when(fc).getController("bible");
-
- // do test
- fc.invokeMethod(sr);
-
- // verify
- verify(testController).getAllFeatures();
- }
-}
Copied: trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/FrontControllerTest.java (from rev 243, 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/FrontControllerTest.java (rev 0)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/framework/FrontControllerTest.java 2012-04-23 11:52:53 UTC (rev 253)
@@ -0,0 +1,239 @@
+package com.tyndalehouse.step.rest.framework;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.servlet.ServletOutputStream;
+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.controllers.BibleController;
+import com.tyndalehouse.step.rest.framework.ClientErrorResolver;
+import com.tyndalehouse.step.rest.framework.ControllerCacheKey;
+import com.tyndalehouse.step.rest.framework.FrontController;
+import com.tyndalehouse.step.rest.framework.ResponseCache;
+import com.tyndalehouse.step.rest.framework.StepRequest;
+
+/**
+ * tests the front controller parsing process
+ *
+ * @author Chris
+ *
+ */
+ at 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;
+ @Mock
+ private StepRequest stepRequest;
+
+ /**
+ * 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
+ */
+ @Test
+ public void testDoGet() throws IOException {
+ final HttpServletRequest req = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
+
+ when(req.getRequestURI()).thenReturn(sampleRequest);
+ when(req.getServletPath()).thenReturn("step-web/");
+ when(req.getContextPath()).thenReturn("rest/");
+
+ final FrontController fc = spy(this.fcUnderTest);
+
+ final ServletOutputStream mockOutputStream = mock(ServletOutputStream.class);
+
+ doReturn(mockOutputStream).when(response).getOutputStream();
+ final byte[] sampleResponse = new byte[] { 1, 2, 3 };
+ doReturn(sampleResponse).when(fc).invokeMethod(any(StepRequest.class));
+
+ // do the test
+ fc.doGet(req, response);
+ verify(mockOutputStream).write(sampleResponse);
+ }
+
+ /**
+ * tests what happens when doGet catches an exception
+ */
+ @Test
+ public void testDoGetHasException() {
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final StepInternalException testException = new StepInternalException("A test exception");
+
+ final FrontController fc = spy(this.fcUnderTest);
+ final StepRequest parsedRequest = new StepRequest("blah", "SomeController", "someMethod",
+ new String[] { "arg1", "arg2" });
+
+ // TODO remove this/
+ // doThrow(testException).when(fc).parseRequest(request);
+ doNothing().when(fc).handleError(response, testException, parsedRequest);
+
+ // do the test
+ fc.doGet(request, response);
+
+ }
+
+ /**
+ * tests that the headers are setup correctly
+ */
+ @Test
+ public void testHeadersSetupCorrectly() {
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+
+ final int sampleRequestLength = 10;
+ this.fcUnderTest.setupHeaders(response, sampleRequestLength);
+
+ verify(response).addDateHeader(eq("Date"), anyLong());
+ verify(response).setCharacterEncoding("UTF-8");
+ verify(response).setContentType("application/json");
+ verify(response).setContentLength(sampleRequestLength);
+
+ }
+
+ /**
+ * tests that resolving method works
+ *
+ * @throws IllegalAccessException uncaught exception
+ * @throws InvocationTargetException uncaught exception
+ */
+ @Test
+ public void testGetControllerMethod() throws IllegalAccessException, InvocationTargetException {
+ final BibleInformationService bibleInfo = mock(BibleInformationService.class);
+ final BibleController controllerInstance = new BibleController(bibleInfo);
+
+ // when
+ final Method controllerMethod = this.fcUnderTest.getControllerMethod("getBibleVersions",
+ controllerInstance, null, null);
+
+ // then
+ controllerMethod.invoke(controllerInstance);
+ verify(bibleInfo).getAvailableBibleVersions();
+ }
+
+ /**
+ * tests the get controller method
+ */
+ @Test
+ public void testGetController() {
+ final String controllerName = "Bible";
+ final BibleController mockController = mock(BibleController.class);
+ when(this.guiceInjector.getInstance(BibleController.class)).thenReturn(mockController);
+
+ // when
+ final Object controller = this.fcUnderTest.getController(controllerName);
+
+ // then
+ assertEquals(controller.getClass(), mockController.getClass());
+ }
+
+ /**
+ * tests various combinations for getClasses
+ */
+ @Test
+ public void testGetClasses() {
+ assertEquals(0, this.fcUnderTest.getClasses(null).length);
+ assertEquals(0, this.fcUnderTest.getClasses(new Object[0]).length);
+ assertArrayEquals(new Class<?>[] { String.class, Integer.class },
+ this.fcUnderTest.getClasses(new Object[] { "hello", Integer.valueOf(1) }));
+
+ }
+
+ /**
+ * tests that we encode using json mapper and set to UTF 8
+ */
+ @Test
+ public void testJsonEncoding() {
+ final byte[] encodedJsonResponse = this.fcUnderTest.getEncodedJsonResponse("abc");
+
+ // this reprensents the string "{abc}"
+ final byte[] expectedValues = new byte[] { 34, 97, 98, 99, 34 };
+
+ assertArrayEquals(expectedValues, encodedJsonResponse);
+ }
+
+ /**
+ * If an error was thrown, we should map it and output
+ *
+ * @throws IOException uncaught exception
+ */
+ @Test
+ public void testDoErrorHandlesCorrectly() throws IOException {
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ // final StepRequest stepRequest = new StepRequest("blah", "controller", "method", null);
+ final ServletOutputStream outputStream = mock(ServletOutputStream.class);
+ final Throwable exception = new Exception();
+ when(response.getOutputStream()).thenReturn(outputStream);
+ when(this.stepRequest.getCacheKey()).thenReturn(new ControllerCacheKey("method", "results"));
+
+ // do test
+ this.fcUnderTest.handleError(response, exception, this.stepRequest);
+
+ // check
+ verify(outputStream).write(any(byte[].class));
+ }
+
+ /**
+ * We check that invoke method calls the correct controller and method with the right arguments
+ */
+ @Test
+ public void testInvokeMethod() {
+ final StepRequest sr = new StepRequest("blah", "bible", "getAllFeatures", new String[] {});
+ final BibleController testController = mock(BibleController.class);
+
+ final FrontController fc = spy(this.fcUnderTest);
+ doReturn(testController).when(fc).getController("bible");
+
+ // do test
+ fc.invokeMethod(sr);
+
+ // verify
+ verify(testController).getAllFeatures();
+ }
+}
More information about the Tynstep-svn
mailing list