Source code: com/opencms/launcher/A_CmsLauncher.java
1 /*
2 * File : $Source: /usr/local/cvs/opencms/src/com/opencms/launcher/Attic/A_CmsLauncher.java,v $
3 * Date : $Date: 2003/02/26 10:30:36 $
4 * Version: $Revision: 1.41 $
5 *
6 * This library is part of OpenCms -
7 * the Open Source Content Mananagement System
8 *
9 * Copyright (C) 2001 The OpenCms Group
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * For further information about OpenCms, please see the
22 * OpenCms Website: http://www.opencms.org
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
28
29
30 package com.opencms.launcher;
31
32 import com.opencms.boot.I_CmsLogChannels;
33 import com.opencms.core.A_OpenCms;
34 import com.opencms.core.CmsException;
35 import com.opencms.core.I_CmsConstants;
36 import com.opencms.core.I_CmsResponse;
37 import com.opencms.file.CmsFile;
38 import com.opencms.file.CmsObject;
39 import com.opencms.file.CmsRequestContext;
40 import com.opencms.template.A_CmsXmlContent;
41 import com.opencms.template.CmsRootTemplate;
42 import com.opencms.template.CmsTemplateClassManager;
43 import com.opencms.template.I_CmsTemplate;
44
45 import java.io.IOException;
46 import java.io.OutputStream;
47 import java.util.Hashtable;
48
49 /**
50 * Abstract OpenCms launcher class.
51 * <P>
52 * This class implements basic functionality for all OpenCms launchers.
53 * For each relevant file type (e.g. XML control files, plain text files,
54 * JavaScript files,...) a customized launcher has to be implemented.
55 * <P>
56 * Every extending class has to implement the abstract methods
57 * <UL>
58 * <LI>getLauncherId() to indicate the type of the launcher</LI>
59 * <LI>launch() to be called by initlaunch</LI>
60 * </UL>
61 * <P>
62 * The functionality of this class is
63 * <UL>
64 * <LI>provide a global cache for template class results</LI>
65 * <LI>receive the system's launcher call, do some relevant initial
66 * things and call the launch() method</LI>
67 * <LI>provide some utility methods</LI>
68 * </UL>
69 *
70 * @author Alexander Lucas
71 * @version $Revision: 1.41 $ $Date: 2003/02/26 10:30:36 $
72 */
73 abstract class A_CmsLauncher implements I_CmsLauncher,I_CmsLogChannels,I_CmsConstants {
74
75 /** Boolean for additional debug output control */
76 private static final boolean C_DEBUG = false;
77
78 /** Value of the filesystem counter, when the last template clear cache was done. */
79 private static long m_lastFsCounterTemplate = 0;
80
81 /** Value of the filesystem counter, when the last XML file clear cache was done. */
82 private static long m_lastFsCounterFile = 0;
83
84 /** The template cache that holds all cached templates */
85 protected static I_CmsTemplateCache m_templateCache = new CmsTemplateCache();
86
87 /**
88 * Utility method used by the launcher implementation to give control
89 * to the CanonicalRoot.
90 * The CanonicalRoot will call the master template and return a byte array of the
91 * generated output.
92 *
93 * @param cms CmsObject Object for accessing system resources.
94 * @param templateClass Class that should generate the output of the master template.
95 * @param masterTemplate CmsFile Object with masterTemplate for the output.
96 * @param parameters Hashtable with all parameters for the template class.
97 * @return byte array with the generated output or null if there were errors.
98 * @throws CmsException
99 *
100 */
101 protected byte[] callCanonicalRoot(CmsObject cms, I_CmsTemplate templateClass, CmsFile masterTemplate, Hashtable parameters) throws CmsException {
102 try {
103 com.opencms.template.CmsRootTemplate root = (CmsRootTemplate)CmsTemplateClassManager.getClassInstance(cms, "com.opencms.template.CmsRootTemplate");
104 return root.getMasterTemplate(cms, templateClass, masterTemplate, m_templateCache, parameters);
105 }
106 catch(Exception e) {
107
108 // There is no document we could show.
109 handleException(cms, e, "Received error while calling canonical root for requested file " + masterTemplate.getName() + ". ");
110 }
111 return null;
112 }
113
114 /**
115 * Method for clearing this launchers template cache.
116 */
117 public void clearCache() {
118 m_templateCache.clearCache();
119 System.gc();
120 }
121
122 /**
123 * Gets the name of the class in the form "[ClassName] "
124 * This can be used for error logging purposes.
125 * @return name of this class
126 */
127 protected String getClassName() {
128 String name = getClass().getName();
129 return "[" + name.substring(name.lastIndexOf(".") + 1) + "] ";
130 }
131
132 /** Default constructor to create a new launcher */
133
134 /*public A_CmsLauncher() {
135 if(I_CmsLogChannels.C_PREPROCESSOR_IS_LOGGING && A_OpenCms.isLogging() ) {
136 A_OpenCms.log(C_OPENCMS_DEBUG, getClassName() + "Initialized successfully.");
137 }
138 }*/
139
140 /**
141 * Gets the ID that indicates the type of the launcher.
142 * @return launcher ID
143 */
144 public abstract int getLauncherId();
145
146 /**
147 * Gets a reference to the global template cache
148 * @return Template cache
149 */
150 public static I_CmsTemplateCache getTemplateCache() {
151 return m_templateCache;
152 }
153
154 /**
155 * Calls the CmsClassManager to get an instance of the given template class.
156 * The returned object is checked to be an implementing class of the interface
157 * I_CmsTemplate.
158 * If the template cache of the template class is not yet setted, this will
159 * be done, too.
160 * @param cms CmsObject object for accessing system resources.
161 * @param classname Name of the requested template class.
162 * @return Instance of the template class.
163 * @throws CmsException.
164 */
165 protected I_CmsTemplate getTemplateClass(CmsObject cms, String classname) throws CmsException {
166 if(I_CmsLogChannels.C_PREPROCESSOR_IS_LOGGING && A_OpenCms.isLogging() && C_DEBUG) {
167 A_OpenCms.log(C_OPENCMS_DEBUG, getClassName() + "Getting start template class " + classname + ". ");
168 }
169 Object o = CmsTemplateClassManager.getClassInstance(cms, classname);
170
171 // Check, if the loaded class really is a OpenCms template class.
172
173 // This is done be checking the implemented interface.
174 if(!(o instanceof I_CmsTemplate)) {
175 String errorMessage = "Class " + classname + " is no OpenCms template class.";
176 if(I_CmsLogChannels.C_PREPROCESSOR_IS_LOGGING && A_OpenCms.isLogging() ) {
177 A_OpenCms.log(C_OPENCMS_CRITICAL, "[CmsTemplateClassManager] " + errorMessage);
178 }
179 throw new CmsException(errorMessage, CmsException.C_XML_NO_TEMPLATE_CLASS);
180 }
181 I_CmsTemplate cmsTemplate = (I_CmsTemplate)o;
182 if(!cmsTemplate.isTemplateCacheSet()) {
183 cmsTemplate.setTemplateCache(m_templateCache);
184 }
185 return cmsTemplate;
186 }
187
188 /**
189 * Utility method to handle any occurence of an execption.
190 * <P>
191 * If the Exception is NO CmsException (i.e. it was not detected previously)
192 * it will be written to the logfile.
193 * <P>
194 * If the current user is the anonymous user, no further execption will
195 * be thrown, but a server error will be sent
196 * (we want to prevent the user from seeing any exeptions).
197 * Otherwise a new Exception will be thrown.
198 *
199 * @param cms CmsObject Object for accessing system resources.
200 * @param e Exception that should be handled.
201 * @param errorText Error message that should be shown.
202 * @throws CmsException
203 */
204 public void handleException(CmsObject cms, Exception e, String errorText) throws CmsException {
205
206 // Print out some error messages
207 if(I_CmsLogChannels.C_PREPROCESSOR_IS_LOGGING && A_OpenCms.isLogging() ) {
208 A_OpenCms.log(C_OPENCMS_CRITICAL, getClassName() + errorText);
209 A_OpenCms.log(C_OPENCMS_CRITICAL, getClassName() + "--> Exception: " + com.opencms.util.Utils.getStackTrace(e));
210 A_OpenCms.log(C_OPENCMS_CRITICAL, getClassName() + "--> Cannot create output for this file. Must send error. Sorry.");
211 }
212
213 // If the user is "Guest", we send an servlet error.
214
215 // Otherwise we try to throw an exception.
216 CmsRequestContext reqContext = cms.getRequestContext();
217 if((!C_DEBUG) && cms.anonymousUser().equals(reqContext.currentUser())) {
218 throw new CmsException(errorText, CmsException.C_SERVICE_UNAVAILABLE, e);
219 }
220 else {
221 if(e instanceof CmsException) {
222 throw (CmsException)e;
223 }
224 else {
225 throw new CmsException(errorText, CmsException.C_LAUNCH_ERROR, e);
226 }
227 }
228 }
229
230 /**
231 * Start method called by the OpenCms system to show a resource.
232 * <P>
233 * In this method initial values valid for all launchers can be set
234 * and the _clearcache parameter is checked.
235 * After this the abstract method launch(...) is called to
236 * invoke the customized part of the launcher.
237 *
238 * @param cms CmsObject Object for accessing system resources.
239 * @param file CmsFile Object with the selected resource to be shown.
240 * @param startTemplateClass Name of the template class to start with.
241 * @param openCms a instance of A_OpenCms for redirect-needs
242 * @throws CmsException
243 */
244 public void initlaunch(CmsObject cms, CmsFile file, String startTemplateClass, A_OpenCms openCms) throws CmsException {
245
246 // First some debugging output.
247 if(I_CmsLogChannels.C_PREPROCESSOR_IS_LOGGING && A_OpenCms.isLogging() && C_DEBUG ) {
248 A_OpenCms.log(C_OPENCMS_CRITICAL, getClassName() + "Launcher started for " + file.getName());
249 }
250
251 // Check all values to be valid
252 String errorMessage = null;
253 if(file == null) {
254 errorMessage = "Got \"null\" CmsFile object. :-(";
255 }
256 if(cms == null) {
257 errorMessage = "Actual cms object missing";
258 }
259 if(errorMessage != null) {
260 if(I_CmsLogChannels.C_PREPROCESSOR_IS_LOGGING && A_OpenCms.isLogging() ) {
261 A_OpenCms.log(C_OPENCMS_CRITICAL, getClassName() + errorMessage);
262 }
263 throw new CmsException(errorMessage, CmsException.C_LAUNCH_ERROR);
264 }
265
266 // Check the clearcache parameter
267 String clearcache = cms.getRequestContext().getRequest().getParameter("_clearcache");
268
269 // Clear launcher caches if this is required
270 clearLauncherCache(cms,
271 ((clearcache != null) && ("all".equals(clearcache) || "file".equals(clearcache))),
272 ((clearcache != null) && ("all".equals(clearcache) || "template".equals(clearcache))));
273
274 launch(cms, file, startTemplateClass, openCms);
275 }
276
277 /**
278 * Compatibility method to ensure the legacy cache command line parameters
279 * are still supported.<p>
280 *
281 * @param cms an initialized CmsObject
282 * @param clearClasses if true, CmsTemplateClassManager is cleared
283 * @param clearFiles if true, A_CmsXmlContent cache is cleared
284 * @param clearTemplates if true, internal template cache is cleared.
285 */
286 private static void clearLauncherCache(CmsObject cms, boolean clearFiles, boolean clearTemplates) {
287 long currentFsCounter = cms.getFileSystemChanges();
288 if(clearFiles || (currentFsCounter > m_lastFsCounterFile)) {
289 A_CmsXmlContent.clearFileCache();
290 m_lastFsCounterFile = currentFsCounter;
291 }
292 if(clearTemplates || (currentFsCounter > m_lastFsCounterTemplate)) {
293 m_templateCache.clearCache();
294 m_lastFsCounterTemplate = currentFsCounter;
295 }
296 }
297
298 /**
299 * Clear the XML template cache that is maintained in the launcher.
300 * To use this method, call it on one of the classes that extend
301 * A_CmsLauncher (e.g. com.opencms.launcher.CmsXmlLauncher.clearLauncherCache()).
302 * @param cms an initialized CmsObject
303 */
304 public static void clearLauncherCache(CmsObject cms) {
305 clearLauncherCache(cms, true, true);
306 }
307
308
309 /**
310 * Unitary method to start generating the output.
311 * Every launcher has to implement this method.
312 * In it possibly the selected file will be analyzed, and the
313 * Canonical Root will be called with the appropriate
314 * template class, template file and parameters. At least the
315 * canonical root's output must be written to the HttpServletResponse.
316 *
317 * @param cms CmsObject Object for accessing system resources
318 * @param file CmsFile Object with the selected resource to be shown
319 * @param startTemplateClass Name of the template class to start with.
320 * @param openCms a instance of A_OpenCms for redirect-needs
321 * @throws CmsException
322 */
323 protected abstract void launch(CmsObject cms, CmsFile file, String startTemplateClass, A_OpenCms openCms) throws CmsException;
324
325 /**
326 * Writes a given byte array to the HttpServletRespose output stream.
327 * @param result byte array that should be written.
328 * @param mimeType MIME type that should be set for the output.
329 * @throws CmsException
330 */
331 protected void writeBytesToResponse(CmsObject cms, byte[] result) throws CmsException {
332 try {
333 I_CmsResponse resp = cms.getRequestContext().getResponse();
334 if((!cms.getRequestContext().isStreaming()) && result != null && !resp.isRedirected()) {
335 // Only write any output to the response output stream if
336 // the current request is neither redirected nor streamed.
337 OutputStream out = resp.getOutputStream();
338
339 resp.setContentLength(result.length);
340 resp.setHeader("Connection", "keep-alive");
341 out.write(result);
342 out.close();
343 }
344 }
345 catch(IOException ioe) {
346 if(C_LOGGING && A_OpenCms.isLogging(C_OPENCMS_DEBUG) ) {
347 A_OpenCms.log(C_OPENCMS_DEBUG, getClassName() + "IO error while writing to response stream for " + cms.getRequestContext().getFileUri());
348 A_OpenCms.log(C_OPENCMS_DEBUG, getClassName() + ioe);
349 }
350 }
351 catch(Exception e) {
352 String errorMessage = "Cannot write output to HTTP response stream";
353 handleException(cms, e, errorMessage);
354 }
355 }
356
357 /**
358 * Sets the currently running OpenCms instance.
359 */
360 public void setOpenCms(A_OpenCms openCms) {
361 // normally we don't need the instance - ignoring
362 // if a launcher uses this, it should overload this method
363 }
364 }