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/07/04 07:44:12 UTC

[01/16] incubator-freemarker git commit: FREEMARKER-55: Adding skeletal FreemarkerView

Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 19071828a -> b230056e7


FREEMARKER-55: Adding skeletal FreemarkerView


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/584b46b8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/584b46b8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/584b46b8

Branch: refs/heads/3
Commit: 584b46b86aee16134f1f1c9e6d2cdb79bb7f8016
Parents: f3b89b5
Author: Woonsan Ko <wo...@apache.org>
Authored: Wed Jun 28 16:18:14 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Wed Jun 28 16:18:14 2017 -0400

----------------------------------------------------------------------
 freemarker-spring/build.gradle                  |  3 +-
 .../spring/web/view/AbstractFreemarkerView.java | 66 +++++++++++++++++
 .../spring/web/view/FreemarkerView.java         | 23 ++++++
 .../spring/web/view/FreemarkerViewTest.java     | 78 ++++++++++++++++++++
 4 files changed, 169 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/584b46b8/freemarker-spring/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-spring/build.gradle b/freemarker-spring/build.gradle
index 3efdbe5..60e03b2 100644
--- a/freemarker-spring/build.gradle
+++ b/freemarker-spring/build.gradle
@@ -27,7 +27,8 @@ inAggregateJavadoc = true
 dependencies {
     compile project(":freemarker-core")
 
-    compileOnly "javax.servlet:servlet-api:2.5"
+    // TODO: what's difference between compileOnly and compile??
+    compile "org.apache.geronimo.specs:geronimo-servlet_3.0_spec:1.0"
 
     def springVersion = "4.3.9.RELEASE"
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/584b46b8/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
new file mode 100644
index 0000000..a2a2e8b
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
@@ -0,0 +1,66 @@
+/*
+ * 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.web.view;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.ParseException;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateNotFoundException;
+import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
+import org.springframework.web.servlet.view.AbstractView;
+
+public abstract class AbstractFreemarkerView extends AbstractView {
+
+    private Configuration configuration;
+    private String templateName;
+
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    public String getTemplateName() {
+        return templateName;
+    }
+
+    public void setTemplateName(String templateName) {
+        this.templateName = templateName;
+    }
+
+    @Override
+    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
+            HttpServletResponse response) throws Exception {
+        getTemplate().process(model, response.getWriter());
+    }
+
+    protected Template getTemplate()
+            throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
+        return getConfiguration().getTemplate(getTemplateName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/584b46b8/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
new file mode 100644
index 0000000..da3ad09
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerView.java
@@ -0,0 +1,23 @@
+/*
+ * 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.web.view;
+
+public class FreemarkerView extends AbstractFreemarkerView {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/584b46b8/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
new file mode 100644
index 0000000..64f50e0
--- /dev/null
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.web.view;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+
+public class FreemarkerViewTest {
+
+    private ServletContext servletContext;
+
+    private Configuration configuration;
+
+    @Before
+    public void setUp() throws Exception {
+        servletContext = new MockServletContext();
+
+        StringTemplateLoader templateLoader = new StringTemplateLoader();
+        templateLoader.putTemplate("hello.ftl", "Hello, ${name!\"World\"}! Visit count: ${visitCount!0}");
+        configuration = new Configuration.Builder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)
+                .templateLoader(templateLoader).build();
+    }
+
+    @Test
+    public void testViewRendering() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myservlet/handler.do");
+        request.setContextPath("/mycontext");
+        request.setServletPath("/myservlet");
+        request.setPathInfo(";mypathinfo");
+        request.setQueryString("?param1=value1");
+
+        FreemarkerView view = new FreemarkerView();
+        view.setServletContext(servletContext);
+        view.setConfiguration(configuration);
+        view.setTemplateName("hello.ftl");
+
+        int visitCount = 0;
+        Map<String, Object> model = new HashMap<String, Object>();
+
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        view.render(model, request, response);
+        assertEquals("Hello, World! Visit count: 0", response.getContentAsString());
+
+        response = new MockHttpServletResponse();
+        model.put("name", "Dan");
+        model.put("visitCount", ++visitCount);
+        view.render(model, request, response);
+        assertEquals("Hello, Dan! Visit count: 1", response.getContentAsString());
+    }
+}


[11/16] incubator-freemarker git commit: FREEMARKER-55: Adding FreemarkerViewResolverTest

Posted by dd...@apache.org.
FREEMARKER-55: Adding FreemarkerViewResolverTest


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/4088f91f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/4088f91f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/4088f91f

Branch: refs/heads/3
Commit: 4088f91f62b678d2c4bebc25375d7fc822f47420
Parents: b375e14
Author: Woonsan Ko <wo...@apache.org>
Authored: Sun Jul 2 02:22:52 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Sun Jul 2 02:22:52 2017 -0400

----------------------------------------------------------------------
 .../spring/web/view/AbstractFreemarkerView.java | 13 +--
 .../spring/web/view/FreemarkerViewResolver.java | 22 +++++
 .../web/view/FreemarkerViewResolverTest.java    | 98 ++++++++++++++++++++
 .../spring/web/view/FreemarkerViewTest.java     |  2 +-
 4 files changed, 124 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4088f91f/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
index 38c2e3e..cb13ac4 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
@@ -39,7 +39,8 @@ public abstract class AbstractFreemarkerView extends AbstractTemplateView {
 
     private Configuration configuration;
     private ObjectWrapperAndUnwrapper objectWrapper;
-    private String name;
+
+    // TODO: how to determine locale, customLookupCondition and ignoreMissing? From viewResolver settings?
     private Locale locale;
     private Serializable customLookupCondition;
     private boolean ignoreMissing;
@@ -60,14 +61,6 @@ public abstract class AbstractFreemarkerView extends AbstractTemplateView {
         this.objectWrapper = objectWrapper;
     }
 
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public Locale getLocale() {
         return locale;
     }
@@ -100,7 +93,7 @@ public abstract class AbstractFreemarkerView extends AbstractTemplateView {
 
     protected Template getTemplate()
             throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
-        return getConfiguration().getTemplate(getName(), getLocale(), getCustomLookupCondition(), isIgnoreMissing());
+        return getConfiguration().getTemplate(getUrl(), getLocale(), getCustomLookupCondition(), isIgnoreMissing());
     }
 
     protected abstract TemplateHashModel createModel(Map<String, Object> map,

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4088f91f/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
index ecacd42..5f7d6fb 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
@@ -39,6 +39,8 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver impleme
     private ServletContextHashModel servletContextModel;
     private TaglibFactory taglibFactory;
 
+    private String normalizedPrefix;
+
     public FreemarkerViewResolver() {
         setViewClass(requiredViewClass());
     }
@@ -58,6 +60,19 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver impleme
     }
 
     @Override
+    public void setPrefix(String prefix) {
+        super.setPrefix(prefix);
+
+        final String prefixValue = getPrefix();
+
+        if (prefixValue.startsWith("/")) {
+            normalizedPrefix = prefixValue.substring(1);
+        } else {
+            normalizedPrefix = prefixValue;
+        }
+    }
+
+    @Override
     public void afterPropertiesSet() throws Exception {
         if (configuration == null) {
             throw new IllegalStateException("Configuration is not set.");
@@ -101,6 +116,13 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver impleme
     @Override
     protected AbstractUrlBasedView buildView(String viewName) throws Exception {
         FreemarkerView view = (FreemarkerView) super.buildView(viewName);
+        final String url;
+        if (normalizedPrefix != null) {
+            url = normalizedPrefix + viewName + getSuffix();
+        } else {
+            url = viewName + getSuffix();
+        }
+        view.setUrl(url);
         view.setConfiguration(configuration);
         view.setObjectWrapper(objectWrapper);
         view.setPageContextServlet(pageContextServlet);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4088f91f/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolverTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolverTest.java
new file mode 100644
index 0000000..7baf7f2
--- /dev/null
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolverTest.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.web.view;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+
+public class FreemarkerViewResolverTest {
+
+    private ServletContext servletContext;
+    private GenericWebApplicationContext applicationContext;
+
+    private StringTemplateLoader templateLoader;
+    private Configuration configuration;
+
+    private FreemarkerViewResolver viewResolver;
+
+    private String prefix = "/WEB-INF/freemarker/";
+    private String normalizedPrefix = "WEB-INF/freemarker/";
+    private String suffix = ".ftl";
+
+    @Before
+    public void setUp() throws Exception {
+        servletContext = new MockServletContext();
+
+        applicationContext = new GenericWebApplicationContext(servletContext);
+        applicationContext.refresh();
+        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
+
+        templateLoader = new StringTemplateLoader();
+        templateLoader.putTemplate(normalizedPrefix + "hello" + suffix, "Hello, World!");
+
+        configuration = new Configuration.Builder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)
+                .templateLoader(templateLoader).build();
+
+        viewResolver = new FreemarkerViewResolver();
+        viewResolver.setServletContext(servletContext);
+        viewResolver.setApplicationContext(applicationContext);
+        viewResolver.setConfiguration(configuration);
+        viewResolver.setPrefix(prefix);
+        viewResolver.setSuffix(suffix);
+        viewResolver.afterPropertiesSet();
+    }
+
+    @Test
+    public void testViewResolver() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/mytest.do");
+        request.setContextPath("/mycontext");
+        request.setServletPath("/myservlet");
+
+        MockHttpServletResponse response = new MockHttpServletResponse();
+
+        FreemarkerView view = resolveFreemarkerView("hello", null);//Locale.ENGLISH);
+        Map<String, Object> model = new HashMap<String, Object>();
+        view.render(model, request, response);
+
+        assertEquals("Hello, World!", response.getContentAsString());
+    }
+
+    private FreemarkerView resolveFreemarkerView(final String name, final Locale locale) throws Exception {
+        FreemarkerView view = (FreemarkerView) viewResolver.resolveViewName(name, locale);
+        view.setServletContext(servletContext);
+        view.setApplicationContext(applicationContext);
+        return view;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4088f91f/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
index 4a6f4b1..32862c5 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -156,7 +156,7 @@ public class FreemarkerViewTest {
         view.setServletContextModel(viewResolver.getServletContextModel());
         view.setTaglibFactory(viewResolver.getTaglibFactory());
 
-        view.setName(name);
+        view.setUrl(name);
 
         return view;
     }


[07/16] incubator-freemarker git commit: Merge branch '3' into feature/FREEMARKER-55

Posted by dd...@apache.org.
Merge branch '3' into feature/FREEMARKER-55


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

Branch: refs/heads/3
Commit: c2589eeb0517006715d427b591d186fafff7a32b
Parents: cb4fab3 c5feb63
Author: Woonsan Ko <wo...@apache.org>
Authored: Thu Jun 29 23:31:44 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Thu Jun 29 23:31:44 2017 -0400

----------------------------------------------------------------------
 .../core/FM2ASTToFM3SourceConverter.java        | 115 ++++++++++++++++++-
 .../converter/FM2ToFM3ConverterTest.java        |  18 +++
 2 files changed, 129 insertions(+), 4 deletions(-)
----------------------------------------------------------------------



[10/16] incubator-freemarker git commit: Merge branch '3' into feature/FREEMARKER-55

Posted by dd...@apache.org.
Merge branch '3' into feature/FREEMARKER-55


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

Branch: refs/heads/3
Commit: b375e1478f3ef3f5c12ac51890454c810e3dc057
Parents: 9083de1 507b89b
Author: Woonsan Ko <wo...@apache.org>
Authored: Sun Jul 2 01:25:49 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Sun Jul 2 01:25:49 2017 -0400

----------------------------------------------------------------------
 .../core/FM2ASTToFM3SourceConverter.java        | 209 +++++++++++++++++--
 .../core/UnexpectedNodeContentException.java    |  17 +-
 .../converter/FM2ToFM3ConverterTest.java        |  30 +++
 3 files changed, 234 insertions(+), 22 deletions(-)
----------------------------------------------------------------------



[05/16] incubator-freemarker git commit: FREEMARKER-55: Adding test for Application attributes.

Posted by dd...@apache.org.
FREEMARKER-55: Adding test for Application attributes.


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

Branch: refs/heads/3
Commit: 8e8c724b6f2ae003c67c4bc0c41fb026c0b9f6ad
Parents: 36b0694
Author: Woonsan Ko <wo...@apache.org>
Authored: Thu Jun 29 01:21:40 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Thu Jun 29 01:21:40 2017 -0400

----------------------------------------------------------------------
 .../spring/web/view/FreemarkerView.java         | 93 +++++++++++++++++++-
 .../spring/web/view/FreemarkerViewTest.java     | 10 +--
 2 files changed, 95 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e8c724b/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 21b2a60..934a458 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
@@ -18,8 +18,17 @@
  */
 package org.apache.freemarker.spring.web.view;
 
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.Map;
 
+import javax.servlet.GenericServlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -35,12 +44,40 @@ import org.apache.freemarker.servlet.jsp.TaglibFactory;
 
 public class FreemarkerView extends AbstractFreemarkerView {
 
+    private PageContextServletConfig pageContextServletConfig;
+
+    private PageContextServlet pageContextServlet;
+
     private ServletContextHashModel servletContextModel;
 
     private TaglibFactory taglibFactory;
 
+    public PageContextServlet getPageContextServlet() {
+        // TODO: proper locking...
+        if (pageContextServlet == null) {
+            pageContextServlet = new PageContextServlet();
+            pageContextServletConfig = new PageContextServletConfig(getServletContext(), getBeanName());
+
+            try {
+                pageContextServlet.init(pageContextServletConfig);
+            } catch (ServletException e) {
+                // never happen
+            }
+        }
+
+        return pageContextServlet;
+    }
+
+    public void setPageContextServlet(PageContextServlet pageContextServlet) {
+        this.pageContextServlet = pageContextServlet;
+    }
+
     public ServletContextHashModel getServletContextModel() {
-        // TODO
+        // TODO: proper locking...
+        if (servletContextModel == null) {
+            servletContextModel = new ServletContextHashModel(getPageContextServlet(), getObjectWrapperForModel());
+        }
+
         return servletContextModel;
     }
 
@@ -62,8 +99,10 @@ public class FreemarkerView extends AbstractFreemarkerView {
             HttpServletRequest request, HttpServletResponse response) {
         AllHttpScopesHashModel model = new AllHttpScopesHashModel(objectWrapperForModel, getServletContext(), request);
         model.putUnlistedModel(FreemarkerServlet.KEY_APPLICATION, getServletContextModel());
-        model.putUnlistedModel(FreemarkerServlet.KEY_SESSION, getHttpSessionModel(objectWrapperForModel, request, response));
-        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST, new HttpRequestHashModel(request, response, objectWrapperForModel));
+        model.putUnlistedModel(FreemarkerServlet.KEY_SESSION,
+                getHttpSessionModel(objectWrapperForModel, request, response));
+        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST,
+                new HttpRequestHashModel(request, response, objectWrapperForModel));
         model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST_PARAMETERS,
                 new HttpRequestParametersHashModel(request, objectWrapperForModel));
         model.putUnlistedModel(FreemarkerServlet.KEY_JSP_TAGLIBS, getTaglibFactory());
@@ -77,4 +116,52 @@ public class FreemarkerView extends AbstractFreemarkerView {
         HttpSessionHashModel sessionModel = new HttpSessionHashModel(null, request, response, objectWrapperForModel);
         return sessionModel;
     }
+
+    /**
+     * Extending {@link GenericServlet} for {@link PageContext#getPage()} in JSP Tag Library support.
+     */
+    @SuppressWarnings("serial")
+    private static class PageContextServlet extends GenericServlet {
+
+        @Override
+        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
+            // Do nothing
+        }
+
+    }
+
+    /**
+     * {@link ServletConfig} for {@link PageContextServlet}.
+     */
+    private class PageContextServletConfig implements ServletConfig {
+
+        private ServletContext servletContext;
+        private String servletName;
+
+        public PageContextServletConfig(ServletContext servletContext, String servletName) {
+            this.servletContext = servletContext;
+            this.servletName = servletName;
+        }
+
+        @Override
+        public String getServletName() {
+            return servletName;
+        }
+
+        @Override
+        public ServletContext getServletContext() {
+            return servletContext;
+        }
+
+        @Override
+        public String getInitParameter(String name) {
+            return null;
+        }
+
+        @Override
+        public Enumeration<String> getInitParameterNames() {
+            return Collections.enumeration(Collections.<String> emptySet());
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e8c724b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
index 0435004..4f21e58 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -93,12 +93,12 @@ public class FreemarkerViewTest {
         request.setPathInfo(";mypathinfo");
         request.addParameter("token1", "value1");
         request.setSession(session);
-        request.setAttribute("visitorCount", visitorCount);
+        request.setAttribute("promotion", "Fresh blue berries");
 
         // TODO: Add 'Application.attributeName' example, too.
         templateLoader.putTemplate("default-model.ftl",
-                "${name!}, you have ${Session.itemCountInCart!0} items in cart. "
-                        + "BTW, you're ${Request.visitorCount}th visitor. "
+                "${name!}, you have ${Session.itemCountInCart!0} items in cart. " + "Hot deal: ${Request.promotion}. "
+                        + "BTW, you're ${Application.visitorCount}th visitor. "
                         + "(token1: ${RequestParameters['token1']!})");
 
         FreemarkerView view = new FreemarkerView();
@@ -112,8 +112,8 @@ public class FreemarkerViewTest {
         final long count = visitorCount.incrementAndGet();
         MockHttpServletResponse response = new MockHttpServletResponse();
         view.render(model, request, response);
-        assertEquals("Dan, you have 3 items in cart. BTW, you're " + count + "th visitor. (token1: value1)",
-                response.getContentAsString());
+        assertEquals("Dan, you have 3 items in cart. Hot deal: Fresh blue berries. BTW, you're " + count
+                + "th visitor. (token1: value1)", response.getContentAsString());
     }
 
     @Test


[09/16] incubator-freemarker git commit: Adding FreemarkerViewResolver and improving FreemarkerViewTest with JspTaglibFactory and example.

Posted by dd...@apache.org.
Adding FreemarkerViewResolver and improving FreemarkerViewTest with JspTaglibFactory and example.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/9083de1b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/9083de1b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/9083de1b

Branch: refs/heads/3
Commit: 9083de1ba04d9d54b80109ed86941da72337cba5
Parents: 83e896c
Author: Woonsan Ko <wo...@apache.org>
Authored: Sun Jul 2 01:25:01 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Sun Jul 2 01:25:01 2017 -0400

----------------------------------------------------------------------
 freemarker-spring/build.gradle                  |  40 ++++--
 .../spring/web/view/AbstractFreemarkerView.java |  37 ++----
 .../spring/web/view/FreemarkerView.java         | 129 ++-----------------
 .../spring/web/view/FreemarkerViewResolver.java |  90 ++++++++++++-
 .../spring/web/view/PageContextServlet.java     |  39 ++++++
 .../web/view/PageContextServletConfig.java      |  56 ++++++++
 .../freemarker/spring/web/view/EchoTag.java     |  55 ++++++++
 .../spring/web/view/FreemarkerViewTest.java     |  61 ++++++---
 .../src/test/resources/WEB-INF/echo.tld         |  46 +++++++
 .../src/test/resources/WEB-INF/web.xml          |  23 ++++
 10 files changed, 408 insertions(+), 168 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-spring/build.gradle b/freemarker-spring/build.gradle
index 1865cc2..dce28d9 100644
--- a/freemarker-spring/build.gradle
+++ b/freemarker-spring/build.gradle
@@ -29,33 +29,57 @@ dependencies {
     compile project(":freemarker-core")
     compile project(":freemarker-servlet")
 
-    // TODO: what's difference between compileOnly and compile??
-    compile "org.apache.geronimo.specs:geronimo-servlet_3.0_spec:1.0"
-
+    def geronimoServletSpec3Version = "1.0"
     def springVersion = "4.3.9.RELEASE"
 
-    compile("org.springframework:spring-core:$springVersion") {
+    compileOnly "org.apache.geronimo.specs:geronimo-servlet_3.0_spec:${geronimoServletSpec3Version}"
+
+    compileOnly("org.springframework:spring-core:$springVersion") {
         exclude group: "commons-logging", module: "commons-logging"
     }
-    compile("org.springframework:spring-beans:$springVersion") {
+    compileOnly("org.springframework:spring-beans:$springVersion") {
         exclude group: "commons-logging", module: "commons-logging"
     }
-    compile("org.springframework:spring-context:$springVersion") {
+    compileOnly("org.springframework:spring-context:$springVersion") {
         exclude group: "commons-logging", module: "commons-logging"
     }
-    compile("org.springframework:spring-web:$springVersion") {
+    compileOnly("org.springframework:spring-web:$springVersion") {
         exclude group: "commons-logging", module: "commons-logging"
     }
-    compile("org.springframework:spring-webmvc:$springVersion") {
+    compileOnly("org.springframework:spring-webmvc:$springVersion") {
         exclude group: "commons-logging", module: "commons-logging"
     }
 
     // ------------------------------------------------------------------------
     // For tests
 
+    def taglibsStandardVersion = "1.2.1"
+
+    testCompile "org.apache.geronimo.specs:geronimo-servlet_3.0_spec:${geronimoServletSpec3Version}"
+
+    testCompile("org.springframework:spring-core:$springVersion") {
+        exclude group: "commons-logging", module: "commons-logging"
+    }
+    testCompile("org.springframework:spring-beans:$springVersion") {
+        exclude group: "commons-logging", module: "commons-logging"
+    }
+    testCompile("org.springframework:spring-context:$springVersion") {
+        exclude group: "commons-logging", module: "commons-logging"
+    }
+    testCompile("org.springframework:spring-web:$springVersion") {
+        exclude group: "commons-logging", module: "commons-logging"
+    }
+    testCompile("org.springframework:spring-webmvc:$springVersion") {
+        exclude group: "commons-logging", module: "commons-logging"
+    }
     testCompile("org.springframework:spring-test:$springVersion") {
         exclude group: "commons-logging", module: "commons-logging"
     }
+
+    testCompile "javax.servlet.jsp:jsp-api:2.1"
+    testCompile "org.apache.taglibs:taglibs-standard-spec:${taglibsStandardVersion}"
+    testCompile "org.apache.taglibs:taglibs-standard-impl:${taglibsStandardVersion}"
+
 }
 
 jar {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
index 595ada2..38c2e3e 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
@@ -32,13 +32,13 @@ import org.apache.freemarker.core.Template;
 import org.apache.freemarker.core.TemplateNotFoundException;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
 import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
-import org.springframework.web.servlet.view.AbstractView;
+import org.springframework.web.servlet.view.AbstractTemplateView;
 
-public abstract class AbstractFreemarkerView extends AbstractView {
+public abstract class AbstractFreemarkerView extends AbstractTemplateView {
 
     private Configuration configuration;
+    private ObjectWrapperAndUnwrapper objectWrapper;
     private String name;
     private Locale locale;
     private Serializable customLookupCondition;
@@ -49,15 +49,17 @@ public abstract class AbstractFreemarkerView extends AbstractView {
     }
 
     public void setConfiguration(Configuration configuration) {
-        if (!(configuration.getObjectWrapper() instanceof ObjectWrapperAndUnwrapper)) {
-            throw new RuntimeException(AbstractFreemarkerView.class.getSimpleName() + " requires an ObjectWrapper that "
-                    + "implements " + ObjectWrapperAndUnwrapper.class.getName() + ", but this class doesn't do that: "
-                    + configuration.getObjectWrapper().getClass().getName());
-        }
-
         this.configuration = configuration;
     }
 
+    public ObjectWrapperAndUnwrapper getObjectWrapper() {
+        return objectWrapper;
+    }
+
+    public void setObjectWrapper(ObjectWrapperAndUnwrapper objectWrapper) {
+        this.objectWrapper = objectWrapper;
+    }
+
     public String getName() {
         return name;
     }
@@ -91,9 +93,9 @@ public abstract class AbstractFreemarkerView extends AbstractView {
     }
 
     @Override
-    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
+    protected void renderMergedTemplateModel(Map<String, Object> model, HttpServletRequest request,
             HttpServletResponse response) throws Exception {
-        getTemplate().process(createModel(model, getObjectWrapperForModel(), request, response), response.getWriter());
+        getTemplate().process(createModel(model, getObjectWrapper(), request, response), response.getWriter());
     }
 
     protected Template getTemplate()
@@ -101,19 +103,6 @@ public abstract class AbstractFreemarkerView extends AbstractView {
         return getConfiguration().getTemplate(getName(), getLocale(), getCustomLookupCondition(), isIgnoreMissing());
     }
 
-    protected ObjectWrapperAndUnwrapper getObjectWrapperForModel() {
-        ObjectWrapperAndUnwrapper wrapper;
-
-        if (configuration.isObjectWrapperSet()) {
-            wrapper = (ObjectWrapperAndUnwrapper) configuration.getObjectWrapper();
-        } else {
-            // TODO: need to cache this?
-            wrapper = new DefaultObjectWrapper.Builder(configuration.getIncompatibleImprovements()).build();
-        }
-
-        return wrapper;
-    }
-
     protected abstract TemplateHashModel createModel(Map<String, Object> map,
             ObjectWrapperAndUnwrapper objectWrapperForModel, HttpServletRequest request, HttpServletResponse response);
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/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 64b3158..2210b98 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
@@ -18,17 +18,8 @@
  */
 package org.apache.freemarker.spring.web.view;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Enumeration;
 import java.util.Map;
 
-import javax.servlet.GenericServlet;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
@@ -42,38 +33,15 @@ import org.apache.freemarker.servlet.HttpRequestParametersHashModel;
 import org.apache.freemarker.servlet.HttpSessionHashModel;
 import org.apache.freemarker.servlet.ServletContextHashModel;
 import org.apache.freemarker.servlet.jsp.TaglibFactory;
-import org.apache.freemarker.servlet.jsp.TaglibFactoryBuilder;
 
 public class FreemarkerView extends AbstractFreemarkerView {
 
-    private volatile PageContextServlet pageContextServlet;
-
-    private volatile ServletContextHashModel servletContextModel;
-
-    private volatile TaglibFactory taglibFactory;
+    private PageContextServlet pageContextServlet;
+    private ServletContextHashModel servletContextModel;
+    private TaglibFactory taglibFactory;
 
     public PageContextServlet getPageContextServlet() {
-        PageContextServlet servlet = pageContextServlet;
-
-        if (servlet == null) {
-            synchronized (this) {
-                servlet = pageContextServlet;
-
-                if (servlet == null) {
-                    servlet = new PageContextServlet();
-
-                    try {
-                        servlet.init(new PageContextServletConfig(getServletContext(), getBeanName()));
-                    } catch (ServletException e) {
-                        // never happens...
-                    }
-
-                    pageContextServlet = servlet;
-                }
-            }
-        }
-
-        return servlet;
+        return pageContextServlet;
     }
 
     public void setPageContextServlet(PageContextServlet pageContextServlet) {
@@ -81,20 +49,7 @@ public class FreemarkerView extends AbstractFreemarkerView {
     }
 
     public ServletContextHashModel getServletContextModel() {
-        ServletContextHashModel contextModel = servletContextModel;
-
-        if (contextModel == null) {
-            synchronized (this) {
-                contextModel = servletContextModel;
-
-                if (contextModel == null) {
-                    contextModel = new ServletContextHashModel(getPageContextServlet(), getObjectWrapperForModel());
-                    servletContextModel = contextModel;
-                }
-            }
-        }
-
-        return contextModel;
+        return servletContextModel;
     }
 
     public void setServletContextModel(ServletContextHashModel servletContextModel) {
@@ -102,22 +57,7 @@ public class FreemarkerView extends AbstractFreemarkerView {
     }
 
     public TaglibFactory getTaglibFactory() {
-        TaglibFactory tlFactory = taglibFactory;
-
-        if (tlFactory == null) {
-            synchronized (this) {
-                tlFactory = taglibFactory;
-
-                if (tlFactory == null) {
-                    tlFactory = new TaglibFactoryBuilder(getServletContext(), getObjectWrapperForModel())
-                            .build();
-
-                    taglibFactory = tlFactory;
-                }
-            }
-        }
-
-        return tlFactory;
+        return taglibFactory;
     }
 
     public void setTaglibFactory(TaglibFactory taglibFactory) {
@@ -125,15 +65,15 @@ public class FreemarkerView extends AbstractFreemarkerView {
     }
 
     @Override
-    protected TemplateHashModel createModel(Map<String, Object> map, ObjectWrapperAndUnwrapper objectWrapperForModel,
+    protected TemplateHashModel createModel(Map<String, Object> map, ObjectWrapperAndUnwrapper objectWrapper,
             HttpServletRequest request, HttpServletResponse response) {
 
-        AllHttpScopesHashModel model = new AllHttpScopesHashModel(objectWrapperForModel, getServletContext(), request);
+        AllHttpScopesHashModel model = new AllHttpScopesHashModel(objectWrapper, getServletContext(), request);
 
         model.putUnlistedModel(FreemarkerServlet.KEY_APPLICATION, getServletContextModel());
 
         model.putUnlistedModel(FreemarkerServlet.KEY_SESSION,
-                getHttpSessionModel(objectWrapperForModel, request, response));
+                getHttpSessionModel(objectWrapper, request, response));
 
         HttpRequestHashModel requestModel = (HttpRequestHashModel) request
                 .getAttribute(FreemarkerServlet.ATTR_REQUEST_MODEL);
@@ -141,9 +81,9 @@ public class FreemarkerView extends AbstractFreemarkerView {
                 .getAttribute(FreemarkerServlet.ATTR_REQUEST_PARAMETERS_MODEL);
 
         if (requestModel == null || requestModel.getRequest() != request) {
-            requestModel = new HttpRequestHashModel(request, response, objectWrapperForModel);
+            requestModel = new HttpRequestHashModel(request, response, objectWrapper);
             request.setAttribute(FreemarkerServlet.ATTR_REQUEST_MODEL, requestModel);
-            requestParametersModel = new HttpRequestParametersHashModel(request, objectWrapperForModel);
+            requestParametersModel = new HttpRequestParametersHashModel(request, objectWrapper);
         }
 
         model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST, requestModel);
@@ -175,51 +115,4 @@ public class FreemarkerView extends AbstractFreemarkerView {
         return sessionModel;
     }
 
-    /**
-     * Extending {@link GenericServlet} for {@link PageContext#getPage()} in JSP Tag Library support.
-     */
-    @SuppressWarnings("serial")
-    private static class PageContextServlet extends GenericServlet {
-
-        @Override
-        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
-            // Do nothing
-        }
-
-    }
-
-    /**
-     * {@link ServletConfig} for {@link PageContextServlet}.
-     */
-    private class PageContextServletConfig implements ServletConfig {
-
-        private ServletContext servletContext;
-        private String servletName;
-
-        public PageContextServletConfig(ServletContext servletContext, String servletName) {
-            this.servletContext = servletContext;
-            this.servletName = servletName;
-        }
-
-        @Override
-        public String getServletName() {
-            return servletName;
-        }
-
-        @Override
-        public ServletContext getServletContext() {
-            return servletContext;
-        }
-
-        @Override
-        public String getInitParameter(String name) {
-            return null;
-        }
-
-        @Override
-        public Enumeration<String> getInitParameterNames() {
-            return Collections.enumeration(Collections.<String> emptySet());
-        }
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
index 6d7ab40..ecacd42 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
@@ -18,9 +18,26 @@
  */
 package org.apache.freemarker.spring.web.view;
 
+import javax.servlet.ServletException;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.servlet.ServletContextHashModel;
+import org.apache.freemarker.servlet.jsp.TaglibFactory;
+import org.apache.freemarker.servlet.jsp.TaglibFactoryBuilder;
+import org.springframework.beans.factory.InitializingBean;
 import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
+import org.springframework.web.servlet.view.AbstractUrlBasedView;
+
+public class FreemarkerViewResolver extends AbstractTemplateViewResolver implements InitializingBean {
 
-public class FreemarkerViewResolver extends AbstractTemplateViewResolver {
+    private Configuration configuration;
+
+    private ObjectWrapperAndUnwrapper objectWrapper;
+    private PageContextServlet pageContextServlet;
+    private ServletContextHashModel servletContextModel;
+    private TaglibFactory taglibFactory;
 
     public FreemarkerViewResolver() {
         setViewClass(requiredViewClass());
@@ -32,9 +49,80 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver {
         setSuffix(suffix);
     }
 
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        if (configuration == null) {
+            throw new IllegalStateException("Configuration is not set.");
+        }
+
+        if (objectWrapper == null) {
+            if (configuration.isObjectWrapperSet()) {
+                if (!(configuration.getObjectWrapper() instanceof ObjectWrapperAndUnwrapper)) {
+                    throw new RuntimeException(
+                            FreemarkerViewResolver.class.getSimpleName() + " requires an ObjectWrapper that "
+                                    + "implements " + ObjectWrapperAndUnwrapper.class.getName()
+                                    + ", but the Configuration's ObjectWrapper doesn't do that: "
+                                    + configuration.getObjectWrapper().getClass().getName());
+                }
+
+                objectWrapper = (ObjectWrapperAndUnwrapper) configuration.getObjectWrapper();
+            } else {
+                objectWrapper = new DefaultObjectWrapper.Builder(configuration.getIncompatibleImprovements()).build();
+            }
+        }
+
+        pageContextServlet = new PageContextServlet();
+
+        try {
+            pageContextServlet
+                    .init(new PageContextServletConfig(getServletContext(), FreemarkerViewResolver.class.getName()));
+        } catch (ServletException e) {
+            // never happens...
+        }
+
+        servletContextModel = new ServletContextHashModel(pageContextServlet, objectWrapper);
+
+        taglibFactory = new TaglibFactoryBuilder(getServletContext(), objectWrapper).build();
+    }
+
     @Override
     protected Class<?> requiredViewClass() {
         return FreemarkerView.class;
     }
 
+    @Override
+    protected AbstractUrlBasedView buildView(String viewName) throws Exception {
+        FreemarkerView view = (FreemarkerView) super.buildView(viewName);
+        view.setConfiguration(configuration);
+        view.setObjectWrapper(objectWrapper);
+        view.setPageContextServlet(pageContextServlet);
+        view.setServletContextModel(servletContextModel);
+        view.setTaglibFactory(taglibFactory);
+        return view;
+    }
+
+    protected ObjectWrapperAndUnwrapper getObjectWrapper() {
+        return objectWrapper;
+    }
+
+    protected PageContextServlet getPageContextServlet() {
+        return pageContextServlet;
+    }
+
+    protected ServletContextHashModel getServletContextModel() {
+        return servletContextModel;
+    }
+
+    protected TaglibFactory getTaglibFactory() {
+        return taglibFactory;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
new file mode 100644
index 0000000..94b586b
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
@@ -0,0 +1,39 @@
+/*
+ * 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.web.view;
+
+import java.io.IOException;
+
+import javax.servlet.GenericServlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * <code>GenericServlet</code> to support {@link javax.servlet.jsp.PageContext#getPage()} when JspTaglibs is used.
+ */
+@SuppressWarnings("serial")
+class PageContextServlet extends GenericServlet {
+
+    @Override
+    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
+        // Do nothing
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
new file mode 100644
index 0000000..0d42ba4
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
@@ -0,0 +1,56 @@
+/*
+ * 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.web.view;
+
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+class PageContextServletConfig implements ServletConfig {
+
+    private ServletContext servletContext;
+    private String servletName;
+
+    public PageContextServletConfig(ServletContext servletContext, String servletName) {
+        this.servletContext = servletContext;
+        this.servletName = servletName;
+    }
+
+    @Override
+    public String getServletName() {
+        return servletName;
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return servletContext;
+    }
+
+    @Override
+    public String getInitParameter(String name) {
+        return null;
+    }
+
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        return Collections.enumeration(Collections.<String> emptySet());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/EchoTag.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/EchoTag.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/EchoTag.java
new file mode 100644
index 0000000..155474f
--- /dev/null
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/EchoTag.java
@@ -0,0 +1,55 @@
+/*
+ * 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.web.view;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * Simple Example JSP Tag Library for unit test.
+ */
+@SuppressWarnings("serial")
+public class EchoTag extends TagSupport {
+
+    private String message;
+
+    public EchoTag() {
+        super();
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public int doEndTag() throws JspException {
+        try {
+            pageContext.getOut().print(message);
+        } catch (IOException e) {
+            throw new JspException("Message printing error.", e);
+        }
+        return EVAL_PAGE;
+    }
+
+    public void release() {
+        this.message = null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
index 80fc2b3..4a6f4b1 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -34,25 +34,41 @@ import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.mock.web.MockHttpSession;
 import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.GenericWebApplicationContext;
 
 public class FreemarkerViewTest {
 
     private ServletContext servletContext;
+    private GenericWebApplicationContext applicationContext;
 
     private StringTemplateLoader templateLoader;
-
     private Configuration configuration;
 
+    private FreemarkerViewResolver viewResolver;
+
     private AtomicLong visitorCount;
 
     @Before
     public void setUp() throws Exception {
         servletContext = new MockServletContext();
-        visitorCount = new AtomicLong();
-        servletContext.setAttribute("visitorCount", visitorCount);
+
+        applicationContext = new GenericWebApplicationContext(servletContext);
+        applicationContext.refresh();
+        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
+
         templateLoader = new StringTemplateLoader();
         configuration = new Configuration.Builder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)
                 .templateLoader(templateLoader).build();
+
+        viewResolver = new FreemarkerViewResolver();
+        viewResolver.setServletContext(servletContext);
+        viewResolver.setApplicationContext(applicationContext);
+        viewResolver.setConfiguration(configuration);
+        viewResolver.afterPropertiesSet();
+
+        visitorCount = new AtomicLong();
+        servletContext.setAttribute("visitorCount", visitorCount);
     }
 
     @Test
@@ -63,10 +79,7 @@ public class FreemarkerViewTest {
 
         templateLoader.putTemplate("hello.ftl", "Hello, ${name!\"World\"}! Visit count: ${visitCount!0}");
 
-        FreemarkerView view = new FreemarkerView();
-        view.setServletContext(servletContext);
-        view.setConfiguration(configuration);
-        view.setName("hello.ftl");
+        FreemarkerView view = createFreemarkerView("hello.ftl");
 
         int visitCount = 0;
         Map<String, Object> model = new HashMap<String, Object>();
@@ -100,10 +113,7 @@ public class FreemarkerViewTest {
                         + "BTW, you're ${Application.visitorCount}th visitor. "
                         + "(token1: ${RequestParameters['token1']!})");
 
-        FreemarkerView view = new FreemarkerView();
-        view.setServletContext(servletContext);
-        view.setConfiguration(configuration);
-        view.setName("default-model.ftl");
+        FreemarkerView view = createFreemarkerView("default-model.ftl");
 
         Map<String, Object> model = new HashMap<String, Object>();
         model.put("name", "Dan");
@@ -121,16 +131,33 @@ public class FreemarkerViewTest {
         request.setContextPath("/mycontext");
         request.setServletPath("/myservlet");
 
-        // TODO: 
-        templateLoader.putTemplate("taglibs.ftl", "");
+        templateLoader.putTemplate("taglibs.ftl",
+                "<#assign e=JspTaglibs ['http://freemarker.org/jsp/example/echo'] >"
+                + "<#assign msg=\"Hello!\" />"
+                + "<@e.echo message=msg />");
 
-        FreemarkerView view = new FreemarkerView();
-        view.setServletContext(servletContext);
-        view.setConfiguration(configuration);
-        view.setName("taglibs.ftl");
+        FreemarkerView view = createFreemarkerView("taglibs.ftl");
 
         Map<String, Object> model = new HashMap<String, Object>();
         MockHttpServletResponse response = new MockHttpServletResponse();
         view.render(model, request, response);
+        assertEquals("Hello!", response.getContentAsString());
+    }
+
+    private FreemarkerView createFreemarkerView(final String name) {
+        FreemarkerView view = new FreemarkerView();
+
+        view.setServletContext(servletContext);
+        view.setApplicationContext(applicationContext);
+        view.setConfiguration(configuration);
+        view.setObjectWrapper(viewResolver.getObjectWrapper());
+
+        view.setPageContextServlet(viewResolver.getPageContextServlet());
+        view.setServletContextModel(viewResolver.getServletContextModel());
+        view.setTaglibFactory(viewResolver.getTaglibFactory());
+
+        view.setName(name);
+
+        return view;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/test/resources/WEB-INF/echo.tld
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/resources/WEB-INF/echo.tld b/freemarker-spring/src/test/resources/WEB-INF/echo.tld
new file mode 100644
index 0000000..aff4d98
--- /dev/null
+++ b/freemarker-spring/src/test/resources/WEB-INF/echo.tld
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<taglib xmlns="http://java.sun.com/xml/ns/javaee"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
+        version="2.1">
+
+    <description>Test Echo Tag Library</description>
+    <display-name>Test Echo Tag Library</display-name>
+    <tlib-version>1.2</tlib-version>
+    <short-name>e</short-name>
+    <uri>http://freemarker.org/jsp/example/echo</uri>
+
+    <tag>
+        <description>
+            Print the message.
+        </description>
+        <name>echo</name>
+        <tag-class>org.apache.freemarker.spring.web.view.EchoTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <description>
+                Message string.
+            </description>
+            <name>message</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+    </tag>
+
+</taglib>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9083de1b/freemarker-spring/src/test/resources/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/resources/WEB-INF/web.xml b/freemarker-spring/src/test/resources/WEB-INF/web.xml
new file mode 100644
index 0000000..f091779
--- /dev/null
+++ b/freemarker-spring/src/test/resources/WEB-INF/web.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<web-app version="3.0">
+
+  <display-name>Test Web Application descriptor in Apache FreeMarker Spring Framework support module</display-name>
+  <description>Test Web Application descriptor in Apache FreeMarker Spring Framework support module</description>
+
+</web-app>


[04/16] incubator-freemarker git commit: FREEMARKER-55: Adding more tests regarding FreemarkerView's model

Posted by dd...@apache.org.
FREEMARKER-55: Adding more tests regarding FreemarkerView's model


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/36b0694f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/36b0694f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/36b0694f

Branch: refs/heads/3
Commit: 36b0694f335c319946f908729be95f1808f23b2a
Parents: 334d9cd
Author: Woonsan Ko <wo...@apache.org>
Authored: Thu Jun 29 00:41:17 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Thu Jun 29 00:41:17 2017 -0400

----------------------------------------------------------------------
 .../spring/web/view/FreemarkerView.java         |  7 +-
 .../spring/web/view/FreemarkerViewTest.java     | 73 ++++++++++++++++++--
 2 files changed, 68 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/36b0694f/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 c13a49f..21b2a60 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
@@ -22,7 +22,6 @@ import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
 
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.TemplateHashModel;
@@ -41,6 +40,7 @@ public class FreemarkerView extends AbstractFreemarkerView {
     private TaglibFactory taglibFactory;
 
     public ServletContextHashModel getServletContextModel() {
+        // TODO
         return servletContextModel;
     }
 
@@ -62,10 +62,7 @@ public class FreemarkerView extends AbstractFreemarkerView {
             HttpServletRequest request, HttpServletResponse response) {
         AllHttpScopesHashModel model = new AllHttpScopesHashModel(objectWrapperForModel, getServletContext(), request);
         model.putUnlistedModel(FreemarkerServlet.KEY_APPLICATION, getServletContextModel());
-        HttpSession session = request.getSession(false);
-        if (session != null) {
-            model.putUnlistedModel(FreemarkerServlet.KEY_SESSION, getHttpSessionModel(objectWrapperForModel, request, response));
-        }
+        model.putUnlistedModel(FreemarkerServlet.KEY_SESSION, getHttpSessionModel(objectWrapperForModel, request, response));
         model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST, new HttpRequestHashModel(request, response, objectWrapperForModel));
         model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST_PARAMETERS,
                 new HttpRequestParametersHashModel(request, objectWrapperForModel));

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/36b0694f/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
index 4d24632..0435004 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 
 import javax.servlet.ServletContext;
 
@@ -31,31 +32,36 @@ import org.junit.Before;
 import org.junit.Test;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockHttpSession;
 import org.springframework.mock.web.MockServletContext;
 
 public class FreemarkerViewTest {
 
     private ServletContext servletContext;
 
+    private StringTemplateLoader templateLoader;
+
     private Configuration configuration;
 
+    private AtomicLong visitorCount;
+
     @Before
     public void setUp() throws Exception {
         servletContext = new MockServletContext();
-
-        StringTemplateLoader templateLoader = new StringTemplateLoader();
-        templateLoader.putTemplate("hello.ftl", "Hello, ${name!\"World\"}! Visit count: ${visitCount!0}");
+        visitorCount = new AtomicLong();
+        servletContext.setAttribute("visitorCount", visitorCount);
+        templateLoader = new StringTemplateLoader();
         configuration = new Configuration.Builder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)
                 .templateLoader(templateLoader).build();
     }
 
     @Test
-    public void testViewRendering() throws Exception {
-        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myservlet/handler.do");
+    public void testViewWithBasicModel() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/mytest.do");
         request.setContextPath("/mycontext");
         request.setServletPath("/myservlet");
-        request.setPathInfo(";mypathinfo");
-        request.setQueryString("?param1=value1");
+
+        templateLoader.putTemplate("hello.ftl", "Hello, ${name!\"World\"}! Visit count: ${visitCount!0}");
 
         FreemarkerView view = new FreemarkerView();
         view.setServletContext(servletContext);
@@ -75,4 +81,57 @@ public class FreemarkerViewTest {
         view.render(model, request, response);
         assertEquals("Hello, Dan! Visit count: 1", response.getContentAsString());
     }
+
+    @Test
+    public void testViewWithDefaultServletModel() throws Exception {
+        MockHttpSession session = new MockHttpSession(servletContext);
+        session.setAttribute("itemCountInCart", 3);
+
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/mytest.do");
+        request.setContextPath("/mycontext");
+        request.setServletPath("/myservlet");
+        request.setPathInfo(";mypathinfo");
+        request.addParameter("token1", "value1");
+        request.setSession(session);
+        request.setAttribute("visitorCount", visitorCount);
+
+        // TODO: Add 'Application.attributeName' example, too.
+        templateLoader.putTemplate("default-model.ftl",
+                "${name!}, you have ${Session.itemCountInCart!0} items in cart. "
+                        + "BTW, you're ${Request.visitorCount}th visitor. "
+                        + "(token1: ${RequestParameters['token1']!})");
+
+        FreemarkerView view = new FreemarkerView();
+        view.setServletContext(servletContext);
+        view.setConfiguration(configuration);
+        view.setName("default-model.ftl");
+
+        Map<String, Object> model = new HashMap<String, Object>();
+        model.put("name", "Dan");
+
+        final long count = visitorCount.incrementAndGet();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        view.render(model, request, response);
+        assertEquals("Dan, you have 3 items in cart. BTW, you're " + count + "th visitor. (token1: value1)",
+                response.getContentAsString());
+    }
+
+    @Test
+    public void testViewWithTaglibs() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/mytest.do");
+        request.setContextPath("/mycontext");
+        request.setServletPath("/myservlet");
+
+        // TODO: 
+        templateLoader.putTemplate("taglibs.ftl", "");
+
+        FreemarkerView view = new FreemarkerView();
+        view.setServletContext(servletContext);
+        view.setConfiguration(configuration);
+        view.setName("taglibs.ftl");
+
+        Map<String, Object> model = new HashMap<String, Object>();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        view.render(model, request, response);
+    }
 }


[14/16] incubator-freemarker git commit: FREEMARKER-55: polising javadocs

Posted by dd...@apache.org.
FREEMARKER-55: polising javadocs


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/53d9ef94
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/53d9ef94
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/53d9ef94

Branch: refs/heads/3
Commit: 53d9ef941514945310f6df642faf558d996256bf
Parents: c5e9fe3
Author: Woonsan Ko <wo...@apache.org>
Authored: Tue Jul 4 00:13:26 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Tue Jul 4 00:13:26 2017 -0400

----------------------------------------------------------------------
 .../servlet/jsp/TaglibFactoryBuilder.java         | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/53d9ef94/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
index 6d4405d..34daec3 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
@@ -33,11 +33,29 @@ import org.apache.freemarker.servlet.jsp.TaglibFactory.ClearMetaInfTldSource;
 import org.apache.freemarker.servlet.jsp.TaglibFactory.MetaInfTldSource;
 import org.apache.freemarker.servlet.jsp.TaglibFactory.WebInfPerLibJarMetaInfTldSource;
 
+/**
+ * Builder for {@link TaglibFactory}.
+ */
 public class TaglibFactoryBuilder {
 
+    /**
+     * Servlet context.
+     */
     private final ServletContext servletContext;
+
+    /**
+     * Object wrapper to be used in model building.
+     */
     private final ObjectWrapper objectWrapper;
+
+    /**
+     * TLD locations to look for when finding available JSP tag libraries.
+     */
     private List<MetaInfTldSource> metaInfTldSources = new ArrayList<>();
+
+    /**
+     * TLD classpath locations to look for when finding available JSP tag libraries.
+     */
     private List<String> classPathTlds = new ArrayList<>();
 
     public TaglibFactoryBuilder(ServletContext servletContext, ObjectWrapper objectWrapper) {


[03/16] incubator-freemarker git commit: FREEMARKER-55: adding model building code.

Posted by dd...@apache.org.
FREEMARKER-55: adding model building code.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/334d9cde
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/334d9cde
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/334d9cde

Branch: refs/heads/3
Commit: 334d9cde950f06e480027d3064e53b6c1cfa54e2
Parents: ec2d37c
Author: Woonsan Ko <wo...@apache.org>
Authored: Wed Jun 28 23:36:49 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Wed Jun 28 23:36:49 2017 -0400

----------------------------------------------------------------------
 freemarker-spring/build.gradle                  |  2 +
 .../spring/web/view/AbstractFreemarkerView.java | 67 ++++++++++++++++++--
 .../spring/web/view/FreemarkerView.java         | 60 ++++++++++++++++++
 .../spring/web/view/FreemarkerViewTest.java     |  2 +-
 4 files changed, 123 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/334d9cde/freemarker-spring/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-spring/build.gradle b/freemarker-spring/build.gradle
index 60e03b2..1865cc2 100644
--- a/freemarker-spring/build.gradle
+++ b/freemarker-spring/build.gradle
@@ -25,7 +25,9 @@ published = true
 inAggregateJavadoc = true
 
 dependencies {
+
     compile project(":freemarker-core")
+    compile project(":freemarker-servlet")
 
     // TODO: what's difference between compileOnly and compile??
     compile "org.apache.geronimo.specs:geronimo-servlet_3.0_spec:1.0"

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/334d9cde/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
index a2a2e8b..595ada2 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
@@ -19,6 +19,8 @@
 package org.apache.freemarker.spring.web.view;
 
 import java.io.IOException;
+import java.io.Serializable;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
@@ -28,39 +30,90 @@ import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.ParseException;
 import org.apache.freemarker.core.Template;
 import org.apache.freemarker.core.TemplateNotFoundException;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
 import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
 import org.springframework.web.servlet.view.AbstractView;
 
 public abstract class AbstractFreemarkerView extends AbstractView {
 
     private Configuration configuration;
-    private String templateName;
+    private String name;
+    private Locale locale;
+    private Serializable customLookupCondition;
+    private boolean ignoreMissing;
 
     public Configuration getConfiguration() {
         return configuration;
     }
 
     public void setConfiguration(Configuration configuration) {
+        if (!(configuration.getObjectWrapper() instanceof ObjectWrapperAndUnwrapper)) {
+            throw new RuntimeException(AbstractFreemarkerView.class.getSimpleName() + " requires an ObjectWrapper that "
+                    + "implements " + ObjectWrapperAndUnwrapper.class.getName() + ", but this class doesn't do that: "
+                    + configuration.getObjectWrapper().getClass().getName());
+        }
+
         this.configuration = configuration;
     }
 
-    public String getTemplateName() {
-        return templateName;
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+
+    public Serializable getCustomLookupCondition() {
+        return customLookupCondition;
     }
 
-    public void setTemplateName(String templateName) {
-        this.templateName = templateName;
+    public void setCustomLookupCondition(Serializable customLookupCondition) {
+        this.customLookupCondition = customLookupCondition;
+    }
+
+    public boolean isIgnoreMissing() {
+        return ignoreMissing;
+    }
+
+    public void setIgnoreMissing(boolean ignoreMissing) {
+        this.ignoreMissing = ignoreMissing;
     }
 
     @Override
     protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
             HttpServletResponse response) throws Exception {
-        getTemplate().process(model, response.getWriter());
+        getTemplate().process(createModel(model, getObjectWrapperForModel(), request, response), response.getWriter());
     }
 
     protected Template getTemplate()
             throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
-        return getConfiguration().getTemplate(getTemplateName());
+        return getConfiguration().getTemplate(getName(), getLocale(), getCustomLookupCondition(), isIgnoreMissing());
+    }
+
+    protected ObjectWrapperAndUnwrapper getObjectWrapperForModel() {
+        ObjectWrapperAndUnwrapper wrapper;
+
+        if (configuration.isObjectWrapperSet()) {
+            wrapper = (ObjectWrapperAndUnwrapper) configuration.getObjectWrapper();
+        } else {
+            // TODO: need to cache this?
+            wrapper = new DefaultObjectWrapper.Builder(configuration.getIncompatibleImprovements()).build();
+        }
+
+        return wrapper;
     }
 
+    protected abstract TemplateHashModel createModel(Map<String, Object> map,
+            ObjectWrapperAndUnwrapper objectWrapperForModel, HttpServletRequest request, HttpServletResponse response);
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/334d9cde/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 da3ad09..c13a49f 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
@@ -18,6 +18,66 @@
  */
 package org.apache.freemarker.spring.web.view;
 
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.servlet.AllHttpScopesHashModel;
+import org.apache.freemarker.servlet.FreemarkerServlet;
+import org.apache.freemarker.servlet.HttpRequestHashModel;
+import org.apache.freemarker.servlet.HttpRequestParametersHashModel;
+import org.apache.freemarker.servlet.HttpSessionHashModel;
+import org.apache.freemarker.servlet.ServletContextHashModel;
+import org.apache.freemarker.servlet.jsp.TaglibFactory;
+
 public class FreemarkerView extends AbstractFreemarkerView {
 
+    private ServletContextHashModel servletContextModel;
+
+    private TaglibFactory taglibFactory;
+
+    public ServletContextHashModel getServletContextModel() {
+        return servletContextModel;
+    }
+
+    public void setServletContextModel(ServletContextHashModel servletContextModel) {
+        this.servletContextModel = servletContextModel;
+    }
+
+    public TaglibFactory getTaglibFactory() {
+        // TODO
+        return taglibFactory;
+    }
+
+    public void setTaglibFactory(TaglibFactory taglibFactory) {
+        this.taglibFactory = taglibFactory;
+    }
+
+    @Override
+    protected TemplateHashModel createModel(Map<String, Object> map, ObjectWrapperAndUnwrapper objectWrapperForModel,
+            HttpServletRequest request, HttpServletResponse response) {
+        AllHttpScopesHashModel model = new AllHttpScopesHashModel(objectWrapperForModel, getServletContext(), request);
+        model.putUnlistedModel(FreemarkerServlet.KEY_APPLICATION, getServletContextModel());
+        HttpSession session = request.getSession(false);
+        if (session != null) {
+            model.putUnlistedModel(FreemarkerServlet.KEY_SESSION, getHttpSessionModel(objectWrapperForModel, request, response));
+        }
+        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST, new HttpRequestHashModel(request, response, objectWrapperForModel));
+        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST_PARAMETERS,
+                new HttpRequestParametersHashModel(request, objectWrapperForModel));
+        model.putUnlistedModel(FreemarkerServlet.KEY_JSP_TAGLIBS, getTaglibFactory());
+        model.putAll(map);
+        return model;
+    }
+
+    protected HttpSessionHashModel getHttpSessionModel(ObjectWrapperAndUnwrapper objectWrapperForModel,
+            HttpServletRequest request, HttpServletResponse response) {
+        // TODO
+        HttpSessionHashModel sessionModel = new HttpSessionHashModel(null, request, response, objectWrapperForModel);
+        return sessionModel;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/334d9cde/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
index 64f50e0..4d24632 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -60,7 +60,7 @@ public class FreemarkerViewTest {
         FreemarkerView view = new FreemarkerView();
         view.setServletContext(servletContext);
         view.setConfiguration(configuration);
-        view.setTemplateName("hello.ftl");
+        view.setName("hello.ftl");
 
         int visitCount = 0;
         Map<String, Object> model = new HashMap<String, Object>();


[08/16] incubator-freemarker git commit: FREEMARKER-55: Adding FreemarkerViewResolver

Posted by dd...@apache.org.
FREEMARKER-55: Adding FreemarkerViewResolver


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/83e896c0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/83e896c0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/83e896c0

Branch: refs/heads/3
Commit: 83e896c01ebe2fd3fa5b0997f6ee177ccbeed2f5
Parents: c2589ee
Author: Woonsan Ko <wo...@apache.org>
Authored: Thu Jun 29 23:56:20 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Thu Jun 29 23:56:20 2017 -0400

----------------------------------------------------------------------
 .../spring/web/view/FreemarkerViewResolver.java | 40 ++++++++++++++++++++
 1 file changed, 40 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/83e896c0/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
new file mode 100644
index 0000000..6d7ab40
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
@@ -0,0 +1,40 @@
+/*
+ * 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.web.view;
+
+import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
+
+public class FreemarkerViewResolver extends AbstractTemplateViewResolver {
+
+    public FreemarkerViewResolver() {
+        setViewClass(requiredViewClass());
+    }
+
+    public FreemarkerViewResolver(String prefix, String suffix) {
+        this();
+        setPrefix(prefix);
+        setSuffix(suffix);
+    }
+
+    @Override
+    protected Class<?> requiredViewClass() {
+        return FreemarkerView.class;
+    }
+
+}


[13/16] incubator-freemarker git commit: polishing API and javadocs.

Posted by dd...@apache.org.
polishing API and javadocs.


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

Branch: refs/heads/3
Commit: c5e9fe30857c3175a777df62416caff283ed6fea
Parents: 6ff7849
Author: Woonsan Ko <wo...@apache.org>
Authored: Tue Jul 4 00:03:43 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Tue Jul 4 00:03:43 2017 -0400

----------------------------------------------------------------------
 .../spring/web/view/AbstractFreemarkerView.java | 107 +++++++++++++++----
 .../spring/web/view/FreemarkerView.java         |  56 +++++++++-
 .../spring/web/view/FreemarkerViewResolver.java |  98 +++++++++++------
 .../spring/web/view/PageContextServlet.java     |   5 +-
 .../web/view/PageContextServletConfig.java      |   6 +-
 5 files changed, 214 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5e9fe30/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
index cb13ac4..2996aa9 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/AbstractFreemarkerView.java
@@ -19,7 +19,6 @@
 package org.apache.freemarker.spring.web.view;
 
 import java.io.IOException;
-import java.io.Serializable;
 import java.util.Locale;
 import java.util.Map;
 
@@ -33,56 +32,103 @@ import org.apache.freemarker.core.TemplateNotFoundException;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContextException;
 import org.springframework.web.servlet.view.AbstractTemplateView;
 
+/**
+ * Adapter base class for FreeMarker template-based views, with the ability to access {@link Configuration}
+ * and {@link ObjectWrapperAndUnwrapper}.
+ */
 public abstract class AbstractFreemarkerView extends AbstractTemplateView {
 
+    private static Logger log = LoggerFactory.getLogger(AbstractFreemarkerView.class);
+
+    /**
+     * FreeMarker {@link Configuration} instance.
+     */
     private Configuration configuration;
+
+    /**
+     * {@link ObjectWrapperAndUnwrapper} instance to use in model building.
+     */
     private ObjectWrapperAndUnwrapper objectWrapper;
 
-    // TODO: how to determine locale, customLookupCondition and ignoreMissing? From viewResolver settings?
+    /**
+     * Template {@link Locale}.
+     */
     private Locale locale;
-    private Serializable customLookupCondition;
-    private boolean ignoreMissing;
 
+    /**
+     * Get FreeMarker {@link Configuration} instance.
+     * @return {@link Configuration} instance
+     */
     public Configuration getConfiguration() {
         return configuration;
     }
 
+    /**
+     * Set FreeMarker {@link Configuration} instance.
+     * @param configuration {@link Configuration} instance
+     */
     public void setConfiguration(Configuration configuration) {
         this.configuration = configuration;
     }
 
+    /**
+     * Get {@link ObjectWrapperAndUnwrapper} that is used in model building.
+     * @return {@link ObjectWrapperAndUnwrapper} that is used in model building
+     */
     public ObjectWrapperAndUnwrapper getObjectWrapper() {
         return objectWrapper;
     }
 
+    /**
+     * Set {@link ObjectWrapperAndUnwrapper} that is used in model building.
+     * @param objectWrapper {@link ObjectWrapperAndUnwrapper} that is used in model building
+     */
     public void setObjectWrapper(ObjectWrapperAndUnwrapper objectWrapper) {
         this.objectWrapper = objectWrapper;
     }
 
+    /**
+     * Get template locale.
+     * @return template locale
+     */
     public Locale getLocale() {
         return locale;
     }
 
+    /**
+     * Set template locale.
+     * @param locale template locale
+     */
     public void setLocale(Locale locale) {
         this.locale = locale;
     }
 
-    public Serializable getCustomLookupCondition() {
-        return customLookupCondition;
-    }
-
-    public void setCustomLookupCondition(Serializable customLookupCondition) {
-        this.customLookupCondition = customLookupCondition;
-    }
-
-    public boolean isIgnoreMissing() {
-        return ignoreMissing;
-    }
-
-    public void setIgnoreMissing(boolean ignoreMissing) {
-        this.ignoreMissing = ignoreMissing;
+    @Override
+    public boolean checkResource(Locale locale) throws Exception {
+        if (this.locale == null) {
+            this.locale = locale;
+        }
+
+        try {
+            // Check whether the underlying resource exists by trying to get the template.
+            getTemplate();
+            return true;
+        } catch (TemplateNotFoundException e) {
+            log.debug("No view found for URL: {}", getUrl());
+        } catch (MalformedTemplateNameException e) {
+            throw new ApplicationContextException("Malformed template name: " + getUrl(), e);
+        } catch (ParseException e) {
+            throw new ApplicationContextException("Template parsing exception: " + getUrl(), e);
+        } catch (IOException e) {
+            throw new ApplicationContextException("Template IO exception: " + getUrl(), e);
+        }
+
+        return false;
     }
 
     @Override
@@ -91,11 +137,34 @@ public abstract class AbstractFreemarkerView extends AbstractTemplateView {
         getTemplate().process(createModel(model, getObjectWrapper(), request, response), response.getWriter());
     }
 
+    /**
+     * Get template from the FreeMarker {@link Configuration} instance.
+     * @return template from the FreeMarker {@link Configuration} instance
+     * @throws TemplateNotFoundException if template is not found
+     * @throws MalformedTemplateNameException if template name is malformed
+     * @throws ParseException if the template is syntactically bad
+     * @throws IOException if template cannot be read due to IO error
+     */
     protected Template getTemplate()
             throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
-        return getConfiguration().getTemplate(getUrl(), getLocale(), getCustomLookupCondition(), isIgnoreMissing());
+        return getConfiguration().getTemplate(normalizeTemplateName(getUrl()), getLocale());
     }
 
+    /**
+     * Create model for the template.
+     * @param map map as initial source for the template model
+     * @param objectWrapperForModel ObjectWrapper to be used in model building
+     * @param request request
+     * @param response response
+     * @return model for the template
+     */
     protected abstract TemplateHashModel createModel(Map<String, Object> map,
             ObjectWrapperAndUnwrapper objectWrapperForModel, HttpServletRequest request, HttpServletResponse response);
+
+    private String normalizeTemplateName(String name) {
+        if (name != null) {
+            return (name.startsWith("/")) ? name.substring(1) : name;
+        }
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5e9fe30/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 2210b98..f3ac63b 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
@@ -20,6 +20,7 @@ package org.apache.freemarker.spring.web.view;
 
 import java.util.Map;
 
+import javax.servlet.GenericServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
@@ -34,32 +35,74 @@ import org.apache.freemarker.servlet.HttpSessionHashModel;
 import org.apache.freemarker.servlet.ServletContextHashModel;
 import org.apache.freemarker.servlet.jsp.TaglibFactory;
 
+/**
+ * FreeMarker template based view implementation, with being able to provide a {@link ServletContextHashModel}
+ * and {@link TaglibFactory} models to the templates.
+ */
 public class FreemarkerView extends AbstractFreemarkerView {
 
-    private PageContextServlet pageContextServlet;
+    /**
+     * Internal servlet instance to provide a page object in JSP tag library usages.
+     * @see {@link javax.servlet.jsp.PageContext#getPage()}
+     */
+    private GenericServlet pageContextServlet;
+
+    /**
+     * {@link ServletContextHashModel} instance for templates to access servlet context attributes.
+     */
     private ServletContextHashModel servletContextModel;
+
+    /**
+     * {@link TaglibFactory} instance for templates to be able to use JSP tag libraries.
+     */
     private TaglibFactory taglibFactory;
 
-    public PageContextServlet getPageContextServlet() {
+    /**
+     * Get {@link GenericServlet} instance which is a page object in JSP tag library usages.
+     * @return {@link GenericServlet} instance which is a page object in JSP tag library usages
+     */
+    public GenericServlet getPageContextServlet() {
         return pageContextServlet;
     }
 
-    public void setPageContextServlet(PageContextServlet pageContextServlet) {
+    /**
+     * Set {@link GenericServlet} instance which is a page object in JSP tag library usages.
+     * @param pageContextServlet {@link GenericServlet} instance which is a page object in JSP tag library
+     * usages
+     */
+    public void setPageContextServlet(GenericServlet pageContextServlet) {
         this.pageContextServlet = pageContextServlet;
     }
 
+    /**
+     * Get {@link ServletContextHashModel} instance by which templates can access servlet context attributes.
+     * @return {@link ServletContextHashModel} instance by which templates can access servlet context attributes
+     */
     public ServletContextHashModel getServletContextModel() {
         return servletContextModel;
     }
 
+    /**
+     * Set {@link ServletContextHashModel} instance by which templates can access servlet context attributes.
+     * @param servletContextModel {@link ServletContextHashModel} instance by which templates can access servlet
+     * context attributes
+     */
     public void setServletContextModel(ServletContextHashModel servletContextModel) {
         this.servletContextModel = servletContextModel;
     }
 
+    /**
+     * Get {@link TaglibFactory} instance by which templates can use JSP tag libraries.
+     * @return {@link TaglibFactory} instance by which templates can use JSP tag libraries.
+     */
     public TaglibFactory getTaglibFactory() {
         return taglibFactory;
     }
 
+    /**
+     * Set {@link TaglibFactory} instance by which templates can use JSP tag libraries.
+     * @param taglibFactory {@link TaglibFactory} instance by which templates can use JSP tag libraries.
+     */
     public void setTaglibFactory(TaglibFactory taglibFactory) {
         this.taglibFactory = taglibFactory;
     }
@@ -96,6 +139,13 @@ public class FreemarkerView extends AbstractFreemarkerView {
         return model;
     }
 
+    /**
+     * Get {@link HttpSessionHashModel} instance by which templates can access session attributes.
+     * @param objectWrapperForModel ObjectWrapper to be used in model building
+     * @param request request
+     * @param response response
+     * @return {@link HttpSessionHashModel} instance by which templates can access session attributes
+     */
     protected HttpSessionHashModel getHttpSessionModel(ObjectWrapperAndUnwrapper objectWrapperForModel,
             HttpServletRequest request, HttpServletResponse response) {
         HttpSessionHashModel sessionModel;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5e9fe30/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
index 5f7d6fb..57e6c4c 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreemarkerViewResolver.java
@@ -18,6 +18,7 @@
  */
 package org.apache.freemarker.spring.web.view;
 
+import javax.servlet.GenericServlet;
 import javax.servlet.ServletException;
 
 import org.apache.freemarker.core.Configuration;
@@ -29,50 +30,72 @@ import org.apache.freemarker.servlet.jsp.TaglibFactoryBuilder;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
 import org.springframework.web.servlet.view.AbstractUrlBasedView;
-
+import org.springframework.web.servlet.view.UrlBasedViewResolver;
+
+/**
+ * FreeMarker template view resolver implementation, extending {@link AbstractTemplateViewResolver} that extends
+ * {@link UrlBasedViewResolver}.
+ * <p>
+ * The FreeMarker {@link Configuration} property must be set at least. Otherwise this throws {@link IllegalStateException}
+ * during initialization. In the bean initialization phase, this retrieves {@link ObjectWrapperAndUnwrapper} from
+ * the {@link Configuration} and instantiate the internal page object ({@link PageContextServlet}) for JSP tag
+ * library usages, {@link ServletContextHashModel} property for servlet context attribute accesses and {@link TaglibFactory}
+ * property for JSP tag library usages.
+ * </p>
+ */
 public class FreemarkerViewResolver extends AbstractTemplateViewResolver implements InitializingBean {
 
+    /**
+     * FreeMarker {@link Configuration} instance.
+     */
     private Configuration configuration;
 
+    /**
+     * {@link ObjectWrapperAndUnwrapper} instance to be used in model building.
+     */
     private ObjectWrapperAndUnwrapper objectWrapper;
-    private PageContextServlet pageContextServlet;
+
+    /**
+     * Internal servlet instance to provide a page object in JSP tag library usages.
+     * @see {@link javax.servlet.jsp.PageContext#getPage()}
+     */
+    private GenericServlet pageContextServlet;
+
+    /**
+     * {@link ServletContextHashModel} instance for templates to access servlet context attributes.
+     */
     private ServletContextHashModel servletContextModel;
-    private TaglibFactory taglibFactory;
 
-    private String normalizedPrefix;
+    /**
+     * {@link TaglibFactory} instance for templates to be able to use JSP tag libraries.
+     */
+    private TaglibFactory taglibFactory;
 
+    /**
+     * Constructs view resolver.
+     */
     public FreemarkerViewResolver() {
-        setViewClass(requiredViewClass());
-    }
-
-    public FreemarkerViewResolver(String prefix, String suffix) {
-        this();
-        setPrefix(prefix);
-        setSuffix(suffix);
+        super();
+        setViewClass(FreemarkerView.class);
     }
 
+    /**
+     * Get FreeMarker {@link Configuration} instance.
+     * @return FreeMarker {@link Configuration} instance
+     */
     public Configuration getConfiguration() {
         return configuration;
     }
 
+    /**
+     * Set FreeMarker {@link Configuration} instance.
+     * @param configuration FreeMarker {@link Configuration} instance
+     */
     public void setConfiguration(Configuration configuration) {
         this.configuration = configuration;
     }
 
     @Override
-    public void setPrefix(String prefix) {
-        super.setPrefix(prefix);
-
-        final String prefixValue = getPrefix();
-
-        if (prefixValue.startsWith("/")) {
-            normalizedPrefix = prefixValue.substring(1);
-        } else {
-            normalizedPrefix = prefixValue;
-        }
-    }
-
-    @Override
     public void afterPropertiesSet() throws Exception {
         if (configuration == null) {
             throw new IllegalStateException("Configuration is not set.");
@@ -98,7 +121,7 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver impleme
 
         try {
             pageContextServlet
-                    .init(new PageContextServletConfig(getServletContext(), FreemarkerViewResolver.class.getName()));
+                    .init(new PageContextServletConfig(getServletContext(), PageContextServlet.class.getSimpleName()));
         } catch (ServletException e) {
             // never happens...
         }
@@ -116,13 +139,6 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver impleme
     @Override
     protected AbstractUrlBasedView buildView(String viewName) throws Exception {
         FreemarkerView view = (FreemarkerView) super.buildView(viewName);
-        final String url;
-        if (normalizedPrefix != null) {
-            url = normalizedPrefix + viewName + getSuffix();
-        } else {
-            url = viewName + getSuffix();
-        }
-        view.setUrl(url);
         view.setConfiguration(configuration);
         view.setObjectWrapper(objectWrapper);
         view.setPageContextServlet(pageContextServlet);
@@ -131,18 +147,34 @@ public class FreemarkerViewResolver extends AbstractTemplateViewResolver impleme
         return view;
     }
 
+    /**
+     * Get {@link ObjectWrapperAndUnwrapper} that is used in model building.
+     * @return {@link ObjectWrapperAndUnwrapper} that is used in model building
+     */
     protected ObjectWrapperAndUnwrapper getObjectWrapper() {
         return objectWrapper;
     }
 
-    protected PageContextServlet getPageContextServlet() {
+    /**
+     * Get {@link GenericServlet} instance which is a page object in JSP tag library usages.
+     * @return {@link GenericServlet} instance which is a page object in JSP tag library usages
+     */
+    protected GenericServlet getPageContextServlet() {
         return pageContextServlet;
     }
 
+    /**
+     * Get {@link ServletContextHashModel} instance by which templates can access servlet context attributes.
+     * @return {@link ServletContextHashModel} instance by which templates can access servlet context attributes
+     */
     protected ServletContextHashModel getServletContextModel() {
         return servletContextModel;
     }
 
+    /**
+     * Get {@link TaglibFactory} instance by which templates can use JSP tag libraries.
+     * @return {@link TaglibFactory} instance by which templates can use JSP tag libraries.
+     */
     protected TaglibFactory getTaglibFactory() {
         return taglibFactory;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5e9fe30/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
index 94b586b..d2b7868 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
@@ -26,10 +26,11 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
 /**
- * <code>GenericServlet</code> to support {@link javax.servlet.jsp.PageContext#getPage()} when JspTaglibs is used.
+ * A built-in internal servlet class to be used as page object in JSP tag libraries used in FreeMarker templates.
+ * @see {@link javax.servlet.jsp.PageContext#getPage()}
  */
 @SuppressWarnings("serial")
-class PageContextServlet extends GenericServlet {
+final class PageContextServlet extends GenericServlet {
 
     @Override
     public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5e9fe30/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
index 0d42ba4..de94649 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServletConfig.java
@@ -24,7 +24,11 @@ import java.util.Enumeration;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 
-class PageContextServletConfig implements ServletConfig {
+/**
+ * A built-in internal {@link ServletConfig} class used when initializing the page context servlet
+ * ({@link PageContextServlet}) internally.
+ */
+final class PageContextServletConfig implements ServletConfig {
 
     private ServletContext servletContext;
     private String servletName;


[02/16] incubator-freemarker git commit: Merge branch '3' into feature/FREEMARKER-55

Posted by dd...@apache.org.
Merge branch '3' into feature/FREEMARKER-55


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

Branch: refs/heads/3
Commit: ec2d37c6dbf19ec4aca839b9bea737e0881e0f02
Parents: 584b46b 2548f5c
Author: Woonsan Ko <wo...@apache.org>
Authored: Wed Jun 28 16:19:19 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Wed Jun 28 16:19:19 2017 -0400

----------------------------------------------------------------------
 FM3-CHANGE-LOG.txt                              |   6 +-
 .../freemarker/core/AttemptLoggingTest.java     | 100 +++++++++++++++++++
 .../freemarker/core/ConfigurationTest.java      |  32 +++++-
 .../core/TemplateConfigurationTest.java         |   1 +
 .../core/templatesuite/templates/boolean.ftl    |   4 +
 .../core/AttemptExceptionReporter.java          |  45 +++++++++
 .../apache/freemarker/core/Configuration.java   |  21 ++++
 .../org/apache/freemarker/core/Environment.java |  35 ++++---
 .../core/LoggingAttemptExceptionReporter.java   |  43 ++++++++
 .../core/MutableProcessingConfiguration.java    |  87 +++++++++++++++-
 .../core/ProcessingConfiguration.java           |  26 ++++-
 .../org/apache/freemarker/core/Template.java    |  14 ++-
 .../freemarker/core/TemplateConfiguration.java  |  27 ++++-
 freemarker-core/src/main/javacc/FTL.jj          |   2 +-
 14 files changed, 415 insertions(+), 28 deletions(-)
----------------------------------------------------------------------



[06/16] incubator-freemarker git commit: FREEMARKER-55: Add TaglibFactoryBuilder to reuse TaglibFactory creation logic

Posted by dd...@apache.org.
FREEMARKER-55: Add TaglibFactoryBuilder to reuse TaglibFactory creation logic


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

Branch: refs/heads/3
Commit: cb4fab3ae483d2fb645d296aff0ab94c78a8d4b9
Parents: 8e8c724
Author: Woonsan Ko <wo...@apache.org>
Authored: Thu Jun 29 23:30:47 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Thu Jun 29 23:30:47 2017 -0400

----------------------------------------------------------------------
 .../freemarker/servlet/FreemarkerServlet.java   | 170 +++++--------------
 .../servlet/HttpSessionHashModel.java           |  26 +--
 .../servlet/jsp/TaglibFactoryBuilder.java       | 149 ++++++++++++++++
 .../spring/web/view/FreemarkerView.java         | 112 +++++++++---
 .../spring/web/view/FreemarkerViewTest.java     |   1 -
 5 files changed, 295 insertions(+), 163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cb4fab3a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
index cbd2fd7..923f9d4 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
@@ -27,9 +27,9 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.GregorianCalendar;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.regex.Pattern;
@@ -65,10 +65,8 @@ import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
 import org.apache.freemarker.core.util._SecurityUtil;
 import org.apache.freemarker.core.util._StringUtil;
 import org.apache.freemarker.servlet.jsp.TaglibFactory;
-import org.apache.freemarker.servlet.jsp.TaglibFactory.ClasspathMetaInfTldSource;
-import org.apache.freemarker.servlet.jsp.TaglibFactory.ClearMetaInfTldSource;
 import org.apache.freemarker.servlet.jsp.TaglibFactory.MetaInfTldSource;
-import org.apache.freemarker.servlet.jsp.TaglibFactory.WebInfPerLibJarMetaInfTldSource;
+import org.apache.freemarker.servlet.jsp.TaglibFactoryBuilder;
 import org.slf4j.Logger;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -448,9 +446,9 @@ public class FreemarkerServlet extends HttpServlet {
 
     // Note these names start with dot, so they're essentially invisible from
     // a freemarker script.
-    private static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
-    private static final String ATTR_REQUEST_PARAMETERS_MODEL = ".freemarker.RequestParameters";
-    private static final String ATTR_SESSION_MODEL = ".freemarker.Session";
+    public static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
+    public static final String ATTR_REQUEST_PARAMETERS_MODEL = ".freemarker.RequestParameters";
+    public static final String ATTR_SESSION_MODEL = ".freemarker.Session";
     
     /** @deprecated We only keeps this attribute for backward compatibility, but actually aren't using it. */
     @Deprecated
@@ -642,7 +640,7 @@ public class FreemarkerServlet extends HttpServlet {
                 } else if (name.equals(INIT_PARAM_EXCEPTION_ON_MISSING_TEMPLATE)) {
                     exceptionOnMissingTemplate = _StringUtil.getYesNo(value);
                 } else if (name.equals(INIT_PARAM_META_INF_TLD_LOCATIONS)) {
-                    metaInfTldSources = parseAsMetaInfTldLocations(value);
+                    metaInfTldSources = TaglibFactoryBuilder.parseMetaInfTldLocations(InitParamParser.parseCommaSeparatedList(value));
                 } else if (name.equals(INIT_PARAM_CLASSPATH_TLDS)) {
                     List newClasspathTlds = new ArrayList();
                     if (classpathTlds != null) {
@@ -678,44 +676,6 @@ public class FreemarkerServlet extends HttpServlet {
         }
         LOG.debug("Using object wrapper {}", config.getObjectWrapper());
     }
-    
-    private List/*<MetaInfTldSource>*/ parseAsMetaInfTldLocations(String value) throws ParseException {
-        List/*<MetaInfTldSource>*/ metaInfTldSources = null;
-        
-        List/*<String>*/ values = InitParamParser.parseCommaSeparatedList(value);
-        for (Iterator it = values.iterator(); it.hasNext(); ) {
-            final String itemStr = (String) it.next();
-            final MetaInfTldSource metaInfTldSource;
-            if (itemStr.equals(META_INF_TLD_LOCATION_WEB_INF_PER_LIB_JARS)) {
-                metaInfTldSource = WebInfPerLibJarMetaInfTldSource.INSTANCE;
-            } else if (itemStr.startsWith(META_INF_TLD_LOCATION_CLASSPATH)) {
-                String itemRightSide = itemStr.substring(META_INF_TLD_LOCATION_CLASSPATH.length()).trim();
-                if (itemRightSide.length() == 0) {
-                    metaInfTldSource = new ClasspathMetaInfTldSource(Pattern.compile(".*", Pattern.DOTALL));
-                } else if (itemRightSide.startsWith(":")) {
-                    final String regexpStr = itemRightSide.substring(1).trim();
-                    if (regexpStr.length() == 0) {
-                        throw new ParseException("Empty regular expression after \""
-                                + META_INF_TLD_LOCATION_CLASSPATH + ":\"", -1);
-                    }
-                    metaInfTldSource = new ClasspathMetaInfTldSource(Pattern.compile(regexpStr));   
-                } else {
-                    throw new ParseException("Invalid \"" + META_INF_TLD_LOCATION_CLASSPATH
-                            + "\" value syntax: " + value, -1);
-                }
-            } else if (itemStr.startsWith(META_INF_TLD_LOCATION_CLEAR)) {
-                metaInfTldSource = ClearMetaInfTldSource.INSTANCE;
-            } else {
-                throw new ParseException("Item has no recognized source type prefix: " + itemStr, -1);
-            }
-            if (metaInfTldSources == null) {
-                metaInfTldSources = new ArrayList();
-            }
-            metaInfTldSources.add(metaInfTldSource);
-        }
-        
-        return metaInfTldSources;
-    }
 
     /**
      * Create the template loader. The default implementation will create a {@link ClassTemplateLoader} if the template
@@ -1000,8 +960,8 @@ public class FreemarkerServlet extends HttpServlet {
                 sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL);
                 if (sessionModel == null || sessionModel.isOrphaned(session)) {
                     sessionModel = new HttpSessionHashModel(session, objectWrapper);
-                    initializeSessionAndInstallModel(request, response, 
-                            sessionModel, session);
+                    session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
+                    initializeSession(request, response);
                 }
             } else {
                 sessionModel = new HttpSessionHashModel(this, request, response, objectWrapper);
@@ -1040,73 +1000,47 @@ public class FreemarkerServlet extends HttpServlet {
      * The default implementation configures it based on the servlet-init parameters and various other environmental
      * settings, so if you override this method, you should call super, then adjust the result.
      */
-    protected TaglibFactory createTaglibFactory(ObjectWrapper objectWrapper,
-            ServletContext servletContext) throws TemplateModelException {
-        TaglibFactory taglibFactory = new TaglibFactory(servletContext);
-        
-        taglibFactory.setObjectWrapper(objectWrapper);
-        
-        {
-            List/*<MetaInfTldSource>*/ mergedMetaInfTldSources = new ArrayList();
+    @SuppressWarnings("unchecked")
+    protected TaglibFactory createTaglibFactory(ObjectWrapper objectWrapper, ServletContext servletContext)
+            throws TemplateModelException {
 
-            if (metaInfTldSources != null) {
-                mergedMetaInfTldSources.addAll(metaInfTldSources);
-            }
-            
-            String sysPropVal = _SecurityUtil.getSystemProperty(SYSTEM_PROPERTY_META_INF_TLD_SOURCES, null);
-            if (sysPropVal != null) {
-                try {
-                    List metaInfTldSourcesSysProp = parseAsMetaInfTldLocations(sysPropVal);
-                    if (metaInfTldSourcesSysProp != null) {
-                        mergedMetaInfTldSources.addAll(metaInfTldSourcesSysProp);
-                    }
-                } catch (ParseException e) {
-                    throw new TemplateModelException("Failed to parse system property \""
-                            + SYSTEM_PROPERTY_META_INF_TLD_SOURCES + "\"", e);
-                }
-            }
+        List<MetaInfTldSource> metaInfTldSourcesFromSysProp = null;
+        try {
+            final String prop = _SecurityUtil.getSystemProperty(SYSTEM_PROPERTY_META_INF_TLD_SOURCES, null);
+            metaInfTldSourcesFromSysProp = (List<MetaInfTldSource>) ((prop != null)
+                    ? TaglibFactoryBuilder.parseMetaInfTldLocations(InitParamParser.parseCommaSeparatedList(prop))
+                    : Collections.emptyList());
+        } catch (ParseException e) {
+            throw new TemplateModelException(
+                    "Failed to parse system property \"" + SYSTEM_PROPERTY_META_INF_TLD_SOURCES + "\"", e);
+        }
 
-            List/*<Pattern>*/ jettyTaglibJarPatterns = null;
-            try {
-                final String attrVal = (String) servletContext.getAttribute(ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS);
-                jettyTaglibJarPatterns = attrVal != null ? InitParamParser.parseCommaSeparatedPatterns(attrVal) : null;
-            } catch (Exception e) {
-                LOG.error("Failed to parse application context attribute \""
-                        + ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS + "\" - it will be ignored", e);
-            }
-            if (jettyTaglibJarPatterns != null) {
-                for (Iterator/*<Pattern>*/ it = jettyTaglibJarPatterns.iterator(); it.hasNext(); ) {
-                    Pattern pattern = (Pattern) it.next();
-                    mergedMetaInfTldSources.add(new ClasspathMetaInfTldSource(pattern));
-                }
-            }
-            
-            taglibFactory.setMetaInfTldSources(mergedMetaInfTldSources);
+        List<Pattern> jettyTaglibJarPatterns = null;
+        try {
+            final String attrVal = (String) servletContext.getAttribute(ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS);
+            jettyTaglibJarPatterns = (attrVal != null) ? InitParamParser.parseCommaSeparatedPatterns(attrVal)
+                    : Collections.emptyList();
+        } catch (Exception e) {
+            LOG.error("Failed to parse application context attribute \"" + ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS
+                    + "\" - it will be ignored", e);
         }
-        
-        {
-            List/*<String>*/ mergedClassPathTlds = new ArrayList();
-            if (classpathTlds != null) {
-                mergedClassPathTlds.addAll(classpathTlds);
-            }
-            
-            String sysPropVal = _SecurityUtil.getSystemProperty(SYSTEM_PROPERTY_CLASSPATH_TLDS, null);
-            if (sysPropVal != null) {
-                try {
-                    List/*<String>*/ classpathTldsSysProp = InitParamParser.parseCommaSeparatedList(sysPropVal);
-                    if (classpathTldsSysProp != null) {
-                        mergedClassPathTlds.addAll(classpathTldsSysProp);
-                    }
-                } catch (ParseException e) {
-                    throw new TemplateModelException("Failed to parse system property \""
-                            + SYSTEM_PROPERTY_CLASSPATH_TLDS + "\"", e);
-                }
-            }
-            
-            taglibFactory.setClasspathTlds(mergedClassPathTlds);
+
+        List<String> classpathTldsFromSysProp = null;
+        try {
+            final String prop = _SecurityUtil.getSystemProperty(SYSTEM_PROPERTY_CLASSPATH_TLDS, null);
+            classpathTldsFromSysProp = (prop != null) ? InitParamParser.parseCommaSeparatedList(prop)
+                    : Collections.emptyList();
+        } catch (ParseException e) {
+            throw new TemplateModelException(
+                    "Failed to parse system property \"" + SYSTEM_PROPERTY_CLASSPATH_TLDS + "\"", e);
         }
-        
-        return taglibFactory;        
+
+        return new TaglibFactoryBuilder(servletContext, objectWrapper)
+                .addAllMetaInfTldSources(metaInfTldSources)
+                .addAllMetaInfTldSources(metaInfTldSourcesFromSysProp)
+                .addAllJettyMetaInfTldJarPatterns(jettyTaglibJarPatterns)
+                .addAllClasspathTlds(classpathTlds)
+                .addAllClasspathTlds(classpathTldsFromSysProp).build();
     }
 
     /**
@@ -1134,14 +1068,6 @@ public class FreemarkerServlet extends HttpServlet {
     protected List/*<MetaInfTldSource>*/ createDefaultMetaInfTldSources() {
         return TaglibFactory.DEFAULT_META_INF_TLD_SOURCES;
     }
-    
-    void initializeSessionAndInstallModel(HttpServletRequest request,
-            HttpServletResponse response, HttpSessionHashModel sessionModel, 
-            HttpSession session)
-            throws ServletException, IOException {
-        session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
-        initializeSession(request, response);
-    }
 
     /**
      * Maps the request URL to a template path (template name) that is passed to
@@ -1279,10 +1205,8 @@ public class FreemarkerServlet extends HttpServlet {
      * @param request the actual HTTP request
      * @param response the actual HTTP response
      */
-    protected void initializeSession(
-        HttpServletRequest request,
-        HttpServletResponse response)
-        throws ServletException, IOException {
+    protected void initializeSession(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cb4fab3a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpSessionHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpSessionHashModel.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpSessionHashModel.java
index 216fd94..469dc29 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpSessionHashModel.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpSessionHashModel.java
@@ -21,6 +21,7 @@ package org.apache.freemarker.servlet;
 
 import java.io.Serializable;
 
+import javax.servlet.GenericServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
@@ -40,7 +41,7 @@ public final class HttpSessionHashModel implements TemplateHashModel, Serializab
     private transient final ObjectWrapper wrapper;
 
     // These are required for lazy initializing session
-    private transient final FreemarkerServlet servlet;
+    private transient final GenericServlet servlet;
     private transient final HttpServletRequest request;
     private transient final HttpServletResponse response;
     
@@ -62,16 +63,15 @@ public final class HttpSessionHashModel implements TemplateHashModel, Serializab
      * Use this constructor when the session isn't already created. It is passed
      * enough parameters so that the session can be properly initialized after
      * it's detected that it was created.
-     * @param servlet the FreemarkerServlet that created this model. If the
-     * model is not created through FreemarkerServlet, leave this argument as
-     * null.
+     * @param servlet the servlet (e.g, FreemarkerServlet) that created this model. If the
+     * model is not created through FreemarkerServlet, this argument can be left as null.
      * @param request the actual request
      * @param response the actual response
      * @param wrapper an object wrapper used to wrap session attributes
      */
-    public HttpSessionHashModel(FreemarkerServlet servlet, HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper) {
+    public HttpSessionHashModel(GenericServlet servlet, HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper) {
         this.wrapper = wrapper;
-        
+
         this.servlet = servlet;
         this.request = request;
         this.response = response;
@@ -88,8 +88,11 @@ public final class HttpSessionHashModel implements TemplateHashModel, Serializab
             session = request.getSession(false);
             if (session != null && servlet != null) {
                 try {
-                    servlet.initializeSessionAndInstallModel(request, response, 
-                            this, session);
+                    session.setAttribute(FreemarkerServlet.ATTR_SESSION_MODEL, this);
+
+                    if (servlet instanceof FreemarkerServlet) {
+                        ((FreemarkerServlet) servlet).initializeSession(request, response);
+                    }
                 } catch (RuntimeException e) {
                     throw e;
                 } catch (Exception e) {
@@ -99,14 +102,13 @@ public final class HttpSessionHashModel implements TemplateHashModel, Serializab
         }
     }
 
-    boolean isOrphaned(HttpSession currentSession) {
+    public boolean isOrphaned(HttpSession currentSession) {
         return (session != null && session != currentSession) || 
             (session == null && request == null);
     }
-    
+
     @Override
-    public boolean isEmpty()
-    throws TemplateModelException {
+    public boolean isEmpty() throws TemplateModelException {
         checkSessionExistence();
         return session == null || !session.getAttributeNames().hasMoreElements();
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cb4fab3a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
new file mode 100644
index 0000000..6d4405d
--- /dev/null
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactoryBuilder.java
@@ -0,0 +1,149 @@
+/*
+ * 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.servlet.jsp;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletContext;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.servlet.FreemarkerServlet;
+import org.apache.freemarker.servlet.jsp.TaglibFactory.ClasspathMetaInfTldSource;
+import org.apache.freemarker.servlet.jsp.TaglibFactory.ClearMetaInfTldSource;
+import org.apache.freemarker.servlet.jsp.TaglibFactory.MetaInfTldSource;
+import org.apache.freemarker.servlet.jsp.TaglibFactory.WebInfPerLibJarMetaInfTldSource;
+
+public class TaglibFactoryBuilder {
+
+    private final ServletContext servletContext;
+    private final ObjectWrapper objectWrapper;
+    private List<MetaInfTldSource> metaInfTldSources = new ArrayList<>();
+    private List<String> classPathTlds = new ArrayList<>();
+
+    public TaglibFactoryBuilder(ServletContext servletContext, ObjectWrapper objectWrapper) {
+        this.servletContext = servletContext;
+        this.objectWrapper = objectWrapper;
+    }
+
+    public TaglibFactoryBuilder addMetaInfTldSource(MetaInfTldSource metaInfTldSource) {
+        metaInfTldSources.add(metaInfTldSource);
+        return this;
+    }
+
+    public TaglibFactoryBuilder addAllMetaInfTldSources(List<MetaInfTldSource> metaInfTldSources) {
+        this.metaInfTldSources.addAll(metaInfTldSources);
+        return this;
+    }
+
+    public TaglibFactoryBuilder addMetaInfTldLocation(String metaInfTldLocation) throws ParseException {
+        return addMetaInfTldSource(parseMetaInfTldLocation(metaInfTldLocation));
+    }
+
+    public TaglibFactoryBuilder addMetaInfTldLocations(List<String> metaInfTldLocations) throws ParseException {
+        return addAllMetaInfTldSources(parseMetaInfTldLocations(metaInfTldLocations));
+    }
+
+    public TaglibFactoryBuilder addJettyMetaInfTldJarPattern(Pattern pattern) {
+        return addMetaInfTldSource(new ClasspathMetaInfTldSource(pattern));
+    }
+
+    public TaglibFactoryBuilder addAllJettyMetaInfTldJarPatterns(List<Pattern> patterns) {
+        for (Pattern pattern : patterns) {
+            addJettyMetaInfTldJarPattern(pattern);
+        }
+
+        return this;
+    }
+
+    public TaglibFactoryBuilder addClasspathTld(String classpathTld) {
+        classPathTlds.add(classpathTld);
+        return this;
+    }
+
+    public TaglibFactoryBuilder addAllClasspathTlds(List<String> classpathTlds) {
+        classPathTlds.addAll(classpathTlds);
+        return this;
+    }
+
+    public TaglibFactory build() {
+        TaglibFactory taglibFactory = new TaglibFactory(servletContext);
+        taglibFactory.setObjectWrapper(objectWrapper);
+        taglibFactory.setMetaInfTldSources(metaInfTldSources);
+        taglibFactory.setClasspathTlds(classPathTlds);
+        return taglibFactory;
+    }
+
+    public static MetaInfTldSource parseMetaInfTldLocation(String value) throws ParseException {
+        MetaInfTldSource metaInfTldSource;
+
+        if (value.equals(FreemarkerServlet.META_INF_TLD_LOCATION_WEB_INF_PER_LIB_JARS)) {
+            metaInfTldSource = WebInfPerLibJarMetaInfTldSource.INSTANCE;
+        } else if (value.startsWith(FreemarkerServlet.META_INF_TLD_LOCATION_CLASSPATH)) {
+            String itemRightSide = value.substring(FreemarkerServlet.META_INF_TLD_LOCATION_CLASSPATH.length())
+                    .trim();
+
+            if (itemRightSide.length() == 0) {
+                metaInfTldSource = new ClasspathMetaInfTldSource(Pattern.compile(".*", Pattern.DOTALL));
+            } else if (itemRightSide.startsWith(":")) {
+                final String regexpStr = itemRightSide.substring(1).trim();
+                if (regexpStr.length() == 0) {
+                    throw new ParseException("Empty regular expression after \""
+                            + FreemarkerServlet.META_INF_TLD_LOCATION_CLASSPATH + ":\"", -1);
+                }
+                metaInfTldSource = new ClasspathMetaInfTldSource(Pattern.compile(regexpStr));
+            } else {
+                throw new ParseException("Invalid \"" + FreemarkerServlet.META_INF_TLD_LOCATION_CLASSPATH
+                        + "\" value syntax: " + value, -1);
+            }
+        } else if (value.startsWith(FreemarkerServlet.META_INF_TLD_LOCATION_CLEAR)) {
+            metaInfTldSource = ClearMetaInfTldSource.INSTANCE;
+        } else {
+            throw new ParseException("Item has no recognized source type prefix: " + value, -1);
+        }
+
+        return metaInfTldSource;
+    }
+
+    public static List<MetaInfTldSource> parseMetaInfTldLocations(List<String> values) throws ParseException {
+        List<MetaInfTldSource> metaInfTldSources = null;
+
+        if (values != null) {
+            for (String value : values) {
+                final MetaInfTldSource metaInfTldSource = parseMetaInfTldLocation(value);
+
+                if (metaInfTldSources == null) {
+                    metaInfTldSources = new ArrayList();
+                }
+
+                metaInfTldSources.add(metaInfTldSource);
+            }
+        }
+
+        if (metaInfTldSources == null) {
+            metaInfTldSources = Collections.emptyList();
+        }
+
+        return metaInfTldSources;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cb4fab3a/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 934a458..64b3158 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
@@ -31,6 +31,7 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
 
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.TemplateHashModel;
@@ -41,31 +42,38 @@ import org.apache.freemarker.servlet.HttpRequestParametersHashModel;
 import org.apache.freemarker.servlet.HttpSessionHashModel;
 import org.apache.freemarker.servlet.ServletContextHashModel;
 import org.apache.freemarker.servlet.jsp.TaglibFactory;
+import org.apache.freemarker.servlet.jsp.TaglibFactoryBuilder;
 
 public class FreemarkerView extends AbstractFreemarkerView {
 
-    private PageContextServletConfig pageContextServletConfig;
+    private volatile PageContextServlet pageContextServlet;
 
-    private PageContextServlet pageContextServlet;
+    private volatile ServletContextHashModel servletContextModel;
 
-    private ServletContextHashModel servletContextModel;
-
-    private TaglibFactory taglibFactory;
+    private volatile TaglibFactory taglibFactory;
 
     public PageContextServlet getPageContextServlet() {
-        // TODO: proper locking...
-        if (pageContextServlet == null) {
-            pageContextServlet = new PageContextServlet();
-            pageContextServletConfig = new PageContextServletConfig(getServletContext(), getBeanName());
-
-            try {
-                pageContextServlet.init(pageContextServletConfig);
-            } catch (ServletException e) {
-                // never happen
+        PageContextServlet servlet = pageContextServlet;
+
+        if (servlet == null) {
+            synchronized (this) {
+                servlet = pageContextServlet;
+
+                if (servlet == null) {
+                    servlet = new PageContextServlet();
+
+                    try {
+                        servlet.init(new PageContextServletConfig(getServletContext(), getBeanName()));
+                    } catch (ServletException e) {
+                        // never happens...
+                    }
+
+                    pageContextServlet = servlet;
+                }
             }
         }
 
-        return pageContextServlet;
+        return servlet;
     }
 
     public void setPageContextServlet(PageContextServlet pageContextServlet) {
@@ -73,12 +81,20 @@ public class FreemarkerView extends AbstractFreemarkerView {
     }
 
     public ServletContextHashModel getServletContextModel() {
-        // TODO: proper locking...
-        if (servletContextModel == null) {
-            servletContextModel = new ServletContextHashModel(getPageContextServlet(), getObjectWrapperForModel());
+        ServletContextHashModel contextModel = servletContextModel;
+
+        if (contextModel == null) {
+            synchronized (this) {
+                contextModel = servletContextModel;
+
+                if (contextModel == null) {
+                    contextModel = new ServletContextHashModel(getPageContextServlet(), getObjectWrapperForModel());
+                    servletContextModel = contextModel;
+                }
+            }
         }
 
-        return servletContextModel;
+        return contextModel;
     }
 
     public void setServletContextModel(ServletContextHashModel servletContextModel) {
@@ -86,8 +102,22 @@ public class FreemarkerView extends AbstractFreemarkerView {
     }
 
     public TaglibFactory getTaglibFactory() {
-        // TODO
-        return taglibFactory;
+        TaglibFactory tlFactory = taglibFactory;
+
+        if (tlFactory == null) {
+            synchronized (this) {
+                tlFactory = taglibFactory;
+
+                if (tlFactory == null) {
+                    tlFactory = new TaglibFactoryBuilder(getServletContext(), getObjectWrapperForModel())
+                            .build();
+
+                    taglibFactory = tlFactory;
+                }
+            }
+        }
+
+        return tlFactory;
     }
 
     public void setTaglibFactory(TaglibFactory taglibFactory) {
@@ -97,23 +127,51 @@ public class FreemarkerView extends AbstractFreemarkerView {
     @Override
     protected TemplateHashModel createModel(Map<String, Object> map, ObjectWrapperAndUnwrapper objectWrapperForModel,
             HttpServletRequest request, HttpServletResponse response) {
+
         AllHttpScopesHashModel model = new AllHttpScopesHashModel(objectWrapperForModel, getServletContext(), request);
+
         model.putUnlistedModel(FreemarkerServlet.KEY_APPLICATION, getServletContextModel());
+
         model.putUnlistedModel(FreemarkerServlet.KEY_SESSION,
                 getHttpSessionModel(objectWrapperForModel, request, response));
-        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST,
-                new HttpRequestHashModel(request, response, objectWrapperForModel));
-        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST_PARAMETERS,
-                new HttpRequestParametersHashModel(request, objectWrapperForModel));
+
+        HttpRequestHashModel requestModel = (HttpRequestHashModel) request
+                .getAttribute(FreemarkerServlet.ATTR_REQUEST_MODEL);
+        HttpRequestParametersHashModel requestParametersModel = (HttpRequestParametersHashModel) request
+                .getAttribute(FreemarkerServlet.ATTR_REQUEST_PARAMETERS_MODEL);
+
+        if (requestModel == null || requestModel.getRequest() != request) {
+            requestModel = new HttpRequestHashModel(request, response, objectWrapperForModel);
+            request.setAttribute(FreemarkerServlet.ATTR_REQUEST_MODEL, requestModel);
+            requestParametersModel = new HttpRequestParametersHashModel(request, objectWrapperForModel);
+        }
+
+        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST, requestModel);
+        model.putUnlistedModel(FreemarkerServlet.KEY_REQUEST_PARAMETERS, requestParametersModel);
+
         model.putUnlistedModel(FreemarkerServlet.KEY_JSP_TAGLIBS, getTaglibFactory());
+
         model.putAll(map);
+
         return model;
     }
 
     protected HttpSessionHashModel getHttpSessionModel(ObjectWrapperAndUnwrapper objectWrapperForModel,
             HttpServletRequest request, HttpServletResponse response) {
-        // TODO
-        HttpSessionHashModel sessionModel = new HttpSessionHashModel(null, request, response, objectWrapperForModel);
+        HttpSessionHashModel sessionModel;
+        HttpSession session = request.getSession(false);
+
+        if (session != null) {
+            sessionModel = (HttpSessionHashModel) session.getAttribute(FreemarkerServlet.ATTR_SESSION_MODEL);
+
+            if (sessionModel == null || sessionModel.isOrphaned(session)) {
+                sessionModel = new HttpSessionHashModel(session, objectWrapperForModel);
+                session.setAttribute(FreemarkerServlet.ATTR_SESSION_MODEL, sessionModel);
+            }
+        } else {
+            sessionModel = new HttpSessionHashModel(getPageContextServlet(), request, response, objectWrapperForModel);
+        }
+
         return sessionModel;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cb4fab3a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
index 4f21e58..80fc2b3 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/web/view/FreemarkerViewTest.java
@@ -95,7 +95,6 @@ public class FreemarkerViewTest {
         request.setSession(session);
         request.setAttribute("promotion", "Fresh blue berries");
 
-        // TODO: Add 'Application.attributeName' example, too.
         templateLoader.putTemplate("default-model.ftl",
                 "${name!}, you have ${Session.itemCountInCart!0} items in cart. " + "Hot deal: ${Request.promotion}. "
                         + "BTW, you're ${Application.visitorCount}th visitor. "


[15/16] incubator-freemarker git commit: FREEMARKER-55: Merged: Freemarker View and ViewResolver implementation

Posted by dd...@apache.org.
FREEMARKER-55: Merged: Freemarker View and ViewResolver implementation

Merge commit 'refs/pull/25/head' of https://github.com/apache/incubator-freemarker into 3


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/09785b68
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/09785b68
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/09785b68

Branch: refs/heads/3
Commit: 09785b68234074f1623778d360829e3ee2f95b32
Parents: 1907182 53d9ef9
Author: ddekany <dd...@apache.org>
Authored: Tue Jul 4 09:27:26 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Jul 4 09:30:45 2017 +0200

----------------------------------------------------------------------
 .../freemarker/servlet/FreemarkerServlet.java   | 170 +++++------------
 .../servlet/HttpSessionHashModel.java           |  26 +--
 .../servlet/jsp/TaglibFactoryBuilder.java       | 167 +++++++++++++++++
 freemarker-spring/build.gradle                  |  41 ++++-
 .../spring/web/view/AbstractFreemarkerView.java | 170 +++++++++++++++++
 .../spring/web/view/FreemarkerView.java         | 168 +++++++++++++++++
 .../spring/web/view/FreemarkerViewResolver.java | 182 +++++++++++++++++++
 .../spring/web/view/PageContextServlet.java     |  40 ++++
 .../web/view/PageContextServletConfig.java      |  60 ++++++
 .../freemarker/spring/web/view/EchoTag.java     |  55 ++++++
 .../web/view/FreemarkerViewResolverTest.java    |  98 ++++++++++
 .../spring/web/view/FreemarkerViewTest.java     | 163 +++++++++++++++++
 .../src/test/resources/WEB-INF/echo.tld         |  46 +++++
 .../src/test/resources/WEB-INF/web.xml          |  23 +++
 14 files changed, 1267 insertions(+), 142 deletions(-)
----------------------------------------------------------------------



[12/16] incubator-freemarker git commit: Merge branch '3' into feature/FREEMARKER-55

Posted by dd...@apache.org.
Merge branch '3' into feature/FREEMARKER-55


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/6ff7849b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/6ff7849b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/6ff7849b

Branch: refs/heads/3
Commit: 6ff7849be9bc71ee6fe81f4db6ab3530d7c8296e
Parents: 4088f91 1907182
Author: Woonsan Ko <wo...@apache.org>
Authored: Mon Jul 3 22:23:05 2017 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Mon Jul 3 22:23:05 2017 -0400

----------------------------------------------------------------------
 FM3-CHANGE-LOG.txt                              |   9 +-
 .../core/FM2ASTToFM3SourceConverter.java        | 674 ++++++++++++++-----
 .../freemarker/converter/FM2ToFM3Converter.java |  13 +-
 .../converter/FM2ToFM3ConverterTest.java        | 102 ++-
 .../freemarker/core/util/FTLUtilTest.java       |  10 +
 .../freemarker/core/ast-strlitinterpolation.ast |   2 +-
 .../core/templatesuite/templates/recover.ftl    |   8 +-
 .../apache/freemarker/core/util/FTLUtil.java    |  38 +-
 freemarker-core/src/main/javacc/FTL.jj          |   6 +-
 9 files changed, 661 insertions(+), 201 deletions(-)
----------------------------------------------------------------------



[16/16] incubator-freemarker git commit: (JavaDoc syntax fix)

Posted by dd...@apache.org.
(JavaDoc syntax fix)


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

Branch: refs/heads/3
Commit: b230056e7bc12cc356e550e2944b23b05bb98e1f
Parents: 09785b6
Author: ddekany <dd...@apache.org>
Authored: Tue Jul 4 09:43:49 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Jul 4 09:43:49 2017 +0200

----------------------------------------------------------------------
 .../org/apache/freemarker/spring/web/view/PageContextServlet.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b230056e/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
index d2b7868..7b8e923 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/PageContextServlet.java
@@ -27,7 +27,8 @@ import javax.servlet.ServletResponse;
 
 /**
  * A built-in internal servlet class to be used as page object in JSP tag libraries used in FreeMarker templates.
- * @see {@link javax.servlet.jsp.PageContext#getPage()}
+ *
+ * @see javax.servlet.jsp.PageContext#getPage()
  */
 @SuppressWarnings("serial")
 final class PageContextServlet extends GenericServlet {