diff --git a/apps/showcase/src/main/resources/struts-tiles.xml b/apps/showcase/src/main/resources/struts-tiles.xml index e05296b87..178f9ed68 100644 --- a/apps/showcase/src/main/resources/struts-tiles.xml +++ b/apps/showcase/src/main/resources/struts-tiles.xml @@ -13,6 +13,10 @@ showcase.index + + showcase.freemarker + + /tiles/layout.jsp /tiles/layout.jsp diff --git a/apps/showcase/src/main/webapp/WEB-INF/tiles.xml b/apps/showcase/src/main/webapp/WEB-INF/tiles.xml index 4f581433f..b58dd064b 100644 --- a/apps/showcase/src/main/webapp/WEB-INF/tiles.xml +++ b/apps/showcase/src/main/webapp/WEB-INF/tiles.xml @@ -21,16 +21,22 @@ */ --> - + - - - - - + + + + + + + + + + + diff --git a/apps/showcase/src/main/webapp/tiles/body.ftl b/apps/showcase/src/main/webapp/tiles/body.ftl new file mode 100644 index 000000000..e9e9ef185 --- /dev/null +++ b/apps/showcase/src/main/webapp/tiles/body.ftl @@ -0,0 +1,6 @@ +
+

This example illustrates the freemarker support in the Struts/Tiles Plugin.

+ +

Tiles 2 is an effort to extract the Tiles library from Struts. It is currently housed + in the Sandbox area of the Apache Struts Subversion repository.

+
\ No newline at end of file diff --git a/apps/showcase/src/main/webapp/tiles/body.jsp b/apps/showcase/src/main/webapp/tiles/body.jsp index 8b58dcc40..11057226c 100644 --- a/apps/showcase/src/main/webapp/tiles/body.jsp +++ b/apps/showcase/src/main/webapp/tiles/body.jsp @@ -1,6 +1,15 @@ +<%@taglib prefix="s" uri="/struts-tags" %>

This example illustrates the Struts/Tiles Plugin.

Tiles 2 is an effort to extract the Tiles library from Struts. It is currently housed in the Sandbox area of the Apache Struts Subversion repository.

+ +

Features

+ +
\ No newline at end of file diff --git a/apps/showcase/src/main/webapp/tiles/layout.jsp b/apps/showcase/src/main/webapp/tiles/layout.jsp index 209c1a75d..3162ffbc3 100644 --- a/apps/showcase/src/main/webapp/tiles/layout.jsp +++ b/apps/showcase/src/main/webapp/tiles/layout.jsp @@ -13,4 +13,3 @@

- diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java b/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java index 5f62988a7..0227eb40a 100644 --- a/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java +++ b/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java @@ -101,6 +101,7 @@ public class FreemarkerResult extends StrutsResultSupport { protected Configuration configuration; protected ObjectWrapper wrapper; protected FreemarkerManager freemarkerManager; + private Writer writer; /* * Struts results are constructed for each result execution @@ -199,10 +200,18 @@ public class FreemarkerResult extends StrutsResultSupport { return configuration.getObjectWrapper(); } + + public void setWriter(Writer writer) { + this.writer = writer; + } + /** * The default writer writes directly to the response writer. */ protected Writer getWriter() throws IOException { + if(writer != null) { + return writer; + } return ServletActionContext.getResponse().getWriter(); } diff --git a/plugins/jsf/src/main/java/org/apache/struts2/jsf/FacesResult.java b/plugins/jsf/src/main/java/org/apache/struts2/jsf/FacesResult.java index 4be7bbf0f..f98fa030b 100644 --- a/plugins/jsf/src/main/java/org/apache/struts2/jsf/FacesResult.java +++ b/plugins/jsf/src/main/java/org/apache/struts2/jsf/FacesResult.java @@ -48,8 +48,7 @@ public class FacesResult extends StrutsResultSupport implements Result { * config and then renders the result by delegating to the * FacesRender.render(). * - * @see org.apache.struts2.dispatcher.StrutsResultSupport#doExecute(java.lang.String, - * com.opensymphony. + * @see org.apache.struts2.dispatcher.StrutsResultSupport#doExecute(String, ActionInvocation) */ protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/ConfiguredServletContext.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/ConfiguredServletContext.java new file mode 100644 index 000000000..a28c1ac25 --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/ConfiguredServletContext.java @@ -0,0 +1,185 @@ +/* + * 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.tiles; + + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; + +/** + * ServletContext implementation which allows Struts + * to inject initialization parameters into the context + * in order to reduce the amount of configuration required + * within web.xml for using Tiles. + * + * The specified init parameters are only utilized if + * they are not explicitaly defined in the web.xml + * + * @version $Rev$ + * @since Struts 2.0.1 + */ +@SuppressWarnings("deprecation") +public class ConfiguredServletContext implements ServletContext { + + private ServletContext rootContext; + private Map initParameters; + + + public ConfiguredServletContext(ServletContext context, Map initParameters) { + this.rootContext = context; + this.initParameters = initParameters; + } + + public ServletContext getContext(String string) { + return rootContext.getContext(string); + } + + public int getMajorVersion() { + return rootContext.getMajorVersion(); + } + + public int getMinorVersion() { + return rootContext.getMinorVersion(); + } + + public String getMimeType(String string) { + return rootContext.getMimeType(string); + } + + public Set getResourcePaths(String string) { + return rootContext.getResourcePaths(string); + } + + public URL getResource(String string) throws MalformedURLException { + return rootContext.getResource(string); + } + + public InputStream getResourceAsStream(String string) { + return rootContext.getResourceAsStream(string); + } + + public RequestDispatcher getRequestDispatcher(String string) { + return rootContext.getRequestDispatcher(string); + } + + public RequestDispatcher getNamedDispatcher(String string) { + return rootContext.getNamedDispatcher(string); + } + + @SuppressWarnings("deprecation") + public Servlet getServlet(String string) throws ServletException { + return rootContext.getServlet(string); + } + + @SuppressWarnings("deprecation") + public Enumeration getServlets() { + return rootContext.getServlets(); //To change body of implemented methods use File | Settings | File Templates. + } + + @SuppressWarnings("deprecation") + public Enumeration getServletNames() { + return rootContext.getServletNames(); + } + + public void log(String string) { + rootContext.log(string); + } + + @SuppressWarnings("deprecation") + public void log(Exception exception, String string) { + rootContext.log(exception, string); + } + + public void log(String string, Throwable throwable) { + rootContext.log(string, throwable); + } + + public String getRealPath(String string) { + return rootContext.getRealPath(string); + } + + public String getServerInfo() { + return rootContext.getServerInfo(); + } + + public String getInitParameter(String string) { + String parm = rootContext.getInitParameter(string); + if (parm == null) { + return initParameters.get(string); + } + return parm; + } + + public Enumeration getInitParameterNames() { + return new CompositeEnumeration( + rootContext.getInitParameterNames(), + initParameters.keySet().iterator()); + } + + public Object getAttribute(String string) { + return rootContext.getAttribute(string); + } + + public Enumeration getAttributeNames() { + return rootContext.getAttributeNames(); + } + + public void setAttribute(String string, Object object) { + rootContext.setAttribute(string, object); + } + + public void removeAttribute(String string) { + rootContext.removeAttribute(string); + } + + public String getServletContextName() { + return rootContext.getServletContextName(); + } + + class CompositeEnumeration implements Enumeration { + + private Enumeration first; + private Iterator second; + + + public CompositeEnumeration(Enumeration first, Iterator second) { + this.first = first; + this.second = second; + } + + public boolean hasMoreElements() { + return first.hasMoreElements() || second.hasNext(); + } + + public Object nextElement() { + if (first.hasMoreElements()) { + return first.nextElement(); + } + + return second.next(); + } + } +} diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java index 7ef223126..479fec380 100644 --- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java @@ -73,7 +73,7 @@ public class StrutsTilesContainerFactory extends TilesContainerFactory { } /** - * Wrapper factory, used to wrap the TilesRequestContext with a + * Wrapper factory, used to decorate the TilesRequestContext with a * FreemarkerResult aware version. * */ diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java new file mode 100644 index 000000000..9c1a4d4f7 --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java @@ -0,0 +1,73 @@ +/* + * $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.tiles; + +import org.apache.tiles.listener.TilesListener; +import org.apache.tiles.TilesContainer; +import org.apache.tiles.TilesException; +import org.apache.tiles.factory.TilesContainerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.servlet.ServletContext; +import java.util.Map; +import java.util.HashMap; + +/** + * Listener used to automatically inject ServletContext + * init parameters so that they don't need to be configured + * explicitly for tiles integration. This is provided + * mainly for backwards compatibility with Struts 2.0.1 + * configuration. + * + * @since Struts 2.0.2 + * @version $Rev$ + * + */ +public class StrutsTilesListener extends TilesListener { + + private static final Log LOG = + LogFactory.getLog(StrutsTilesListener.class); + + private static final Map INIT; + + static { + INIT = new HashMap(); + INIT.put(TilesContainerFactory.CONTAINER_FACTORY_INIT_PARAM, + StrutsTilesContainerFactory.class.getName()); + } + + protected TilesContainer createContainer(ServletContext context) + throws TilesException { + if(context.getInitParameter(TilesContainerFactory.CONTEXT_FACTORY_INIT_PARAM) == null) { + context = decorate(context); + } + else { + LOG.warn("Tiles container factory is explicitly set. Not injecting struts configuration."); + } + return super.createContainer(context); + } + + protected ServletContext decorate(ServletContext context) { + return new ConfiguredServletContext(context, INIT); + } + +} diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesRequestContext.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesRequestContext.java index d81b017aa..ead169e2d 100644 --- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesRequestContext.java +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesRequestContext.java @@ -21,16 +21,18 @@ package org.apache.struts2.tiles; import com.opensymphony.xwork2.ActionInvocation; -import freemarker.template.TemplateException; +import com.opensymphony.xwork2.inject.Container; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.dispatcher.Dispatcher; import org.apache.struts2.views.freemarker.FreemarkerResult; import org.apache.tiles.context.TilesRequestContext; import org.apache.tiles.context.TilesRequestContextWrapper; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** @@ -49,6 +51,7 @@ public class StrutsTilesRequestContext extends TilesRequestContextWrapper { private static final Log LOG = LogFactory.getLog(StrutsTilesRequestContext.class); + /** * The mask used to detect requests which should be intercepted. */ @@ -86,8 +89,6 @@ public class StrutsTilesRequestContext extends TilesRequestContextWrapper { * be used in order to setup the appropriate model. * * @throws IOException - * @throws ServletException - * @throws Exception */ public void include(String include) throws IOException { if (include.endsWith(mask)) { @@ -95,20 +96,29 @@ public class StrutsTilesRequestContext extends TilesRequestContextWrapper { LOG.debug("Intercepting tiles include '" + include + "'. Processing as freemarker result."); } HttpServletRequest request = (HttpServletRequest) getRequest(); + HttpServletResponse response = (HttpServletResponse) getResponse(); ActionInvocation invocation = ServletActionContext.getActionContext(request).getActionInvocation(); - FreemarkerResult result = new FreemarkerResult(); - try { + FreemarkerResult result = new FreemarkerResult(); + result.setWriter(response.getWriter()); + + Container container = Dispatcher.getInstance() + .getConfigurationManager() + .getConfiguration().getContainer(); + + container.inject(result); + result.doExecute(include, invocation); - } catch (TemplateException e) { + } catch (Exception e) { LOG.error("Error invoking Freemarker template", e); - throw new IOException("Error invoking Freemarker template."+ e.getMessage()); + throw new IOException("Error invoking Freemarker template." + e.getMessage()); } } else { super.include(include); } } + }