Added tagSyntax and interpolationSyntax dropdowns. Did cleanup/refactoring of old code along the way.
diff --git a/build.gradle b/build.gradle
index f307eb1..8d9c7d5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -36,6 +36,9 @@
repositories {
mavenCentral()
+ maven {
+ url "https://repository.apache.org/content/repositories/snapshots/"
+ }
}
buildscript {
diff --git a/dependencies.gradle b/dependencies.gradle
index c7fa0d2..33bcf98 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -30,7 +30,7 @@
dropwizard_bundles_redirect: "io.dropwizard-bundles:dropwizard-redirect-bundle:1.0.5",
// App. specific:
- freemarker: "org.freemarker:freemarker:2.3.27-incubating",
+ freemarker: "org.freemarker:freemarker:2.3.28-incubating-SNAPSHOT",
jersey_core: "org.glassfish.jersey.core:jersey-core:$jeresy_version",
jackson_databind: "com.fasterxml.jackson.core:jackson-databind:$jackson_version",
diff --git a/src/main/java/org/apache/freemarker/onlinetester/model/ErrorCode.java b/src/main/java/org/apache/freemarker/onlinetester/model/ErrorCode.java
index c983e87..b766edf 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/model/ErrorCode.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/model/ErrorCode.java
@@ -21,5 +21,4 @@
public enum ErrorCode {
FREEMARKER_SERVICE_TIMEOUT
-
}
diff --git a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteRequest.java b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteRequest.java
index a206131..2552fa4 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteRequest.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteRequest.java
@@ -18,6 +18,8 @@
*/
package org.apache.freemarker.onlinetester.model;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
public class ExecuteRequest {
private String template;
@@ -25,7 +27,45 @@
private String outputFormat;
private String locale;
private String timeZone;
+ private String tagSyntax;
+ private String interpolationSyntax;
+ public static enum Field {
+ DATA_MODEL("dataModel"),
+ TEMPLATE("template"),
+ OUTPUT_FORMAT("outputFormat"),
+ LOCALE("locale"),
+ TIME_ZONE("timeZone"),
+ TAG_SYNTAX("tagSyntax"),
+ INTERPOLATION_SYNTAX("interpolationSyntax");
+
+ private final String fieldName;
+
+ private Field(String filedName) {
+ this.fieldName = filedName;
+ }
+
+ public String toString() {
+ return getFieldName();
+ }
+
+ @JsonValue
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ @JsonCreator
+ public static Field fromEnumString(String val) {
+ for(Field field : values()) {
+ if(field.getFieldName().equals(val)) {
+ return field;
+ }
+ }
+ throw new IllegalArgumentException("Invalid string value passed: " + val);
+ }
+
+ }
+
public ExecuteRequest() {
}
@@ -74,5 +114,21 @@
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
+
+ public String getTagSyntax() {
+ return tagSyntax;
+ }
+
+ public void setTagSyntax(String tagSyntax) {
+ this.tagSyntax = tagSyntax;
+ }
+
+ public String getInterpolationSyntax() {
+ return interpolationSyntax;
+ }
+
+ public void setInterpolationSyntax(String interpolationSyntax) {
+ this.interpolationSyntax = interpolationSyntax;
+ }
}
diff --git a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResourceField.java b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResourceField.java
deleted file mode 100644
index 71ad454..0000000
--- a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResourceField.java
+++ /dev/null
@@ -1,57 +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.model;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonValue;
-
-public enum ExecuteResourceField {
- DATA_MODEL("dataModel"),
- TEMPLATE("template"),
- OUTPUT_FORMAT("outputFormat"),
- LOCALE("locale"),
- TIME_ZONE("timeZone");
-
- private final String fieldName;
-
- private ExecuteResourceField(String filedName) {
- this.fieldName = filedName;
- }
-
- public String toString() {
- return getFieldName();
- }
-
- @JsonValue
- public String getFieldName() {
- return fieldName;
- }
-
- @JsonCreator
- public static ExecuteResourceField fromEnumString(String val) {
- for(ExecuteResourceField field : values()) {
- if(field.getFieldName().equals(val)) {
- return field;
- }
- }
- throw new IllegalArgumentException("Invalid string value passed: " + val);
- }
-
-}
diff --git a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponse.java b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponse.java
index 41c33f1..5876d74 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponse.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponse.java
@@ -23,10 +23,10 @@
public class ExecuteResponse {
private String result;
- private List<ExecuteResourceProblem> problems;
+ private List<ExecuteResponseProblem> problems;
private boolean truncatedResult;
- public ExecuteResponse(String result, List<ExecuteResourceProblem> problems, boolean truncatedResult) {
+ public ExecuteResponse(String result, List<ExecuteResponseProblem> problems, boolean truncatedResult) {
this.result = result;
this.problems = problems;
this.truncatedResult = truncatedResult;
@@ -36,11 +36,11 @@
}
- public List<ExecuteResourceProblem> getProblems() {
+ public List<ExecuteResponseProblem> getProblems() {
return problems;
}
- public void setProblems(List<ExecuteResourceProblem> problems) {
+ public void setProblems(List<ExecuteResponseProblem> problems) {
this.problems = problems;
}
diff --git a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResourceProblem.java b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponseProblem.java
similarity index 81%
rename from src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResourceProblem.java
rename to src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponseProblem.java
index 3c69d43..d7e02f6 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResourceProblem.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/model/ExecuteResponseProblem.java
@@ -19,26 +19,26 @@
package org.apache.freemarker.onlinetester.model;
-public class ExecuteResourceProblem {
+public class ExecuteResponseProblem {
- private ExecuteResourceField field;
+ private ExecuteRequest.Field field;
private String message;
// Needed for JSON unmarshalling
- public ExecuteResourceProblem() {
+ public ExecuteResponseProblem() {
//
}
- public ExecuteResourceProblem(ExecuteResourceField field, String message) {
+ public ExecuteResponseProblem(ExecuteRequest.Field field, String message) {
this.field = field;
this.message = message;
}
- public ExecuteResourceField getField() {
+ public ExecuteRequest.Field getField() {
return field;
}
- public void setField(ExecuteResourceField field) {
+ public void setField(ExecuteRequest.Field field) {
this.field = field;
}
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java
index 3303e13..3607691 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResource.java
@@ -24,7 +24,6 @@
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;
@@ -38,18 +37,22 @@
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.model.ExecuteResponseProblem;
+import org.apache.freemarker.onlinetester.services.AllowedSettingValues;
import org.apache.freemarker.onlinetester.services.FreeMarkerService;
+import org.apache.freemarker.onlinetester.services.FreeMarkerService.ExecuteTemplateArgs;
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;
+import freemarker.template.Configuration;
+import freemarker.template.utility.StringUtil;
+/**
+ * AJAX API for executing the template submitted.
+ */
@Path("/api/execute")
public class ExecuteApiResource {
private static final int MAX_TEMPLATE_INPUT_LENGTH = 10000;
@@ -62,17 +65,16 @@
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
+ private static final String SERVICE_TIMEOUT_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.";
+ public static final int DEFAULT_TAG_SYNTAX = Configuration.ANGLE_BRACKET_TAG_SYNTAX;
+ public static final int DEFAULT_INTERPLOATION_SYNTAX = Configuration.LEGACY_INTERPOLATION_SYNTAX;
+
private final FreeMarkerService freeMarkerService;
public ExecuteApiResource(FreeMarkerService freeMarkerService) {
@@ -80,8 +82,8 @@
}
@POST
- @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
public Response formResult(
ExecuteRequest req) {
ExecuteResponse resp = new ExecuteResponse();
@@ -90,118 +92,98 @@
return Response.status(400).entity("Empty Template & data").build();
}
- List<ExecuteResourceProblem> problems = new ArrayList<ExecuteResourceProblem>();
+ List<ExecuteResponseProblem> problems = new ArrayList<>();
- 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);
+ ExecuteTemplateArgs serviceArgs = new ExecuteTemplateArgs()
+ .templateSourceCode(lengthCheckAndGetTemplate(req, problems))
+ .dataModel(parseDataModel(req, problems))
+ .outputFormat(parseChoiceField(
+ ExecuteRequest.Field.OUTPUT_FORMAT, req.getOutputFormat(),
+ AllowedSettingValues.DEFAULT_OUTPUT_FORMAT, AllowedSettingValues.OUTPUT_FORMAT_MAP,
+ problems))
+ .locale(parseChoiceField(
+ ExecuteRequest.Field.LOCALE, req.getLocale(),
+ AllowedSettingValues.DEFAULT_LOCALE, AllowedSettingValues.LOCALE_MAP,
+ problems))
+ .timeZone(parseChoiceField(
+ ExecuteRequest.Field.TIME_ZONE, req.getTimeZone(),
+ AllowedSettingValues.DEFAULT_TIME_ZONE, AllowedSettingValues.TIME_ZONE_MAP,
+ problems))
+ .tagSyntax(parseChoiceField(
+ ExecuteRequest.Field.TAG_SYNTAX, req.getTagSyntax(),
+ AllowedSettingValues.DEFAULT_TAG_SYNTAX, AllowedSettingValues.TAG_SYNTAX_MAP,
+ problems))
+ .interpolationSyntax(parseChoiceField(
+ ExecuteRequest.Field.INTERPOLATION_SYNTAX, req.getInterpolationSyntax(),
+ AllowedSettingValues.DEFAULT_INTERPOLATION_SYNTAX, AllowedSettingValues.INTERPOLATION_SYNTAX_MAP,
+ problems));
if (!problems.isEmpty()) {
resp.setProblems(problems);
return buildFreeMarkerResponse(resp);
}
- FreeMarkerServiceResponse freeMarkerServiceResponse;
+ FreeMarkerServiceResponse serviceResponse;
try {
- freeMarkerServiceResponse = freeMarkerService.calculateTemplateOutput(
- template, dataModel,
- outputFormat, locale, timeZone);
+ serviceResponse = freeMarkerService.executeTemplate(serviceArgs);
} catch (RejectedExecutionException e) {
- String error = SERVICE_OVERBURDEN_ERROR_MESSAGE;
+ String error = SERVICE_TIMEOUT_ERROR_MESSAGE;
return Response.serverError().entity(new ErrorResponse(ErrorCode.FREEMARKER_SERVICE_TIMEOUT, error)).build();
}
- if (!freeMarkerServiceResponse.isSuccesful()){
- Throwable failureReason = freeMarkerServiceResponse.getFailureReason();
+ if (!serviceResponse.isSuccesful()){
+ Throwable failureReason = serviceResponse.getFailureReason();
String error = ExceptionUtils.getMessageWithCauses(failureReason);
- problems.add(new ExecuteResourceProblem(ExecuteResourceField.TEMPLATE, error));
+ problems.add(new ExecuteResponseProblem(ExecuteRequest.Field.TEMPLATE, error));
resp.setProblems(problems);
return buildFreeMarkerResponse(resp);
}
- String result = freeMarkerServiceResponse.getTemplateOutput();
+ String result = serviceResponse.getTemplateOutput();
resp.setResult(result);
- resp.setTruncatedResult(freeMarkerServiceResponse.isTemplateOutputTruncated());
+ resp.setTruncatedResult(serviceResponse.isTemplateOutputTruncated());
return buildFreeMarkerResponse(resp);
}
- private String getTemplate(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+ private String lengthCheckAndGetTemplate(ExecuteRequest req, List<ExecuteResponseProblem> problems) {
String template = req.getTemplate();
-
- if (template.length() > MAX_TEMPLATE_INPUT_LENGTH) {
+ if (template != null && 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));
+ problems.add(new ExecuteResponseProblem(ExecuteRequest.Field.TEMPLATE, error));
return null;
}
-
return template;
}
- private Map<String, Object> getDataModel(ExecuteRequest req, List<ExecuteResourceProblem> problems) {
+ private Map<String, Object> parseDataModel(ExecuteRequest req, List<ExecuteResponseProblem> 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));
+ problems.add(new ExecuteResponseProblem(ExecuteRequest.Field.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())));
+ problems.add(new ExecuteResponseProblem(ExecuteRequest.Field.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;
+ private <T> T parseChoiceField(ExecuteRequest.Field name, String rawValue, T defaultValue,
+ Map<String, ? extends T> rawToParsedMap, List<ExecuteResponseProblem> problems) {
+ if (StringUtils.isBlank(rawValue)) {
+ return defaultValue;
}
- Locale locale = AllowedSettingValuesMaps.LOCALE_MAP.get(localeStr);
- if (locale == null) {
- problems.add(new ExecuteResourceProblem(
- ExecuteResourceField.LOCALE,
- formatMessage(UNKNOWN_LOCALE_ERROR_MESSAGE, localeStr)));
+ T parsedValue = rawToParsedMap.get(rawValue);
+ if (parsedValue == null) {
+ problems.add(new ExecuteResponseProblem(name,
+ formatMessage("Invalid value for \"{0}\": {1}", name, StringUtil.jQuote(rawValue))));
}
- 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;
+ return parsedValue;
}
private Response buildFreeMarkerResponse(ExecuteResponse executeResponse){
diff --git a/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java b/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java
index 1f7a802..89c6da1 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/resources/WebPageResource.java
@@ -49,7 +49,9 @@
@FormParam("dataModel") String dataModel,
@FormParam("outputFormat") String outputFormat,
@FormParam("locale") String locale,
- @FormParam("timeZone") String timeZone) {
+ @FormParam("timeZone") String timeZone,
+ @FormParam("tagSyntax") String tagSyntax,
+ @FormParam("interpolationSyntax") String interpolationSyntax) {
FreeMarkerOnlineView view = new FreeMarkerOnlineView();
view.setTemplate(template);
view.setDataModel(dataModel);
diff --git a/src/main/java/org/apache/freemarker/onlinetester/services/AllowedSettingValuesMaps.java b/src/main/java/org/apache/freemarker/onlinetester/services/AllowedSettingValues.java
similarity index 65%
rename from src/main/java/org/apache/freemarker/onlinetester/services/AllowedSettingValuesMaps.java
rename to src/main/java/org/apache/freemarker/onlinetester/services/AllowedSettingValues.java
index e3111aa..6911144 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/services/AllowedSettingValuesMaps.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/services/AllowedSettingValues.java
@@ -32,6 +32,8 @@
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
+import com.google.common.collect.ImmutableMap;
+
import freemarker.core.HTMLOutputFormat;
import freemarker.core.OutputFormat;
import freemarker.core.PlainTextOutputFormat;
@@ -39,32 +41,26 @@
import freemarker.core.UndefinedOutputFormat;
import freemarker.core.XHTMLOutputFormat;
import freemarker.core.XMLOutputFormat;
+import freemarker.template.Configuration;
/**
- * Maps of the setting values the caller can chose from (these are the value shown in a dropdown on the UI).
+ * Maps of the FreeMarker configuration setting values the remote caller can
+ * chose from (these are the value shown in a dropdown on the UI). This is
+ * possibly more restricted than what FreeMarker supports, for security reasons.
*/
-public class AllowedSettingValuesMaps {
+public class AllowedSettingValues {
public static final OutputFormat DEFAULT_OUTPUT_FORMAT = UndefinedOutputFormat.INSTANCE;
public static final String DEFAULT_OUTPUT_FORMAT_KEY = DEFAULT_OUTPUT_FORMAT.getName();
- public static final Map<String, OutputFormat> OUTPUT_FORMAT_MAP;
- static {
- Map<String, OutputFormat> map = new HashMap<String, OutputFormat>();
-
- addOutputFormatToMap(map, UndefinedOutputFormat.INSTANCE);
- addOutputFormatToMap(map, HTMLOutputFormat.INSTANCE);
- addOutputFormatToMap(map, XMLOutputFormat.INSTANCE);
- addOutputFormatToMap(map, XHTMLOutputFormat.INSTANCE);
- addOutputFormatToMap(map, RTFOutputFormat.INSTANCE);
- addOutputFormatToMap(map, PlainTextOutputFormat.INSTANCE);
-
- OUTPUT_FORMAT_MAP = Collections.unmodifiableMap(map);
- }
+ public static final Map<String, OutputFormat> OUTPUT_FORMAT_MAP = ImmutableMap.<String, OutputFormat>builder()
+ .put(UndefinedOutputFormat.INSTANCE.getName(), UndefinedOutputFormat.INSTANCE)
+ .put(HTMLOutputFormat.INSTANCE.getName(), HTMLOutputFormat.INSTANCE)
+ .put(XMLOutputFormat.INSTANCE.getName(), XMLOutputFormat.INSTANCE)
+ .put(XHTMLOutputFormat.INSTANCE.getName(), XHTMLOutputFormat.INSTANCE)
+ .put(RTFOutputFormat.INSTANCE.getName(), RTFOutputFormat.INSTANCE)
+ .put(PlainTextOutputFormat.INSTANCE.getName(), PlainTextOutputFormat.INSTANCE)
+ .build();
- private static void addOutputFormatToMap(Map<String, OutputFormat> map, OutputFormat outputFormat) {
- map.put(outputFormat.getName(), outputFormat);
- }
-
public static final Locale DEFAULT_LOCALE = Locale.US;
public static final String DEFAULT_LOCALE_KEY = DEFAULT_LOCALE.toString();
public static final Map<String, Locale> LOCALE_MAP;
@@ -92,14 +88,12 @@
}
public static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("America/Los_Angeles");
-
public static final String DEFAULT_TIME_ZONE_KEY;
-
public static final Map<String, TimeZone> TIME_ZONE_MAP;
static {
String[] availableIDs = TimeZone.getAvailableIDs();
- DEFAULT_TIME_ZONE_KEY = AllowedSettingValuesMaps.DEFAULT_TIME_ZONE.getID();
+ DEFAULT_TIME_ZONE_KEY = AllowedSettingValues.DEFAULT_TIME_ZONE.getID();
if (!ArrayUtils.contains(availableIDs, DEFAULT_TIME_ZONE_KEY)) {
ArrayUtils.add(availableIDs, DEFAULT_TIME_ZONE_KEY);
}
@@ -112,4 +106,18 @@
TIME_ZONE_MAP = Collections.unmodifiableMap(map);
}
+ public static final String DEFAULT_TAG_SYNTAX_KEY = "angleBracket";
+ public static final Map<String, Integer> TAG_SYNTAX_MAP = ImmutableMap.of(
+ "angleBracket", Configuration.ANGLE_BRACKET_TAG_SYNTAX,
+ "squareBracket", Configuration.SQUARE_BRACKET_TAG_SYNTAX,
+ "autoDetect", Configuration.AUTO_DETECT_TAG_SYNTAX);
+ public static final int DEFAULT_TAG_SYNTAX = TAG_SYNTAX_MAP.get(DEFAULT_TAG_SYNTAX_KEY);
+
+ public static final String DEFAULT_INTERPOLATION_SYNTAX_KEY = "legacy";
+ public static final Map<String, Integer> INTERPOLATION_SYNTAX_MAP = ImmutableMap.of(
+ "legacy", Configuration.LEGACY_INTERPOLATION_SYNTAX,
+ "dollar", Configuration.DOLLAR_INTERPOLATION_SYNTAX,
+ "squareBracket", Configuration.SQUARE_BRACKET_INTERPOLATION_SYNTAX);
+ public static final int DEFAULT_INTERPOLATION_SYNTAX = Configuration.LEGACY_INTERPOLATION_SYNTAX;
+
}
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 fee66b7..20f9e78 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerService.java
@@ -52,6 +52,7 @@
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
+import freemarker.template.utility.StringUtil;
public class FreeMarkerService {
@@ -108,23 +109,13 @@
// Suppress it
}
});
- freeMarkerConfig.setLocale(AllowedSettingValuesMaps.DEFAULT_LOCALE);
- freeMarkerConfig.setTimeZone(AllowedSettingValuesMaps.DEFAULT_TIME_ZONE);
- freeMarkerConfig.setOutputFormat(AllowedSettingValuesMaps.DEFAULT_OUTPUT_FORMAT);
+ freeMarkerConfig.setLocale(AllowedSettingValues.DEFAULT_LOCALE);
+ freeMarkerConfig.setTimeZone(AllowedSettingValues.DEFAULT_TIME_ZONE);
+ freeMarkerConfig.setOutputFormat(AllowedSettingValues.DEFAULT_OUTPUT_FORMAT);
freeMarkerConfig.setOutputEncoding("UTF-8");
}
/**
- * @param templateSourceCode
- * The FTL to execute; not {@code null}.
- * @param dataModel
- * The FreeMarker data-model to execute the template with; maybe {@code null}.
- * @param outputFormat
- * The output format to execute the template with; maybe {@code null}.
- * @param locale
- * The locale to execute the template with; maybe {@code null}.
- * @param timeZone
- * The time zone to execute the template with; maybe {@code null}.
*
* @return The result of the template parsing and evaluation. The method won't throw exception if that fails due to
* errors in the template provided, instead it indicates this fact in the response object. That's because
@@ -137,13 +128,11 @@
* meaning of {@link RejectedExecutionException} either.
*/
@SuppressWarnings("deprecation") // for Thread.stop()
- public FreeMarkerServiceResponse calculateTemplateOutput(
- String templateSourceCode, Object dataModel, OutputFormat outputFormat, Locale locale, TimeZone timeZone)
+ public FreeMarkerServiceResponse executeTemplate(ExecuteTemplateArgs args)
throws RejectedExecutionException {
Objects.requireNonNull(templateExecutor, "templateExecutor was null - was postConstruct ever called?");
- final CalculateTemplateOutput task = new CalculateTemplateOutput(
- templateSourceCode, dataModel, outputFormat, locale, timeZone);
+ final ExecuteTempalteTask task = new ExecuteTempalteTask(args);
Future<FreeMarkerServiceResponse> future = templateExecutor.submit(task);
synchronized (task) {
@@ -203,7 +192,7 @@
logger.warn("Calling Thread.stop() on unresponsive long template processing, which didn't "
+ "respond to Template.interrupt() on time. Service state may will be inconsistent; "
+ "JVM restart recommended!\n"
- + "Template (quoted): \"" + StringEscapeUtils.escapeJava(templateSourceCode) + "\"");
+ + "Template (quoted): \"" + StringEscapeUtils.escapeJava(args.templateSourceCode) + "\"");
}
templateExecutorThread.stop();
}
@@ -217,7 +206,7 @@
templateExecutionEnded = true;
}
} // sync
- } catch (InterruptedException e1) {
+ } catch (InterruptedException e2) {
// Just continue...
}
}
@@ -226,14 +215,14 @@
logger.debug("Long template processing has ended.");
try {
return future.get();
- } catch (InterruptedException | ExecutionException e1) {
- throw new FreeMarkerServiceException("Failed to get result from template executor task", e1);
+ } catch (InterruptedException | ExecutionException e2) {
+ throw new FreeMarkerServiceException("Failed to get result from template executor task", e2);
}
} else {
throw new FreeMarkerServiceException(
"Couldn't stop long running template processing within " + ABORTION_LOOP_TIME_LIMIT
+ " ms. It's possibly stuck forever. Such problems can exhaust the executor pool. "
- + "Template (quoted): \"" + StringEscapeUtils.escapeJava(templateSourceCode) + "\"");
+ + "Template (quoted): " + StringUtil.jQuote(args.templateSourceCode));
}
}
}
@@ -265,25 +254,65 @@
logger.debug("The template had error(s)", e);
return new FreeMarkerServiceResponse.Builder().buildForFailure(e);
}
+
+ /**
+ * Argument to {@link FreeMarkerService#executeTemplate(ExecuteTemplateArgs)}; fluent API to deal with many parameters,
+ * most of which is optional. Only {@code templateSourceCode} must be set to non-{@code null}.
+ */
+ public static class ExecuteTemplateArgs {
+ private String templateSourceCode;
+ private Object dataModel;
+ private OutputFormat outputFormat;
+ private Locale locale;
+ private TimeZone timeZone;
+ private Integer tagSyntax;
+ private Integer interpolationSyntax;
- private class CalculateTemplateOutput implements Callable<FreeMarkerServiceResponse> {
+ public ExecuteTemplateArgs templateSourceCode(String templateSourceCode) {
+ this.templateSourceCode = templateSourceCode;
+ return this;
+ }
+
+ public ExecuteTemplateArgs dataModel(Object dataModel) {
+ this.dataModel = dataModel;
+ return this;
+ }
+
+ public ExecuteTemplateArgs outputFormat(OutputFormat outputFormat) {
+ this.outputFormat = outputFormat;
+ return this;
+ }
+
+ public ExecuteTemplateArgs locale(Locale locale) {
+ this.locale = locale;
+ return this;
+ }
+
+ public ExecuteTemplateArgs timeZone(TimeZone timeZone) {
+ this.timeZone = timeZone;
+ return this;
+ }
+
+ public ExecuteTemplateArgs tagSyntax(Integer tagSyntax) {
+ this.tagSyntax = tagSyntax;
+ return this;
+ }
+
+ public ExecuteTemplateArgs interpolationSyntax(Integer interpolationSyntax) {
+ this.interpolationSyntax = interpolationSyntax;
+ return this;
+ }
+ }
+
+ private class ExecuteTempalteTask implements Callable<FreeMarkerServiceResponse> {
+ private final ExecuteTemplateArgs args;
private boolean templateExecutionStarted;
private Thread templateExecutorThread;
- private final String templateSourceCode;
- private final Object dataModel;
- private final OutputFormat outputFormat;
- private final Locale locale;
- private final TimeZone timeZone;
private boolean taskEnded;
- private CalculateTemplateOutput(String templateSourceCode, Object dataModel,
- OutputFormat outputFormat, Locale locale, TimeZone timeZone) {
- this.templateSourceCode = templateSourceCode;
- this.dataModel = dataModel;
- this.outputFormat = outputFormat;
- this.locale = locale;
- this.timeZone = timeZone;
+ private ExecuteTempalteTask(ExecuteTemplateArgs args) {
+ this.args = args;
}
@Override
@@ -293,19 +322,25 @@
try {
TemplateConfiguration tCfg = new TemplateConfiguration();
tCfg.setParentConfiguration(freeMarkerConfig);
- if (outputFormat != null) {
- tCfg.setOutputFormat(outputFormat);
+
+ if (args.outputFormat != null) {
+ tCfg.setOutputFormat(args.outputFormat);
}
- if (locale != null) {
- tCfg.setLocale(locale);
+ if (args.locale != null) {
+ tCfg.setLocale(args.locale);
}
- if (timeZone != null) {
- tCfg.setTimeZone(timeZone);
+ if (args.timeZone != null) {
+ tCfg.setTimeZone(args.timeZone);
+ }
+ if (args.tagSyntax != null) {
+ tCfg.setTagSyntax(args.tagSyntax);
+ }
+ if (args.interpolationSyntax != null) {
+ tCfg.setInterpolationSyntax(args.interpolationSyntax);
}
template = new Template(null, null,
- new StringReader(templateSourceCode), freeMarkerConfig, tCfg, null);
-
+ new StringReader(args.templateSourceCode), freeMarkerConfig, tCfg, null);
tCfg.apply(template);
} catch (ParseException e) {
// Expected (part of normal operation)
@@ -326,7 +361,7 @@
notifyAll();
}
try {
- template.process(dataModel, new LengthLimitedWriter(writer, maxOutputLength));
+ template.process(args.dataModel, new LengthLimitedWriter(writer, maxOutputLength));
} finally {
synchronized (this) {
templateExecutorThread = null;
@@ -337,7 +372,7 @@
} catch (LengthLimitExceededException e) {
// Not really an error, we just cut the output here.
resultTruncated = true;
- writer.write(new MessageFormat(MAX_OUTPUT_LENGTH_EXCEEDED_TERMINATION, AllowedSettingValuesMaps.DEFAULT_LOCALE)
+ writer.write(new MessageFormat(MAX_OUTPUT_LENGTH_EXCEEDED_TERMINATION, AllowedSettingValues.DEFAULT_LOCALE)
.format(new Object[] { maxOutputLength }));
// Falls through
} catch (TemplateException e) {
diff --git a/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceException.java b/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceException.java
index 2ca7ee4..177b9ce 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceException.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceException.java
@@ -28,7 +28,6 @@
public FreeMarkerServiceException(String message) {
super(message);
- // TODO Auto-generated constructor stub
}
public FreeMarkerServiceException(String message, Throwable cause) {
diff --git a/src/main/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineView.java b/src/main/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineView.java
index c90e2a5..3932dda 100644
--- a/src/main/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineView.java
+++ b/src/main/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineView.java
@@ -25,47 +25,79 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.function.BiFunction;
import io.dropwizard.views.View;
import org.apache.commons.lang3.StringUtils;
import org.apache.freemarker.onlinetester.model.SelectionOption;
-import org.apache.freemarker.onlinetester.services.AllowedSettingValuesMaps;
+import org.apache.freemarker.onlinetester.services.AllowedSettingValues;
import freemarker.template.Configuration;
public class FreeMarkerOnlineView extends View {
- private static final List<SelectionOption> LOCALE_SELECTION_OPTIONS = toLocaleSelectionOptions(AllowedSettingValuesMaps.LOCALE_MAP);
- private static final List<SelectionOption> TIME_ZONE_SELECTION_OPTIONS = toSelectionOptions(AllowedSettingValuesMaps.TIME_ZONE_MAP);
- private static final List<SelectionOption> OUTPUT_FORMAT_SELECTION_OPTIONS = toSelectionOptions(AllowedSettingValuesMaps.OUTPUT_FORMAT_MAP);
+ private static final List<SelectionOption> LOCALE_SELECTION_OPTIONS = toSelectionOptions(
+ AllowedSettingValues.LOCALE_MAP,
+ (k, v) -> truncate(v.getDisplayName(Locale.US), 18) + "; " + v.toString(),
+ true);
+ private static final List<SelectionOption> TIME_ZONE_SELECTION_OPTIONS = toSelectionOptions(
+ AllowedSettingValues.TIME_ZONE_MAP,
+ (k, v) -> truncate(k, 25),
+ true);
+ private static final List<SelectionOption> OUTPUT_FORMAT_SELECTION_OPTIONS = toSelectionOptions(
+ AllowedSettingValues.OUTPUT_FORMAT_MAP,
+ (k, v) -> k,
+ true);
+ private static final List<SelectionOption> TAG_SYNTAX_SELECTION_OPTIONS = toSelectionOptions(
+ AllowedSettingValues.TAG_SYNTAX_MAP,
+ (k, v) -> {
+ String label = k;
+ if (v == Configuration.ANGLE_BRACKET_TAG_SYNTAX) {
+ label += ", like <#...>, <@...>";
+ } else if (v == Configuration.SQUARE_BRACKET_TAG_SYNTAX) {
+ label += ", like [#...], [@...]";
+ }
+ return label;
+ },
+ false);
+ private static final List<SelectionOption> INTERPOLATION_SYNTAX_SELECTION_OPTIONS = toSelectionOptions(
+ AllowedSettingValues.INTERPOLATION_SYNTAX_MAP, (k, v) -> {
+ String label = k;
+ if (v == Configuration.LEGACY_INTERPOLATION_SYNTAX) {
+ label += ", like ${...}, #{...}";
+ } else if (v == Configuration.DOLLAR_INTERPOLATION_SYNTAX) {
+ label += ", like ${...}";
+ } else if (v == Configuration.SQUARE_BRACKET_INTERPOLATION_SYNTAX) {
+ label += ", like [=...]";
+ }
+ return label;
+ },
+ false);
private String template = "";
private String dataModel = "";
- private String outputFormat = AllowedSettingValuesMaps.DEFAULT_OUTPUT_FORMAT_KEY;
- private String locale = AllowedSettingValuesMaps.DEFAULT_LOCALE_KEY;
- private String timeZone = AllowedSettingValuesMaps.DEFAULT_TIME_ZONE_KEY;
+ private String outputFormat = AllowedSettingValues.DEFAULT_OUTPUT_FORMAT_KEY;
+ private String locale = AllowedSettingValues.DEFAULT_LOCALE_KEY;
+ private String timeZone = AllowedSettingValues.DEFAULT_TIME_ZONE_KEY;
+ private String tagSyntax = String.valueOf(AllowedSettingValues.DEFAULT_TAG_SYNTAX_KEY);
+ private String interpolationSyntax = String.valueOf(AllowedSettingValues.DEFAULT_INTERPOLATION_SYNTAX_KEY);
private boolean execute;
-
- private static List<SelectionOption> toSelectionOptions(Map<String, ?> settingValueMap) {
+
+ private static <V> List<SelectionOption> toSelectionOptions(
+ Map<String, ? extends V> settingValueMap,
+ BiFunction<String, ? super V, String> kvpToLabel, boolean sortByLabel) {
ArrayList<SelectionOption> selectionOptions = new ArrayList<SelectionOption>(settingValueMap.size());
- for (String key : settingValueMap.keySet()) {
- selectionOptions.add(new SelectionOption(key, truncate(key, 25)));
+ for (Map.Entry<String, ? extends V> ent : settingValueMap.entrySet()) {
+ String key = ent.getKey();
+ selectionOptions.add(new SelectionOption(
+ key,
+ kvpToLabel.apply(key, ent.getValue())));
}
- Collections.sort(selectionOptions);
- return selectionOptions;
- }
-
- private static List<SelectionOption> toLocaleSelectionOptions(Map<String, Locale> localeMap) {
- ArrayList<SelectionOption> selectionOptions = new ArrayList<SelectionOption>(localeMap.size());
- for (Map.Entry<String, Locale> ent : localeMap.entrySet()) {
- Locale locale = ent.getValue();
- selectionOptions.add(
- new SelectionOption(ent.getKey(),
- truncate(locale.getDisplayName(Locale.US), 18) + "; " + locale.toString()));
+ if (sortByLabel) {
+ Collections.sort(selectionOptions);
}
- Collections.sort(selectionOptions);
return selectionOptions;
}
@@ -118,12 +150,20 @@
return TIME_ZONE_SELECTION_OPTIONS;
}
+ public List<SelectionOption> getTagSyntaxes() {
+ return TAG_SYNTAX_SELECTION_OPTIONS;
+ }
+
+ public List<SelectionOption> getInterpolationSyntaxes() {
+ return INTERPOLATION_SYNTAX_SELECTION_OPTIONS;
+ }
+
public String getOutputFormat() {
return outputFormat;
}
public void setOutputFormat(String outputFormat) {
- this.outputFormat = withDefault(outputFormat, AllowedSettingValuesMaps.DEFAULT_OUTPUT_FORMAT_KEY);
+ this.outputFormat = withDefault(outputFormat, AllowedSettingValues.DEFAULT_OUTPUT_FORMAT_KEY);
}
public String getLocale() {
@@ -131,7 +171,7 @@
}
public void setLocale(String locale) {
- this.locale = withDefault(locale, AllowedSettingValuesMaps.DEFAULT_LOCALE_KEY);
+ this.locale = withDefault(locale, AllowedSettingValues.DEFAULT_LOCALE_KEY);
}
public String getTimeZone() {
@@ -139,10 +179,26 @@
}
public void setTimeZone(String timeZone) {
- this.timeZone = withDefault(timeZone, AllowedSettingValuesMaps.DEFAULT_TIME_ZONE_KEY);
+ this.timeZone = withDefault(timeZone, AllowedSettingValues.DEFAULT_TIME_ZONE_KEY);
}
- public boolean isExecute() {
+ public String getTagSyntax() {
+ return tagSyntax;
+ }
+
+ public void setTagSyntax(String tagSyntax) {
+ this.tagSyntax = withDefault(tagSyntax, AllowedSettingValues.DEFAULT_TAG_SYNTAX_KEY);
+ }
+
+ public String getInterpolationSyntax() {
+ return interpolationSyntax;
+ }
+
+ public void setInterpolationSyntax(String interpolationSyntax) {
+ this.interpolationSyntax = withDefault(interpolationSyntax, AllowedSettingValues.DEFAULT_INTERPOLATION_SYNTAX_KEY);
+ }
+
+ public boolean isExecute() {
return execute;
}
diff --git a/src/main/resources/assets/js/script.js b/src/main/resources/assets/js/script.js
index 776d90a..9afba14 100644
--- a/src/main/resources/assets/js/script.js
+++ b/src/main/resources/assets/js/script.js
@@ -17,6 +17,8 @@
* under the License.
*/
+// IMPORTANT! If you modify this file, increase the number after "?v=" in the FreeMarker template!
+
$(document).ready(function() {
$("#eval-btn").click(function() {
execute();
@@ -42,7 +44,9 @@
"dataModel": $("#dataModel").val(),
"outputFormat": $("#outputFormat").val(),
"locale": $("#locale").val(),
- "timeZone": $("#timeZone").val()
+ "timeZone": $("#timeZone").val(),
+ "tagSyntax": $("#tagSyntax").val(),
+ "interpolationSyntax": $("#interpolationSyntax").val(),
}
$.ajax({
@@ -102,3 +106,5 @@
$(".resultContainer").show();
autosize.update($("#result"));
}
+
+//IMPORTANT! If you modify this file, increase the number after "?v=" in the FreeMarker template!
diff --git a/src/main/resources/freemarker-online.yml b/src/main/resources/freemarker-online.yml
index a582b87..27070aa 100644
--- a/src/main/resources/freemarker-online.yml
+++ b/src/main/resources/freemarker-online.yml
@@ -36,7 +36,7 @@
appenders: []
viewRendererConfiguration:
.ftl:
- incompatibleImprovements: 2.3.27
+ incompatibleImprovements: 2.3.28
locale: en_US
timeZone: UTC
outputEncoding: UTF-8
\ No newline at end of file
diff --git a/src/main/resources/view/freemarker-online.ftl b/src/main/resources/view/freemarker-online.ftl
index 982fcfa..7b13c68 100644
--- a/src/main/resources/view/freemarker-online.ftl
+++ b/src/main/resources/view/freemarker-online.ftl
@@ -34,7 +34,7 @@
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.blockUI/2.70/jquery.blockUI.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/autosize.js/3.0.8/autosize.min.js"></script>
- <script src="assets/js/script.js?v=3"></script>
+ <script src="assets/js/script.js?v=4"></script><!-- Always increase v if the script.js is changed! -->
<script>
$(function() {
// Auto-focus on first form input:
@@ -124,6 +124,16 @@
helpHover='Date/time values are shown as seen from this time zone' />
</div>
</div>
+ <div class="formPanel">
+ <div class="horizontalBox">
+ <@u.htmlSelect caption="Tag syntax" name="tagSyntax" selectionOptions=tagSyntaxes
+ helpLink='https://freemarker.apache.org/docs/dgui_misc_alternativesyntax.html#dgui_misc_alternativesyntax_tag' />
+ </div>
+ <div class="horizontalBox">
+ <@u.htmlSelect caption="Interpolation syntax" name="interpolationSyntax" selectionOptions=interpolationSyntaxes
+ helpLink='https://freemarker.apache.org/docs/dgui_misc_alternativesyntax.html#dgui_misc_alternativesyntax_interpolation' />
+ </div>
+ </div>
<div class="formBottomButtonsContainer">
<input id="eval-btn" type="button" value="Evaluate" class="pure-button pure-button-primary"/>
<span class="faint">Ctrl+Enter in input fields will submit this form too</span>
diff --git a/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java b/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java
index a422016..7d3aeea 100644
--- a/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java
+++ b/src/test/java/org/apache/freemarker/onlinetester/ApplicationStartsTest.java
@@ -33,7 +33,7 @@
public class ApplicationStartsTest {
@ClassRule
- public final static DropwizardAppRule RULE = new DropwizardAppRule<FreeMarkerOnlineTesterConfiguration>
+ public final static DropwizardAppRule<FreeMarkerOnlineTesterConfiguration> RULE = new DropwizardAppRule<>
(FreeMarkerOnlineTester.class,
Resources.getResource("freemarker-online.yml").getPath());
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java
index 7fa3fb4..ef89470 100644
--- a/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java
+++ b/src/test/java/org/apache/freemarker/onlinetester/resources/ExecuteApiResourceTest.java
@@ -19,16 +19,19 @@
package org.apache.freemarker.onlinetester.resources;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+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 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.apache.freemarker.onlinetester.model.ExecuteResponseProblem;
import org.junit.Test;
public class ExecuteApiResourceTest extends ResourceTest {
@@ -53,7 +56,7 @@
assertEquals(200, resp.getStatus());
ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
assertNotNull(response.getProblems());
- assertTrue(containsProblem(response, ExecuteResourceField.DATA_MODEL));
+ assertTrue(containsProblem(response, ExecuteRequest.Field.DATA_MODEL));
}
@Test
@@ -63,8 +66,8 @@
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);
+ assertTrue(containsProblem(response, ExecuteRequest.Field.DATA_MODEL));
+ String problemMessage = getProblemMessage(response, ExecuteRequest.Field.DATA_MODEL);
assertThat(problemMessage, containsString("data model"));
assertThat(problemMessage, containsString("limit"));
}
@@ -76,8 +79,8 @@
assertEquals(200, resp.getStatus());
ExecuteResponse response = resp.readEntity(ExecuteResponse.class);
assertNotNull(response.getProblems());
- assertTrue(containsProblem(response, ExecuteResourceField.TEMPLATE));
- String problemMessage = getProblemMessage(response, ExecuteResourceField.TEMPLATE);
+ assertTrue(containsProblem(response, ExecuteRequest.Field.TEMPLATE));
+ String problemMessage = getProblemMessage(response, ExecuteRequest.Field.TEMPLATE);
assertThat(problemMessage, containsString("template"));
assertThat(problemMessage, containsString("limit"));
}
@@ -88,17 +91,22 @@
req.setOutputFormat("wrongOutputFormat");
req.setLocale("wrongLocale");
req.setTimeZone("wrongTimeZone");
+ req.setTagSyntax("wrongTagSyntax");
+ req.setInterpolationSyntax("wrongInterpolationSyntax");
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"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.TEMPLATE), containsString("limit"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.DATA_MODEL), containsString("limit"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.OUTPUT_FORMAT), containsString("wrongOutputFormat"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.LOCALE), containsString("wrongLocale"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.TIME_ZONE), containsString("wrongTimeZone"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.TAG_SYNTAX), containsString("wrongTagSyntax"));
+ assertThat(getProblemMessage(response, ExecuteRequest.Field.INTERPOLATION_SYNTAX), containsString(
+ "wrongInterpolationSyntax"));
}
private String create30KString() {
@@ -109,8 +117,8 @@
return sb.toString();
}
- private boolean containsProblem(ExecuteResponse response, ExecuteResourceField field) {
- for (ExecuteResourceProblem problem : response.getProblems()) {
+ private boolean containsProblem(ExecuteResponse response, ExecuteRequest.Field field) {
+ for (ExecuteResponseProblem problem : response.getProblems()) {
if (problem.getField() == field) {
return true;
}
@@ -118,8 +126,8 @@
return false;
}
- private String getProblemMessage(ExecuteResponse response, ExecuteResourceField field) {
- for (ExecuteResourceProblem problem : response.getProblems()) {
+ private String getProblemMessage(ExecuteResponse response, ExecuteRequest.Field field) {
+ for (ExecuteResponseProblem problem : response.getProblems()) {
if (problem.getField() == field) {
return problem.getMessage();
}
diff --git a/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java b/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java
index 739628f..091911a 100644
--- a/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java
+++ b/src/test/java/org/apache/freemarker/onlinetester/resources/WebPageResourceTest.java
@@ -21,24 +21,17 @@
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.apache.freemarker.onlinetester.services.FreeMarkerService;
+import org.apache.freemarker.onlinetester.services.FreeMarkerService.ExecuteTemplateArgs;
+import org.apache.freemarker.onlinetester.view.FreeMarkerOnlineView;
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 {
@@ -50,9 +43,7 @@
@Test
public void testInitialForm() {
- when(freeMarkerService.calculateTemplateOutput(
- anyString(), anyMap(), any(OutputFormat.class), any(Locale.class), any(TimeZone.class)))
- .thenThrow(new AssertionError());
+ when(freeMarkerService.executeTemplate(any(ExecuteTemplateArgs.class))).thenThrow(new AssertionError());
FreeMarkerOnlineView view = webPageResource.blankForm();
assertEquals(view.getTemplate(), "");
assertEquals(view.getDataModel(), "");
@@ -60,10 +51,8 @@
@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);
+ when(freeMarkerService.executeTemplate(any(ExecuteTemplateArgs.class))).thenThrow(new AssertionError());
+ FreeMarkerOnlineView view = webPageResource.formResult(null, null, null, null, null, null, null);
assertEquals(view.getTemplate(), "");
assertEquals(view.getDataModel(), "");
}
diff --git a/src/test/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceTest.java b/src/test/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceTest.java
index 37c52c9..3865265 100644
--- a/src/test/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceTest.java
+++ b/src/test/java/org/apache/freemarker/onlinetester/services/FreeMarkerServiceTest.java
@@ -36,6 +36,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import org.apache.freemarker.onlinetester.services.FreeMarkerService.ExecuteTemplateArgs;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
@@ -44,6 +45,7 @@
import freemarker.core.Environment;
import freemarker.core.HTMLOutputFormat;
import freemarker.core.ParseException;
+import freemarker.template.Configuration;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
@@ -77,8 +79,8 @@
@Test
public void testCalculationOfATemplateWithNoDataModel() {
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- "test", Collections.<String, Object>emptyMap(), null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode("test").dataModel(Collections.emptyMap()));
assertThat(serviceResponse.isSuccesful(), is(true));
assertThat(serviceResponse.getTemplateOutput(), is("test"));
}
@@ -88,8 +90,8 @@
HashMap<String, Object> dataModel = new HashMap<>();
dataModel.put("var1", "val1");
String templateSourceCode = "${var1}";
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- templateSourceCode, dataModel, null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(templateSourceCode).dataModel(dataModel));
assertThat(serviceResponse.getTemplateOutput(), equalTo("val1"));
}
@@ -99,8 +101,8 @@
dataModel.put("var1", "val1");
dataModel.put("var2", "val2");
String template = "${var1?capitalize} ${var2?cap_first}";
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, dataModel, null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).dataModel(dataModel));
assertThat(serviceResponse.getTemplateOutput(), equalTo("Val1 Val2"));
}
@@ -108,13 +110,13 @@
public void testOutputFormatParamterMatters() {
String template = "${'&'}";
{
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, null, null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template));
assertThat(serviceResponse.getTemplateOutput(), equalTo("&"));
}
{
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, null, HTMLOutputFormat.INSTANCE, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).outputFormat(HTMLOutputFormat.INSTANCE));
assertThat(serviceResponse.getTemplateOutput(), equalTo("&"));
}
}
@@ -123,13 +125,13 @@
public void testLocaleParameterMatters() {
String template = "${.locale}";
{
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, null, null, new Locale("en", "US"), null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).locale(Locale.US));
assertThat(serviceResponse.getTemplateOutput(), equalTo("en_US"));
}
{
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, null, null, new Locale("ru", "RU"), null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).locale(new Locale("ru", "RU")));
assertThat(serviceResponse.getTemplateOutput(), equalTo("ru_RU"));
}
}
@@ -140,33 +142,68 @@
String gmt1Result;
{
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, null, null, null, TimeZone.getTimeZone("GMT+01"));
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).timeZone(TimeZone.getTimeZone("GMT+01")));
gmt1Result = serviceResponse.getTemplateOutput();
}
String gmt2Result;
{
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- template, null, null, new Locale("ru", "RU"), null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).locale(new Locale("ru", "RU")));
gmt2Result = serviceResponse.getTemplateOutput();
}
assertThat(gmt1Result, not(equalTo(gmt2Result)));
}
+
+ @Test
+ public void testTagSyntaxParameterMatters() {
+ String template = "[#if true]1[/#if]<#if true>2</#if>";
+ {
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).tagSyntax(Configuration.ANGLE_BRACKET_TAG_SYNTAX));
+ assertThat(serviceResponse.getTemplateOutput(), equalTo("[#if true]1[/#if]2"));
+ }
+ for (int tagSyntax : new int[] { Configuration.SQUARE_BRACKET_TAG_SYNTAX, Configuration.AUTO_DETECT_TAG_SYNTAX }) {
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).tagSyntax(tagSyntax));
+ assertThat(serviceResponse.getTemplateOutput(), equalTo("1<#if true>2</#if>"));
+ }
+ }
+
+ @Test
+ public void testInterpolationSyntaxParameterMatters() {
+ String template = "${1} #{2} [=3]";
+ {
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).interpolationSyntax(Configuration.LEGACY_INTERPOLATION_SYNTAX));
+ assertThat(serviceResponse.getTemplateOutput(), equalTo("1 2 [=3]"));
+ }
+ {
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).interpolationSyntax(Configuration.DOLLAR_INTERPOLATION_SYNTAX));
+ assertThat(serviceResponse.getTemplateOutput(), equalTo("1 #{2} [=3]"));
+ }
+ {
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(template).interpolationSyntax(Configuration.SQUARE_BRACKET_INTERPOLATION_SYNTAX));
+ assertThat(serviceResponse.getTemplateOutput(), equalTo("${1} #{2} 3"));
+ }
+ }
@Test
public void testTemplateWithSyntaxError() {
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- "test ${xx", Collections.<String, Object>emptyMap(), null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode("test ${xx").dataModel(Collections.emptyMap()));
assertThat(serviceResponse.isSuccesful(), is(false));
assertThat(serviceResponse.getFailureReason(), instanceOf(ParseException.class));
}
@Test
public void testTemplateWithEvaluationError() {
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- "test ${x}", Collections.<String, Object>emptyMap(), null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode("test ${x}").dataModel(Collections.emptyMap()));
assertThat(serviceResponse.isSuccesful(), is(false));
assertThat(serviceResponse.getFailureReason(), instanceOf(TemplateException.class));
}
@@ -174,8 +211,8 @@
@Test
public void testResultAlmostTruncation() {
serviceBuilder.setMaxOutputLength(5);
- FreeMarkerServiceResponse serviceResponse = getService().calculateTemplateOutput(
- TRUNCATION_TEST_TEMPLATE, Collections.<String, Object>emptyMap(), null, null, null);
+ FreeMarkerServiceResponse serviceResponse = getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(TRUNCATION_TEST_TEMPLATE).dataModel(Collections.emptyMap()));
assertThat(serviceResponse.isSuccesful(), is(true));
assertThat(serviceResponse.isTemplateOutputTruncated(), is(false));
assertThat(serviceResponse.getTemplateOutput(), equalTo(TRUNCATION_TEST_TEMPLATE));
@@ -185,8 +222,8 @@
public void testResultTruncation() {
serviceBuilder.setMaxOutputLength(4);
FreeMarkerService service = getService();
- FreeMarkerServiceResponse serviceResponse = service.calculateTemplateOutput(
- TRUNCATION_TEST_TEMPLATE, Collections.<String, Object>emptyMap(), null, null, null);
+ FreeMarkerServiceResponse serviceResponse = service.executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode(TRUNCATION_TEST_TEMPLATE).dataModel(Collections.emptyMap()));
assertThat(serviceResponse.isSuccesful(), is(true));
assertThat(serviceResponse.isTemplateOutputTruncated(), is(true));
assertThat(serviceResponse.getTemplateOutput(),
@@ -205,8 +242,9 @@
@Override
public FreeMarkerServiceResponse call() throws Exception {
- return getService().calculateTemplateOutput(
- "<#list 1.. as _></#list>", Collections.<String, Object>emptyMap(), null, null, null);
+ return getService().executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode("<#list 1.. as _></#list>")
+ .dataModel(Collections.emptyMap()));
}
});
@@ -231,7 +269,8 @@
new Thread(new Runnable() {
@Override
public void run() {
- service.calculateTemplateOutput("<@blocker/>", blockerDataModel, null, null, null);
+ service.executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode("<@blocker/>").dataModel(blockerDataModel));
}
}).start();
}
@@ -253,7 +292,8 @@
// Shouldn't accept on more tasks:
try {
- service.calculateTemplateOutput("<@blocker/>", blockerDataModel, null, null, null);
+ service.executeTemplate(new ExecuteTemplateArgs()
+ .templateSourceCode("<@blocker/>").dataModel(blockerDataModel));
fail("Expected RejectedExecutionException, but nothing was thrown.");
} catch (RejectedExecutionException e) {
// Expected
diff --git a/src/test/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineViewTest.java b/src/test/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineViewTest.java
index b9572ba..e632d77 100644
--- a/src/test/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineViewTest.java
+++ b/src/test/java/org/apache/freemarker/onlinetester/view/FreeMarkerOnlineViewTest.java
@@ -26,7 +26,7 @@
import org.junit.Test;
-import org.apache.freemarker.onlinetester.services.AllowedSettingValuesMaps;
+import org.apache.freemarker.onlinetester.services.AllowedSettingValues;
import freemarker.core.HTMLOutputFormat;
@@ -41,9 +41,9 @@
FreeMarkerOnlineView view = new FreeMarkerOnlineView();
assertEquals(view.getTemplate(), "");
assertEquals(view.getDataModel(), "");
- assertEquals(view.getOutputFormat(), AllowedSettingValuesMaps.DEFAULT_OUTPUT_FORMAT_KEY);
- assertEquals(view.getLocale(), AllowedSettingValuesMaps.DEFAULT_LOCALE_KEY);
- assertEquals(view.getTimeZone(), AllowedSettingValuesMaps.DEFAULT_TIME_ZONE_KEY);
+ assertEquals(view.getOutputFormat(), AllowedSettingValues.DEFAULT_OUTPUT_FORMAT_KEY);
+ assertEquals(view.getLocale(), AllowedSettingValues.DEFAULT_LOCALE_KEY);
+ assertEquals(view.getTimeZone(), AllowedSettingValues.DEFAULT_TIME_ZONE_KEY);
}
@Test