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/09/13 09:49:10 UTC
[09/36] incubator-freemarker git commit: FREEMARKER-55: Adding
initial message function.
FREEMARKER-55: Adding initial message function.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/3b83475f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/3b83475f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/3b83475f
Branch: refs/heads/3
Commit: 3b83475f111019842b6070581ca310890ba199d1
Parents: f1e8a4d
Author: Woonsan Ko <wo...@apache.org>
Authored: Sat Sep 2 23:49:38 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Sat Sep 2 23:49:38 2017 -0400
----------------------------------------------------------------------
.../AbstractSpringTemplateCallableModel.java | 106 +++++++++++++++++++
.../AbstractSpringTemplateDirectiveModel.java | 70 +-----------
.../AbstractSpringTemplateFunctionModel.java | 69 ++++++++++++
.../freemarker/spring/model/BindDirective.java | 10 +-
.../spring/model/MessageFunction.java | 98 +++++++++++++++++
.../spring/web/view/FreeMarkerView.java | 2 +
6 files changed, 282 insertions(+), 73 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3b83475f/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
new file mode 100644
index 0000000..431c066
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
@@ -0,0 +1,106 @@
+/*
+ * 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.spring.model;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.ObjectWrappingException;
+import org.apache.freemarker.core.model.TemplateCallableModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.springframework.web.servlet.support.BindStatus;
+import org.springframework.web.servlet.support.RequestContext;
+
+/**
+ * Abstract TemplateCallableModel for derived classes to support Spring MVC based templating environment.
+ */
+public abstract class AbstractSpringTemplateCallableModel implements TemplateCallableModel {
+
+ // TODO: namespace this into 'spring.nestedPath'??
+ /**
+ * @see <code>org.springframework.web.servlet.tags.NestedPathTag#NESTED_PATH_VARIABLE_NAME</code>
+ */
+ private static final String NESTED_PATH_VARIABLE_NAME = "nestedPath";
+
+ private final HttpServletRequest request;
+ private final HttpServletResponse response;
+
+ public AbstractSpringTemplateCallableModel(HttpServletRequest request, HttpServletResponse response) {
+ this.request = request;
+ this.response = response;
+ }
+
+ protected final HttpServletRequest getRequest() {
+ return request;
+ }
+
+ protected final HttpServletResponse getResponse() {
+ return response;
+ }
+
+ /**
+ * Find {@link BindStatus} with no {@code htmlEscape} option from {@link RequestContext} by the {@code path}
+ * and wrap it as a {@link TemplateModel}.
+ * <P>
+ * <EM>NOTE:</EM> In FreeMarker, there is no need to depend on <code>BindStatus#htmlEscape</code> option
+ * as FreeMarker template expressions can easily set escape option by themselves.
+ * Therefore, this method always get a {@link BindStatus} with {@code htmlEscape} option set to {@code false}.
+ * @param env Environment
+ * @param objectWrapperAndUnwrapper ObjectWrapperAndUnwrapper
+ * @param requestContext Spring RequestContext
+ * @param path bind path
+ * @param ignoreNestedPath flag whether or not to ignore the nested path
+ * @return {@link TemplateModel} wrapping a {@link BindStatus} with no {@code htmlEscape} option from {@link RequestContext}
+ * by the {@code path}
+ * @throws ObjectWrappingException if fails to wrap the <code>BindStatus</code> object
+ */
+ protected final TemplateModel getBindStatusTemplateModel(Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper,
+ RequestContext requestContext, String path, boolean ignoreNestedPath) throws ObjectWrappingException {
+ final String resolvedPath = (ignoreNestedPath) ? path : resolveNestedPath(env, objectWrapperAndUnwrapper, path);
+ BindStatus status = requestContext.getBindStatus(resolvedPath, false);
+
+ if (status != null) {
+ if (!(objectWrapperAndUnwrapper instanceof DefaultObjectWrapper)) {
+ throw new IllegalArgumentException("objectWrapperAndUnwrapper is not a DefaultObjectWrapper.");
+ }
+
+ return ((DefaultObjectWrapper) objectWrapperAndUnwrapper).wrap(status);
+ }
+
+ return null;
+ }
+
+ private String resolveNestedPath(final Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper,
+ final String path) {
+ // TODO: should read it from request or env??
+ // or read spring.nestedPath first and read request attribute next??
+ String nestedPath = (String) request.getAttribute(NESTED_PATH_VARIABLE_NAME);
+
+ if (nestedPath != null && !path.startsWith(nestedPath)
+ && !path.equals(nestedPath.substring(0, nestedPath.length() - 1))) {
+ return nestedPath + path;
+ }
+
+ return path;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3b83475f/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
index e1b34b4..c4ed76c 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
@@ -30,31 +30,18 @@ import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
-import org.apache.freemarker.core.model.ObjectWrappingException;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.view.AbstractTemplateView;
/**
* Abstract TemplateDirectiveModel for derived classes to support Spring MVC based templating environment.
*/
-public abstract class AbstractSpringTemplateDirectiveModel implements TemplateDirectiveModel {
-
- // TODO: namespace this into 'spring.nestedPath'??
- /**
- * @see <code>org.springframework.web.servlet.tags.NestedPathTag#NESTED_PATH_VARIABLE_NAME</code>
- */
- private static final String NESTED_PATH_VARIABLE_NAME = "nestedPath";
-
- private final HttpServletRequest request;
- private final HttpServletResponse response;
+public abstract class AbstractSpringTemplateDirectiveModel extends AbstractSpringTemplateCallableModel implements TemplateDirectiveModel {
public AbstractSpringTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) {
- this.request = request;
- this.response = response;
+ super(request, response);
}
@Override
@@ -82,57 +69,4 @@ public abstract class AbstractSpringTemplateDirectiveModel implements TemplateDi
ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext)
throws TemplateException, IOException;
- protected final HttpServletRequest getRequest() {
- return request;
- }
-
- protected final HttpServletResponse getResponse() {
- return response;
- }
-
- /**
- * Find {@link BindStatus} with no {@code htmlEscape} option from {@link RequestContext} by the {@code path}
- * and wrap it as a {@link TemplateModel}.
- * <P>
- * <EM>NOTE:</EM> In FreeMarker, there is no need to depend on <code>BindStatus#htmlEscape</code> option
- * as FreeMarker template expressions can easily set escape option by themselves.
- * Therefore, this method always get a {@link BindStatus} with {@code htmlEscape} option set to {@code false}.
- * @param env Environment
- * @param objectWrapperAndUnwrapper ObjectWrapperAndUnwrapper
- * @param requestContext Spring RequestContext
- * @param path bind path
- * @param ignoreNestedPath flag whether or not to ignore the nested path
- * @return {@link TemplateModel} wrapping a {@link BindStatus} with no {@code htmlEscape} option from {@link RequestContext}
- * by the {@code path}
- * @throws ObjectWrappingException if fails to wrap the <code>BindStatus</code> object
- */
- protected final TemplateModel getBindStatusTemplateModel(Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper,
- RequestContext requestContext, String path, boolean ignoreNestedPath) throws ObjectWrappingException {
- final String resolvedPath = (ignoreNestedPath) ? path : resolveNestedPath(env, objectWrapperAndUnwrapper, path);
- BindStatus status = requestContext.getBindStatus(resolvedPath, false);
-
- if (status != null) {
- if (!(objectWrapperAndUnwrapper instanceof DefaultObjectWrapper)) {
- throw new IllegalArgumentException("objectWrapperAndUnwrapper is not a DefaultObjectWrapper.");
- }
-
- return ((DefaultObjectWrapper) objectWrapperAndUnwrapper).wrap(status);
- }
-
- return null;
- }
-
- private String resolveNestedPath(final Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper,
- final String path) {
- // TODO: should read it from request or env??
- // or read spring.nestedPath first and read request attribute next??
- String nestedPath = (String) request.getAttribute(NESTED_PATH_VARIABLE_NAME);
-
- if (nestedPath != null && !path.startsWith(nestedPath)
- && !path.equals(nestedPath.substring(0, nestedPath.length() - 1))) {
- return nestedPath + path;
- }
-
- return path;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3b83475f/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java
new file mode 100644
index 0000000..c0fe502
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java
@@ -0,0 +1,69 @@
+/*
+ * 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.spring.model;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.springframework.web.servlet.support.RequestContext;
+import org.springframework.web.servlet.view.AbstractTemplateView;
+
+/**
+ * Abstract TemplateFunctionModel for derived classes to support Spring MVC based templating environment.
+ */
+public abstract class AbstractSpringTemplateFunctionModel extends AbstractSpringTemplateCallableModel
+ implements TemplateFunctionModel {
+
+ public AbstractSpringTemplateFunctionModel(HttpServletRequest request, HttpServletResponse response) {
+ super(request, response);
+ }
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
+ final ObjectWrapper objectWrapper = env.getObjectWrapper();
+
+ if (!(objectWrapper instanceof ObjectWrapperAndUnwrapper)) {
+ throw new TemplateException(
+ "The ObjectWrapper of environment wasn't instance of ObjectWrapperAndUnwrapper.");
+ }
+
+ TemplateModel rcModel = env.getVariable(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE);
+
+ if (rcModel == null) {
+ throw new TemplateException(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE + " not found.");
+ }
+
+ RequestContext requestContext = (RequestContext) ((ObjectWrapperAndUnwrapper) objectWrapper).unwrap(rcModel);
+
+ return executeInternal(args, callPlace, env, (ObjectWrapperAndUnwrapper) objectWrapper, requestContext);
+ }
+
+ protected abstract TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env,
+ ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext)
+ throws TemplateException;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3b83475f/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindDirective.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindDirective.java
index b4b8ad9..0fbbe2f 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindDirective.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindDirective.java
@@ -75,12 +75,12 @@ public class BindDirective extends AbstractSpringTemplateDirectiveModel {
ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext)
throws TemplateException, IOException {
final String path = CallableUtils.getStringArgument(args, PATH_PARAM_IDX, this);
- boolean ignoreNestedPath = CallableUtils.getOptionalBooleanArgument(args, IGNORE_NESTED_PATH_PARAM_IDX, this,
- false);
+ final boolean ignoreNestedPath = CallableUtils.getOptionalBooleanArgument(args, IGNORE_NESTED_PATH_PARAM_IDX,
+ this, false);
- TemplateModel statusModel = getBindStatusTemplateModel(env, objectWrapperAndUnwrapper, requestContext, path,
- ignoreNestedPath);
- TemplateModel[] nestedContentArgs = new TemplateModel[] { statusModel };
+ final TemplateModel statusModel = getBindStatusTemplateModel(env, objectWrapperAndUnwrapper, requestContext,
+ path, ignoreNestedPath);
+ final TemplateModel[] nestedContentArgs = new TemplateModel[] { statusModel };
callPlace.executeNestedContent(nestedContentArgs, out, env);
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3b83475f/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
new file mode 100644
index 0000000..d440963
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
@@ -0,0 +1,98 @@
+/*
+ * 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.spring.model;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.SimpleString;
+import org.apache.freemarker.core.util.CallableUtils;
+import org.apache.freemarker.core.util.StringToIndexMap;
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceResolvable;
+import org.springframework.web.servlet.support.RequestContext;
+
+public class MessageFunction extends AbstractSpringTemplateFunctionModel {
+
+ private static final int CODE_PARAM_IDX = 0;
+ private static final int MESSAGE_PARAM_IDX = 1;
+
+ private static final String MESSAGE_PARAM_NAME = "message";
+
+ private static final ArgumentArrayLayout ARGS_LAYOUT =
+ ArgumentArrayLayout.create(
+ 1,
+ true,
+ StringToIndexMap.of(
+ MESSAGE_PARAM_NAME, MESSAGE_PARAM_IDX),
+ false);
+
+ public MessageFunction(HttpServletRequest request, HttpServletResponse response) {
+ super(request, response);
+ }
+
+ @Override
+ public TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env,
+ ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext)
+ throws TemplateException {
+ final MessageSource messageSource = requestContext.getMessageSource();
+
+ if (messageSource == null) {
+ throw new TemplateException("MessageSource not found.");
+ }
+
+ String message = null;
+
+ final String code = CallableUtils.getStringArgument(args, CODE_PARAM_IDX, this);
+
+ if (code != null && !code.isEmpty()) {
+ List<Object> msgArgumentList = null;
+ // TODO: How to read message arguments from the varags?
+
+ // TODO: Is it okay to set the default value to null to avoid NoSuchMessageException from Spring MessageSource?
+ message = messageSource.getMessage(code, (msgArgumentList == null) ? null : msgArgumentList.toArray(),
+ null, requestContext.getLocale());
+ } else {
+ final TemplateModel messageModel = CallableUtils.getOptionalArgument(args, MESSAGE_PARAM_IDX,
+ TemplateModel.class, this);
+ if (messageModel != null) {
+ MessageSourceResolvable messageResolvable = (MessageSourceResolvable) objectWrapperAndUnwrapper
+ .unwrap(messageModel);
+ message = messageSource.getMessage(messageResolvable, requestContext.getLocale());
+ }
+ }
+
+ return (message != null) ? new SimpleString(message) : null;
+ }
+
+ @Override
+ public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3b83475f/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java
index 1e94a97..f34fd4b 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java
@@ -39,6 +39,7 @@ import org.apache.freemarker.servlet.IncludePage;
import org.apache.freemarker.servlet.ServletContextHashModel;
import org.apache.freemarker.servlet.jsp.TaglibFactory;
import org.apache.freemarker.spring.model.BindDirective;
+import org.apache.freemarker.spring.model.MessageFunction;
/**
* FreeMarker template based view implementation, with being able to provide a {@link ServletContextHashModel}
@@ -178,6 +179,7 @@ public class FreeMarkerView extends AbstractFreeMarkerView {
final HttpServletRequest request, final HttpServletResponse response) {
final SimpleHash springCallableHash = new SimpleHash(objectWrapper);
springCallableHash.put("bind", new BindDirective(request, response));
+ springCallableHash.put("message", new MessageFunction(request, response));
return springCallableHash;
}
}