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;
     }
 }