You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/06/25 16:05:22 UTC

[2/2] incubator-freemarker-online-tester git commit: Further cleanup: Upgraded Dropwizard to the latest, also Jersey to 2.x. Removed Spring dependencies (we haven't utilized it apart from a few IoC-related annotations, which I have replaced with a few li

Further cleanup: Upgraded Dropwizard to the latest, also Jersey to 2.x. Removed Spring dependencies (we haven't utilized it apart from a few IoC-related annotations, which I have replaced with a few lines of code in FreeMarkerOnlineTester, following the Dropwizard convention). Some other minor cleanups.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/commit/8b699eb5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/tree/8b699eb5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/diff/8b699eb5

Branch: refs/heads/master
Commit: 8b699eb519b12bf1720d9fc77930be0f03e5cb41
Parents: 90a6e05
Author: ddekany <dd...@apache.org>
Authored: Sun Jun 25 18:05:05 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Jun 25 18:05:05 2017 +0200

----------------------------------------------------------------------
 build.gradle                                    |  22 +-
 dependencies.gradle                             |  69 +++---
 .../dropwizard/FreeMarkerOnlineTester.java      |  37 +---
 ...reeMarkerOnlineTesterOverallHealthCheck.java |  30 +++
 .../healthchecks/MyProjectHealthCheck.java      |  32 ---
 .../resources/ExecuteApiResource.java           | 219 ++++++++++++++++++
 .../FreeMarkerOnlineExecuteResource.java        | 220 -------------------
 .../resources/FreeMarkerOnlineResource.java     |  63 ------
 .../onlinetester/resources/TestResource.java    |  18 --
 .../onlinetester/resources/WebPageResource.java |  63 ++++++
 .../services/FreeMarkerService.java             | 113 ++++++----
 .../spring/SpringConfiguration.java             |   8 -
 .../onlinetester/util/DataModelParser.java      |   4 +-
 src/main/resources/freemarker-online.yml        |   4 +-
 src/main/resources/spring/bootstrap-context.xml |  38 ----
 .../onlinetester/ApplicationStartsTest.java     |  48 ++++
 .../platform/DropWizardServiceTest.java         |  41 ----
 .../platform/YamlPropertiesPersister.java       |  91 --------
 .../resources/ExecuteApiResourceTest.java       | 134 +++++++++++
 .../FreeMarkerOnlineExecuteResourceTest.java    | 159 --------------
 .../resources/FreeMarkerOnlineResourceTest.java |  70 ------
 .../onlinetester/resources/ResourceTest.java    |  17 ++
 .../resources/WebPageResourceTest.java          |  71 ++++++
 .../services/FreeMarkerServiceTest.java         |  83 ++++---
 src/test/resources/logback-test.xml             |  34 +++
 src/test/resources/spring/test-context.xml      |  26 ---
 26 files changed, 763 insertions(+), 951 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index c700e9b..9a010ee 100644
--- a/build.gradle
+++ b/build.gradle
@@ -55,30 +55,16 @@ dependencies {
     compile libraries.dropwizard_views
     compile libraries.dropwizard_views_freemarker
     compile libraries.dropwizard_assets
-    compile libraries.springCore
-    compile libraries.springContext
-    compile libraries.springContextSupport
-    compile libraries.springExpression
-    compile libraries.springSecurityCore
-    compile libraries.springTransaction
-    compile libraries.springBeans
-    compile libraries.springWeb
-
-    testCompile libraries.dropwizard_testing
-    testCompile libraries.springTest
-    testCompile libraries.junit
-    testCompile libraries.mockito
-    testCompile libraries.hamcrest
-
     compile libraries.freemarker
     compile libraries.jackson_databind
     compile libraries.commonLangs
     compile libraries.findBugs
 
-    testCompile libraries.selenium_java
+    testCompile libraries.dropwizard_testing
+    testCompile libraries.junit
+    testCompile libraries.mockito
+    testCompile libraries.hamcrest
     testCompile libraries.jersey_grrizle
-    testCompile libraries.jersey_client
-    testCompile libraries.springJersey
 }
 
 compileJava {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/dependencies.gradle
----------------------------------------------------------------------
diff --git a/dependencies.gradle b/dependencies.gradle
index b5d1598..a27abc2 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -17,51 +17,32 @@
  * under the License.
  */
 
-project.ext.set("libraries", "")
-ext.dw_version = "1.1.1";
-ext.spring_version = "4.3.9.RELEASE";
+ext.dropwizard_version = "1.1.1";
 ext.jackson_version = "2.8.9";
-
-project.libraries = [
-        dropwizard: "io.dropwizard:dropwizard-core:$dw_version",
-        dropwizard_client: "io.dropwizard:dropwizard-client:$dw_version",
-        dropwizard_views: "io.dropwizard:dropwizard-views:$dw_version",
-        dropwizard_views_freemarker: "io.dropwizard:dropwizard-views-freemarker:$dw_version",
-        dropwizard_assets: "io.dropwizard:dropwizard-assets:$dw_version",
-        guava: 'com.google.guava:guava:13.0.1',
-        jersey_core: 'com.sun.jersey:jersey-core:1.1.4.1',
-
-        //Spring
-        springCore: "org.springframework:spring-core:$spring_version",
-        springContext: "org.springframework:spring-context:$spring_version",
-        springContextSupport: "org.springframework:spring-context-support:$spring_version",
-        springExpression: "org.springframework:spring-expression:$spring_version",
-        springTransaction: "org.springframework:spring-tx:$spring_version",
-        springBeans: "org.springframework:spring-beans:$spring_version",
-        springJersey: "com.sun.jersey.contribs:jersey-spring:1.7",
-        springWeb: "org.springframework:spring-web:$spring_version",
-
-        // Security
-        // Spring and Spring Security support for dropwizard
-        springSecurityCore: "org.springframework.security:spring-security-core:3.1.4.RELEASE",
-        dropwizardAuth: "io.dropwizard:dropwizard-auth:$dw_version",
-
-        // Spring test
-        springTest: "org.springframework:spring-test:$spring_version",
-
-        //Test libs
-        dropwizard_testing: "io.dropwizard:dropwizard-testing:$dw_version",
-        junit: 'junit:junit-dep:4.11',
-        mockito: 'org.mockito:mockito-core:1.9.0',
-        hamcrest: 'org.hamcrest:hamcrest-library:1.3',
-        selenium_java: 'org.seleniumhq.selenium:selenium-java:2.41.0',
-        jersey_client: 'com.sun.jersey:jersey-client:1.17.1',
-        jersey_grrizle: 'com.sun.jersey.jersey-test-framework:jersey-test-framework-grizzly:1.17',
-
-        // Others
-        freemarker: 'org.freemarker:freemarker:2.3.26-incubating',
+ext.jeresy_version = "2.25";
+ext.libraries = [
+        // Dropwizard:
+        dropwizard: "io.dropwizard:dropwizard-core:$dropwizard_version",
+        dropwizard_client: "io.dropwizard:dropwizard-client:$dropwizard_version",
+        dropwizard_views: "io.dropwizard:dropwizard-views:$dropwizard_version",
+        dropwizard_views_freemarker: "io.dropwizard:dropwizard-views-freemarker:$dropwizard_version",
+        dropwizard_assets: "io.dropwizard:dropwizard-assets:$dropwizard_version",
+
+        // App. specific:
+        freemarker: "org.freemarker:freemarker:2.3.26-incubating",
+        jersey_core: "org.glassfish.jersey.core:jersey-core:$jeresy_version",
         jackson_databind: "com.fasterxml.jackson.core:jackson-databind:$jackson_version",
-        commonLangs: "org.apache.commons:commons-lang3:3.3.2",
-        findBugs: "com.google.code.findbugs:annotations:3.0.0"
 
+        // Commons:
+        findBugs: "com.google.code.findbugs:annotations:3.0.0",
+        commonLangs: "org.apache.commons:commons-lang3:3.3.2",
+        guava: "com.google.guava:guava:13.0.1",
+
+        // Test:
+        dropwizard_testing: "io.dropwizard:dropwizard-testing:$dropwizard_version",
+        dropwizard_client: "io.dropwizard:dropwizard-client:$dropwizard_version",
+        junit: "junit:junit-dep:4.11",
+        mockito: "org.mockito:mockito-core:1.9.0",
+        hamcrest: "org.hamcrest:hamcrest-library:1.3",
+        jersey_grrizle: "org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:$jeresy_version"
 ]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/dropwizard/FreeMarkerOnlineTester.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/dropwizard/FreeMarkerOnlineTester.java b/src/main/java/org/apache/freemarker/onlinetester/dropwizard/FreeMarkerOnlineTester.java
index 3c48efd..529a2da 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/dropwizard/FreeMarkerOnlineTester.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/dropwizard/FreeMarkerOnlineTester.java
@@ -1,19 +1,16 @@
 package org.apache.freemarker.onlinetester.dropwizard;
 
 
-import com.codahale.metrics.health.HealthCheck;
+import org.apache.freemarker.onlinetester.healthchecks.FreeMarkerOnlineTesterOverallHealthCheck;
+import org.apache.freemarker.onlinetester.resources.ExecuteApiResource;
+import org.apache.freemarker.onlinetester.resources.WebPageResource;
+import org.apache.freemarker.onlinetester.services.FreeMarkerService;
 
 import io.dropwizard.Application;
 import io.dropwizard.assets.AssetsBundle;
 import io.dropwizard.setup.Bootstrap;
 import io.dropwizard.setup.Environment;
 import io.dropwizard.views.ViewBundle;
-import org.apache.freemarker.onlinetester.spring.SpringConfiguration;
-import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
-
-
-import javax.ws.rs.Path;
-import java.util.Map;
 
 public class FreeMarkerOnlineTester extends Application<FreeMarkerOnlineTesterConfiguration> {
 
@@ -28,31 +25,15 @@ public class FreeMarkerOnlineTester extends Application<FreeMarkerOnlineTesterCo
 
     @Override
     public void run(FreeMarkerOnlineTesterConfiguration configuration, Environment environment) throws Exception {
-        AnnotationConfigWebApplicationContext context = initializeSpringContext();
-
-
-        Map<String, Object> resources = context.getBeansWithAnnotation(Path.class);
-        for(Map.Entry<String,Object> entry : resources.entrySet()) {
-            environment.jersey().register(entry.getValue());
-        }
-
-        Map<String, HealthCheck> healthChecks = context.getBeansOfType(HealthCheck.class);
-        for(Map.Entry<String,HealthCheck> entry : healthChecks.entrySet()) {
-            environment.healthChecks().register("", entry.getValue());
-        }
-    }
-
-    private AnnotationConfigWebApplicationContext initializeSpringContext() {
-        AnnotationConfigWebApplicationContext springContext = new AnnotationConfigWebApplicationContext();
-        springContext.register(SpringConfiguration.class);
-        springContext.refresh();
-        springContext.start();
-        return springContext;
+        FreeMarkerService service = new FreeMarkerService.Builder().build();
+        environment.jersey().register(new ExecuteApiResource(service));
+        environment.jersey().register(new WebPageResource());
+        environment.healthChecks().register("overall", new FreeMarkerOnlineTesterOverallHealthCheck());
     }
 
     @Override
     public void initialize(Bootstrap<FreeMarkerOnlineTesterConfiguration> bootstrap) {
-        bootstrap.addBundle(new ViewBundle());
+        bootstrap.addBundle(new ViewBundle<>());
         bootstrap.addBundle(new AssetsBundle());
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/healthchecks/FreeMarkerOnlineTesterOverallHealthCheck.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/healthchecks/FreeMarkerOnlineTesterOverallHealthCheck.java b/src/main/java/org/apache/freemarker/onlinetester/healthchecks/FreeMarkerOnlineTesterOverallHealthCheck.java
new file mode 100644
index 0000000..cf0ab8e
--- /dev/null
+++ b/src/main/java/org/apache/freemarker/onlinetester/healthchecks/FreeMarkerOnlineTesterOverallHealthCheck.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.onlinetester.healthchecks;
+
+import com.codahale.metrics.health.HealthCheck;
+
+public class FreeMarkerOnlineTesterOverallHealthCheck extends HealthCheck {
+
+    @Override
+    protected Result check() throws Exception {
+        return Result.healthy(); // we're always healthy!
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/healthchecks/MyProjectHealthCheck.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/healthchecks/MyProjectHealthCheck.java b/src/main/java/org/apache/freemarker/onlinetester/healthchecks/MyProjectHealthCheck.java
deleted file mode 100644
index 6322100..0000000
--- a/src/main/java/org/apache/freemarker/onlinetester/healthchecks/MyProjectHealthCheck.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.healthchecks;
-
-import com.codahale.metrics.health.HealthCheck;
-import org.springframework.stereotype.Component;
-
-@Component
-public class MyProjectHealthCheck extends HealthCheck {
-
-    @Override
-    protected Result check() throws Exception {
-        return Result.healthy(); // we're always healthy!
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java
new file mode 100644
index 0000000..3303e13
--- /dev/null
+++ b/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.onlinetester.resources;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.RejectedExecutionException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.freemarker.onlinetester.model.ErrorCode;
+import org.apache.freemarker.onlinetester.model.ErrorResponse;
+import org.apache.freemarker.onlinetester.model.ExecuteRequest;
+import org.apache.freemarker.onlinetester.model.ExecuteResourceField;
+import org.apache.freemarker.onlinetester.model.ExecuteResourceProblem;
+import org.apache.freemarker.onlinetester.model.ExecuteResponse;
+import org.apache.freemarker.onlinetester.services.AllowedSettingValuesMaps;
+import org.apache.freemarker.onlinetester.services.FreeMarkerService;
+import org.apache.freemarker.onlinetester.services.FreeMarkerServiceResponse;
+import org.apache.freemarker.onlinetester.util.DataModelParser;
+import org.apache.freemarker.onlinetester.util.DataModelParsingException;
+import org.apache.freemarker.onlinetester.util.ExceptionUtils;
+
+import freemarker.core.OutputFormat;
+
+@Path("/api/execute")
+public class ExecuteApiResource {
+    private static final int MAX_TEMPLATE_INPUT_LENGTH = 10000;
+
+    private static final int MAX_DATA_MODEL_INPUT_LENGTH = 10000;
+
+    private static final String MAX_TEMPLATE_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE
+            = "The template length has exceeded the {0} character limit set for this service.";
+
+    private static final String MAX_DATA_MODEL_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE
+            = "The data model length has exceeded the {0} character limit set for this service.";
+
+    private static final String UNKNOWN_OUTPUT_FORMAT_ERROR_MESSAGE = "Unknown output format: {0}";
+    private static final String UNKNOWN_LOCALE_ERROR_MESSAGE = "Unknown locale: {0}";
+    private static final String UNKNOWN_TIME_ZONE_ERROR_MESSAGE = "Unknown time zone: {0}";
+
+    private static final String SERVICE_OVERBURDEN_ERROR_MESSAGE
+            = "Sorry, the service is overburden and couldn't handle your request now. Try again later.";
+
+    static final String DATA_MODEL_ERROR_MESSAGE_HEADING = "Failed to parse data model:";
+    static final String DATA_MODEL_ERROR_MESSAGE_FOOTER = "Note: This is NOT a FreeMarker error message. "
+            + "The data model syntax is specific to this online service.";
+
+    private final FreeMarkerService freeMarkerService;
+
+    public ExecuteApiResource(FreeMarkerService freeMarkerService) {
+        this.freeMarkerService = freeMarkerService;
+    }
+
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response formResult(
+            ExecuteRequest req) {
+        ExecuteResponse resp = new ExecuteResponse();
+        
+        if (StringUtils.isBlank(req.getTemplate()) && StringUtils.isBlank(req.getDataModel())) {
+            return Response.status(400).entity("Empty Template & data").build();
+        }
+
+        List<ExecuteResourceProblem> problems = new ArrayList<ExecuteResourceProblem>();
+        
+        String template = getTemplate(req, problems);
+        Map<String, Object> dataModel = getDataModel(req, problems);
+        OutputFormat outputFormat = getOutputFormat(req, problems);
+        Locale locale = getLocale(req, problems);
+        TimeZone timeZone = getTimeZone(req, problems);
+        
+        if (!problems.isEmpty()) {
+            resp.setProblems(problems);
+            return buildFreeMarkerResponse(resp);
+        }
+        
+        FreeMarkerServiceResponse freeMarkerServiceResponse;
+        try {
+            freeMarkerServiceResponse = freeMarkerService.calculateTemplateOutput(
+                    template, dataModel,
+                    outputFormat, locale, timeZone);
+        } catch (RejectedExecutionException e) {
+            String error = SERVICE_OVERBURDEN_ERROR_MESSAGE;
+            return Response.serverError().entity(new ErrorResponse(ErrorCode.FREEMARKER_SERVICE_TIMEOUT, error)).build();
+        }
+        if (!freeMarkerServiceResponse.isSuccesful()){
+            Throwable failureReason = freeMarkerServiceResponse.getFailureReason();
+            String error = ExceptionUtils.getMessageWithCauses(failureReason);
+            problems.add(new ExecuteResourceProblem(ExecuteResourceField.TEMPLATE, error));
+            resp.setProblems(problems);
+            return buildFreeMarkerResponse(resp);
+        }
+
+        String result = freeMarkerServiceResponse.getTemplateOutput();
+        resp.setResult(result);
+        resp.setTruncatedResult(freeMarkerServiceResponse.isTemplateOutputTruncated());
+        return buildFreeMarkerResponse(resp);
+    }
+
+    private String getTemplate(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+        String template = req.getTemplate();
+        
+        if (template.length() > MAX_TEMPLATE_INPUT_LENGTH) {
+            String error = formatMessage(MAX_TEMPLATE_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE, MAX_TEMPLATE_INPUT_LENGTH);
+            problems.add(new ExecuteResourceProblem(ExecuteResourceField.TEMPLATE, error));
+            return null;
+        }
+        
+        return template;
+    }
+
+    private Map<String, Object> getDataModel(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+        String dataModel = req.getDataModel();
+
+        if (dataModel.length() > MAX_DATA_MODEL_INPUT_LENGTH) {
+            String error = formatMessage(
+                    MAX_DATA_MODEL_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE, MAX_DATA_MODEL_INPUT_LENGTH);
+            problems.add(new ExecuteResourceProblem(ExecuteResourceField.DATA_MODEL, error));
+            return null;
+        }
+        
+        try {
+            return DataModelParser.parse(dataModel, freeMarkerService.getFreeMarkerTimeZone());
+        } catch (DataModelParsingException e) {
+            problems.add(new ExecuteResourceProblem(ExecuteResourceField.DATA_MODEL, decorateResultText(e.getMessage())));
+            return null;
+        }
+    }
+
+    private OutputFormat getOutputFormat(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+        String outputFormatStr = req.getOutputFormat();
+        
+        if (StringUtils.isBlank(outputFormatStr)) {
+            return AllowedSettingValuesMaps.DEFAULT_OUTPUT_FORMAT;
+        }
+    
+        OutputFormat outputFormat = AllowedSettingValuesMaps.OUTPUT_FORMAT_MAP.get(outputFormatStr);
+        if (outputFormat == null) {
+            problems.add(new ExecuteResourceProblem(
+                    ExecuteResourceField.OUTPUT_FORMAT,
+                    formatMessage(UNKNOWN_OUTPUT_FORMAT_ERROR_MESSAGE, outputFormatStr)));
+        }
+        return outputFormat;
+    }
+
+    private Locale getLocale(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+        String localeStr = req.getLocale();
+        
+        if (StringUtils.isBlank(localeStr)) {
+            return AllowedSettingValuesMaps.DEFAULT_LOCALE;
+        }
+        
+        Locale locale = AllowedSettingValuesMaps.LOCALE_MAP.get(localeStr);
+        if (locale == null) {
+            problems.add(new ExecuteResourceProblem(
+                    ExecuteResourceField.LOCALE,
+                    formatMessage(UNKNOWN_LOCALE_ERROR_MESSAGE, localeStr)));
+        }
+        return locale;
+    }
+
+    private TimeZone getTimeZone(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+        String timeZoneStr = req.getTimeZone();
+        
+        if (StringUtils.isBlank(timeZoneStr)) {
+            return AllowedSettingValuesMaps.DEFAULT_TIME_ZONE;
+        }
+        
+        TimeZone timeZone = AllowedSettingValuesMaps.TIME_ZONE_MAP.get(timeZoneStr);
+        if (timeZone == null) {
+            problems.add(new ExecuteResourceProblem(
+                    ExecuteResourceField.TIME_ZONE,
+                    formatMessage(UNKNOWN_TIME_ZONE_ERROR_MESSAGE, timeZoneStr)));
+        }
+        return timeZone;
+    }
+
+    private Response buildFreeMarkerResponse(ExecuteResponse executeResponse){
+        return Response.ok().entity(executeResponse).build();
+    }
+    
+    private String decorateResultText(String resultText) {
+        return DATA_MODEL_ERROR_MESSAGE_HEADING + "\n\n" + resultText + "\n\n" + DATA_MODEL_ERROR_MESSAGE_FOOTER;
+    }
+    
+    private String formatMessage(String key, Object... params) {
+        return new MessageFormat(key, Locale.US).format(params);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResource.java
deleted file mode 100644
index c850720..0000000
--- a/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResource.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.resources;
-
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.concurrent.RejectedExecutionException;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.freemarker.onlinetester.model.ErrorCode;
-import org.apache.freemarker.onlinetester.model.ExecuteResourceProblem;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import org.apache.freemarker.onlinetester.model.ErrorResponse;
-import org.apache.freemarker.onlinetester.model.ExecuteRequest;
-import org.apache.freemarker.onlinetester.model.ExecuteResourceField;
-import org.apache.freemarker.onlinetester.model.ExecuteResponse;
-import org.apache.freemarker.onlinetester.services.AllowedSettingValuesMaps;
-import org.apache.freemarker.onlinetester.services.FreeMarkerService;
-import org.apache.freemarker.onlinetester.services.FreeMarkerServiceResponse;
-import org.apache.freemarker.onlinetester.util.DataModelParser;
-import org.apache.freemarker.onlinetester.util.DataModelParsingException;
-import org.apache.freemarker.onlinetester.util.ExceptionUtils;
-
-import freemarker.core.OutputFormat;
-
-@Path("/api/execute")
-@Component
-public class FreeMarkerOnlineExecuteResource {
-    private static final int MAX_TEMPLATE_INPUT_LENGTH = 10000;
-
-    private static final int MAX_DATA_MODEL_INPUT_LENGTH = 10000;
-
-    private static final String MAX_TEMPLATE_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE
-            = "The template length has exceeded the {0} character limit set for this service.";
-
-    private static final String MAX_DATA_MODEL_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE
-            = "The data model length has exceeded the {0} character limit set for this service.";
-
-    private static final String UNKNOWN_OUTPUT_FORMAT_ERROR_MESSAGE = "Unknown output format: {0}";
-    private static final String UNKNOWN_LOCALE_ERROR_MESSAGE = "Unknown locale: {0}";
-    private static final String UNKNOWN_TIME_ZONE_ERROR_MESSAGE = "Unknown time zone: {0}";
-
-    private static final String SERVICE_OVERBURDEN_ERROR_MESSAGE
-            = "Sorry, the service is overburden and couldn't handle your request now. Try again later.";
-
-    static final String DATA_MODEL_ERROR_MESSAGE_HEADING = "Failed to parse data model:";
-    static final String DATA_MODEL_ERROR_MESSAGE_FOOTER = "Note: This is NOT a FreeMarker error message. "
-            + "The data model syntax is specific to this online service.";
-
-    @Autowired
-    private FreeMarkerService freeMarkerService;
-
-    @POST
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response formResult(
-            ExecuteRequest req) {
-        ExecuteResponse resp = new ExecuteResponse();
-        
-        if (StringUtils.isBlank(req.getTemplate()) && StringUtils.isBlank(req.getDataModel())) {
-            return Response.status(400).entity("Empty Template & data").build();
-        }
-
-        List<ExecuteResourceProblem> problems = new ArrayList<ExecuteResourceProblem>();
-        
-        String template = getTemplate(req, problems);
-        Map<String, Object> dataModel = getDataModel(req, problems);
-        OutputFormat outputFormat = getOutputFormat(req, problems);
-        Locale locale = getLocale(req, problems);
-        TimeZone timeZone = getTimeZone(req, problems);
-        
-        if (!problems.isEmpty()) {
-            resp.setProblems(problems);
-            return buildFreeMarkerResponse(resp);
-        }
-        
-        FreeMarkerServiceResponse freeMarkerServiceResponse;
-        try {
-            freeMarkerServiceResponse = freeMarkerService.calculateTemplateOutput(
-                    template, dataModel,
-                    outputFormat, locale, timeZone);
-        } catch (RejectedExecutionException e) {
-            String error = SERVICE_OVERBURDEN_ERROR_MESSAGE;
-            return Response.serverError().entity(new ErrorResponse(ErrorCode.FREEMARKER_SERVICE_TIMEOUT, error)).build();
-        }
-        if (!freeMarkerServiceResponse.isSuccesful()){
-            Throwable failureReason = freeMarkerServiceResponse.getFailureReason();
-            String error = ExceptionUtils.getMessageWithCauses(failureReason);
-            problems.add(new ExecuteResourceProblem(ExecuteResourceField.TEMPLATE, error));
-            resp.setProblems(problems);
-            return buildFreeMarkerResponse(resp);
-        }
-
-        String result = freeMarkerServiceResponse.getTemplateOutput();
-        resp.setResult(result);
-        resp.setTruncatedResult(freeMarkerServiceResponse.isTemplateOutputTruncated());
-        return buildFreeMarkerResponse(resp);
-    }
-
-    private String getTemplate(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
-        String template = req.getTemplate();
-        
-        if (template.length() > MAX_TEMPLATE_INPUT_LENGTH) {
-            String error = formatMessage(MAX_TEMPLATE_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE, MAX_TEMPLATE_INPUT_LENGTH);
-            problems.add(new ExecuteResourceProblem(ExecuteResourceField.TEMPLATE, error));
-            return null;
-        }
-        
-        return template;
-    }
-
-    private Map<String, Object> getDataModel(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
-        String dataModel = req.getDataModel();
-        
-        if (dataModel.length() > MAX_DATA_MODEL_INPUT_LENGTH) {
-            String error = formatMessage(
-                    MAX_DATA_MODEL_INPUT_LENGTH_EXCEEDED_ERROR_MESSAGE, MAX_DATA_MODEL_INPUT_LENGTH);
-            problems.add(new ExecuteResourceProblem(ExecuteResourceField.DATA_MODEL, error));
-            return null;
-        }
-        
-        try {
-            return DataModelParser.parse(dataModel, freeMarkerService.getFreeMarkerTimeZone());
-        } catch (DataModelParsingException e) {
-            problems.add(new ExecuteResourceProblem(ExecuteResourceField.DATA_MODEL, decorateResultText(e.getMessage())));
-            return null;
-        }
-    }
-
-    private OutputFormat getOutputFormat(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
-        String outputFormatStr = req.getOutputFormat();
-        
-        if (StringUtils.isBlank(outputFormatStr)) {
-            return AllowedSettingValuesMaps.DEFAULT_OUTPUT_FORMAT;
-        }
-    
-        OutputFormat outputFormat = AllowedSettingValuesMaps.OUTPUT_FORMAT_MAP.get(outputFormatStr);
-        if (outputFormat == null) {
-            problems.add(new ExecuteResourceProblem(
-                    ExecuteResourceField.OUTPUT_FORMAT,
-                    formatMessage(UNKNOWN_OUTPUT_FORMAT_ERROR_MESSAGE, outputFormatStr)));
-        }
-        return outputFormat;
-    }
-
-    private Locale getLocale(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
-        String localeStr = req.getLocale();
-        
-        if (StringUtils.isBlank(localeStr)) {
-            return AllowedSettingValuesMaps.DEFAULT_LOCALE;
-        }
-        
-        Locale locale = AllowedSettingValuesMaps.LOCALE_MAP.get(localeStr);
-        if (locale == null) {
-            problems.add(new ExecuteResourceProblem(
-                    ExecuteResourceField.LOCALE,
-                    formatMessage(UNKNOWN_LOCALE_ERROR_MESSAGE, localeStr)));
-        }
-        return locale;
-    }
-
-    private TimeZone getTimeZone(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
-        String timeZoneStr = req.getTimeZone();
-        
-        if (StringUtils.isBlank(timeZoneStr)) {
-            return AllowedSettingValuesMaps.DEFAULT_TIME_ZONE;
-        }
-        
-        TimeZone timeZone = AllowedSettingValuesMaps.TIME_ZONE_MAP.get(timeZoneStr);
-        if (timeZone == null) {
-            problems.add(new ExecuteResourceProblem(
-                    ExecuteResourceField.TIME_ZONE,
-                    formatMessage(UNKNOWN_TIME_ZONE_ERROR_MESSAGE, timeZoneStr)));
-        }
-        return timeZone;
-    }
-
-    private Response buildFreeMarkerResponse(ExecuteResponse executeResponse){
-        return Response.ok().entity(executeResponse).build();
-    }
-    
-    private String decorateResultText(String resultText) {
-        return DATA_MODEL_ERROR_MESSAGE_HEADING + "\n\n" + resultText + "\n\n" + DATA_MODEL_ERROR_MESSAGE_FOOTER;
-    }
-    
-    private String formatMessage(String key, Object... params) {
-        return new MessageFormat(key, Locale.US).format(params);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResource.java
deleted file mode 100644
index ebf82a1..0000000
--- a/src/main/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResource.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.resources;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-import org.springframework.stereotype.Component;
-
-import org.apache.freemarker.onlinetester.view.FreeMarkerOnlineView;
-
-@Path("/")
-@Component
-public class FreeMarkerOnlineResource {
-
-    @GET
-    @Produces(MediaType.TEXT_HTML)
-    public FreeMarkerOnlineView blankForm() {
-        return new FreeMarkerOnlineView();
-    }
-
-    @POST
-    @Produces(MediaType.TEXT_HTML)
-    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    public FreeMarkerOnlineView formResult(
-            @FormParam("template") String template,
-            @FormParam("dataModel") String dataModel,
-            @FormParam("outputFormat") String outputFormat,
-            @FormParam("locale") String locale,
-            @FormParam("timeZone") String timeZone) {
-        FreeMarkerOnlineView view = new FreeMarkerOnlineView();
-        view.setTemplate(template);
-        view.setDataModel(dataModel);
-        view.setOutputFormat(outputFormat);
-        view.setLocale(locale);
-        view.setTimeZone(timeZone);
-        view.setExecute(true);
-        return view;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/resources/TestResource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/TestResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/TestResource.java
deleted file mode 100644
index df790bf..0000000
--- a/src/main/java/org/apache/freemarker/onlinetester/resources/TestResource.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.apache.freemarker.onlinetester.resources;
-
-import org.springframework.stereotype.Component;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/test")
-@Component
-public class TestResource {
-    @GET
-    @Produces(MediaType.TEXT_HTML)
-    public String blankForm() {
-        return "Hello";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java
new file mode 100644
index 0000000..1f7a802
--- /dev/null
+++ b/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.onlinetester.resources;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.freemarker.onlinetester.view.FreeMarkerOnlineView;
+
+/**
+ * The HTML web page shown in the browser.
+ */
+@Path("/")
+public class WebPageResource {
+
+    @GET
+    @Produces(MediaType.TEXT_HTML)
+    public FreeMarkerOnlineView blankForm() {
+        return new FreeMarkerOnlineView();
+    }
+
+    @POST
+    @Produces(MediaType.TEXT_HTML)
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public FreeMarkerOnlineView formResult(
+            @FormParam("template") String template,
+            @FormParam("dataModel") String dataModel,
+            @FormParam("outputFormat") String outputFormat,
+            @FormParam("locale") String locale,
+            @FormParam("timeZone") String timeZone) {
+        FreeMarkerOnlineView view = new FreeMarkerOnlineView();
+        view.setTemplate(template);
+        view.setDataModel(dataModel);
+        view.setOutputFormat(outputFormat);
+        view.setLocale(locale);
+        view.setTimeZone(timeZone);
+        view.setExecute(true);
+        return view;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java b/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java
index 4487abe..c1efce4 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java
@@ -34,16 +34,12 @@ import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import javax.annotation.PostConstruct;
-
 import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.freemarker.onlinetester.util.LengthLimitExceededException;
 import org.apache.freemarker.onlinetester.util.LengthLimitedWriter;
 import org.eclipse.jetty.util.BlockingArrayQueue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import org.apache.freemarker.onlinetester.util.LengthLimitExceededException;
 
 import freemarker.core.FreeMarkerInternalsAccessor;
 import freemarker.core.OutputFormat;
@@ -55,13 +51,11 @@ import freemarker.template.Template;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateExceptionHandler;
 
-@Service
 public class FreeMarkerService {
 
     private static final int DEFAULT_MAX_OUTPUT_LENGTH = 100000;
     private static final int DEFAULT_MAX_THREADS = Math.max(2,
             (int) Math.round(Runtime.getRuntime().availableProcessors() * 3.0 / 4));
-    /** Not implemented yet, will need 2.3.22, even then a _CoreAPI call. */
     private static final long DEFAULT_MAX_TEMPLATE_EXECUTION_TIME = 2000;
     private static final int MIN_DEFAULT_MAX_QUEUE_LENGTH = 2;
     private static final int MAX_DEFAULT_MAX_QUEUE_LENGTH_MILLISECONDS = 30000;
@@ -75,17 +69,32 @@ public class FreeMarkerService {
     
     private static final Logger logger = LoggerFactory.getLogger(FreeMarkerService.class);
 
+    private final int maxOutputLength;
+    private final int maxThreads;
+    private final Integer maxQueueLength;
+    private final long maxTemplateExecutionTime;
+
     private final Configuration freeMarkerConfig;
+    private final ExecutorService templateExecutor;
     
-    private ExecutorService templateExecutor;
-    
-    private int maxOutputLength = DEFAULT_MAX_OUTPUT_LENGTH;
-    
-    private int maxThreads = DEFAULT_MAX_THREADS;
-    private Integer maxQueueLength;
-    private long maxTemplateExecutionTime = DEFAULT_MAX_TEMPLATE_EXECUTION_TIME;
+    private FreeMarkerService(Builder bulder) {
+        maxOutputLength = bulder.getMaxOutputLength();
+        maxThreads = bulder.getMaxThreads();
+        maxQueueLength = bulder.getMaxQueueLength();
+        maxTemplateExecutionTime = bulder.getMaxTemplateExecutionTime();
+
+        int actualMaxQueueLength = maxQueueLength != null
+                ? maxQueueLength
+                : Math.max(
+                        MIN_DEFAULT_MAX_QUEUE_LENGTH,
+                        (int) (MAX_DEFAULT_MAX_QUEUE_LENGTH_MILLISECONDS / maxTemplateExecutionTime));
+        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
+                maxThreads, maxThreads,
+                THREAD_KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS,
+                new BlockingArrayQueue<Runnable>(actualMaxQueueLength));
+        threadPoolExecutor.allowCoreThreadTimeOut(true);
+        templateExecutor = threadPoolExecutor;
 
-    public FreeMarkerService() {
         freeMarkerConfig = new Configuration(Configuration.getVersion());
         freeMarkerConfig.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
         freeMarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
@@ -192,33 +201,17 @@ public class FreeMarkerService {
         return maxOutputLength;
     }
 
-    public void setMaxOutputLength(int maxOutputLength) {
-        this.maxOutputLength = maxOutputLength;
-    }
-
     public int getMaxThreads() {
         return maxThreads;
     }
     
-    public void setMaxThreads(int maxThreads) {
-        this.maxThreads = maxThreads;
-    }
-    
     public int getMaxQueueLength() {
         return maxQueueLength;
     }
     
-    public void setMaxQueueLength(int maxQueueLength) {
-        this.maxQueueLength = maxQueueLength;
-    }
-
     public long getMaxTemplateExecutionTime() {
         return maxTemplateExecutionTime;
     }
-    
-    public void setMaxTemplateExecutionTime(long maxTemplateExecutionTime) {
-        this.maxTemplateExecutionTime = maxTemplateExecutionTime;
-    }
 
     /**
      * Returns the time zone used by the FreeMarker templates.
@@ -232,21 +225,6 @@ public class FreeMarkerService {
         return new FreeMarkerServiceResponse.Builder().buildForFailure(e);
     }
 
-    @PostConstruct
-    public void postConstruct() {
-        int actualMaxQueueLength = maxQueueLength != null
-                ? maxQueueLength
-                : Math.max(
-                        MIN_DEFAULT_MAX_QUEUE_LENGTH,
-                        (int) (MAX_DEFAULT_MAX_QUEUE_LENGTH_MILLISECONDS / maxTemplateExecutionTime));
-        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
-                maxThreads, maxThreads,
-                THREAD_KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS,
-                new BlockingArrayQueue<Runnable>(actualMaxQueueLength));
-        threadPoolExecutor.allowCoreThreadTimeOut(true);
-        templateExecutor = threadPoolExecutor;
-    }
-    
     private class CalculateTemplateOutput implements Callable<FreeMarkerServiceResponse> {
         
         private boolean templateExecutionStarted;
@@ -361,4 +339,47 @@ public class FreeMarkerService {
         
     }
 
+    public static class Builder {
+        private int maxOutputLength = DEFAULT_MAX_OUTPUT_LENGTH;
+        private int maxThreads = DEFAULT_MAX_THREADS;
+        private Integer maxQueueLength;
+        private long maxTemplateExecutionTime = DEFAULT_MAX_TEMPLATE_EXECUTION_TIME;
+
+        public int getMaxOutputLength() {
+            return maxOutputLength;
+        }
+
+        public void setMaxOutputLength(int maxOutputLength) {
+            this.maxOutputLength = maxOutputLength;
+        }
+
+        public int getMaxThreads() {
+            return maxThreads;
+        }
+
+        public void setMaxThreads(int maxThreads) {
+            this.maxThreads = maxThreads;
+        }
+
+        public Integer getMaxQueueLength() {
+            return maxQueueLength;
+        }
+
+        public void setMaxQueueLength(Integer maxQueueLength) {
+            this.maxQueueLength = maxQueueLength;
+        }
+
+        public long getMaxTemplateExecutionTime() {
+            return maxTemplateExecutionTime;
+        }
+
+        public void setMaxTemplateExecutionTime(long maxTemplateExecutionTime) {
+            this.maxTemplateExecutionTime = maxTemplateExecutionTime;
+        }
+
+        public FreeMarkerService build() {
+            return new FreeMarkerService(this);
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/spring/SpringConfiguration.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/spring/SpringConfiguration.java b/src/main/java/org/apache/freemarker/onlinetester/spring/SpringConfiguration.java
deleted file mode 100644
index a4fe003..0000000
--- a/src/main/java/org/apache/freemarker/onlinetester/spring/SpringConfiguration.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.apache.freemarker.onlinetester.spring;
-
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@ComponentScan(basePackages = {"org.apache.freemarker.onlinetester"})
-public class SpringConfiguration {}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/java/org/apache/freemarker/onlinetester/util/DataModelParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/onlinetester/util/DataModelParser.java b/src/main/java/org/apache/freemarker/onlinetester/util/DataModelParser.java
index b356be6..4f203db 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/util/DataModelParser.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/util/DataModelParser.java
@@ -34,7 +34,7 @@ import java.util.regex.Pattern;
 
 import javax.xml.parsers.DocumentBuilder;
 
-import org.springframework.util.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.w3c.dom.Document;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.InputSource;
@@ -85,7 +85,7 @@ public final class DataModelParser {
     }
 
     public static Map<String, Object> parse(String src, TimeZone timeZone) throws DataModelParsingException {
-        if (!StringUtils.hasText(src)) {
+        if (StringUtils.isBlank(src)) {
             return Collections.emptyMap();
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/resources/freemarker-online.yml
----------------------------------------------------------------------
diff --git a/src/main/resources/freemarker-online.yml b/src/main/resources/freemarker-online.yml
index f7606d0..eac938b 100644
--- a/src/main/resources/freemarker-online.yml
+++ b/src/main/resources/freemarker-online.yml
@@ -33,6 +33,4 @@ logging:
 #      logFormat:
 server:
   requestLog:
-    appenders:
-      - type: console
-        threshold: OFF
\ No newline at end of file
+    appenders: []

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/main/resources/spring/bootstrap-context.xml
----------------------------------------------------------------------
diff --git a/src/main/resources/spring/bootstrap-context.xml b/src/main/resources/spring/bootstrap-context.xml
deleted file mode 100644
index 8d8e518..0000000
--- a/src/main/resources/spring/bootstrap-context.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-   Licensed to the Apache Software Foundation (ASF) under one
-   or more contributor license agreements.  See the NOTICE file
-   distributed with this work for additional information
-   regarding copyright ownership.  The ASF licenses this file
-   to you under the Apache License, Version 2.0 (the
-   "License"); you may not use this file except in compliance
-   with the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing,
-   software distributed under the License is distributed on an
-   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-   KIND, either express or implied.  See the License for the
-   specific language governing permissions and limitations
-   under the License.
--->
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:context="http://www.springframework.org/schema/context"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd ">
-
-    <context:component-scan base-package="org.apache.freemarker.onlinetester"/>
-
-    <context:annotation-config/>
-
-    <!-- Use the system properties (initalized by DW) to configure spring context files -->
-    <bean id="propertyPlaceholderConfigurer"
-          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-        <property name="ignoreUnresolvablePlaceholders" value="true"/>
-        <property name="ignoreResourceNotFound" value="true"/>
-    </bean>
-
-</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java b/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java
new file mode 100644
index 0000000..a422016
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.onlinetester;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.freemarker.onlinetester.dropwizard.FreeMarkerOnlineTester;
+import org.apache.freemarker.onlinetester.dropwizard.FreeMarkerOnlineTesterConfiguration;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+import io.dropwizard.testing.junit.DropwizardAppRule;
+
+public class ApplicationStartsTest {
+
+    @ClassRule
+    public final static DropwizardAppRule RULE = new DropwizardAppRule<FreeMarkerOnlineTesterConfiguration>
+            (FreeMarkerOnlineTester.class,
+            Resources.getResource("freemarker-online.yml").getPath());
+
+
+    @Test
+    public void test() throws Exception {
+        assertEquals(
+                200,
+                RULE.client().target("http://localhost:" + RULE.getLocalPort() + "/").request().get().getStatus());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/platform/DropWizardServiceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/platform/DropWizardServiceTest.java b/src/test/java/org/apache/freemarker/onlinetester/platform/DropWizardServiceTest.java
deleted file mode 100644
index c467a04..0000000
--- a/src/test/java/org/apache/freemarker/onlinetester/platform/DropWizardServiceTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.platform;
-
-import com.google.common.io.Resources;
-import io.dropwizard.testing.junit.DropwizardAppRule;
-
-import org.apache.freemarker.onlinetester.dropwizard.FreeMarkerOnlineTester;
-import org.apache.freemarker.onlinetester.dropwizard.FreeMarkerOnlineTesterConfiguration;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-
-public class DropWizardServiceTest {
-    @ClassRule
-    public static TestRule testRule = new DropwizardAppRule<FreeMarkerOnlineTesterConfiguration>(FreeMarkerOnlineTester.class,
-            Resources.getResource("freemarker-online.yml").getPath());
-
-
-    @Test
-    public void testServerIsUp() throws Exception {
-        ((DropwizardAppRule) testRule).getApplication();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/platform/YamlPropertiesPersister.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/platform/YamlPropertiesPersister.java b/src/test/java/org/apache/freemarker/onlinetester/platform/YamlPropertiesPersister.java
deleted file mode 100644
index 4257e40..0000000
--- a/src/test/java/org/apache/freemarker/onlinetester/platform/YamlPropertiesPersister.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.platform;
-
-import com.fasterxml.jackson.dataformat.yaml.snakeyaml.Yaml;
-import org.springframework.util.PropertiesPersister;
-import org.springframework.util.StringUtils;
-
-import java.io.*;
-import java.util.Map;
-import java.util.Properties;
-
-public class YamlPropertiesPersister implements PropertiesPersister {
-    @Override
-    public void load(Properties props, InputStream is) throws IOException {
-        load(props, new InputStreamReader(is));
-    }
-
-    /**
-     * We want to traverse map representing Yaml object and each time we find String=String pair we want to
-     * save it as Property. As we are going deeper into map we generate compound key as path-like String
-     *
-     * @see org.springframework.util.PropertiesPersister#load(java.util.Properties, java.io.Reader)
-     */
-    @Override
-    public void load(Properties props, Reader reader) throws IOException {
-        Yaml yaml = new Yaml();
-        @SuppressWarnings("unchecked")
-        Map<String, Object> map = (Map<String, Object>) yaml.load(reader);
-        // now we can populate supplied props
-        assignProperties(props, map, null);
-    }
-
-    @SuppressWarnings("unchecked")
-    public void assignProperties(Properties props, Map<String, Object> map, String path) {
-        for (Map.Entry<String, Object> entry : map.entrySet()) {
-            String key = entry.getKey();
-            if (!StringUtils.isEmpty(path))
-                key = path + "." + key;
-            Object val = entry.getValue();
-            if (val instanceof String) {
-                // see if we need to create a compound key
-                props.put(key, val);
-            } else if (val instanceof Map) {
-                assignProperties(props, (Map<String, Object>) val, key);
-            }
-        }
-    }
-
-    @Override
-    public void store(Properties props, OutputStream os, String header) throws IOException {
-        throw new IllegalStateException("Current implementation is a read-only");
-    }
-
-    @Override
-    public void store(Properties props, Writer writer, String header) throws IOException {
-        throw new IllegalStateException("Current implementation is a read-only");
-    }
-
-    @Override
-    public void loadFromXml(Properties props, InputStream is) throws IOException {
-        throw new IllegalStateException("Use DefaultPropertiesPersister if you want to read/write XML");
-    }
-
-    @Override
-    public void storeToXml(Properties props, OutputStream os, String header) throws IOException {
-        throw new IllegalStateException("Use DefaultPropertiesPersister if you want to load/store to XML");
-    }
-
-    @Override
-    public void storeToXml(Properties props, OutputStream os, String header, String encoding) throws IOException {
-        throw new IllegalStateException("Use DefaultPropertiesPersister if you want to read/write XML");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java
new file mode 100644
index 0000000..7fa3fb4
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.onlinetester.resources;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Response;
+
+import org.apache.freemarker.onlinetester.model.ExecuteRequest;
+import org.apache.freemarker.onlinetester.model.ExecuteResourceField;
+import org.apache.freemarker.onlinetester.model.ExecuteResourceProblem;
+import org.apache.freemarker.onlinetester.model.ExecuteResponse;
+import org.junit.Test;
+
+public class ExecuteApiResourceTest extends ResourceTest {
+    private static final String DATA_MODEL = "user=John";
+    private static final String TEMPLATE_WITH_VARIABLE = "Welcome ${user}";
+    private static final String TEMPLATE_PLAIN = "Welcome John";
+    private static final String MALFORMED_DATA_MODEL = "userJohn";
+
+    @Test
+    public void testSuccessRequest() throws Exception {
+        ExecuteRequest req = new ExecuteRequest(TEMPLATE_WITH_VARIABLE, DATA_MODEL);
+        Response resp = postJSON(req);
+        assertEquals(200, resp.getStatus());
+        ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
+        assertNull(response.getProblems());
+    }
+
+    @Test
+    public void testMalformedDataModel() throws Exception {
+        ExecuteRequest req = new ExecuteRequest(TEMPLATE_PLAIN, MALFORMED_DATA_MODEL);
+        Response resp = postJSON(req);
+        assertEquals(200, resp.getStatus());
+        ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
+        assertNotNull(response.getProblems());
+        assertTrue(containsProblem(response, ExecuteResourceField.DATA_MODEL));
+    }
+
+    @Test
+    public void testLongDataModel() throws Exception {
+        ExecuteRequest req = new ExecuteRequest(TEMPLATE_PLAIN, create30KString());
+        Response resp = postJSON(req);
+        assertEquals(200, resp.getStatus());
+        ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
+        assertNotNull(response.getProblems());
+        assertTrue(containsProblem(response, ExecuteResourceField.DATA_MODEL));
+        String problemMessage = getProblemMessage(response, ExecuteResourceField.DATA_MODEL);
+        assertThat(problemMessage, containsString("data model"));
+        assertThat(problemMessage, containsString("limit"));
+    }
+
+    @Test
+    public void testLongTemplate() throws Exception {
+        ExecuteRequest req = new ExecuteRequest(create30KString(), DATA_MODEL);
+        Response resp = postJSON(req);
+        assertEquals(200, resp.getStatus());
+        ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
+        assertNotNull(response.getProblems());
+        assertTrue(containsProblem(response, ExecuteResourceField.TEMPLATE));
+        String problemMessage = getProblemMessage(response, ExecuteResourceField.TEMPLATE);
+        assertThat(problemMessage, containsString("template"));
+        assertThat(problemMessage, containsString("limit"));
+    }
+
+    @Test
+    public void testMultipleErrorsDataModel() throws Exception {
+        ExecuteRequest req = new ExecuteRequest(create30KString(), create30KString());
+        req.setOutputFormat("wrongOutputFormat");
+        req.setLocale("wrongLocale");
+        req.setTimeZone("wrongTimeZone");
+
+        Response resp = postJSON(req);
+        
+        assertEquals(200, resp.getStatus());
+        ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
+        assertNotNull(response.getProblems());
+        assertThat(getProblemMessage(response, ExecuteResourceField.TEMPLATE), containsString("limit"));
+        assertThat(getProblemMessage(response, ExecuteResourceField.DATA_MODEL), containsString("limit"));
+        assertThat(getProblemMessage(response, ExecuteResourceField.OUTPUT_FORMAT), containsString("wrongOutputFormat"));
+        assertThat(getProblemMessage(response, ExecuteResourceField.LOCALE), containsString("wrongLocale"));
+        assertThat(getProblemMessage(response, ExecuteResourceField.TIME_ZONE), containsString("wrongTimeZone"));
+    }
+    
+    private String create30KString() {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 30000 / 10; i++) {
+            sb.append("0123456789");
+        }
+        return sb.toString();
+    }
+
+    private boolean containsProblem(ExecuteResponse response, ExecuteResourceField field) {
+        for (ExecuteResourceProblem problem : response.getProblems()) {
+            if (problem.getField() == field) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String getProblemMessage(ExecuteResponse response, ExecuteResourceField field) {
+        for (ExecuteResourceProblem problem : response.getProblems()) {
+            if (problem.getField() == field) {
+                return problem.getMessage();
+            }
+        }
+        return null;
+    }
+
+    protected Response postJSON(ExecuteRequest req) {
+        return RULE.target("/api/execute").request().post(Entity.json(req));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResourceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResourceTest.java
deleted file mode 100644
index d0f81cb..0000000
--- a/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineExecuteResourceTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.resources;
-
-import static org.hamcrest.Matchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.freemarker.onlinetester.model.ExecuteRequest;
-import org.apache.freemarker.onlinetester.model.ExecuteResourceField;
-import org.apache.freemarker.onlinetester.model.ExecuteResourceProblem;
-import org.apache.freemarker.onlinetester.model.ExecuteResponse;
-import org.junit.Test;
-import org.springframework.web.context.ContextLoaderListener;
-import org.springframework.web.context.request.RequestContextListener;
-
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
-import com.sun.jersey.test.framework.AppDescriptor;
-import com.sun.jersey.test.framework.JerseyTest;
-import com.sun.jersey.test.framework.WebAppDescriptor;
-
-public class FreeMarkerOnlineExecuteResourceTest extends JerseyTest {
-    private static final String DATA_MODEL = "user=John";
-    private static final String TEMPLATE_WITH_VARIABLE = "Welcome ${user}";
-    private static final String TEMPLATE_PLAIN = "Welcome John";
-    private static final String MALFORMED_DATA_MODEL = "userJohn";
-    private static final String EXECUTE_API = "api/execute";
-    @Override
-    protected AppDescriptor configure() {
-        return new WebAppDescriptor.Builder("org.apache.freemarker.onlinetester.resources")
-                        .contextPath("/")
-                        .contextListenerClass(ContextLoaderListener.class)
-                        .contextParam("contextConfigLocation", "classpath:spring/bootstrap-context.xml")
-                        .servletClass(SpringServlet.class)
-                        .requestListenerClass(RequestContextListener.class)
-                        .build();
-    }
-
-    @Test
-    public void testSuccessRequest() throws Exception {
-        ExecuteRequest req = new ExecuteRequest(TEMPLATE_WITH_VARIABLE, DATA_MODEL);
-        ClientResponse resp = client().resource(getBaseURI().toString() + EXECUTE_API)
-                .header("Content-Type", "application/json").entity(req).post(ClientResponse.class);
-        assertEquals(200, resp.getStatus());
-        ExecuteResponse response = resp.getEntity(ExecuteResponse.class);
-        assertNull(response.getProblems());
-    }
-
-    @Test
-    public void testMalformedDataModel() throws Exception {
-        ExecuteRequest req = new ExecuteRequest(TEMPLATE_PLAIN, MALFORMED_DATA_MODEL);
-        ClientResponse resp = client().resource(getBaseURI().toString() + EXECUTE_API)
-                .header("Content-Type", "application/json").entity(req).post(ClientResponse.class);
-        assertEquals(200, resp.getStatus());
-        ExecuteResponse response = resp.getEntity(ExecuteResponse.class);
-        assertNotNull(response.getProblems());
-        assertTrue(containsProblem(response, ExecuteResourceField.DATA_MODEL));
-    }
-
-    @Test
-    public void testLongDataModel() throws Exception {
-        ExecuteRequest req = new ExecuteRequest(TEMPLATE_PLAIN, create30KString());
-        ClientResponse resp = client().resource(getBaseURI().toString() + EXECUTE_API)
-                .header("Content-Type", "application/json").entity(req).post(ClientResponse.class);
-        assertEquals(200, resp.getStatus());
-        ExecuteResponse response = resp.getEntity(ExecuteResponse.class);
-        assertNotNull(response.getProblems());
-        assertTrue(containsProblem(response, ExecuteResourceField.DATA_MODEL));
-        String problemMessage = getProblemMessage(response, ExecuteResourceField.DATA_MODEL);
-        assertThat(problemMessage, containsString("data model"));
-        assertThat(problemMessage, containsString("limit"));
-    }
-
-    @Test
-    public void testLongTemplate() throws Exception {
-        ExecuteRequest req = new ExecuteRequest(create30KString(), DATA_MODEL);
-        ClientResponse resp = client().resource(getBaseURI().toString() + EXECUTE_API)
-                .header("Content-Type", "application/json").entity(req).post(ClientResponse.class);
-        assertEquals(200, resp.getStatus());
-        ExecuteResponse response = resp.getEntity(ExecuteResponse.class);
-        assertNotNull(response.getProblems());
-        assertTrue(containsProblem(response, ExecuteResourceField.TEMPLATE));
-        String problemMessage = getProblemMessage(response, ExecuteResourceField.TEMPLATE);
-        assertThat(problemMessage, containsString("template"));
-        assertThat(problemMessage, containsString("limit"));
-    }
-
-    @Test
-    public void testMultipleErrorsDataModel() throws Exception {
-        ExecuteRequest req = new ExecuteRequest(create30KString(), create30KString());
-        req.setOutputFormat("wrongOutputFormat");
-        req.setLocale("wrongLocale");
-        req.setTimeZone("wrongTimeZone");
-        
-        ClientResponse resp = client().resource(getBaseURI() + EXECUTE_API)
-                .header("Content-Type", "application/json").entity(req).post(ClientResponse.class);
-        
-        assertEquals(200, resp.getStatus());
-        ExecuteResponse response = resp.getEntity(ExecuteResponse.class);
-        assertNotNull(response.getProblems());
-        assertThat(getProblemMessage(response, ExecuteResourceField.TEMPLATE), containsString("limit"));
-        assertThat(getProblemMessage(response, ExecuteResourceField.DATA_MODEL), containsString("limit"));
-        assertThat(getProblemMessage(response, ExecuteResourceField.OUTPUT_FORMAT), containsString("wrongOutputFormat"));
-        assertThat(getProblemMessage(response, ExecuteResourceField.LOCALE), containsString("wrongLocale"));
-        assertThat(getProblemMessage(response, ExecuteResourceField.TIME_ZONE), containsString("wrongTimeZone"));
-    }
-    
-    private String create30KString() {
-        final String veryLongString;
-        {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < 30000 / 10; i++) {
-                sb.append("0123456789");
-            }
-            veryLongString = sb.toString();
-        }
-        return veryLongString;
-    }
-
-    private boolean containsProblem(ExecuteResponse response, ExecuteResourceField field) {
-        for (ExecuteResourceProblem problem : response.getProblems()) {
-            if (problem.getField() == field) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String getProblemMessage(ExecuteResponse response, ExecuteResourceField field) {
-        for (ExecuteResourceProblem problem : response.getProblems()) {
-            if (problem.getField() == field) {
-                return problem.getMessage();
-            }
-        }
-        return null;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResourceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResourceTest.java
deleted file mode 100644
index 4f6ef7c..0000000
--- a/src/test/java/org/apache/freemarker/onlinetester/resources/FreeMarkerOnlineResourceTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.onlinetester.resources;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyMap;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.when;
-
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import org.apache.freemarker.onlinetester.services.FreeMarkerService;
-import org.apache.freemarker.onlinetester.view.FreeMarkerOnlineView;
-
-import freemarker.core.OutputFormat;
-
-@RunWith(MockitoJUnitRunner.class)
-public class FreeMarkerOnlineResourceTest {
-
-    @InjectMocks
-    FreeMarkerOnlineResource freeMarkerOnlineResultResource;
-
-    @Mock
-    FreeMarkerService freeMarkerService;
-
-    @Test
-    public void testInitialForm() {
-        when(freeMarkerService.calculateTemplateOutput(
-                anyString(), anyMap(), any(OutputFormat.class), any(Locale.class), any(TimeZone.class)))
-                .thenThrow(new AssertionError());
-        FreeMarkerOnlineView view = freeMarkerOnlineResultResource.blankForm();
-        assertEquals(view.getTemplate(), "");
-        assertEquals(view.getDataModel(), "");
-    }
-    
-    @Test
-    public void testPostedBlankForm() {
-        when(freeMarkerService.calculateTemplateOutput(
-                anyString(), anyMap(), any(OutputFormat.class), any(Locale.class), any(TimeZone.class)))
-                .thenThrow(new AssertionError());
-        FreeMarkerOnlineView view = freeMarkerOnlineResultResource.formResult(null, null, null, null, null);
-        assertEquals(view.getTemplate(), "");
-        assertEquals(view.getDataModel(), "");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/resources/ResourceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/ResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/ResourceTest.java
new file mode 100644
index 0000000..4872cbf
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/onlinetester/resources/ResourceTest.java
@@ -0,0 +1,17 @@
+package org.apache.freemarker.onlinetester.resources;
+
+import org.apache.freemarker.onlinetester.services.FreeMarkerService;
+import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
+import org.junit.ClassRule;
+
+import io.dropwizard.testing.junit.ResourceTestRule;
+
+public abstract class ResourceTest {
+
+    @ClassRule
+    public static final ResourceTestRule RULE = ResourceTestRule.builder()
+            .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
+            .addResource(new ExecuteApiResource(new FreeMarkerService.Builder().build()))
+            .build();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker-online-tester/blob/8b699eb5/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java
new file mode 100644
index 0000000..739628f
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.onlinetester.resources;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import org.apache.freemarker.onlinetester.services.FreeMarkerService;
+import org.apache.freemarker.onlinetester.view.FreeMarkerOnlineView;
+
+import freemarker.core.OutputFormat;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebPageResourceTest {
+
+    @InjectMocks
+    WebPageResource webPageResource;
+
+    @Mock
+    FreeMarkerService freeMarkerService;
+
+    @Test
+    public void testInitialForm() {
+        when(freeMarkerService.calculateTemplateOutput(
+                anyString(), anyMap(), any(OutputFormat.class), any(Locale.class), any(TimeZone.class)))
+                .thenThrow(new AssertionError());
+        FreeMarkerOnlineView view = webPageResource.blankForm();
+        assertEquals(view.getTemplate(), "");
+        assertEquals(view.getDataModel(), "");
+    }
+    
+    @Test
+    public void testPostedBlankForm() {
+        when(freeMarkerService.calculateTemplateOutput(
+                anyString(), anyMap(), any(OutputFormat.class), any(Locale.class), any(TimeZone.class)))
+                .thenThrow(new AssertionError());
+        FreeMarkerOnlineView view = webPageResource.formResult(null, null, null, null, null);
+        assertEquals(view.getTemplate(), "");
+        assertEquals(view.getDataModel(), "");
+    }
+    
+}