Author: musachy
Date: Thu Nov 12 06:06:40 2009
New Revision: 835248
URL:
http://svn.apache.org/viewvc?rev=835248&view=revLog:
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);
+ }
+ }
+
+}
+