| Method from org.apache.cocoon.servlet.CocoonServlet Detail: |
protected void addClassLoaderDirectory(String dir) {
// Nothing
}
|
protected void addClassLoaderURL(URL URL) {
// Nothing
}
|
protected synchronized void createCocoon() throws ServletException {
// Recheck that we need to create the cocoon object. It can have been created by
// a concurrent invocation to this method.
if (this.cocoon != null) {
return;
}
/* HACK for reducing class loader problems. */
/* example: xalan extensions fail if someone adds xalan jars in tomcat3.2.1/lib */
if (this.initClassLoader) {
try {
Thread.currentThread().setContextClassLoader(this.classLoader);
} catch (Exception e) {
}
}
updateEnvironment();
forceLoad();
forceProperty();
try {
this.exception = null;
URL configFile = (URL) this.appContext.get(Constants.CONTEXT_CONFIG_URL);
if (getLogger().isInfoEnabled()) {
getLogger().info("Reloading from: " + configFile.toExternalForm());
}
Cocoon c = (Cocoon) ClassUtils.newInstance("org.apache.cocoon.Cocoon");
ContainerUtil.enableLogging(c, getCocoonLogger());
c.setLoggerManager(getLoggerManager());
ContainerUtil.contextualize(c, this.appContext);
final ComponentManager parent = this.getParentComponentManager();
if (parent != null) {
ContainerUtil.compose(c, parent);
}
if (this.enableInstrumentation) {
c.setInstrumentManager(getInstrumentManager());
}
ContainerUtil.initialize(c);
this.creationTime = System.currentTimeMillis();
this.cocoon = c;
} catch (Exception e) {
if (getLogger().isErrorEnabled()) {
getLogger().error("Exception reloading", e);
}
this.exception = e;
disposeCocoon();
}
}
Creates the Cocoon object and handles exception handling. |
public void destroy() {
if (this.initClassLoader) {
try {
Thread.currentThread().setContextClassLoader(this.classLoader);
} catch (Exception e) {
// Ignored
}
}
if (this.cocoon != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Servlet destroyed - disposing Cocoon");
}
disposeCocoon();
}
if (this.instrumentManager instanceof Disposable) {
((Disposable) this.instrumentManager).dispose();
}
if (this.parentComponentManager != null && this.parentComponentManager instanceof Disposable) {
((Disposable) this.parentComponentManager).dispose();
}
this.appContext = null;
this.classLoader = null;
this.log = null;
this.loggerManager = null;
}
Dispose Cocoon when servlet is destroyed |
protected final void disposeCocoon() {
if (this.cocoon != null) {
ContainerUtil.dispose(this.cocoon);
this.cocoon = null;
}
}
|
protected String getClassPath() throws ServletException {
StringBuffer buildClassPath = new StringBuffer();
File root = null;
if (servletContextPath != null) {
// Old method. There *MUST* be a better method than this...
String classDir = this.servletContext.getRealPath("/WEB-INF/classes");
String libDir = this.servletContext.getRealPath("/WEB-INF/lib");
if (libDir != null) {
root = new File(libDir);
}
if (classDir != null) {
buildClassPath.append(classDir);
addClassLoaderDirectory(classDir);
}
} else {
// New(ish) method for war'd deployments
URL classDirURL = null;
URL libDirURL = null;
try {
classDirURL = this.servletContext.getResource("/WEB-INF/classes");
} catch (MalformedURLException me) {
if (getLogger().isWarnEnabled()) {
this.getLogger().warn("Unable to add WEB-INF/classes to the classpath", me);
}
}
try {
libDirURL = this.servletContext.getResource("/WEB-INF/lib");
} catch (MalformedURLException me) {
if (getLogger().isWarnEnabled()) {
this.getLogger().warn("Unable to add WEB-INF/lib to the classpath", me);
}
}
if (libDirURL != null && libDirURL.toExternalForm().startsWith("file:")) {
root = new File(libDirURL.toExternalForm().substring("file:".length()));
}
if (classDirURL != null) {
buildClassPath.append(classDirURL.toExternalForm());
addClassLoaderURL(classDirURL);
}
}
// Unable to find lib directory. Going the hard way.
if (root == null) {
root = extractLibraries();
}
if (root != null && root.isDirectory()) {
File[] libraries = root.listFiles();
Arrays.sort(libraries);
for (int i = 0; i < libraries.length; i++) {
String fullName = IOUtils.getFullFilename(libraries[i]);
buildClassPath.append(File.pathSeparatorChar).append(fullName);
addClassLoaderDirectory(fullName);
}
}
buildClassPath.append(File.pathSeparatorChar)
.append(SystemUtils.JAVA_CLASS_PATH);
buildClassPath.append(File.pathSeparatorChar)
.append(getExtraClassPath());
return buildClassPath.toString();
}
This builds the important ClassPath used by this Servlet. It
does so in a Servlet Engine neutral way. It uses the
ServletContext's getRealPath method
to get the Servlet 2.2 identified classes and lib directories.
It iterates in alphabetical order through every file in the
lib directory and adds it to the classpath.
Also, we add the files to the ClassLoader for the Cocoon system.
In order to protect ourselves from skitzofrantic classloaders,
we need to work with a known one.
We need to get this to work properly when Cocoon is in a war. |
protected Environment getEnvironment(String uri,
HttpServletRequest req,
HttpServletResponse res) throws Exception {
HttpEnvironment env;
String formEncoding = req.getParameter("cocoon-form-encoding");
if (formEncoding == null) {
formEncoding = this.defaultFormEncoding;
}
env = new HttpEnvironment(uri,
this.servletContextURL,
req,
res,
this.servletContext,
(HttpContext) this.appContext.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT),
this.containerEncoding,
formEncoding);
env.enableLogging(getLogger());
return env;
}
Create the environment for the request |
protected String getExtraClassPath() throws ServletException {
String extraClassPath = this.getInitParameter("extra-classpath");
if (extraClassPath != null) {
StringBuffer sb = new StringBuffer();
StringTokenizer st = new StringTokenizer(extraClassPath, SystemUtils.PATH_SEPARATOR, false);
int i = 0;
while (st.hasMoreTokens()) {
String s = st.nextToken();
if (i++ > 0) {
sb.append(File.pathSeparatorChar);
}
if ((s.charAt(0) == File.separatorChar) ||
(s.charAt(1) == ':")) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("extraClassPath is absolute: " + s);
}
sb.append(s);
addClassLoaderDirectory(s);
} else {
if (s.indexOf("${") != -1) {
String path = StringUtils.replaceToken(s);
sb.append(path);
if (getLogger().isDebugEnabled()) {
getLogger().debug("extraClassPath is not absolute replacing using token: [" + s + "] : " + path);
}
addClassLoaderDirectory(path);
} else {
String path = null;
if (this.servletContextPath != null) {
path = this.servletContextPath + s;
if (getLogger().isDebugEnabled()) {
getLogger().debug("extraClassPath is not absolute pre-pending context path: " + path);
}
} else {
path = this.workDir.toString() + s;
if (getLogger().isDebugEnabled()) {
getLogger().debug("extraClassPath is not absolute pre-pending work-directory: " + path);
}
}
sb.append(path);
addClassLoaderDirectory(path);
}
}
}
return sb.toString();
}
return "";
}
Retreives the "extra-classpath" attribute, that needs to be
added to the class path. |
public String getInitParameter(String name) {
String result = super.getInitParameter(name);
if (result != null) {
result = result.trim();
if (result.length() == 0) {
result = null;
}
}
return result;
}
Get an initialisation parameter. The value is trimmed, and null is returned if the trimmed value
is empty. |
protected String getInitParameter(String name,
String defaultValue) {
String result = getInitParameter(name);
if (result == null) {
if (getLogger() != null && getLogger().isDebugEnabled()) {
getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'");
}
return defaultValue;
} else {
return result;
}
}
Convenience method to access servlet parameters |
protected boolean getInitParameterAsBoolean(String name,
boolean defaultValue) {
String value = getInitParameter(name);
if (value == null) {
if (getLogger() != null && getLogger().isDebugEnabled()) {
getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'");
}
return defaultValue;
}
return BooleanUtils.toBoolean(value);
}
Convenience method to access boolean servlet parameters |
protected int getInitParameterAsInteger(String name,
int defaultValue) {
String value = getInitParameter(name);
if (value == null) {
if (getLogger() != null && getLogger().isDebugEnabled()) {
getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'");
}
return defaultValue;
} else {
return Integer.parseInt(value);
}
}
|
protected Logger getLogger() {
return this.log;
}
|
protected LoggerManager getLoggerManager() {
return this.loggerManager;
}
|
protected synchronized ComponentManager getParentComponentManager() {
if (parentComponentManager != null && parentComponentManager instanceof Disposable) {
((Disposable) parentComponentManager).dispose();
}
parentComponentManager = null;
if (parentComponentManagerClass != null) {
try {
Class pcm = ClassUtils.loadClass(parentComponentManagerClass);
Constructor pcmc = pcm.getConstructor(new Class[]{String.class});
parentComponentManager = (ComponentManager) pcmc.newInstance(new Object[]{parentComponentManagerInitParam});
if (parentComponentManager instanceof LogEnabled) {
((LogEnabled) parentComponentManager).enableLogging(getLogger());
}
if (parentComponentManager instanceof Contextualizable) {
((Contextualizable) parentComponentManager).contextualize(this.appContext);
}
if (parentComponentManager instanceof Initializable) {
((Initializable) parentComponentManager).initialize();
}
} catch (Exception e) {
if (getLogger().isErrorEnabled()) {
getLogger().error("Could not initialize parent component manager.", e);
}
}
}
return parentComponentManager;
}
Instatiates the parent component manager, as specified in the
parent-component-manager init parameter.
If none is specified, the method returns null. |
public void init(ServletConfig conf) throws ServletException {
super.init(conf);
// Check the init-classloader parameter only if it's not already true.
// This is useful for subclasses of this servlet that override the value
// initially set by this class (i.e. false).
if (!this.initClassLoader) {
this.initClassLoader = getInitParameterAsBoolean("init-classloader", false);
}
if (this.initClassLoader) {
// Force context classloader so that JAXP can work correctly
// (see javax.xml.parsers.FactoryFinder.findClassLoader())
try {
Thread.currentThread().setContextClassLoader(this.classLoader);
} catch (Exception e) {
// ignore this
}
}
try {
// FIXME (VG): We shouldn't have to specify these. Need to override
// jaxp implementation of weblogic before initializing logger.
// This piece of code is also required in the Cocoon class.
String value = System.getProperty("javax.xml.parsers.SAXParserFactory");
if (value != null && value.startsWith("weblogic")) {
System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl");
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
}
} catch (Exception e) {
// Ignore security exception
System.out.println("CocoonServlet: Could not check system properties, got: " + e);
}
this.servletContext = conf.getServletContext();
this.appContext.put(Constants.CONTEXT_ENVIRONMENT_CONTEXT, new HttpContext(this.servletContext));
this.servletContextPath = this.servletContext.getRealPath("/");
// first init the work-directory for the logger.
// this is required if we are running inside a war file!
final String workDirParam = getInitParameter("work-directory");
if (workDirParam != null) {
if (this.servletContextPath == null) {
// No context path : consider work-directory as absolute
this.workDir = new File(workDirParam);
} else {
// Context path exists : is work-directory absolute ?
File workDirParamFile = new File(workDirParam);
if (workDirParamFile.isAbsolute()) {
// Yes : keep it as is
this.workDir = workDirParamFile;
} else {
// No : consider it relative to context path
this.workDir = new File(servletContextPath, workDirParam);
}
}
} else {
this.workDir = (File) this.servletContext.getAttribute("javax.servlet.context.tempdir");
this.workDir = new File(workDir, "cocoon-files");
}
this.workDir.mkdirs();
this.appContext.put(Constants.CONTEXT_WORK_DIR, workDir);
String path = this.servletContextPath;
// these two variables are just for debugging. We can't log at this point
// as the logger isn't initialized yet.
String debugPathOne = null, debugPathTwo = null;
if (path == null) {
// Try to figure out the path of the root from that of WEB-INF
try {
path = this.servletContext.getResource("/WEB-INF").toString();
} catch (MalformedURLException me) {
throw new ServletException("Unable to get resource 'WEB-INF'.", me);
}
debugPathOne = path;
path = path.substring(0, path.length() - "WEB-INF".length());
debugPathTwo = path;
}
try {
if (path.indexOf(':") > 1) {
this.servletContextURL = path;
} else {
this.servletContextURL = new File(path).toURL().toExternalForm();
}
} catch (MalformedURLException me) {
// VG: Novell has absolute file names starting with the
// volume name which is easily more then one letter.
// Examples: sys:/apache/cocoon or sys:\apache\cocoon
try {
this.servletContextURL = new File(path).toURL().toExternalForm();
} catch (MalformedURLException ignored) {
throw new ServletException("Unable to determine servlet context URL.", me);
}
}
try {
this.appContext.put("context-root", new URL(this.servletContextURL));
} catch (MalformedURLException ignore) {
// we simply ignore this
}
// Init logger
initLogger();
if (getLogger().isDebugEnabled()) {
getLogger().debug("getRealPath for /: " + this.servletContextPath);
if (this.servletContextPath == null) {
getLogger().debug("getResource for /WEB-INF: " + debugPathOne);
getLogger().debug("Path for Root: " + debugPathTwo);
}
}
this.forceLoadParameter = getInitParameter("load-class", null);
this.forceSystemProperty = getInitParameter("force-property", null);
// Output some debug info
if (getLogger().isDebugEnabled()) {
getLogger().debug("Servlet Context URL: " + this.servletContextURL);
if (workDirParam != null) {
getLogger().debug("Using work-directory " + this.workDir);
} else {
getLogger().debug("Using default work-directory " + this.workDir);
}
}
final String uploadDirParam = conf.getInitParameter("upload-directory");
if (uploadDirParam != null) {
if (this.servletContextPath == null) {
this.uploadDir = new File(uploadDirParam);
} else {
// Context path exists : is upload-directory absolute ?
File uploadDirParamFile = new File(uploadDirParam);
if (uploadDirParamFile.isAbsolute()) {
// Yes : keep it as is
this.uploadDir = uploadDirParamFile;
} else {
// No : consider it relative to context path
this.uploadDir = new File(servletContextPath, uploadDirParam);
}
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Using upload-directory " + this.uploadDir);
}
} else {
this.uploadDir = new File(workDir, "upload-dir" + File.separator);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Using default upload-directory " + this.uploadDir);
}
}
this.uploadDir.mkdirs();
this.appContext.put(Constants.CONTEXT_UPLOAD_DIR, this.uploadDir);
this.enableUploads = getInitParameterAsBoolean("enable-uploads", ENABLE_UPLOADS);
this.autoSaveUploads = getInitParameterAsBoolean("autosave-uploads", SAVE_UPLOADS_TO_DISK);
String overwriteParam = getInitParameter("overwrite-uploads", "rename");
// accepted values are deny|allow|rename - rename is default.
if ("deny".equalsIgnoreCase(overwriteParam)) {
this.allowOverwrite = false;
this.silentlyRename = false;
} else if ("allow".equalsIgnoreCase(overwriteParam)) {
this.allowOverwrite = true;
this.silentlyRename = false; // ignored in this case
} else {
// either rename is specified or unsupported value - default to rename.
this.allowOverwrite = false;
this.silentlyRename = true;
}
this.maxUploadSize = getInitParameterAsInteger("upload-max-size", MAX_UPLOAD_SIZE);
String cacheDirParam = conf.getInitParameter("cache-directory");
if (cacheDirParam != null) {
if (this.servletContextPath == null) {
this.cacheDir = new File(cacheDirParam);
} else {
// Context path exists : is cache-directory absolute ?
File cacheDirParamFile = new File(cacheDirParam);
if (cacheDirParamFile.isAbsolute()) {
// Yes : keep it as is
this.cacheDir = cacheDirParamFile;
} else {
// No : consider it relative to context path
this.cacheDir = new File(servletContextPath, cacheDirParam);
}
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Using cache-directory " + this.cacheDir);
}
} else {
this.cacheDir = IOUtils.createFile(workDir, "cache-dir" + File.separator);
if (getLogger().isDebugEnabled()) {
getLogger().debug("cache-directory was not set - defaulting to " + this.cacheDir);
}
}
this.cacheDir.mkdirs();
this.appContext.put(Constants.CONTEXT_CACHE_DIR, this.cacheDir);
this.appContext.put(Constants.CONTEXT_CONFIG_URL,
getConfigFile(conf.getInitParameter("configurations")));
if (conf.getInitParameter("configurations") == null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("configurations was not set - defaulting to... ?");
}
}
// get allow reload parameter, default is true
this.allowReload = getInitParameterAsBoolean("allow-reload", ALLOW_RELOAD);
String value = conf.getInitParameter("show-time");
this.showTime = BooleanUtils.toBoolean(value) || (this.hiddenShowTime = "hide".equals(value));
if (value == null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("show-time was not set - defaulting to false");
}
}
this.showCocoonVersion = getInitParameterAsBoolean("show-cocoon-version", true);
parentComponentManagerClass = getInitParameter("parent-component-manager", null);
if (parentComponentManagerClass != null) {
int dividerPos = parentComponentManagerClass.indexOf('/");
if (dividerPos != -1) {
parentComponentManagerInitParam = parentComponentManagerClass.substring(dividerPos + 1);
parentComponentManagerClass = parentComponentManagerClass.substring(0, dividerPos);
}
}
this.containerEncoding = getInitParameter("container-encoding", "ISO-8859-1");
this.defaultFormEncoding = getInitParameter("form-encoding", "ISO-8859-1");
this.appContext.put(Constants.CONTEXT_DEFAULT_ENCODING, this.defaultFormEncoding);
this.manageExceptions = getInitParameterAsBoolean("manage-exceptions", true);
this.enableInstrumentation = getInitParameterAsBoolean("enable-instrumentation", false);
this.requestFactory = new RequestFactory(this.autoSaveUploads,
this.uploadDir,
this.allowOverwrite,
this.silentlyRename,
this.maxUploadSize,
this.containerEncoding);
// Add the servlet configuration
this.appContext.put(CONTEXT_SERVLET_CONFIG, conf);
this.createCocoon();
}
Initialize this CocoonServlet instance. You will
notice that I have broken the init into sub methods to make it
easier to maintain (BL). The context is passed to a couple of
the subroutines. This is also because it is better to explicitly
pass variables than implicitely. It is both more maintainable,
and more elegant. |
protected void initLogger() {
final String logLevel = getInitParameter("log-level", "INFO");
final String accesslogger = getInitParameter("servlet-logger", "cocoon");
final Priority logPriority = Priority.getPriorityForName(logLevel);
final CocoonLogFormatter formatter = new CocoonLogFormatter();
formatter.setFormat("%7.7{priority} %{time} [%8.8{category}] " +
"(%{uri}) %{thread}/%{class:short}: %{message}\\n%{throwable}");
final ServletOutputLogTarget servTarget = new ServletOutputLogTarget(this.servletContext, formatter);
final Hierarchy defaultHierarchy = Hierarchy.getDefaultHierarchy();
final ErrorHandler errorHandler = new DefaultErrorHandler();
defaultHierarchy.setErrorHandler(errorHandler);
defaultHierarchy.setDefaultLogTarget(servTarget);
defaultHierarchy.setDefaultPriority(logPriority);
final Logger logger = new LogKitLogger(Hierarchy.getDefaultHierarchy().getLoggerFor(""));
final String loggerManagerClass =
this.getInitParameter("logger-class", LogKitLoggerManager.class.getName());
// the log4j support requires currently that the log4j system is already configured elsewhere
final LoggerManager loggerManager =
newLoggerManager(loggerManagerClass, defaultHierarchy);
ContainerUtil.enableLogging(loggerManager, logger);
final DefaultContext subcontext = new DefaultContext(this.appContext);
subcontext.put("servlet-context", this.servletContext);
subcontext.put("context-work", this.workDir);
if (this.servletContextPath == null) {
File logSCDir = new File(this.workDir, "log");
logSCDir.mkdirs();
if (logger.isWarnEnabled()) {
logger.warn("Setting context-root for LogKit to " + logSCDir);
}
subcontext.put("context-root", logSCDir.toString());
} else {
subcontext.put("context-root", this.servletContextPath);
}
try {
ContainerUtil.contextualize(loggerManager, subcontext);
this.loggerManager = loggerManager;
if (loggerManager instanceof Configurable) {
//Configure the logkit management
String logkitConfig = getInitParameter("logkit-config", "/WEB-INF/logkit.xconf");
// test if this is a qualified url
InputStream is = null;
if (logkitConfig.indexOf(':") == -1) {
is = this.servletContext.getResourceAsStream(logkitConfig);
if (is == null) is = new FileInputStream(logkitConfig);
} else {
URL logkitURL = new URL(logkitConfig);
is = logkitURL.openStream();
}
final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
final Configuration conf = builder.build(is);
ContainerUtil.configure(loggerManager, conf);
}
// let's configure log4j
final String log4jConfig = getInitParameter("log4j-config", null);
if ( log4jConfig != null ) {
final Log4JConfigurator configurator = new Log4JConfigurator(subcontext);
// test if this is a qualified url
InputStream is = null;
if ( log4jConfig.indexOf(':") == -1) {
is = this.servletContext.getResourceAsStream(log4jConfig);
if (is == null) is = new FileInputStream(log4jConfig);
} else {
final URL log4jURL = new URL(log4jConfig);
is = log4jURL.openStream();
}
configurator.doConfigure(is, LogManager.getLoggerRepository());
}
ContainerUtil.initialize(loggerManager);
} catch (Exception e) {
errorHandler.error("Could not set up Cocoon Logger, will use screen instead", e, null);
}
this.log = this.loggerManager.getLoggerForCategory(accesslogger);
final String deprecationLevel = getInitParameter("forbidden-deprecation-level", "ERROR");
Deprecation.setForbiddenLevel(Deprecation.LogLevel.getLevel(deprecationLevel));
}
Set up the log level and path. The default log level is
Priority.ERROR, although it can be overwritten by the parameter
"log-level". The log system goes to both a file and the Servlet
container's log system. Only messages that are Priority.ERROR
and above go to the servlet context. The log messages can
be as restrictive (Priority.FATAL_ERROR and above) or as liberal
(Priority.DEBUG and above) as you want that get routed to the
file. |
protected void manageException(HttpServletRequest req,
HttpServletResponse res,
Environment env,
String uri,
int errorStatus,
String title,
String message,
String description,
Exception e) throws IOException {
if (this.manageExceptions) {
if (env != null) {
env.tryResetResponse();
} else {
res.reset();
}
String type = Notifying.FATAL_NOTIFICATION;
HashMap extraDescriptions = null;
if (errorStatus == HttpServletResponse.SC_NOT_FOUND) {
type = "resource-not-found";
// Do not show the exception stacktrace for such common errors.
e = null;
} else {
extraDescriptions = new HashMap(2);
extraDescriptions.put(Notifying.EXTRA_REQUESTURI, req.getRequestURI());
if (uri != null) {
extraDescriptions.put("Request URI", uri);
}
// Do not show exception stack trace when log level is WARN or above. Show only message.
if (!getLogger().isInfoEnabled()) {
Throwable t = DefaultNotifyingBuilder.getRootCause(e);
if (t != null) extraDescriptions.put(Notifying.EXTRA_CAUSE, t.getMessage());
e = null;
}
}
Notifying n = new DefaultNotifyingBuilder().build(this,
e,
type,
title,
"Cocoon Servlet",
message,
description,
extraDescriptions);
res.setContentType("text/html");
res.setStatus(errorStatus);
Notifier.notify(n, res.getOutputStream(), "text/html");
} else {
res.sendError(errorStatus, title);
res.flushBuffer();
}
}
|
public void service(HttpServletRequest req,
HttpServletResponse res) throws IOException, ServletException {
/* HACK for reducing class loader problems. */
/* example: xalan extensions fail if someone adds xalan jars in tomcat3.2.1/lib */
if (this.initClassLoader) {
try {
Thread.currentThread().setContextClassLoader(this.classLoader);
} catch (Exception e) {
}
}
// used for timing the processing
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// add the cocoon header timestamp
if (this.showCocoonVersion) {
res.addHeader("X-Cocoon-Version", Constants.VERSION);
}
// get the request (wrapped if contains multipart-form data)
HttpServletRequest request;
try{
if (this.enableUploads) {
request = requestFactory.getServletRequest(req);
} else {
request = req;
}
} catch (Exception e) {
if (getLogger().isErrorEnabled()) {
getLogger().error("Problem with Cocoon servlet", e);
}
manageException(req, res, null, null,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Problem in creating the Request", null, null, e);
return;
}
// Get the cocoon engine instance
if (reloadCocoon(request.getPathInfo(), request.getParameter(Constants.RELOAD_PARAM))) {
disposeCocoon();
initLogger();
createCocoon();
}
// Check if cocoon was initialized
if (this.cocoon == null) {
manageException(request, res, null, null,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Initialization Problem",
null /* "Cocoon was not initialized" */,
null /* "Cocoon was not initialized, cannot process request" */,
this.exception);
return;
}
// We got it... Process the request
String uri = request.getServletPath();
if (uri == null) {
uri = "";
}
String pathInfo = request.getPathInfo();
if (pathInfo != null) {
// VG: WebLogic fix: Both uri and pathInfo starts with '/'
// This problem exists only in WL6.1sp2, not in WL6.0sp2 or WL7.0b.
if (uri.length() > 0 && uri.charAt(0) == '/") {
uri = uri.substring(1);
}
uri += pathInfo;
}
if (uri.length() == 0) {
/* empty relative URI
- > HTTP-redirect from /cocoon to /cocoon/ to avoid
StringIndexOutOfBoundsException when calling
"".charAt(0)
else process URI normally
*/
String prefix = request.getRequestURI();
if (prefix == null) {
prefix = "";
}
res.sendRedirect(res.encodeRedirectURL(prefix + "/"));
return;
}
String contentType = null;
ContextMap ctxMap = null;
Environment env;
try{
if (uri.charAt(0) == '/") {
uri = uri.substring(1);
}
// Pass uri into environment without URLDecoding, as it is already decoded.
env = getEnvironment(uri, request, res);
} catch (Exception e) {
if (getLogger().isErrorEnabled()) {
getLogger().error("Problem with Cocoon servlet", e);
}
manageException(request, res, null, uri,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Problem in creating the Environment", null, null, e);
return;
}
try {
try {
// Initialize a fresh log context containing the object model: it
// will be used by the CocoonLogFormatter
ctxMap = ContextMap.getCurrentContext();
// Add thread name (default content for empty context)
String threadName = Thread.currentThread().getName();
ctxMap.set("threadName", threadName);
// Add the object model
ctxMap.set("objectModel", env.getObjectModel());
// Add a unique request id (threadName + currentTime
ctxMap.set("request-id", threadName + System.currentTimeMillis());
if (this.cocoon.process(env)) {
contentType = env.getContentType();
} else {
// We reach this when there is nothing in the processing change that matches
// the request. For example, no matcher matches.
getLogger().fatalError("The Cocoon engine failed to process the request.");
manageException(request, res, env, uri,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Request Processing Failed",
"Cocoon engine failed in process the request",
"The processing engine failed to process the request. This could be due to lack of matching or bugs in the pipeline engine.",
null);
return;
}
} catch (ResourceNotFoundException e) {
if (getLogger().isDebugEnabled()) {
getLogger().warn(e.getMessage(), e);
} else if (getLogger().isWarnEnabled()) {
getLogger().warn(e.getMessage());
}
manageException(request, res, env, uri,
HttpServletResponse.SC_NOT_FOUND,
"Resource Not Found",
"Resource Not Found",
"The requested resource \"" + request.getRequestURI() + "\" could not be found",
e);
return;
} catch (ConnectionResetException e) {
if (getLogger().isDebugEnabled()) {
getLogger().debug(e.toString(), e);
} else if (getLogger().isWarnEnabled()) {
getLogger().warn(e.toString());
}
} catch (IOException e) {
// Tomcat5 wraps SocketException into ClientAbortException which extends IOException.
if (getLogger().isDebugEnabled()) {
getLogger().debug(e.toString(), e);
} else if (getLogger().isWarnEnabled()) {
getLogger().warn(e.toString());
}
} catch (Exception e) {
if (getLogger().isErrorEnabled()) {
getLogger().error("Internal Cocoon Problem", e);
}
manageException(request, res, env, uri,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Internal Server Error", null, null, e);
return;
}
stopWatch.stop();
String timeString = null;
if (getLogger().isInfoEnabled()) {
timeString = processTime(stopWatch.getTime());
getLogger().info("'" + uri + "' " + timeString);
}
if (contentType != null && contentType.equals("text/html")) {
String showTime = request.getParameter(Constants.SHOWTIME_PARAM);
boolean show = this.showTime;
if (showTime != null) {
show = !showTime.equalsIgnoreCase("no");
}
if (show) {
if (timeString == null) {
timeString = processTime(stopWatch.getTime());
}
boolean hide = this.hiddenShowTime;
if (showTime != null) {
hide = showTime.equalsIgnoreCase("hide");
}
ServletOutputStream out = res.getOutputStream();
out.print((hide) ? "< !-- " : "< p >");
out.print(timeString);
out.println((hide) ? " -- >" : "< /p >");
}
}
} finally {
if (ctxMap != null) {
ctxMap.clear();
}
try {
if (request instanceof MultipartHttpServletRequest) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Deleting uploaded file(s).");
}
((MultipartHttpServletRequest) request).cleanup();
}
} catch (IOException e) {
getLogger().error("Cocoon got an Exception while trying to cleanup the uploaded files.", e);
}
/*
* Servlet Specification 2.2, 6.5 Closure of Response Object:
*
* A number of events can indicate that the servlet has provided all of the
* content to satisfy the request and that the response object can be
* considered to be closed. The events are:
* o The termination of the service method of the servlet.
* o When the amount of content specified in the setContentLength method
* of the response has been written to the response.
* o The sendError method is called.
* o The sendRedirect method is called.
* When a response is closed, all content in the response buffer, if any remains,
* must be immediately flushed to the client.
*
* Due to the above, out.flush() and out.close() are not necessary, and sometimes
* (if sendError or sendRedirect were used) request may be already closed.
*/
}
}
Process the specified HttpServletRequest producing output
on the specified HttpServletResponse. |
protected void updateEnvironment() throws ServletException {
this.appContext.put(Constants.CONTEXT_CLASS_LOADER, classLoader);
this.appContext.put(Constants.CONTEXT_CLASSPATH, getClassPath());
}
Method to update the environment before Cocoon instances are created.
This is also useful if you wish to customize any of the 'protected'
variables from this class before a Cocoon instance is built in a derivative
of this class (eg. Cocoon Context). |