1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts.tiles;
23
24 import java.io.IOException;
25 import java.io.Serializable;
26
27 import java.lang.reflect.Method;
28 import java.lang.reflect.InvocationTargetException;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletException;
32 import javax.servlet.ServletRequest;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35 import javax.servlet.jsp.PageContext;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.struts.tiles.definition.ComponentDefinitionsFactoryWrapper;
40 import org.apache.struts.util.RequestUtils;
41
42 /**
43 * Default implementation of TilesUtil.
44 * This class contains default implementation of utilities. This implementation
45 * is intended to be used without Struts.
46 */
47 public class TilesUtilImpl implements Serializable {
48
49 /** Commons Logging instance.*/
50 protected static final Log log = LogFactory.getLog(TilesUtil.class);
51
52 /** Constant name used to store factory in servlet context */
53 public static final String DEFINITIONS_FACTORY =
54 "org.apache.struts.tiles.DEFINITIONS_FACTORY";
55
56 /**
57 * JSP 2.0 include method to use which supports configurable flushing.
58 */
59 private static Method include = null;
60
61 /**
62 * Initialize the include variable with the
63 * JSP 2.0 method if available.
64 */
65 static {
66
67 try {
68
69 Class[] args = new Class[]{String.class, boolean.class};
70 include = PageContext.class.getMethod("include", args);
71 } catch (NoSuchMethodException e) {
72 log.debug("Could not find JSP 2.0 include method. Using old one that doesn't support " +
73 "configurable flushing.", e);
74 }
75 }
76
77 /**
78 * Do a forward using request dispatcher.
79 *
80 * This method is used by the Tiles package anytime a forward is required.
81 * @param uri Uri or Definition name to forward.
82 * @param request Current page request.
83 * @param servletContext Current servlet context.
84 */
85 public void doForward(
86 String uri,
87 HttpServletRequest request,
88 HttpServletResponse response,
89 ServletContext servletContext)
90 throws IOException, ServletException {
91
92 request.getRequestDispatcher(uri).forward(request, response);
93 }
94
95 /**
96 * Do an include using request dispatcher.
97 *
98 * This method is used by the Tiles package when an include is required.
99 * The Tiles package can use indifferently any form of this method.
100 * @param uri Uri or Definition name to forward.
101 * @param request Current page request.
102 * @param response Current page response.
103 * @param servletContext Current servlet context.
104 */
105 public void doInclude(
106 String uri,
107 HttpServletRequest request,
108 HttpServletResponse response,
109 ServletContext servletContext)
110 throws IOException, ServletException {
111
112 request.getRequestDispatcher(uri).include(request, response);
113 }
114
115 /**
116 * Do an include using PageContext.include().
117 *
118 * This method is used by the Tiles package when an include is required.
119 * The Tiles package can use indifferently any form of this method.
120 * @param uri Uri or Definition name to forward.
121 * @param pageContext Current page context.
122 * @param flush If the writer should be flushed before the include
123 */
124 public void doInclude(String uri, PageContext pageContext, boolean flush)
125 throws IOException, ServletException {
126 try {
127
128 if (include != null) {
129 include.invoke(pageContext, new Object[]{uri, Boolean.valueOf(flush)});
130 return;
131 }
132 } catch (IllegalAccessException e) {
133 log.debug("Could not find JSP 2.0 include method. Using old one.", e);
134 } catch (InvocationTargetException e) {
135 log.debug("Unable to execute JSP 2.0 include method. Trying old one.", e);
136 }
137
138 pageContext.include(uri);
139 }
140
141 /**
142 * Get definition factory from appropriate servlet context.
143 * @return Definitions factory or <code>null</code> if not found.
144 */
145 public DefinitionsFactory getDefinitionsFactory(
146 ServletRequest request,
147 ServletContext servletContext) {
148
149 return (DefinitionsFactory) servletContext.getAttribute(DEFINITIONS_FACTORY);
150 }
151
152 /**
153 * Create Definition factory from specified configuration object.
154 * Create an instance of the factory with the class specified in the config
155 * object. Then, initialize this factory and finally store the factory in
156 * appropriate context by calling
157 * {@link #makeDefinitionsFactoryAccessible(DefinitionsFactory, ServletContext)}.
158 * Factory creation is done by {@link #createDefinitionFactoryInstance(String)}.
159 * <p>
160 *
161 * @param servletContext Servlet Context passed to newly created factory.
162 * @param factoryConfig Configuration object passed to factory.
163 * @return newly created factory of type specified in the config object.
164 * @throws DefinitionsFactoryException If an error occur while initializing factory
165 */
166 public DefinitionsFactory createDefinitionsFactory(
167 ServletContext servletContext,
168 DefinitionsFactoryConfig factoryConfig)
169 throws DefinitionsFactoryException {
170
171
172 DefinitionsFactory factory =
173 createDefinitionFactoryInstance(factoryConfig.getFactoryClassname());
174
175 factory.init(factoryConfig, servletContext);
176
177
178 makeDefinitionsFactoryAccessible(factory, servletContext);
179 return factory;
180 }
181
182 /**
183 * Create Definition factory of specified classname.
184 * Factory class must extend the {@link DefinitionsFactory} class.
185 * The factory is wrapped appropriately with {@link ComponentDefinitionsFactoryWrapper}
186 * if it is an instance of the deprecated ComponentDefinitionsFactory class.
187 * @param classname Class name of the factory to create.
188 * @return newly created factory.
189 * @throws DefinitionsFactoryException If an error occur while initializing factory
190 */
191 protected DefinitionsFactory createDefinitionFactoryInstance(String classname)
192 throws DefinitionsFactoryException {
193
194 try {
195 Class factoryClass = RequestUtils.applicationClass(classname);
196 Object factory = factoryClass.newInstance();
197
198
199
200 if (factory instanceof ComponentDefinitionsFactory) {
201 factory =
202 new ComponentDefinitionsFactoryWrapper(
203 (ComponentDefinitionsFactory) factory);
204 }
205 return (DefinitionsFactory) factory;
206
207 } catch (ClassCastException ex) {
208 throw new DefinitionsFactoryException(
209 "Error - createDefinitionsFactory : Factory class '"
210 + classname
211 + " must implement 'TilesDefinitionsFactory'.",
212 ex);
213
214 } catch (ClassNotFoundException ex) {
215 throw new DefinitionsFactoryException(
216 "Error - createDefinitionsFactory : Bad class name '"
217 + classname
218 + "'.",
219 ex);
220
221 } catch (InstantiationException ex) {
222 throw new DefinitionsFactoryException(ex);
223
224 } catch (IllegalAccessException ex) {
225 throw new DefinitionsFactoryException(ex);
226 }
227 }
228
229 /**
230 * Make definition factory accessible to Tags.
231 * Factory is stored in servlet context.
232 * @param factory Factory to be made accessible.
233 * @param servletContext Current servlet context.
234 */
235 protected void makeDefinitionsFactoryAccessible(
236 DefinitionsFactory factory,
237 ServletContext servletContext) {
238
239 servletContext.setAttribute(DEFINITIONS_FACTORY, factory);
240 }
241
242 }