001: package org.apache.turbine.services.jsp;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.File;
023: import java.io.IOException;
024:
025: import javax.servlet.RequestDispatcher;
026: import javax.servlet.ServletConfig;
027: import javax.servlet.http.HttpServletRequest;
028:
029: import org.apache.commons.configuration.Configuration;
030:
031: import org.apache.commons.lang.StringUtils;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: import org.apache.turbine.Turbine;
037: import org.apache.turbine.services.InitializationException;
038: import org.apache.turbine.services.pull.ApplicationTool;
039: import org.apache.turbine.services.pull.tools.TemplateLink;
040: import org.apache.turbine.services.template.BaseTemplateEngineService;
041: import org.apache.turbine.util.RunData;
042: import org.apache.turbine.util.TurbineException;
043:
044: /**
045: * This is a Service that can process JSP templates from within a Turbine
046: * screen.
047: *
048: * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
049: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
050: * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
051: * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
052: * @version $Id: TurbineJspService.java 534527 2007-05-02 16:10:59Z tv $
053: */
054: public class TurbineJspService extends BaseTemplateEngineService
055: implements JspService {
056: /** The base path[s] prepended to filenames given in arguments */
057: private String[] templatePaths;
058:
059: /** The relative path[s] prepended to filenames */
060: private String[] relativeTemplatePaths;
061:
062: /** The buffer size for the output stream. */
063: private int bufferSize;
064:
065: /** Logging */
066: private static Log log = LogFactory.getLog(TurbineJspService.class);
067:
068: /**
069: * Load all configured components and initialize them. This is
070: * a zero parameter variant which queries the Turbine Servlet
071: * for its config.
072: *
073: * @throws InitializationException Something went wrong in the init
074: * stage
075: */
076: public void init() throws InitializationException {
077: try {
078: initJsp();
079: registerConfiguration(JspService.JSP_EXTENSION);
080: setInit(true);
081: } catch (Exception e) {
082: throw new InitializationException(
083: "TurbineJspService failed to initialize", e);
084: }
085: }
086:
087: /**
088: * Performs early initialization of this Turbine service.
089: *
090: * @param config The ServletConfiguration from Turbine
091: *
092: * @throws InitializationException Something went wrong when starting up.
093: * @deprecated use init() instead.
094: */
095: public void init(ServletConfig config)
096: throws InitializationException {
097: init();
098: }
099:
100: /**
101: * Adds some convenience objects to the request. For example an instance
102: * of TemplateLink which can be used to generate links to other templates.
103: *
104: * @param data the turbine rundata object
105: */
106: public void addDefaultObjects(RunData data) {
107: HttpServletRequest req = data.getRequest();
108:
109: //
110: // This is a place where an Application Pull Tool is used
111: // in a regular Java Context. We have no Pull Service with the
112: // Jsp Paging stuff, but we can run our Application Tool by Hand:
113: //
114: ApplicationTool templateLink = new TemplateLink();
115: templateLink.init(data);
116:
117: req.setAttribute(LINK, templateLink);
118: req.setAttribute(RUNDATA, data);
119: }
120:
121: /**
122: * Returns the default buffer size of the JspService
123: *
124: * @return The default buffer size.
125: */
126: public int getDefaultBufferSize() {
127: return bufferSize;
128: }
129:
130: /**
131: * executes the JSP given by templateName.
132: *
133: * @param data A RunData Object
134: * @param templateName the filename of the template.
135: * @throws TurbineException Any exception thrown while processing will be
136: * wrapped into a TurbineException and rethrown.
137: */
138: public void handleRequest(RunData data, String templateName)
139: throws TurbineException {
140: handleRequest(data, templateName, false);
141: }
142:
143: /**
144: * executes the JSP given by templateName.
145: *
146: * @param data A RunData Object
147: * @param templateName the filename of the template.
148: * @param isForward whether to perform a forward or include.
149: * @throws TurbineException Any exception trown while processing will be
150: * wrapped into a TurbineException and rethrown.
151: */
152: public void handleRequest(RunData data, String templateName,
153: boolean isForward) throws TurbineException {
154: /** template name with relative path */
155: String relativeTemplateName = getRelativeTemplateName(templateName);
156:
157: if (StringUtils.isEmpty(relativeTemplateName)) {
158: throw new TurbineException("Template " + templateName
159: + " not found in template paths");
160: }
161:
162: // get the RequestDispatcher for the JSP
163: RequestDispatcher dispatcher = data.getServletContext()
164: .getRequestDispatcher(relativeTemplateName);
165:
166: try {
167: if (isForward) {
168: // forward the request to the JSP
169: dispatcher.forward(data.getRequest(), data
170: .getResponse());
171: } else {
172: data.getOut().flush();
173: // include the JSP
174: dispatcher.include(data.getRequest(), data
175: .getResponse());
176: }
177: } catch (Exception e) {
178: // as JSP service is in Alpha stage, let's try hard to send the
179: // error message to the browser, to speed up debugging
180: try {
181: data.getOut().print(
182: "Error encountered processing a template: "
183: + templateName);
184: e.printStackTrace(data.getOut());
185: } catch (IOException ignored) {
186: }
187:
188: // pass the exception to the caller according to the general
189: // contract for tamplating services in Turbine
190: throw new TurbineException(
191: "Error encountered processing a template: "
192: + templateName, e);
193: }
194: }
195:
196: /**
197: * This method sets up the template cache.
198: */
199: private void initJsp() throws Exception {
200: Configuration config = getConfiguration();
201:
202: // Set relative paths from config.
203: // Needed for javax.servlet.RequestDispatcher
204: relativeTemplatePaths = config
205: .getStringArray(TEMPLATE_PATH_KEY);
206:
207: // Use Turbine Servlet to translate the template paths.
208: templatePaths = new String[relativeTemplatePaths.length];
209: for (int i = 0; i < relativeTemplatePaths.length; i++) {
210: relativeTemplatePaths[i] = warnAbsolute(relativeTemplatePaths[i]);
211:
212: templatePaths[i] = Turbine
213: .getRealPath(relativeTemplatePaths[i]);
214: }
215:
216: bufferSize = config.getInt(JspService.BUFFER_SIZE_KEY,
217: JspService.BUFFER_SIZE_DEFAULT);
218: }
219:
220: /**
221: * Determine whether a given template is available on the
222: * configured template pathes.
223: *
224: * @param template The name of the requested Template
225: * @return True if the template is available.
226: */
227: public boolean templateExists(String template) {
228: for (int i = 0; i < templatePaths.length; i++) {
229: if (templateExists(templatePaths[i], template)) {
230: return true;
231: }
232: }
233: return false;
234: }
235:
236: /**
237: * Determine whether a given template exists on the supplied
238: * template path. This service ATM only supports file based
239: * templates so it simply checks for file existence.
240: *
241: * @param path The absolute (file system) template path
242: * @param template The name of the requested Template
243: * @return True if the template is available.
244: */
245: private boolean templateExists(String path, String template) {
246: return new File(path, template).exists();
247: }
248:
249: /**
250: * Searchs for a template in the default.template path[s] and
251: * returns the template name with a relative path which is
252: * required by <a href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletContext.html#getRequestDispatcher(java.lang.String)">
253: * javax.servlet.RequestDispatcher</a>
254: *
255: * @param template
256: * @return String
257: */
258: public String getRelativeTemplateName(String template) {
259: template = warnAbsolute(template);
260:
261: // Find which template path the template is in
262: // We have a 1:1 match between relative and absolute
263: // pathes so we can use the index for translation.
264: for (int i = 0; i < templatePaths.length; i++) {
265: if (templateExists(templatePaths[i], template)) {
266: return relativeTemplatePaths[i] + "/" + template;
267: }
268: }
269: return null;
270: }
271:
272: /**
273: * Warn if a template name or path starts with "/".
274: *
275: * @param template The template to test
276: * @return The template name with a leading / stripped off
277: */
278: private String warnAbsolute(String template) {
279: if (template.startsWith("/")) {
280: log.warn("Template " + template
281: + " has a leading /, which is wrong!");
282: return template.substring(1);
283: }
284: return template;
285: }
286: }
|