svn commit: r835248 [1/2] - in /struts/struts2/trunk: apps/showcase/src/main/resources/ apps/showcase/src/main/webapp/WEB-INF/ core/src/main/java/org/apache/struts2/dispatcher/ng/listener/ core/src/main/java/org/apache/struts2/views/freemarker/ core/sr...

View: New views
1 Messages — Rating Filter:   Alert me  

svn commit: r835248 [1/2] - in /struts/struts2/trunk: apps/showcase/src/main/resources/ apps/showcase/src/main/webapp/WEB-INF/ core/src/main/java/org/apache/struts2/dispatcher/ng/listener/ core/src/main/java/org/apache/struts2/views/freemarker/ core/sr...

by musachy-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Author: musachy
Date: Thu Nov 12 06:06:40 2009
New Revision: 835248

URL: http://svn.apache.org/viewvc?rev=835248&view=rev
Log:
WW-3291 Update sitemesh-plugin to use version 2.4.2 patch provided by Christian Wolfgang Stone

Added:
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerMapper2DecoratorSelector.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsDecorator.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsFreemarkerDecorator.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityMapper2DecoratorSelector.java
Modified:
    struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml
    struts/struts2/trunk/apps/showcase/src/main/webapp/WEB-INF/web.xml
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/listener/StrutsListener.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerManager.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerPageFilter.java
    struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityPageFilter.java

Modified: struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml (original)
+++ struts/struts2/trunk/apps/showcase/src/main/resources/struts.xml Thu Nov 12 06:06:40 2009
@@ -19,6 +19,8 @@
     <constant name="struts.serve.static" value="true" />
     <constant name="struts.serve.static.browserCache" value="false" />
 
+    <constant name="actionPackages" value="org.apache.struts2.showcase.person"/>
+
     <include file="struts-chat.xml" />
     
     <include file="struts-interactive.xml" />

Modified: struts/struts2/trunk/apps/showcase/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/apps/showcase/src/main/webapp/WEB-INF/web.xml?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/apps/showcase/src/main/webapp/WEB-INF/web.xml (original)
+++ struts/struts2/trunk/apps/showcase/src/main/webapp/WEB-INF/web.xml Thu Nov 12 06:06:40 2009
@@ -20,10 +20,11 @@
         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
     </filter>
 
-    <filter>
-        <filter-name>sitemesh</filter-name>
-        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
-    </filter>
+
+   <filter>
+       <filter-name>sitemesh</filter-name>
+       <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
+   </filter>
 
     <filter-mapping>
         <filter-name>struts-prepare</filter-name>
@@ -62,6 +63,10 @@
       org.apache.struts2.showcase.chat.ChatSessionListener
      </listener-class>
     </listener>
+
+    <listener>
+        <listener-class>org.apache.struts2.dispatcher.ng.listener.StrutsListener</listener-class>
+    </listener>
 
     <!-- SNIPPET START: dwr -->
 
@@ -86,9 +91,30 @@
      <load-on-startup>1</load-on-startup>
    </servlet>
 
+      <!-- Sitemesh Freemarker and Velocity Decorator Servlets. Shares configuration with Struts.-->
+    <servlet>
+        <servlet-name>sitemesh-freemarker</servlet-name>
+        <servlet-class>org.apache.struts2.sitemesh.FreemarkerDecoratorServlet</servlet-class>
+        <init-param>
+            <param-name>default_encoding</param-name>
+            <param-value>UTF-8</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet>
+        <servlet-name>sitemesh-velocity</servlet-name>
+        <servlet-class>org.apache.struts2.sitemesh.VelocityDecoratorServlet</servlet-class>
+        <init-param>
+            <param-name>default_encoding</param-name>
+            <param-value>UTF-8</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
 
    <!-- JavaServer Faces Servlet Mapping, not called directly -->
-     <servlet-mapping>
+    <servlet-mapping>
         <servlet-name>faces</servlet-name>
         <url-pattern>*.action</url-pattern>
    </servlet-mapping>
@@ -98,6 +124,16 @@
         <url-pattern>/dwr/*</url-pattern>
     </servlet-mapping>
 
+    <servlet-mapping>
+        <servlet-name>sitemesh-freemarker</servlet-name>
+        <url-pattern>*.ftl</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>sitemesh-velocity</servlet-name>
+        <url-pattern>*.vm</url-pattern>
+    </servlet-mapping>
+
     <!-- END SNIPPET: dwr -->
 
     <!-- SNIPPET START: example.velocity.filter.chain

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/listener/StrutsListener.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/listener/StrutsListener.java?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/listener/StrutsListener.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/listener/StrutsListener.java Thu Nov 12 06:06:40 2009
@@ -21,6 +21,8 @@
 package org.apache.struts2.dispatcher.ng.listener;
 
 import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.StrutsConstants;
+import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.dispatcher.Dispatcher;
 import org.apache.struts2.dispatcher.ng.InitOperations;
 import org.apache.struts2.dispatcher.ng.PrepareOperations;
@@ -46,6 +48,7 @@
             init.initStaticContentLoader(config, dispatcher);
 
             prepare = new PrepareOperations(config.getServletContext(), dispatcher);
+            sce.getServletContext().setAttribute(StrutsStatics.SERVLET_DISPATCHER, dispatcher);
         } finally {
             init.cleanup();
         }

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerManager.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerManager.java?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerManager.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerManager.java Thu Nov 12 06:06:40 2009
@@ -24,11 +24,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
+import java.text.SimpleDateFormat;
 
 import javax.servlet.GenericServlet;
 import javax.servlet.ServletContext;
@@ -48,6 +45,7 @@
 import com.opensymphony.xwork2.util.logging.Logger;
 import com.opensymphony.xwork2.util.logging.LoggerFactory;
 
+import freemarker.cache.ClassTemplateLoader;
 import freemarker.cache.FileTemplateLoader;
 import freemarker.cache.MultiTemplateLoader;
 import freemarker.cache.TemplateLoader;
@@ -58,11 +56,9 @@
 import freemarker.ext.servlet.HttpRequestParametersHashModel;
 import freemarker.ext.servlet.HttpSessionHashModel;
 import freemarker.ext.servlet.ServletContextHashModel;
-import freemarker.template.ObjectWrapper;
-import freemarker.template.SimpleHash;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateExceptionHandler;
-import freemarker.template.TemplateModel;
+import freemarker.template.*;
+import freemarker.core.Configurable;
+import freemarker.template.utility.StringUtil;
 
 
 /**
@@ -74,7 +70,7 @@
  * <ul>
  *   <li>createConfiguration method</li>
  *   <li>loadSettings method</li>
- *   <li>getTemplateLoader method</li>
+ *   <li>createTemplateLoader method</li>
  *   <li>populateContext method</li>
  * </ul>
  *
@@ -87,7 +83,7 @@
  * Load freemarker settings, default to freemarker.properties (if found in classpath)
  * <p/>
  *
- * <b> getTemplateLoader method</b><br/>
+ * <b> createTemplateLoader method</b><br/>
  * create a freemarker TemplateLoader that loads freemarker template in the following order :-
  * <ol>
  *   <li>path defined in ServletContext init parameter named 'templatePath' or 'TemplatePath' (must be an absolute path)</li>
@@ -102,29 +98,74 @@
  */
 public class FreemarkerManager {
 
+    // coppied from freemarker servlet - so that there is no dependency on it
+    private static final String INITPARAM_TEMPLATE_PATH = "TemplatePath";
+     private static final String INITPARAM_NOCACHE = "NoCache";
+     private static final String INITPARAM_CONTENT_TYPE = "ContentType";
+     private static final String DEFAULT_CONTENT_TYPE = "text/html";
+     private static final String INITPARAM_DEBUG = "Debug";
+
+     public static final String KEY_REQUEST = "Request";
+     public static final String KEY_INCLUDE = "include_page";
+     public static final String KEY_REQUEST_PRIVATE = "__FreeMarkerServlet.Request__";
+     public static final String KEY_REQUEST_PARAMETERS = "RequestParameters";
+     public static final String KEY_SESSION = "Session";
+     public static final String KEY_APPLICATION = "Application";
+     public static final String KEY_APPLICATION_PRIVATE = "__FreeMarkerServlet.Application__";
+     public static final String KEY_JSP_TAGLIBS = "JspTaglibs";
+
+     // Note these names start with dot, so they're essentially invisible from  a freemarker script.
+     public static final String ATTR_TEMPLATE_MODEL = ".freemarker.TemplateModel";  // template model stored in request for siteMesh
+     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";
+     private static final String ATTR_APPLICATION_MODEL = ".freemarker.Application";
+     private static final String ATTR_JSP_TAGLIBS_MODEL = ".freemarker.JspTaglibs";
+
+    public static final String KEY_HASHMODEL_PRIVATE = "__FreeMarkerManager.Request__";
+
+    private static final String EXPIRATION_DATE;
+
+    /**
+     * Adds individual settings.
+     *
+     * @see freemarker.template.Configuration#setSettings for the definition of valid settings
+     */
+    boolean contentTypeEvaluated = false;
+
+    static {
+        // Generate expiration date that is one year from now in the past
+        GregorianCalendar expiration = new GregorianCalendar();
+        expiration.roll(Calendar.YEAR, -1);
+        SimpleDateFormat httpDate =
+                new SimpleDateFormat(
+                        "EEE, dd MMM yyyy HH:mm:ss z",
+                        java.util.Locale.US);
+        EXPIRATION_DATE = httpDate.format(expiration.getTime());
+    }
+
+    // end freemarker definitions...
+
     private static final Logger LOG = LoggerFactory.getLogger(FreemarkerManager.class);
     public static final String CONFIG_SERVLET_CONTEXT_KEY = "freemarker.Configuration";
     public static final String KEY_EXCEPTION = "exception";
 
-    // coppied from freemarker servlet - since they are private
-    protected static final String ATTR_APPLICATION_MODEL = ".freemarker.Application";
-    protected static final String ATTR_JSP_TAGLIBS_MODEL = ".freemarker.JspTaglibs";
-    protected static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
-    protected static final String ATTR_REQUEST_PARAMETERS_MODEL = ".freemarker.RequestParameters";
 
-    // coppied from freemarker servlet - so that there is no dependency on it
-    public static final String KEY_APPLICATION = "Application";
-    public static final String KEY_REQUEST_MODEL = "Request";
-    public static final String KEY_SESSION_MODEL = "Session";
-    public static final String KEY_JSP_TAGLIBS = "JspTaglibs";
-    public static final String KEY_REQUEST_PARAMETER_MODEL = "Parameters";
-    
+
+    protected String templatePath;
+    protected boolean nocache;
+    protected boolean debug;
+    protected Configuration config;
+    protected ObjectWrapper wrapper;
+    protected String contentType = null;
+    protected boolean noCharsetInContentType = true;
+
     protected String encoding;
     protected boolean altMapWrapper;
     protected boolean cacheBeanWrapper;
     protected int mruMaxStrongSize;
     protected Map<String,TagLibrary> tagLibraries;
-    
+
     @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
     public void setEncoding(String encoding) {
         this.encoding = encoding;
@@ -155,21 +196,112 @@
         this.tagLibraries = Collections.unmodifiableMap(map);
     }
 
-    public synchronized freemarker.template.Configuration getConfiguration(ServletContext servletContext) throws TemplateException {
-        freemarker.template.Configuration config = (freemarker.template.Configuration) servletContext.getAttribute(CONFIG_SERVLET_CONTEXT_KEY);
+    public boolean getNoCharsetInContentType() {
+        return noCharsetInContentType;
+    }
 
+    public String getTemplatePath() {
+        return templatePath;
+    }
+
+    public boolean getNocache() {
+        return nocache;
+    }
+
+    public boolean getDebug() {
+        return debug;
+    }
+
+    public Configuration getConfig() {
+        return config;
+    }
+
+    public ObjectWrapper getWrapper() {
+        return wrapper;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    public synchronized freemarker.template.Configuration getConfiguration(ServletContext servletContext) {
         if (config == null) {
-            config = createConfiguration(servletContext);
+            try {
+                init(servletContext);
+            } catch (TemplateException e) {
+                LOG.error("Cannot load freemarker configuration: ",e);
+            }
+//            config = createConfiguration(servletContext);
 
             // store this configuration in the servlet context
             servletContext.setAttribute(CONFIG_SERVLET_CONTEXT_KEY, config);
+
+            config.setWhitespaceStripping(true);
         }
-        
-        config.setWhitespaceStripping(true);
+
 
         return config;
     }
 
+    public void init(ServletContext servletContext) throws TemplateException {
+        config = createConfiguration(servletContext);
+
+        // Set defaults:
+        config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
+        contentType = DEFAULT_CONTENT_TYPE;
+
+        // Process object_wrapper init-param out of order:
+        wrapper = createObjectWrapper(servletContext);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Using object wrapper of class " + wrapper.getClass().getName());
+        }
+        config.setObjectWrapper(wrapper);
+
+        // Process TemplatePath init-param out of order:
+        templatePath = servletContext.getInitParameter(INITPARAM_TEMPLATE_PATH);
+        if (templatePath == null) {
+            templatePath = servletContext.getInitParameter("templatePath");
+        }
+        if (templatePath == null)
+            templatePath = "class://";
+        config.setTemplateLoader(createTemplateLoader(servletContext, templatePath));
+
+        loadSettings(servletContext);
+    }
+
+    /**
+     * Create the instance of the freemarker Configuration object.
+     * <p/>
+     * this implementation
+     * <ul>
+     * <li>obtains the default configuration from Configuration.getDefaultConfiguration()
+     * <li>sets up template loading from a ClassTemplateLoader and a WebappTemplateLoader
+     * <li>sets up the object wrapper to be the BeansWrapper
+     * <li>loads settings from the classpath file /freemarker.properties
+     * </ul>
+     *
+     * @param servletContext
+     */
+    protected freemarker.template.Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
+        freemarker.template.Configuration configuration = new freemarker.template.Configuration();
+
+        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
+
+        if (mruMaxStrongSize > 0) {
+            configuration.setSetting(freemarker.template.Configuration.CACHE_STORAGE_KEY, "strong:" + mruMaxStrongSize);
+        }
+
+        if (encoding != null) {
+            configuration.setDefaultEncoding(encoding);
+        }
+
+
+        configuration.setWhitespaceStripping(true);
+
+        return configuration;
+    }
+
+
     protected ScopesHashModel buildScopesHashModel(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper, ValueStack stack) {
         ScopesHashModel model = new ScopesHashModel(wrapper, servletContext, request, stack);
 
@@ -199,7 +331,7 @@
         // Create hash model wrapper for session
         HttpSession session = request.getSession(false);
         if (session != null) {
-            model.put(KEY_SESSION_MODEL, new HttpSessionHashModel(session, wrapper));
+            model.put(KEY_SESSION, new HttpSessionHashModel(session, wrapper));
         } else {
             // no session means no attributes ???
             //            model.put(KEY_SESSION_MODEL, new SimpleHash());
@@ -213,7 +345,7 @@
             request.setAttribute(ATTR_REQUEST_MODEL, requestModel);
         }
 
-        model.put(KEY_REQUEST_MODEL, requestModel);
+        model.put(KEY_REQUEST, requestModel);
 
 
         // Create hash model wrapper for request parameters
@@ -222,116 +354,62 @@
             reqParametersModel = new HttpRequestParametersHashModel(request);
             request.setAttribute(ATTR_REQUEST_PARAMETERS_MODEL, reqParametersModel);
         }
-        model.put(KEY_REQUEST_PARAMETER_MODEL, reqParametersModel);
+        model.put(ATTR_REQUEST_PARAMETERS_MODEL, reqParametersModel);
 
         return model;
     }
 
-    protected void populateContext(ScopesHashModel model, ValueStack stack, Object action, HttpServletRequest request, HttpServletResponse response) {
-        // put the same objects into the context that the velocity result uses
-        Map standard = ContextUtil.getStandardContext(stack, request, response);
-        model.putAll(standard);
-
-        // support for JSP exception pages, exposing the servlet or JSP exception
-        Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");
-
-        if (exception == null) {
-            exception = (Throwable) request.getAttribute("javax.servlet.error.JspException");
-        }
-
-        if (exception != null) {
-            model.put(KEY_EXCEPTION, exception);
-        }
-    }
-
-    protected BeansWrapper getObjectWrapper() {
+    protected ObjectWrapper createObjectWrapper(ServletContext servletContext) {
         StrutsBeanWrapper wrapper = new StrutsBeanWrapper(altMapWrapper);
         wrapper.setUseCache(cacheBeanWrapper);
         return wrapper;
     }
 
-    /**
-     * The default template loader is a MultiTemplateLoader which includes
-     * a ClassTemplateLoader and a WebappTemplateLoader (and a FileTemplateLoader depending on
-     * the init-parameter 'TemplatePath').
-     * <p/>
-     * The ClassTemplateLoader will resolve fully qualified template includes
-     * that begin with a slash. for example /com/company/template/common.ftl
-     * <p/>
-     * The WebappTemplateLoader attempts to resolve templates relative to the web root folder
-     */
-    protected TemplateLoader getTemplateLoader(ServletContext servletContext) {
-        // construct a FileTemplateLoader for the init-param 'TemplatePath'
-        FileTemplateLoader templatePathLoader = null;
-
-        String templatePath = servletContext.getInitParameter("TemplatePath");
-        if (templatePath == null) {
-            templatePath = servletContext.getInitParameter("templatePath");
-        }
-
-        if (templatePath != null) {
-            try {
-                templatePathLoader = new FileTemplateLoader(new File(templatePath));
-            } catch (IOException e) {
-                LOG.error("Invalid template path specified: " + e.getMessage(), e);
-            }
-        }
-
-        // presume that most apps will require the class and webapp template loader
-        // if people wish to
-        return templatePathLoader != null ?
-                new MultiTemplateLoader(new TemplateLoader[]{
-                        templatePathLoader,
-                        new WebappTemplateLoader(servletContext),
-                        new StrutsClassTemplateLoader()
-                })
-                : new MultiTemplateLoader(new TemplateLoader[]{
-                new WebappTemplateLoader(servletContext),
-                new StrutsClassTemplateLoader()
-        });
-    }
 
-    /**
-     * Create the instance of the freemarker Configuration object.
-     * <p/>
-     * this implementation
-     * <ul>
-     * <li>obtains the default configuration from Configuration.getDefaultConfiguration()
-     * <li>sets up template loading from a ClassTemplateLoader and a WebappTemplateLoader
-     * <li>sets up the object wrapper to be the BeansWrapper
-     * <li>loads settings from the classpath file /freemarker.properties
-     * </ul>
-     *
-     * @param servletContext
+     /**
+     * Create the template loader. The default implementation will create a
+     * {@link ClassTemplateLoader} if the template path starts with "class://",
+     * a {@link FileTemplateLoader} if the template path starts with "file://",
+     * and a {@link WebappTemplateLoader} otherwise.
+     * @param templatePath the template path to create a loader for
+     * @return a newly created template loader
+     * @throws IOException
      */
-    protected freemarker.template.Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
-        freemarker.template.Configuration configuration = new freemarker.template.Configuration();
-
-        configuration.setTemplateLoader(getTemplateLoader(servletContext));
-
-        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
-
-        configuration.setObjectWrapper(getObjectWrapper());
-        
-        if( mruMaxStrongSize > 0 ) {
-            configuration.setSetting(freemarker.template.Configuration.CACHE_STORAGE_KEY, "strong:" + mruMaxStrongSize);
-        }
+    protected TemplateLoader createTemplateLoader(ServletContext servletContext, String templatePath) {
+        TemplateLoader templatePathLoader = null;
 
-        if (encoding != null) {
-            configuration.setDefaultEncoding(encoding);
-        }
+         try {
+             if (templatePath.startsWith("class://")) {
+                 // substring(7) is intentional as we "reuse" the last slash
+                 templatePathLoader = new ClassTemplateLoader(getClass(), templatePath.substring(7));
+             } else if (templatePath.startsWith("file://")) {
+                 templatePathLoader = new FileTemplateLoader(new File(templatePath));
+             }
+         } catch (IOException e) {
+             LOG.error("Invalid template path specified: " + e.getMessage(), e);
+         }
+
+         // presume that most apps will require the class and webapp template loader
+         // if people wish to
+         return templatePathLoader != null ?
+                 new MultiTemplateLoader(new TemplateLoader[]{
+                         templatePathLoader,
+                         new WebappTemplateLoader(servletContext),
+                         new StrutsClassTemplateLoader()
+                 })
+                 : new MultiTemplateLoader(new TemplateLoader[]{
+                 new WebappTemplateLoader(servletContext),
+                 new StrutsClassTemplateLoader()
+         });
+     }
 
-        loadSettings(servletContext, configuration);
-
-        return configuration;
-    }
 
     /**
      * Load the settings from the /freemarker.properties file on the classpath
      *
      * @see freemarker.template.Configuration#setSettings for the definition of valid settings
      */
-    protected void loadSettings(ServletContext servletContext, freemarker.template.Configuration configuration) {
+    protected void loadSettings(ServletContext servletContext) {
         InputStream in = null;
 
         try {
@@ -340,7 +418,22 @@
             if (in != null) {
                 Properties p = new Properties();
                 p.load(in);
-                configuration.setSettings(p);
+
+                Iterator i = p.keySet().iterator();
+                while (i.hasNext()) {
+                    String name = (String) i.next();
+                    String value = (String) p.get(name);
+
+                    if (name == null) {
+                        throw new IOException(
+                                "init-param without param-name.  Maybe the freemarker.properties is not well-formed?");
+                    }
+                    if (value == null) {
+                        throw new IOException(
+                                "init-param without param-value.  Maybe the freemarker.properties is not well-formed?");
+                    }
+                    addSetting(name, value);
+                }
             }
         } catch (IOException e) {
             LOG.error("Error while loading freemarker settings from /freemarker.properties", e);
@@ -357,7 +450,39 @@
         }
     }
 
-    public SimpleHash buildTemplateModel(ValueStack stack, Object action, ServletContext servletContext, HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper) {
+    public void addSetting(String name, String value) throws TemplateException {
+        // Process all other init-params:
+        if (name.equals(INITPARAM_NOCACHE)) {
+            nocache = StringUtil.getYesNo(value);
+        } else if (name.equals(INITPARAM_DEBUG)) {
+            debug = StringUtil.getYesNo(value);
+        } else if (name.equals(INITPARAM_CONTENT_TYPE)) {
+            contentType = value;
+        } else {
+            config.setSetting(name, value);
+        }
+
+        if (contentType != null && !contentTypeEvaluated) {
+            int i = contentType.toLowerCase().indexOf("charset=");
+            contentTypeEvaluated = true;
+            if (i != -1) {
+                char c = ' ';
+                i--;
+                while (i >= 0) {
+                    c = contentType.charAt(i);
+                    if (!Character.isWhitespace(c)) break;
+                    i--;
+                }
+                if (i == -1 || c == ';') {
+                    noCharsetInContentType = false;
+                }
+            }
+        }
+    }
+
+
+
+    public ScopesHashModel buildTemplateModel(ValueStack stack, Object action, ServletContext servletContext, HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper) {
         ScopesHashModel model = buildScopesHashModel(servletContext, request, response, wrapper, stack);
         populateContext(model, stack, action, request, response);
         if (tagLibraries != null) {
@@ -365,6 +490,44 @@
                 model.put(prefix, tagLibraries.get(prefix).getFreemarkerModels(stack, request, response));
             }
         }
+
+        //place the model in the request using the special parameter.  This can be retrieved for freemarker and velocity.
+        request.setAttribute(ATTR_TEMPLATE_MODEL, model);
+
         return model;
     }
+
+
+    protected void populateContext(ScopesHashModel model, ValueStack stack, Object action, HttpServletRequest request, HttpServletResponse response) {
+        // put the same objects into the context that the velocity result uses
+        Map standard = ContextUtil.getStandardContext(stack, request, response);
+        model.putAll(standard);
+
+        // support for JSP exception pages, exposing the servlet or JSP exception
+        Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");
+
+        if (exception == null) {
+            exception = (Throwable) request.getAttribute("javax.servlet.error.JspException");
+        }
+
+        if (exception != null) {
+            model.put(KEY_EXCEPTION, exception);
+        }
+    }
+
+      /**
+     * If the parameter "nocache" was set to true, generate a set of headers
+     * that will advise the HTTP client not to cache the returned page.
+     */
+      private void setBrowserCachingPolicy(HttpServletResponse res) {
+          if (nocache) {
+              // HTTP/1.1 + IE extensions
+              res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, "
+                      + "post-check=0, pre-check=0");
+              // HTTP/1.0
+              res.setHeader("Pragma", "no-cache");
+              // Last resort for those that ignore all of the above
+              res.setHeader("Expires", EXPIRATION_DATE);
+          }
+      }
 }

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/ScopesHashModel.java Thu Nov 12 06:06:40 2009
@@ -32,6 +32,9 @@
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
 
+import java.util.Map;
+import java.util.HashMap;
+
 
 /**
  * Simple Hash model that also searches other scopes.
@@ -39,14 +42,17 @@
  * If the key doesn't exist in this hash, this template model tries to
  * resolve the key within the attributes of the following scopes,
  * in the order stated: Request, Session, Servlet Context
+ *
+ * Updated to subclass AllHttpScopesHashModel.java to incorporate invisible scopes and compatibility with freemarker.
  */
-public class ScopesHashModel extends SimpleHash {
+public class ScopesHashModel extends SimpleHash implements TemplateModel {
 
     private static final long serialVersionUID = 5551686380141886764L;
 
     private HttpServletRequest request;
     private ServletContext servletContext;
     private ValueStack stack;
+    private final Map<String,TemplateModel> unlistedModels = new HashMap<String,TemplateModel>();
 
 
     public ScopesHashModel(ObjectWrapper objectWrapper, ServletContext context, HttpServletRequest request, ValueStack stack) {
@@ -56,6 +62,23 @@
         this.stack = stack;
     }
 
+    // This constructor is for Freemarker Sitemesh integration where the model is somehow lost...
+    public ScopesHashModel(ObjectWrapper objectWrapper, ServletContext context, HttpServletRequest request) {
+         super(objectWrapper);
+         this.servletContext = context;
+         this.request = request;
+    }
+
+    /**
+     * Stores a model in the hash so that it doesn't show up in <tt>keys()</tt>
+     * and <tt>values()</tt> methods. Used to put the Application, Session,
+     * Request, RequestParameters and JspTaglibs objects.
+     * @param key the key under which the model is stored
+     * @param model the stored model
+     */
+    public void putUnlistedModel(String key, TemplateModel model) {
+        unlistedModels.put(key, model);
+    }
 
     public TemplateModel get(String key) throws TemplateModelException {
         // Lookup in default scope
@@ -109,6 +132,13 @@
             }
         }
 
+        // Look in unlisted models
+        model = unlistedModels.get(key);
+        if(model != null) {
+            return wrap(model);
+        }
+
+
         return null;
     }
 

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java Thu Nov 12 06:06:40 2009
@@ -30,11 +30,9 @@
 import freemarker.ext.util.ModelFactory;
 import freemarker.template.ObjectWrapper;
 import freemarker.template.SimpleSequence;
-import freemarker.template.TemplateBooleanModel;
 import freemarker.template.TemplateCollectionModel;
 import freemarker.template.TemplateHashModelEx;
 import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
 
 /**
  * <!-- START SNIPPET: javadoc -->
@@ -54,7 +52,7 @@
 public class StrutsBeanWrapper extends BeansWrapper {
     private boolean altMapWrapper;
 
-    StrutsBeanWrapper(boolean altMapWrapper) {
+    public StrutsBeanWrapper(boolean altMapWrapper) {
         this.altMapWrapper = altMapWrapper;
     }
 

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/velocity/VelocityManager.java Thu Nov 12 06:06:40 2009
@@ -52,6 +52,7 @@
 import org.apache.velocity.tools.view.ToolboxManager;
 import org.apache.velocity.tools.view.context.ChainedContext;
 import org.apache.velocity.tools.view.servlet.ServletToolboxManager;
+import org.apache.commons.lang.xwork.StringUtils;
 
 import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.inject.Container;
@@ -70,6 +71,8 @@
     public static final String STRUTS = "struts";
     private ObjectFactory objectFactory;
 
+    public static final String KEY_VELOCITY_STRUTS_CONTEXT = ".KEY_velocity.struts2.context";
+
     /**
      * the parent JSP tag
      */
@@ -100,9 +103,6 @@
 
     private List<TagLibrary> tagLibraries;
 
-    public VelocityManager() {
-    }
-
     @Inject
     public void setObjectFactory(ObjectFactory fac) {
         this.objectFactory = fac;
@@ -119,35 +119,6 @@
     }
 
     /**
-     * retrieve an instance to the current VelocityManager
-     */
-    /*public synchronized static VelocityManager getInstance() {
-        if (instance == null) {
-            String classname = VelocityManager.class.getName();
-
-            if (Settings.isSet(StrutsConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME)) {
-                classname = Settings.get(StrutsConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME).trim();
-            }
-
-            if (!classname.equals(VelocityManager.class.getName())) {
-                try {
-                    log.info("Instantiating VelocityManager!, " + classname);
-                    // singleton instances shouldn't be built accessing request or session-specific context data
-                    instance = (VelocityManager) ObjectFactory.getObjectFactory().buildBean(classname, null);
-                } catch (Exception e) {
-                    log.fatal("Fatal exception occurred while trying to instantiate a VelocityManager instance, " + classname, e);
-                    instance = new VelocityManager();
-                }
-            } else {
-                instance = new VelocityManager();
-            }
-        }
-
-        return instance;
-    }
-    */
-
-    /**
      * @return a reference to the VelocityEngine used by <b>all</b> struts velocity thingies with the exception of
      *         directly accessed *.vm pages
      */
@@ -171,6 +142,7 @@
      * @return a new StrutsVelocityContext
      */
     public Context createContext(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
+        Context result = null;
         VelocityContext[] chainedContexts = prepareChainedContexts(req, res, stack.getContext());
         StrutsVelocityContext context = new StrutsVelocityContext(chainedContexts, stack);
         Map standardMap = ContextUtil.getStandardContext(stack, req, res);
@@ -192,11 +164,13 @@
         if (toolboxManager != null && ctx != null) {
             ChainedContext chained = new ChainedContext(context, velocityEngine, req, res, ctx);
             chained.setToolbox(toolboxManager.getToolbox(chained));
-            return chained;
+            result = chained;
         } else {
-            return context;
+            result = context;
         }
 
+        req.setAttribute(KEY_VELOCITY_STRUTS_CONTEXT, result);
+        return result;
     }
 
     /**
@@ -389,6 +363,10 @@
         this.toolBoxLocation = toolboxLocation;
     }
 
+    public ToolboxManager getToolboxManager() {
+        return toolboxManager;
+    }
+
     /**
      * allow users to specify via the struts.properties file a set of additional VelocityContexts to chain to the
      * the StrutsVelocityContext.  The intent is to allow these contexts to store helper objects that the ui
@@ -418,7 +396,7 @@
      */
     protected void initToolbox(ServletContext context) {
         /* if we have a toolbox, get a manager for it */
-        if (toolBoxLocation != null) {
+        if (StringUtils.isNotBlank(toolBoxLocation)) {
             toolboxManager = ServletToolboxManager.getInstance(context, toolBoxLocation);
         } else {
             Velocity.info("VelocityViewServlet: No toolbox entry in configuration.");

Added: struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerMapper2DecoratorSelector.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerMapper2DecoratorSelector.java?rev=835248&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerMapper2DecoratorSelector.java (added)
+++ struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerMapper2DecoratorSelector.java Thu Nov 12 06:06:40 2009
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * 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.struts2.sitemesh;
+
+import com.opensymphony.module.sitemesh.mapper.AbstractDecoratorMapper;
+import com.opensymphony.module.sitemesh.Decorator;
+import com.opensymphony.module.sitemesh.Page;
+import com.opensymphony.module.sitemesh.DecoratorMapper;
+import com.opensymphony.sitemesh.DecoratorSelector;
+import com.opensymphony.sitemesh.Content;
+import com.opensymphony.sitemesh.SiteMeshContext;
+import com.opensymphony.sitemesh.compatability.Content2HTMLPage;
+import com.opensymphony.sitemesh.compatability.OldDecorator2NewDecorator;
+import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext;
+import com.opensymphony.sitemesh.webapp.decorator.NoDecorator;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Returns a {@link OldDecorator2NewStrutsFreemarkerDecorator} decorator
+ * for a Freemarker request.
+ *
+ * Won't decorate the output if it finds a "decorator" flag in the request
+ */
+public class FreeMarkerMapper2DecoratorSelector implements DecoratorSelector {
+
+    private final DecoratorMapper decoratorMapper;
+
+    public FreeMarkerMapper2DecoratorSelector(DecoratorMapper decoratorMapper) {
+        this.decoratorMapper = decoratorMapper;
+    }
+
+    public com.opensymphony.sitemesh.Decorator selectDecorator(Content content, SiteMeshContext context) {
+        SiteMeshWebAppContext webAppContext = (SiteMeshWebAppContext) context;
+        HttpServletRequest request = webAppContext.getRequest();
+        com.opensymphony.module.sitemesh.Decorator decorator =
+                decoratorMapper.getDecorator(request, new Content2HTMLPage(content, request));
+        if (decorator == null || decorator.getPage() == null) {
+            return new NoDecorator();
+        } else {
+            return new OldDecorator2NewStrutsFreemarkerDecorator(decorator);
+        }
+    }
+}

Modified: struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerPageFilter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerPageFilter.java?rev=835248&r1=835247&r2=835248&view=diff
==============================================================================
--- struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerPageFilter.java (original)
+++ struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreeMarkerPageFilter.java Thu Nov 12 06:06:40 2009
@@ -21,164 +21,38 @@
 
 package org.apache.struts2.sitemesh;
 
-import java.io.IOException;
-import java.util.Locale;
+import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext;
+import com.opensymphony.sitemesh.webapp.SiteMeshFilter;
+import com.opensymphony.sitemesh.DecoratorSelector;
+import com.opensymphony.module.sitemesh.Factory;
+import com.opensymphony.module.sitemesh.Config;
+import com.opensymphony.xwork2.inject.Inject;
 
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import javax.servlet.*;
 
 import org.apache.struts2.views.freemarker.FreemarkerManager;
 
-import com.opensymphony.module.sitemesh.Decorator;
-import com.opensymphony.module.sitemesh.HTMLPage;
-import com.opensymphony.module.sitemesh.Page;
-import com.opensymphony.xwork2.ActionContext;
-import com.opensymphony.xwork2.ActionInvocation;
-import com.opensymphony.xwork2.LocaleProvider;
-import com.opensymphony.xwork2.inject.Inject;
-import com.opensymphony.xwork2.util.logging.Logger;
-import com.opensymphony.xwork2.util.logging.LoggerFactory;
-import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
-
-import freemarker.template.Configuration;
-import freemarker.template.SimpleHash;
-import freemarker.template.Template;
-
 /**
- *  Applies FreeMarker-based sitemesh decorators.
- *
- *  <!-- START SNIPPET: javadoc -->
- *
- *  The following variables are available to the decorating freemarker page :-
- *  <ul>
- *      <li>${title}           - content of <title> tag in the decorated page</li>
- *      <li>${head}            - content of <head> tag in the decorated page</li>
- *      <li>${body}            - content of t<body> tag in the decorated page</li>
- *      <li>${page.properties} - content of the page properties</li>
- *  </ul>
- *  <p/>
- *  With the following decorated page :-
- *  <pre>
- *  <html>
- *      <meta name="author" content="tm_jee" />
- *      <head>
- *          <title>My Title</title>
- *          <link rel="stylesheet" type="text/css" href="mycss.css" />
- *          <style type="text/javascript" language="javascript" src="myjavascript.js"></script>
- *      </head>
- *      <body<
- *          <h1>Sample</h1>
- *      </body>
- *  </html>
- *  </pre>
- *  <p/>
- *  <table border="1">
- *      <tr>
- *          <td>Properties</td>
- *          <td>Content</td>
- *      </tr>
- *      <tr>
- *          <td>${title}</td>
- *          <td>My Title</td>
- *      </tr>
- *      <tr>
- *          <td>${head}</td>
- *          <td>
- *              <link rel="stylesheet" type="text/css" href="mycss.css" />
- *              <style type="text/javascript" language="javascript" src="myjavascript.js"></script>
- *          </td>
- *      </tr>
- *      <tr>
- *          <td>${body}</td>
- *          <td>
- *              <h1>Sample</h1>
- *          </td>
- *      </tr>
- *      <tr>
- *          <td>${page.properties.meta.author}</td>
- *          <td>tm_jee</td>
- *      </tr>
- *  </table>
- *
- *  <!-- END SNIPPET: javadoc -->
- *
- *  @version $Date$ $Id$
+ * Core Filter for integrating SiteMesh + Freemarker into
+ * a Java web application.
  */
-public class FreeMarkerPageFilter extends TemplatePageFilter {
-    private static final Logger LOG = LoggerFactory.getLogger(FreeMarkerPageFilter.class);
-    
-    private static FreemarkerManager freemarkerManager;
-    
+public class FreeMarkerPageFilter extends SiteMeshFilter {
+
     @Inject(required=false)
     public static void setFreemarkerManager(FreemarkerManager mgr) {
-        freemarkerManager = mgr;
+        OldDecorator2NewStrutsFreemarkerDecorator.setFreemarkerManager(mgr);
     }
 
-    /**
-     *  Applies the decorator, using the relevent contexts
-     *
-     * @param page The page
-     * @param decorator The decorator
-     * @param req The servlet request
-     * @param res The servlet response
-     * @param servletContext The servlet context
-     * @param ctx The action context for this request, populated with the server state
-     */
-    protected void applyDecorator(Page page, Decorator decorator,
-                                  HttpServletRequest req, HttpServletResponse res,
-                                  ServletContext servletContext, ActionContext ctx)
-            throws ServletException, IOException {
-
-        String timerKey = "FreemarkerPageFilter_applyDecorator: ";
-        if (freemarkerManager == null) {
-            throw new ServletException("Missing freemarker dependency");
-        }
-        
-        try {
-            UtilTimerStack.push(timerKey);
-
-            // get the configuration and template
-            Configuration config = freemarkerManager.getConfiguration(servletContext);
-            Template template = config.getTemplate(decorator.getPage(), getLocale(ctx.getActionInvocation(), config)); // WW-1181
-
-            // get the main hash
-            SimpleHash model = freemarkerManager.buildTemplateModel(ctx.getValueStack(), null, servletContext, req, res, config.getObjectWrapper());
-
-            // populate the hash with the page
-            model.put("page", page);
-            if (page instanceof HTMLPage) {
-                HTMLPage htmlPage = ((HTMLPage) page);
-                model.put("head", htmlPage.getHead());
-            }
-            model.put("title",page.getTitle());
-            model.put("body",page.getBody());
-            model.put("page.properties", new SimpleHash(page.getProperties()));
-
-            // finally, render it
-            template.process(model, res.getWriter());
-        } catch (Exception e) {
-            String msg = "Error applying decorator: " + e.getMessage();
-            LOG.error(msg, e);
-            throw new ServletException(msg, e);
-        }
-        finally {
-            UtilTimerStack.pop(timerKey);
-        }
-    }
+    private FilterConfig filterConfig;
 
-    /**
-     * Returns the locale used for the {@link Configuration#getTemplate(String, Locale)} call. The base implementation
-     * simply returns the locale setting of the action (assuming the action implements {@link LocaleProvider}) or, if
-     * the action does not the configuration's locale is returned. Override this method to provide different behaviour,
-     */
-    protected Locale getLocale(ActionInvocation invocation, Configuration configuration) {
-        if (invocation.getAction() instanceof LocaleProvider) {
-            return ((LocaleProvider) invocation.getAction()).getLocale();
-        } else {
-            return configuration.getLocale();
-        }
+     public void init(FilterConfig filterConfig) {
+         this.filterConfig = filterConfig;
+        super.init(filterConfig);
+     }
+
+    protected DecoratorSelector initDecoratorSelector(SiteMeshWebAppContext webAppContext) {
+        Factory factory = Factory.getInstance(new Config(filterConfig));
+        factory.refresh();
+        return new FreeMarkerMapper2DecoratorSelector(factory.getDecoratorMapper());
     }
-
 }

Added: struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java?rev=835248&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java (added)
+++ struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java Thu Nov 12 06:06:40 2009
@@ -0,0 +1,408 @@
+/*
+ * $Id$
+ *
+ * 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.struts2.sitemesh;
+
+import com.opensymphony.module.sitemesh.HTMLPage;
+import com.opensymphony.module.sitemesh.RequestConstants;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import freemarker.core.InvalidReferenceException;
+import freemarker.ext.jsp.TaglibFactory;
+import freemarker.ext.servlet.*;
+import freemarker.template.*;
+import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.StrutsStatics;
+import org.apache.struts2.dispatcher.Dispatcher;
+import org.apache.struts2.dispatcher.StrutsRequestWrapper;
+import org.apache.struts2.dispatcher.ng.listener.StrutsListener;
+import org.apache.struts2.views.freemarker.FreemarkerManager;
+import org.apache.struts2.views.freemarker.ScopesHashModel;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
+/**
+ * <p>This is a SiteMesh FreeMarker view servlet.</p>
+ * <p/>
+ * <p>It overrides the SiteMesh servlet to rely on the
+ * Freemarker Manager in Struts instead of creating it's
+ * own manager</p>
+ */
+public class FreemarkerDecoratorServlet extends freemarker.ext.servlet.FreemarkerServlet {
+    private static final com.opensymphony.xwork2.util.logging.Logger LOG = LoggerFactory.getLogger(FreemarkerDecoratorServlet.class);
+
+
+    protected FreemarkerManager freemarkerManager;
+
+
+    public static final long serialVersionUID = -2440216393145762479L;
+
+    private static final String INITPARAM_TEMPLATE_PATH = "TemplatePath";
+
+    public static final String KEY_REQUEST = "Request";
+    public static final String KEY_INCLUDE = "include_page";
+    public static final String KEY_REQUEST_PRIVATE = "__FreeMarkerServlet.Request__";
+    public static final String KEY_REQUEST_PARAMETERS = "RequestParameters";
+    public static final String KEY_SESSION = "Session";
+    public static final String KEY_APPLICATION = "Application";
+    public static final String KEY_APPLICATION_PRIVATE = "__FreeMarkerServlet.Application__";
+    public static final String KEY_JSP_TAGLIBS = "JspTaglibs";
+
+    // 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";
+    private static final String ATTR_APPLICATION_MODEL = ".freemarker.Application";
+    private static final String ATTR_JSP_TAGLIBS_MODEL = ".freemarker.JspTaglibs";
+
+    private static final String EXPIRATION_DATE;
+
+    static {
+        // Generate expiration date that is one year from now in the past
+        GregorianCalendar expiration = new GregorianCalendar();
+        expiration.roll(Calendar.YEAR, -1);
+        SimpleDateFormat httpDate = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", java.util.Locale.US);
+        EXPIRATION_DATE = httpDate.format(expiration.getTime());
+    }
+
+    protected String templatePath;
+    protected boolean nocache;
+    protected boolean debug;
+    protected Configuration config;
+    private ObjectWrapper wrapper;
+    private String contentType;
+    private boolean noCharsetInContentType;
+
+    public void init() throws ServletException {
+        try {
+            Dispatcher dispatcher = (Dispatcher) getServletContext().getAttribute(StrutsStatics.SERVLET_DISPATCHER);
+            if (dispatcher == null)
+                throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?");
+
+            freemarkerManager = dispatcher.getContainer().getInstance(FreemarkerManager.class);
+            config = createConfiguration();
+
+            // Process object_wrapper init-param out of order:
+            wrapper = config.getObjectWrapper();
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Using object wrapper of class " + wrapper.getClass().getName());
+            }
+
+            // Process all other init-params:
+            Enumeration initpnames = getServletConfig().getInitParameterNames();
+            while (initpnames.hasMoreElements()) {
+                String name = (String) initpnames.nextElement();
+                String value = getInitParameter(name);
+                if (name == null) {
+                    throw new ServletException("init-param without param-name. " + "Maybe the web.xml is not well-formed?");
+                }
+                if (value == null) {
+                    throw new ServletException("init-param without param-value. " + "Maybe the web.xml is not well-formed?");
+                }
+
+                // template path is already handled!
+                if (!INITPARAM_TEMPLATE_PATH.equals(name)) freemarkerManager.addSetting(name, value);
+            }
+            nocache = freemarkerManager.getNocache();
+            debug = freemarkerManager.getDebug();
+            contentType = freemarkerManager.getContentType();
+            noCharsetInContentType = freemarkerManager.getNoCharsetInContentType();
+        } catch (ServletException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        process(request, response);
+    }
+
+    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        process(request, response);
+    }
+
+    private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        // Give chance to subclasses to perform preprocessing
+        if (preprocessRequest(request, response)) {
+            return;
+        }
+
+        String path = requestUrlToTemplatePath(request);
+
+        if (debug) {
+            log("Requested template: " + path);
+        }
+
+        Template template = null;
+        try {
+            template = config.getTemplate(path, deduceLocale(path, request, response));
+        } catch (FileNotFoundException e) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        Object attrContentType = template.getCustomAttribute("content_type");
+        if (attrContentType != null) {
+            response.setContentType(attrContentType.toString());
+        } else {
+            if (noCharsetInContentType) {
+                response.setContentType(contentType + "; charset=" + template.getEncoding());
+            } else {
+                response.setContentType(contentType);
+            }
+        }
+
+        // Set cache policy
+        setBrowserCachingPolicy(response);
+
+        ServletContext servletContext = getServletContext();
+        ScopesHashModel model = (ScopesHashModel) request.getAttribute(freemarkerManager.ATTR_TEMPLATE_MODEL);
+        try {
+            if (model == null) {
+                ActionContext ctx = ServletActionContext.getActionContext(request);
+                model = freemarkerManager.buildTemplateModel(ctx.getValueStack(), ctx.getActionInvocation().getAction(), servletContext, request, response, wrapper);
+            }
+
+            populateModel(model, wrapper, servletContext, request, response);
+
+            // Give subclasses a chance to hook into preprocessing
+            if (preTemplateProcess(request, response, template, model)) {
+                try {
+                    // Process the template
+                    template.process(model, response.getWriter());
+                } finally {
+                    // Give subclasses a chance to hook into postprocessing
+                    postTemplateProcess(request, response, template, model);
+                }
+            }
+        } catch (InvalidReferenceException x) {
+            // this exception is thrown if there is an error processing a reference.  We want to report these!
+            HttpServletRequest req = ((StrutsRequestWrapper) ActionContext.getContext().get("com.opensymphony.xwork2.dispatcher.HttpServletRequest"));
+            String resultCode = ActionContext.getContext().getActionInvocation().getResultCode();
+            if (req == null) req = request;
+
+            StringBuilder msgBuf = new StringBuilder("Error applying freemarker template to\n       request: ");
+            msgBuf.append(req.getRequestURL());
+            if (req.getQueryString() == null) msgBuf.append("?").append(req.getQueryString());
+            msgBuf.append(" with resultCode: ").append(resultCode).append(".\n\n").append(x.getMessage());
+            String msg = msgBuf.toString();
+            LOG.error(msg, x);
+
+            ServletException e = new ServletException(msg, x);
+            // Attempt to set init cause, but don't freak out if the method
+            // is not available (i.e. pre-1.4 JRE). This is required as the
+            // constructor-passed throwable won't show up automatically in
+            // stack traces.
+            try {
+                e.getClass().getMethod("initCause", new Class[]{Throwable.class}).invoke(e, new Object[]{x});
+            } catch (Exception ex) {
+                // Can't set init cause, we're probably running on a pre-1.4
+                // JDK, oh well...
+            }
+            throw e;
+        } catch (TemplateException te) {
+            if (config.getTemplateExceptionHandler().getClass().getName().indexOf("Debug") != -1) {
+                this.log("Error executing FreeMarker template", te);
+            } else {
+                ServletException e = new ServletException("Error executing FreeMarker template", te);
+                // Attempt to set init cause, but don't freak out if the method
+                // is not available (i.e. pre-1.4 JRE). This is required as the
+                // constructor-passed throwable won't show up automatically in
+                // stack traces.
+                try {
+                    e.getClass().getMethod("initCause", new Class[]{Throwable.class}).invoke(e, new Object[]{te});
+                } catch (Exception ex) {
+                    // Can't set init cause, we're probably running on a pre-1.4
+                    // JDK, oh well...
+                }
+                throw e;
+            }
+        }
+    }
+
+
+    /**
+     * Returns the locale used for the
+     * {@link Configuration#getTemplate(String, Locale)} call.
+     * The base implementation simply returns the locale setting of the
+     * configuration. Override this method to provide different behaviour, i.e.
+     * to use the locale indicated in the request.
+     */
+    protected Locale deduceLocale(String templatePath, HttpServletRequest request, HttpServletResponse response) {
+        return config.getLocale();
+    }
+
+
+    /**
+     * Create the instance of the freemarker Configuration object.
+     * <p/>
+     * this implementation
+     * <ul>
+     * <li>obtains the default configuration from Configuration.getDefaultConfiguration()
+     * <li>sets up template loading from a ClassTemplateLoader and a WebappTemplateLoader
+     * <li>sets up the object wrapper to be the BeansWrapper
+     * <li>loads settings from the classpath file /freemarker.properties
+     * </ul>
+     */
+    protected freemarker.template.Configuration createConfiguration() {
+        return freemarkerManager.getConfiguration(this.getServletContext());
+    }
+
+    /**
+     * Called before the execution is passed to template.process().
+     * This is a generic hook you might use in subclasses to perform a specific
+     * action before the template is processed. By default does nothing.
+     * A typical action to perform here is to inject application-specific
+     * objects into the model root
+     * <p/>
+     * <p>Example: Expose the Serlvet context path as "baseDir" for all templates:
+     * <p/>
+     * <pre>
+     *    ((SimpleHash) data).put("baseDir", request.getContextPath() + "/");
+     *    return true;
+     * </pre>
+     *
+     * @param request  the actual HTTP request
+     * @param response the actual HTTP response
+     * @param template the template that will get executed
+     * @return true to process the template, false to suppress template processing.
+     * @see freemarker.ext.servlet.FreemarkerServlet#preTemplateProcess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, freemarker.template.Template, freemarker.template.TemplateModel)
+     */
+    protected boolean preTemplateProcess(HttpServletRequest request, HttpServletResponse response, Template template, TemplateModel templateModel) throws ServletException, IOException {
+        boolean result = super.preTemplateProcess(request, response, template, templateModel);
+
+        SimpleHash hash = (SimpleHash) templateModel;
+
+        HTMLPage htmlPage = (HTMLPage) request.getAttribute(RequestConstants.PAGE);
+
+        String title, body, head;
+
+        if (htmlPage == null) {
+            title = "No Title";
+            body = "No Body";
+            head = "<!-- No head -->";
+        } else {
+            title = htmlPage.getTitle();
+
+            StringWriter buffer = new StringWriter();
+            htmlPage.writeBody(buffer);
+            body = buffer.toString();
+
+            buffer = new StringWriter();
+            htmlPage.writeHead(buffer);
+            head = buffer.toString();
+
+            hash.put("page", htmlPage);
+        }
+
+        hash.put("title", title);
+        hash.put("body", body);
+        hash.put("head", head);
+        hash.put("base", request.getContextPath());
+
+        /*
+          Factory factory = Factory.getInstance(new Config(getServletConfig()));
+          Decorator decorator = factory.getDecoratorMapper().getDecorator(request, htmlPage);
+          -> decorator.getPage()
+          */
+
+        return result;
+    }
+
+    /**
+     * If the parameter "nocache" was set to true, generate a set of headers
+     * that will advise the HTTP client not to cache the returned page.
+     */
+    private void setBrowserCachingPolicy(HttpServletResponse res) {
+        if (nocache) {
+            // HTTP/1.1 + IE extensions
+            res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, " + "post-check=0, pre-check=0");
+            // HTTP/1.0
+            res.setHeader("Pragma", "no-cache");
+            // Last resort for those that ignore all of the above
+            res.setHeader("Expires", EXPIRATION_DATE);
+        }
+    }
+
+    protected ScopesHashModel populateModel(ScopesHashModel params, ObjectWrapper wrapper, ServletContext servletContext, final HttpServletRequest request, final HttpServletResponse response) throws TemplateModelException {
+        try {
+            // Create hash model wrapper for servlet context (the application)
+            ServletContextHashModel servletContextModel = (ServletContextHashModel) servletContext.getAttribute(ATTR_APPLICATION_MODEL);
+            if (servletContextModel == null) {
+                servletContextModel = new ServletContextHashModel(this, wrapper);
+                servletContext.setAttribute(ATTR_APPLICATION_MODEL, servletContextModel);
+                TaglibFactory taglibs = new TaglibFactory(servletContext);
+                servletContext.setAttribute(ATTR_JSP_TAGLIBS_MODEL, taglibs);
+                initializeServletContext(request, response);
+            }
+            params.putUnlistedModel(KEY_APPLICATION, servletContextModel);
+            params.putUnlistedModel(KEY_APPLICATION_PRIVATE, servletContextModel);
+            params.putUnlistedModel(KEY_JSP_TAGLIBS, (TemplateModel) servletContext.getAttribute(ATTR_JSP_TAGLIBS_MODEL));
+            // Create hash model wrapper for session
+            HttpSessionHashModel sessionModel;
+            HttpSession session = request.getSession(false);
+            if (session != null) {
+                sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL);
+                if (sessionModel == null) {
+                    sessionModel = new HttpSessionHashModel(session, wrapper);
+                    session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
+                    initializeSession(request, response);
+                }
+            } else {
+                sessionModel = new HttpSessionHashModel(this, request, response, wrapper);
+            }
+            params.putUnlistedModel(KEY_SESSION, sessionModel);
+
+            // Create hash model wrapper for request
+            HttpRequestHashModel requestModel = (HttpRequestHashModel) request.getAttribute(ATTR_REQUEST_MODEL);
+            if (requestModel == null || requestModel.getRequest() != request) {
+                requestModel = new HttpRequestHashModel(request, response, wrapper);
+                request.setAttribute(ATTR_REQUEST_MODEL, requestModel);
+                request.setAttribute(ATTR_REQUEST_PARAMETERS_MODEL, createRequestParametersHashModel(request));
+            }
+            params.putUnlistedModel(KEY_REQUEST, requestModel);
+            params.putUnlistedModel(KEY_INCLUDE, new IncludePage(request, response));
+            params.putUnlistedModel(KEY_REQUEST_PRIVATE, requestModel);
+
+            // Create hash model wrapper for request parameters
+            HttpRequestParametersHashModel requestParametersModel = (HttpRequestParametersHashModel) request.getAttribute(ATTR_REQUEST_PARAMETERS_MODEL);
+            params.putUnlistedModel(KEY_REQUEST_PARAMETERS, requestParametersModel);
+            return params;
+        } catch (ServletException e) {
+            throw new TemplateModelException(e);
+        } catch (IOException e) {
+            throw new TemplateModelException(e);
+        }
+    }
+}

Added: struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsDecorator.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsDecorator.java?rev=835248&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsDecorator.java (added)
+++ struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsDecorator.java Thu Nov 12 06:06:40 2009
@@ -0,0 +1,203 @@
+/*
+ * $Id$
+ *
+ * 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.struts2.sitemesh;
+
+import com.opensymphony.module.sitemesh.RequestConstants;
+import com.opensymphony.sitemesh.Content;
+import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext;
+import com.opensymphony.sitemesh.webapp.decorator.BaseWebAppDecorator;
+import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import freemarker.template.Configuration;
+import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.dispatcher.Dispatcher;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Locale;
+
+/**
+ * Adapts a SiteMesh 2 {@link com.opensymphony.module.sitemesh.Decorator} to a
+ * SiteMesh 3 {@link com.opensymphony.sitemesh.Decorator}.
+ *
+ * @since SiteMesh 3
+ */
+public abstract class OldDecorator2NewStrutsDecorator extends BaseWebAppDecorator implements RequestConstants {
+
+    protected com.opensymphony.module.sitemesh.Decorator oldDecorator;
+    private static String customEncoding;
+
+    public OldDecorator2NewStrutsDecorator(com.opensymphony.module.sitemesh.Decorator oldDecorator) {
+        this.oldDecorator = oldDecorator;
+    }
+
+    public OldDecorator2NewStrutsDecorator() {
+        oldDecorator = null;
+    }
+
+
+    /**
+     * Applies the decorator, using the relevent contexts
+     *
+     * @param content        The content
+     * @param request        The servlet request
+     * @param response       The servlet response
+     * @param servletContext The servlet context
+     * @param ctx            The action context for this request, populated with the server state
+     */
+    protected abstract void render(Content content, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, ActionContext ctx) throws ServletException, IOException;
+
+    /**
+     * Applies the decorator, creating the relevent contexts and delegating to
+     * the extended applyDecorator().
+     *
+     * @param content        The content
+     * @param request        The servlet request
+     * @param response       The servlet response
+     * @param servletContext The servlet context
+     * @param webAppContext  The web app context
+     */
+
+    protected void render(Content content, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, SiteMeshWebAppContext webAppContext) throws IOException, ServletException {
+
+        // see if the URI path (webapp) is set
+        if (oldDecorator.getURIPath() != null) {
+            // in a security conscious environment, the servlet container
+            // may return null for a given URL
+            if (servletContext.getContext(oldDecorator.getURIPath()) != null) {
+                servletContext = servletContext.getContext(oldDecorator.getURIPath());
+            }
+        }
+
+        ActionContext ctx = ServletActionContext.getActionContext(request);
+        if (ctx == null) {
+            // ok, one isn't associated with the request, so let's create one using the current Dispatcher
+            ValueStack vs = Dispatcher.getInstance().getContainer().getInstance(ValueStackFactory.class).createValueStack();
+            vs.getContext().putAll(Dispatcher.getInstance().createContextMap(request, response, null, servletContext));
+            ctx = new ActionContext(vs.getContext());
+            if (ctx.getActionInvocation() == null) {
+                // put in a dummy ActionSupport so basic functionality still works
+                ActionSupport action = new ActionSupport();
+                vs.push(action);
+                ctx.setActionInvocation(new DummyActionInvocation(action));
+            }
+        }
+
+        // delegate to the actual page decorator
+        render(content, request, response, servletContext, ctx);
+
+    }
+
+    /**
+     * Returns the locale used for the {@link freemarker.template.Configuration#getTemplate(String, java.util.Locale)} call. The base implementation
+     * simply returns the locale setting of the action (assuming the action implements {@link LocaleProvider}) or, if
+     * the action does not the configuration's locale is returned. Override this method to provide different behaviour,
+     */
+    protected Locale getLocale(ActionInvocation invocation, Configuration configuration) {
+        if (invocation.getAction() instanceof LocaleProvider) {
+            return ((LocaleProvider) invocation.getAction()).getLocale();
+        } else {
+            return configuration.getLocale();
+        }
+    }
+
+
+    /**
+     * Gets the L18N encoding of the system.  The default is UTF-8.
+     */
+    protected String getEncoding() {
+        String encoding = customEncoding;
+        if (encoding == null) {
+            encoding = System.getProperty("file.encoding");
+        }
+        if (encoding == null) {
+            encoding = "UTF-8";
+        }
+        return encoding;
+    }
+
+
+    static class DummyActionInvocation implements ActionInvocation {
+
+        private static final long serialVersionUID = -4808072199157363028L;
+
+        ActionSupport action;
+
+        public DummyActionInvocation(ActionSupport action) {
+            this.action = action;
+        }
+
+        public Object getAction() {
+            return action;
+        }
+
+        public boolean isExecuted() {
+            return false;
+        }
+
+        public ActionContext getInvocationContext() {
+            return null;
+        }
+
+        public ActionProxy getProxy() {
+            return null;
+        }
+
+        public Result getResult() throws Exception {
+            return null;
+        }
+
+        public String getResultCode() {
+            return null;
+        }
+
+        public void setResultCode(String resultCode) {
+        }
+
+        public ValueStack getStack() {
+            return null;
+        }
+
+        public void addPreResultListener(PreResultListener listener) {
+        }
+
+        public String invoke() throws Exception {
+            return null;
+        }
+
+        public String invokeActionOnly() throws Exception {
+            return null;
+        }
+
+        public void setActionEventListener(ActionEventListener listener) {
+        }
+
+        public void init(ActionProxy proxy) {
+        }
+    }
+
+}

Added: struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsFreemarkerDecorator.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsFreemarkerDecorator.java?rev=835248&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsFreemarkerDecorator.java (added)
+++ struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsFreemarkerDecorator.java Thu Nov 12 06:06:40 2009
@@ -0,0 +1,108 @@
+/**
+ * Adapts a SiteMesh 2 Freemarker {@link com.opensymphony.module.sitemesh.Decorator} to a
+ * SiteMesh 3 {@link com.opensymphony.sitemesh.Decorator}.
+ *
+ * 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.
+ * @since SiteMesh 2
+ */
+package org.apache.struts2.sitemesh;
+
+import com.opensymphony.module.sitemesh.HTMLPage;
+import com.opensymphony.sitemesh.Content;
+import com.opensymphony.sitemesh.compatability.Content2HTMLPage;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
+import freemarker.template.Configuration;
+import freemarker.template.SimpleHash;
+import freemarker.template.Template;
+import org.apache.struts2.views.freemarker.FreemarkerManager;
+import org.apache.struts2.views.freemarker.ScopesHashModel;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Extends OldDecorator2NewStrutsDecorator to add Struts functionality  for Freemarker
+ */
+public class OldDecorator2NewStrutsFreemarkerDecorator extends OldDecorator2NewStrutsDecorator {
+    private static final Logger LOG = LoggerFactory.getLogger(OldDecorator2NewStrutsFreemarkerDecorator.class);
+
+    private static FreemarkerManager freemarkerManager;
+
+    public static void setFreemarkerManager(FreemarkerManager mgr) {
+        freemarkerManager = mgr;
+    }
+
+    public OldDecorator2NewStrutsFreemarkerDecorator(com.opensymphony.module.sitemesh.Decorator oldDecorator) {
+        this.oldDecorator = oldDecorator;
+    }
+
+    /**
+     * Applies the decorator, using the relevent contexts
+     *
+     * @param content        The content
+     * @param request        The servlet request
+     * @param response       The servlet response
+     * @param servletContext The servlet context
+     * @param ctx            The action context for this request, populated with the server state
+     */
+    protected void render(Content content, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, ActionContext ctx) throws ServletException, IOException {
+        String timerKey = "FreemarkerPageFilter_applyDecorator: ";
+        if (freemarkerManager == null) {
+            throw new ServletException("Missing freemarker dependency");
+        }
+
+        try {
+            UtilTimerStack.push(timerKey);
+
+            // get the configuration and template
+            Configuration config = freemarkerManager.getConfiguration(servletContext);
+            Template template = config.getTemplate(oldDecorator.getPage(), getLocale(ctx.getActionInvocation(), config)); // WW-1181
+
+            // get the main hash
+            ScopesHashModel model = (ScopesHashModel) request.getAttribute(freemarkerManager.ATTR_TEMPLATE_MODEL);
+            if (model == null) {
+                model = freemarkerManager.buildTemplateModel(ctx.getValueStack(), ctx.getActionInvocation().getAction(), servletContext, request, response, config.getObjectWrapper());
+            }
+
+            // populate the hash with the page
+            HTMLPage htmlPage = new Content2HTMLPage(content, request);
+            model.put("page", htmlPage);
+            model.put("head", htmlPage.getHead());
+            model.put("title", htmlPage.getTitle());
+            model.put("body", htmlPage.getBody());
+            model.put("page.properties", new SimpleHash(htmlPage.getProperties()));
+
+            // finally, render it
+            template.process(model, response.getWriter());
+        } catch (Exception e) {
+            String msg = "Error applying decorator to request: " + request.getRequestURL() + "?" + request.getQueryString() + " with message:" + e.getMessage();
+            LOG.error(msg, e);
+            throw new ServletException(msg, e);
+        } finally {
+            UtilTimerStack.pop(timerKey);
+        }
+    }
+
+}
+

Added: struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java?rev=835248&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java (added)
+++ struts/struts2/trunk/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/OldDecorator2NewStrutsVelocityDecorator.java Thu Nov 12 06:06:40 2009
@@ -0,0 +1,108 @@
+/**
+ * Adapts a SiteMesh 2 Velocity {@link com.opensymphony.module.sitemesh.Decorator}
+ * to a SiteMesh 3 {@link com.opensymphony.sitemesh.Decorator}.
+ *
+ *
+ * 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.
+ * @since SiteMesh 2
+ */
+
+package org.apache.struts2.sitemesh;
+
+import com.opensymphony.module.sitemesh.HTMLPage;
+import com.opensymphony.sitemesh.Content;
+import com.opensymphony.sitemesh.compatability.Content2HTMLPage;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.views.velocity.VelocityManager;
+import org.apache.velocity.context.Context;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Extends OldDecorator2NewStrutsDecorator to add Struts functionality for Velocity
+ */
+public class OldDecorator2NewStrutsVelocityDecorator extends OldDecorator2NewStrutsDecorator {
+    private static final Logger LOG = LoggerFactory.getLogger(OldDecorator2NewStrutsFreemarkerDecorator.class);
+
+    private static VelocityManager velocityManager;
+
+    @Inject(required = false)
+    public static void setVelocityManager(VelocityManager mgr) {
+        velocityManager = mgr;
+    }
+
+    public OldDecorator2NewStrutsVelocityDecorator(com.opensymphony.module.sitemesh.Decorator oldDecorator) {
+        this.oldDecorator = oldDecorator;
+    }
+
+    /**
+     * Applies the decorator, using the relevent contexts
+     *
+     * @param content        The content
+     * @param request        The servlet request
+     * @param response       The servlet response
+     * @param servletContext The servlet context
+     * @param ctx            The action context for this request, populated with the server state
+     */
+    protected void render(Content content, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, ActionContext ctx) throws ServletException, IOException {
+        String timerKey = "FreemarkerPageFilter_applyDecorator: ";
+        if (velocityManager == null) {
+            throw new ServletException("Missing freemarker dependency");
+        }
+
+        try {
+
+            // init (if needed)
+            velocityManager.init(servletContext);
+
+            // get encoding
+            String encoding = getEncoding();
+
+            HTMLPage htmlPage = new Content2HTMLPage(content, request);
+
+            // get the template and context
+            org.apache.velocity.Template template = velocityManager.getVelocityEngine().getTemplate(oldDecorator.getPage(), encoding);
+            Context context = velocityManager.createContext(ctx.getValueStack(), request, response);
+
+            // put the page in the context
+            context.put("page", htmlPage);
+            context.put("head", htmlPage.getHead());
+            context.put("title", htmlPage.getTitle());
+            context.put("body", htmlPage.getBody());
+
+            // finally, render it
+            PrintWriter writer = response.getWriter();
+            template.merge(context, writer);
+            writer.flush();
+        } catch (Exception e) {
+            String msg = "Error applying decorator to request: " + request.getRequestURL() + "?" + request.getQueryString() + " with message:" + e.getMessage();
+            LOG.error(msg, e);
+            throw new ServletException(msg, e);
+        }
+    }
+
+}
+