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