Author: cziegeler Date: Fri Apr 8 12:17:34 2005 New Revision: 160589 URL: http://svn.apache.org/viewcvs?view=rev&rev=160589 Log: Let CoreUtil manage the Cocoon lifecycle
Added: cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java (with props) Removed: cocoon/trunk/src/java/org/apache/cocoon/util/log/LoggingHelper.java Modified: cocoon/trunk/src/java/org/apache/cocoon/core/Core.java cocoon/trunk/src/java/org/apache/cocoon/core/CoreUtil.java cocoon/trunk/src/java/org/apache/cocoon/servlet/CocoonServlet.java Added: cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java?view=auto&rev=160589 ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java (added) +++ cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java Fri Apr 8 12:17:34 2005 @@ -0,0 +1,97 @@ +/* + * Copyright 2005 The Apache Software Foundation + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.core; + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import org.apache.avalon.framework.context.DefaultContext; +import org.apache.avalon.framework.logger.Logger; +import org.apache.cocoon.configuration.Settings; +import org.apache.log.LogTarget; + +/** +* The BootstrapEnvironment is the connection between the real environment +* (servlet, cli etc.) and the Cocoon core. The core uses this object to +* access information from the real environment and to pass several objects +* back. +* A BootstrapEnvironment can be used to create a new Cocoon system using +* the [EMAIL PROTECTED] CoreUtil}. +* +* @version SVN $Id:$ +* @since 2.2 +*/ +public interface BootstrapEnvironment { + + /** Log a message during bootstrapping. This is used to log + * information before the logging system is setup. + * @param message A message. + */ + void log(String message); + + /** Log a message during bootstrapping. This is used to log + * information before the logging system is setup. + * @param message A message. + * @param error An error. + */ + void log(String message, Throwable error); + + /** + * Pass the root logger back to the environment. As soon as the + * logging system is set up, this method is called. + * @param rootLogger The root logger. + */ + void setLogger(Logger rootLogger); + + InputStream getInputStream(String path); + + void configure(Settings settings); + void configureLoggingContext(DefaultContext context); + + void configure(DefaultContext context); + + ClassLoader getInitClassLoader(); + + org.apache.cocoon.environment.Context getEnvironmentContext(); + + /** + * Returns the URL to the application context. + */ + String getContextURL(); + + /** + * Returns a file to the application context. + * @return A file pointing to the context or null if the context is not + * writeable. + */ + File getContextForWriting(); + + LogTarget getDefaultLogTarget(); + + /** + * Set the ConfigFile for the Cocoon object. + * + * @param configFileName The file location for the cocoon.xconf + * + * @throws Exception + */ + URL getConfigFile(String configFileName) + throws Exception; + + String getClassPath(Settings settings); +} \ No newline at end of file Propchange: cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cocoon/trunk/src/java/org/apache/cocoon/core/BootstrapEnvironment.java ------------------------------------------------------------------------------ svn:keywords = Id Modified: cocoon/trunk/src/java/org/apache/cocoon/core/Core.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/core/Core.java?view=diff&r1=160588&r2=160589 ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/core/Core.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/core/Core.java Fri Apr 8 12:17:34 2005 @@ -17,8 +17,6 @@ package org.apache.cocoon.core; import java.io.File; -import java.io.InputStream; -import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -28,12 +26,9 @@ import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.context.Contextualizable; -import org.apache.avalon.framework.context.DefaultContext; -import org.apache.avalon.framework.logger.Logger; import org.apache.cocoon.Constants; import org.apache.cocoon.components.ContextHelper; import org.apache.cocoon.configuration.Settings; -import org.apache.log.LogTarget; /** * This is the core Cocoon component. @@ -48,6 +43,7 @@ public class Core implements Contextualizable { + /** The key to lookup the component. */ public static String ROLE = Core.class.getName(); /** Application <code>Context</code> Key for the settings. Please don't @@ -180,47 +176,6 @@ } catch (ContextException ce) { throw new CascadingRuntimeException("Unable to get the settings object from the context.", ce); } - } - - public static interface BootstrapEnvironment { - - void log(String message); - void log(String message, Throwable error); - - InputStream getInputStream(String path); - - void configure(Settings settings); - void configureLoggingContext(DefaultContext context); - - void configure(DefaultContext context); - - ClassLoader getInitClassLoader(); - - org.apache.cocoon.environment.Context getEnvironmentContext(); - - /** - * Returns the URL to the application context. - */ - String getContextURL(); - - /** - * Returns a file to the application context. - * @return A file pointing to the context or null if the context is not - * writeable. - */ - File getContextForWriting(); - - LogTarget getDefaultLogTarget(); - - /** - * Set the ConfigFile for the Cocoon object. - * - * @param configFileName The file location for the cocoon.xconf - * - * @throws Exception - */ - public URL getConfigFile(final Logger logger, final String configFileName) - throws Exception; } } Modified: cocoon/trunk/src/java/org/apache/cocoon/core/CoreUtil.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/core/CoreUtil.java?view=diff&r1=160588&r2=160589 ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/core/CoreUtil.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/core/CoreUtil.java Fri Apr 8 12:17:34 2005 @@ -32,6 +32,7 @@ import org.apache.avalon.excalibur.logger.LogKitLoggerManager; import org.apache.avalon.excalibur.logger.LoggerManager; import org.apache.avalon.framework.CascadingRuntimeException; +import org.apache.avalon.framework.activity.Disposable; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; @@ -43,14 +44,15 @@ import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; +import org.apache.cocoon.Cocoon; import org.apache.cocoon.Constants; import org.apache.cocoon.components.ContextHelper; import org.apache.cocoon.configuration.ConfigurationBuilder; import org.apache.cocoon.configuration.Settings; -import org.apache.cocoon.core.Core.BootstrapEnvironment; import org.apache.cocoon.core.source.SimpleSourceResolver; import org.apache.cocoon.matching.helpers.WildcardHelper; import org.apache.cocoon.util.ClassUtils; +import org.apache.cocoon.util.StringUtils; import org.apache.cocoon.util.log.Log4JConfigurator; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.TraversableSource; @@ -61,6 +63,7 @@ import org.apache.log4j.LogManager; /** + * This is an utility class to create a new Cocoon instance. * * @version SVN $Id$ * @since 2.2 @@ -73,7 +76,7 @@ protected final static String CORE_KEY = Core.class.getName(); /** The callback to the real environment */ - protected final Core.BootstrapEnvironment env; + protected final BootstrapEnvironment env; /** "legacy" support: create an avalon context */ protected final DefaultContext appContext = new DefaultContext(); @@ -81,28 +84,29 @@ /** The settings */ protected final Settings settings; - /** The parent service manager TODO This will be made protected*/ - public ServiceManager parentManager; + /** The parent service manager. */ + protected ServiceManager parentManager; - /** TODO This will be made protected */ - public Logger log; - /** TODO This will be made protected */ - public LoggerManager loggerManager; + /** The root logger. */ + protected Logger log; - /** TODO This will be made protected */ - public Object cocoon; + /** The logger manager. */ + protected LoggerManager loggerManager; + + /** The Cocoon instance (the root processor). */ + protected Cocoon cocoon; /** * The time the cocoon instance was created */ protected long creationTime; - public CoreUtil(Core.BootstrapEnvironment environment) + public CoreUtil(BootstrapEnvironment environment) throws Exception { this.env = environment; // create settings - this.settings = createSettings(this.env); + this.settings = this.createSettings(); this.appContext.put(Core.CONTEXT_SETTINGS, this.settings); if (this.settings.isInitClassloader()) { @@ -157,7 +161,8 @@ this.settings.setWorkDirectory(workDir.getAbsolutePath()); // Init logger - initLogger(); + this.initLogger(); + this.env.setLogger(this.log); // Output some debug info if (this.log.isDebugEnabled()) { @@ -233,7 +238,7 @@ this.settings.setCacheDirectory(cacheDir.getAbsolutePath()); // update settings - final URL u = this.env.getConfigFile(this.log, this.settings.getConfiguration()); + final URL u = this.env.getConfigFile(this.settings.getConfiguration()); this.settings.setConfiguration(u.toExternalForm()); this.appContext.put(Constants.CONTEXT_CONFIG_URL, u); @@ -305,9 +310,8 @@ /** * Get the settings for Cocoon * @param env This provides access to various parts of the used environment. - * TODO Make a non-static, protected method out of this */ - public static Settings createSettings(BootstrapEnvironment env) { + protected Settings createSettings() { // create an empty settings objects final Settings s = new Settings(); @@ -551,7 +555,8 @@ return WildcardHelper.match(null, uri, parsedPattern); } - public static final class RootServiceManager implements ServiceManager { + public static final class RootServiceManager + implements ServiceManager, Disposable { protected final ServiceManager parent; protected final Core cocoon; @@ -561,7 +566,7 @@ this.cocoon = c; } - /* (non-Javadoc) + /** * @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String) */ public boolean hasService(String key) { @@ -574,7 +579,7 @@ return false; } - /* (non-Javadoc) + /** * @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String) */ public Object lookup(String key) throws ServiceException { @@ -587,7 +592,7 @@ throw new ServiceException("Cocoon", "Component for key '" + key + "' not found."); } - /* (non-Javadoc) + /** * @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object) */ public void release(Object component) { @@ -595,12 +600,19 @@ this.parent.release(component); } } + + /** + * @see org.apache.avalon.framework.activity.Disposable#dispose() + */ + public void dispose() { + ContainerUtil.dispose(this.parent); + } } /** * Creates the Cocoon object and handles exception handling. */ - public synchronized void createCocoon() + public synchronized Cocoon createCocoon() throws Exception { /* HACK for reducing class loader problems. */ @@ -621,9 +633,9 @@ if (this.log.isInfoEnabled()) { this.log.info("Reloading from: " + this.settings.getConfiguration()); } - Object c = ClassUtils.newInstance("org.apache.cocoon.Cocoon"); + Cocoon c = (Cocoon)ClassUtils.newInstance("org.apache.cocoon.Cocoon"); ContainerUtil.enableLogging(c, getCocoonLogger()); - // TODO: c.setLoggerManager(this.loggerManager); + c.setLoggerManager(this.loggerManager); ContainerUtil.contextualize(c, this.appContext); // create the Core object @@ -634,27 +646,26 @@ ContainerUtil.initialize(c); this.creationTime = System.currentTimeMillis(); - disposeCocoon(); this.cocoon = c; } catch (Exception e) { this.log.error("Exception reloading", e); this.disposeCocoon(); throw e; } + return this.cocoon; } /** * Gets the current cocoon object. Reload cocoon if configuration * changed or we are reloading. */ - public void getCocoon(final String pathInfo, final String reloadParam) + public Cocoon getCocoon(final String pathInfo, final String reloadParam) throws Exception { if (this.settings.isAllowReload()) { boolean reload = false; if (this.cocoon != null) { - // TODO: activate -/* if (this.cocoon.modifiedSince(this.creationTime)) { + if (this.cocoon.modifiedSince(this.creationTime)) { if (this.log.isInfoEnabled()) { this.log.info("Configuration changed reload attempt"); } @@ -664,7 +675,7 @@ this.log.info("Forced reload attempt"); } reload = true; - } */ + } } else if (pathInfo == null && reloadParam != null) { if (this.log.isInfoEnabled()) { this.log.info("Invalid configurations reload"); @@ -677,6 +688,7 @@ this.createCocoon(); } } + return this.cocoon; } /** @@ -684,6 +696,9 @@ */ public final void disposeCocoon() { if (this.cocoon != null) { + if (this.log.isDebugEnabled()) { + this.log.debug("Disposing Cocoon"); + } ContainerUtil.dispose(this.cocoon); this.cocoon = null; } @@ -766,7 +781,10 @@ * of this class (eg. Cocoon Context). */ protected void updateEnvironment() throws Exception { - // can be overridden + StringBuffer buffer = new StringBuffer(this.env.getClassPath(this.settings)); + buffer.append(File.pathSeparatorChar).append(this.getExtraClassPath()); + + this.appContext.put(Constants.CONTEXT_CLASSPATH, buffer.toString()); } /** @@ -780,13 +798,58 @@ // ignore this } } + this.disposeCocoon(); + } - if (this.cocoon != null) { - if (this.log.isDebugEnabled()) { - this.log.debug("Servlet destroyed - disposing Cocoon"); + /** + * Retreives the "extra-classpath" attribute, that needs to be + * added to the class path. + */ + protected String getExtraClassPath() { + if (this.settings.getExtraClasspaths().size() > 0) { + StringBuffer sb = new StringBuffer(); + final Iterator iter = this.settings.getExtraClasspaths().iterator(); + int i = 0; + while (iter.hasNext()) { + String s = (String)iter.next(); + if (i++ > 0) { + sb.append(File.pathSeparatorChar); + } + if ((s.charAt(0) == File.separatorChar) || + (s.charAt(1) == ':')) { + if (this.log.isDebugEnabled()) { + this.log.debug("extraClassPath is absolute: " + s); + } + sb.append(s); + + } else { + if (s.indexOf("${") != -1) { + String path = StringUtils.replaceToken(s); + sb.append(path); + if (this.log.isDebugEnabled()) { + this.log.debug("extraClassPath is not absolute replacing using token: [" + s + "] : " + path); + } + } else { + String path = null; + if (this.env.getContextForWriting() != null) { + path = this.env.getContextForWriting() + s; + if (this.log.isDebugEnabled()) { + this.log.debug("extraClassPath is not absolute pre-pending context path: " + path); + } + } else { + path = this.settings.getWorkDirectory() + s; + if (this.log.isDebugEnabled()) { + this.log.debug("extraClassPath is not absolute pre-pending work-directory: " + path); + } + } + sb.append(path); + } + } } - this.disposeCocoon(); + return sb.toString(); } + return ""; } + } Modified: cocoon/trunk/src/java/org/apache/cocoon/servlet/CocoonServlet.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/servlet/CocoonServlet.java?view=diff&r1=160588&r2=160589 ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/servlet/CocoonServlet.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/servlet/CocoonServlet.java Fri Apr 8 12:17:34 2005 @@ -15,12 +15,33 @@ */ package org.apache.cocoon.servlet; -import org.apache.avalon.excalibur.logger.LoggerManager; -import org.apache.avalon.framework.container.ContainerUtil; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.SocketException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.avalon.framework.context.DefaultContext; import org.apache.avalon.framework.logger.Logger; -import org.apache.avalon.framework.service.ServiceManager; - import org.apache.cocoon.Cocoon; import org.apache.cocoon.ConnectionResetException; import org.apache.cocoon.Constants; @@ -29,7 +50,7 @@ import org.apache.cocoon.components.notification.Notifier; import org.apache.cocoon.components.notification.Notifying; import org.apache.cocoon.configuration.Settings; -import org.apache.cocoon.core.Core; +import org.apache.cocoon.core.BootstrapEnvironment; import org.apache.cocoon.core.CoreUtil; import org.apache.cocoon.environment.Context; import org.apache.cocoon.environment.Environment; @@ -37,43 +58,13 @@ import org.apache.cocoon.environment.http.HttpEnvironment; import org.apache.cocoon.servlet.multipart.MultipartHttpServletRequest; import org.apache.cocoon.servlet.multipart.RequestFactory; -import org.apache.cocoon.util.ClassUtils; import org.apache.cocoon.util.IOUtils; -import org.apache.cocoon.util.StringUtils; import org.apache.cocoon.util.log.CocoonLogFormatter; - -import org.apache.cocoon.util.log.LoggingHelper; import org.apache.commons.lang.SystemUtils; import org.apache.log.ContextMap; import org.apache.log.LogTarget; import org.apache.log.output.ServletOutputLogTarget; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.MalformedURLException; -import java.net.SocketException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.jar.Attributes; -import java.util.jar.Manifest; - /** * This is the entry point for Cocoon execution as an HTTP Servlet. * @@ -103,14 +94,6 @@ static final float MINUTE = 60 * SECOND; static final float HOUR = 60 * MINUTE; - private Logger log; - private LoggerManager loggerManager; - - /** - * The time the cocoon instance was created - */ - protected long creationTime; - /** * The <code>Cocoon</code> instance */ @@ -124,7 +107,7 @@ /** * Avalon application context */ - protected DefaultContext appContext; + protected org.apache.avalon.framework.context.Context appContext; private String containerEncoding; @@ -133,9 +116,6 @@ /** The classloader that will be set as the context classloader if init-classloader is true */ protected final ClassLoader classLoader = this.getClass().getClassLoader(); - /** The parent ServiceManager, if any. Stored here in order to be able to dispose it in destroy(). */ - private ServiceManager parentServiceManager; - /** * This is the path to the servlet context (or the result * of calling getRealPath('/') on the ServletContext. @@ -154,8 +134,11 @@ */ protected RequestFactory requestFactory; - /** Settings */ - protected Settings settings; + /** CoreUtil */ + protected CoreUtil coreUtil; + + /** The logger */ + protected Logger log; /** * Initialize this <code>CocoonServlet</code> instance. You will @@ -224,15 +207,12 @@ } // initialize settings - Core.BootstrapEnvironment env = new ServletBootstrapEnvironment(conf, this.classLoader, this.servletContextPath, this.servletContextURL); + ServletBootstrapEnvironment env = new ServletBootstrapEnvironment(conf, this.classLoader, this.servletContextPath, this.servletContextURL); try { - CoreUtil util = new CoreUtil(env); - this.settings = util.getCore().getSettings(); - this.appContext = (DefaultContext)util.getCore().getContext(); - this.log = util.log; - this.loggerManager = util.loggerManager; - this.parentServiceManager = util.parentManager; + this.coreUtil = new CoreUtil(env); + this.appContext = coreUtil.getCore().getContext(); + this.log = env.logger; } catch (Exception e) { if ( e instanceof ServletException ) { throw (ServletException)e; @@ -241,7 +221,7 @@ } if (getLogger().isDebugEnabled()) { - getLogger().debug(this.settings.toString()); + getLogger().debug(this.coreUtil.getCore().getSettings().toString()); getLogger().debug("getRealPath for /: " + this.servletContextPath); if (this.servletContextPath == null) { getLogger().debug("getResource for /WEB-INF: " + debugPathOne); @@ -250,14 +230,19 @@ } this.containerEncoding = getInitParameter("container-encoding", "ISO-8859-1"); - this.requestFactory = new RequestFactory(settings.isAutosaveUploads(), - new File(settings.getUploadDirectory()), - settings.isAllowOverwrite(), - settings.isSilentlyRename(), - settings.getMaxUploadSize(), + this.requestFactory = new RequestFactory(coreUtil.getCore().getSettings().isAutosaveUploads(), + new File(coreUtil.getCore().getSettings().getUploadDirectory()), + coreUtil.getCore().getSettings().isAllowOverwrite(), + coreUtil.getCore().getSettings().isSilentlyRename(), + coreUtil.getCore().getSettings().getMaxUploadSize(), this.containerEncoding); - createCocoon(); + try { + this.exception = null; + this.cocoon = this.coreUtil.createCocoon(); + } catch (Exception e) { + this.exception = e; + } if (this.exception == null) { this.servletContext.log("Apache Cocoon " + Constants.VERSION + " is up and ready."); } else { @@ -269,318 +254,12 @@ * Dispose Cocoon when servlet is destroyed */ public void destroy() { - if (this.settings.isInitClassloader()) { - try { - Thread.currentThread().setContextClassLoader(this.classLoader); - } catch (Exception e) { - // ignore this - } - } - - if (this.cocoon != null) { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Servlet destroyed - disposing Cocoon"); - } - disposeCocoon(); - } - - ContainerUtil.dispose(this.parentServiceManager); - } - - /** - * This builds the important ClassPath used by this Servlet. It - * does so in a Servlet Engine neutral way. It uses the - * <code>ServletContext</code>'s <code>getRealPath</code> 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. - * - * @throws ServletException - */ - protected String getClassPath() throws ServletException { - StringBuffer buildClassPath = new StringBuffer(); - - File root = null; - if (this.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); - } - } 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) { - getLogger().warn("Unable to add WEB-INF/classes to the classpath", me); - } - - try { - libDirURL = this.servletContext.getResource("/WEB-INF/lib"); - } catch (MalformedURLException me) { - 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()); - } - } - - // 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); - } - } - - buildClassPath.append(File.pathSeparatorChar) - .append(SystemUtils.JAVA_CLASS_PATH); - - buildClassPath.append(File.pathSeparatorChar) - .append(getExtraClassPath()); - return buildClassPath.toString(); - } - - private File extractLibraries() { - try { - URL manifestURL = this.servletContext.getResource("/META-INF/MANIFEST.MF"); - if (manifestURL == null) { - this.getLogger().fatalError("Unable to get Manifest"); - return null; - } - - Manifest mf = new Manifest(manifestURL.openStream()); - Attributes attr = mf.getMainAttributes(); - String libValue = attr.getValue("Cocoon-Libs"); - if (libValue == null) { - this.getLogger().fatalError("Unable to get 'Cocoon-Libs' attribute from the Manifest"); - return null; - } - - List libList = new ArrayList(); - for (StringTokenizer st = new StringTokenizer(libValue, " "); st.hasMoreTokens();) { - libList.add(st.nextToken()); - } - - File root = new File(this.settings.getWorkDirectory(), "lib"); - root.mkdirs(); - - File[] oldLibs = root.listFiles(); - for (int i = 0; i < oldLibs.length; i++) { - String oldLib = oldLibs[i].getName(); - if (!libList.contains(oldLib)) { - this.getLogger().debug("Removing old library " + oldLibs[i]); - oldLibs[i].delete(); - } - } - - this.getLogger().warn("Extracting libraries into " + root); - byte[] buffer = new byte[65536]; - for (Iterator i = libList.iterator(); i.hasNext();) { - String libName = (String) i.next(); - - long lastModified = -1; - try { - lastModified = Long.parseLong(attr.getValue("Cocoon-Lib-" + libName.replace('.', '_'))); - } catch (Exception e) { - this.getLogger().debug("Failed to parse lastModified: " + attr.getValue("Cocoon-Lib-" + libName.replace('.', '_'))); - } - - File lib = new File(root, libName); - if (lib.exists() && lib.lastModified() != lastModified) { - this.getLogger().debug("Removing modified library " + lib); - lib.delete(); - } - - InputStream is = this.servletContext.getResourceAsStream("/WEB-INF/lib/" + libName); - if (is == null) { - this.getLogger().warn("Skipping " + libName); - } else { - this.getLogger().debug("Extracting " + libName); - OutputStream os = null; - try { - os = new FileOutputStream(lib); - int count; - while ((count = is.read(buffer)) > 0) { - os.write(buffer, 0, count); - } - } finally { - if (is != null) is.close(); - if (os != null) os.close(); - } - } - - if (lastModified != -1) { - lib.setLastModified(lastModified); - } - } - - return root; - } catch (IOException e) { - this.getLogger().fatalError("Exception while processing Manifest file", e); - return null; - } - } - - - /** - * Retreives the "extra-classpath" attribute, that needs to be - * added to the class path. - * - * @throws ServletException - */ - protected String getExtraClassPath() throws ServletException { - if (this.settings.getExtraClasspaths().size() > 0) { - StringBuffer sb = new StringBuffer(); - final Iterator iter = this.settings.getExtraClasspaths().iterator(); - int i = 0; - while (iter.hasNext()) { - String s = (String)iter.next(); - 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); - - } 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); - } - } 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.settings.getWorkDirectory() + s; - if (getLogger().isDebugEnabled()) { - getLogger().debug("extraClassPath is not absolute pre-pending work-directory: " + path); - } - } - sb.append(path); - } - } - } - return sb.toString(); - } - return ""; - } - - protected void initLogger() { - 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 DefaultContext subcontext = new DefaultContext(this.appContext); - subcontext.put("servlet-context", this.servletContext); - subcontext.put("context-work", new File(this.settings.getWorkDirectory())); - if (this.servletContextPath == null) { - File logSCDir = new File(this.settings.getWorkDirectory(), "log"); - logSCDir.mkdirs(); - subcontext.put("context-root", logSCDir.toString()); - } else { - subcontext.put("context-root", this.servletContextPath); - } - - LoggingHelper lh = new LoggingHelper(this.settings, servTarget, subcontext); - this.loggerManager = lh.getLoggerManager(); - this.log = lh.getLogger(); - } - - /** - * Handle the <code>load-class</code> parameter. This overcomes - * limits in many classpath issues. One of the more notorious - * ones is a bug in WebSphere that does not load the URL handler - * for the <code>classloader://</code> protocol. In order to - * overcome that bug, set <code>load-class</code> parameter to - * the <code>com.ibm.servlet.classloader.Handler</code> value. - * - * <p>If you need to load more than one class, then separate each - * entry with whitespace, a comma, or a semi-colon. Cocoon will - * strip any whitespace from the entry.</p> - */ - private void forceLoad() { - final Iterator i = this.settings.getLoadClasses(); - while (i.hasNext()) { - final String fqcn = (String)i.next(); - try { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Loading: " + fqcn); - } - ClassUtils.loadClass(fqcn).newInstance(); - } catch (Exception e) { - if (getLogger().isWarnEnabled()) { - getLogger().warn("Could not load class: " + fqcn, e); - } - // Do not throw an exception, because it is not a fatal error. - } - } - } - - /** - * Handle the "force-property" parameter. - * - * If you need to force more than one property to load, then - * separate each entry with whitespace, a comma, or a semi-colon. - * Cocoon will strip any whitespace from the entry. - */ - private void forceProperty() { - if (this.settings.getForceProperties().size() > 0) { - Properties systemProps = System.getProperties(); - final Iterator i = this.settings.getForceProperties().entrySet().iterator(); - while (i.hasNext()) { - final Map.Entry current = (Map.Entry)i.next(); - try { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Setting: " + current.getKey() + "=" + current.getValue()); - } - systemProps.setProperty(current.getKey().toString(), current.getValue().toString()); - } catch (Exception e) { - if (getLogger().isWarnEnabled()) { - getLogger().warn("Could not set property: " + current.getKey(), e); - } - // Do not throw an exception, because it is not a fatal error. - } - } - System.setProperties(systemProps); + this.servletContext.log("Destroying Cocoon Servlet."); + if ( this.coreUtil != null ) { + this.coreUtil.destroy(); + this.coreUtil = null; } + super.destroy(); } /** @@ -592,7 +271,7 @@ /* HACK for reducing class loader problems. */ /* example: xalan extensions fail if someone adds xalan jars in tomcat3.2.1/lib */ - if (this.settings.isInitClassloader()) { + if (this.coreUtil.getCore().getSettings().isInitClassloader()) { try { Thread.currentThread().setContextClassLoader(this.classLoader); } catch (Exception e) { @@ -609,7 +288,7 @@ // get the request (wrapped if contains multipart-form data) HttpServletRequest request; try{ - if (this.settings.isEnableUploads()) { + if (this.coreUtil.getCore().getSettings().isEnableUploads()) { request = requestFactory.getServletRequest(req); } else { request = req; @@ -626,7 +305,12 @@ } // Get the cocoon engine instance - getCocoon(request.getPathInfo(), request.getParameter(Constants.RELOAD_PARAM)); + try { + this.exception = null; + this.cocoon = this.coreUtil.getCocoon(request.getPathInfo(), request.getParameter(Constants.RELOAD_PARAM)); + } catch (Exception e) { + this.exception = e; + } // Check if cocoon was initialized if (this.cocoon == null) { @@ -766,7 +450,7 @@ if (contentType != null && contentType.equals("text/html")) { String showTime = request.getParameter(Constants.SHOWTIME_PARAM); - boolean show = this.settings.isShowTime(); + boolean show = this.coreUtil.getCore().getSettings().isShowTime(); if (showTime != null) { show = !showTime.equalsIgnoreCase("no"); } @@ -774,7 +458,7 @@ if ( timeString == null ) { timeString = processTime(end - start); } - boolean hide = this.settings.isHideShowTime(); + boolean hide = this.coreUtil.getCore().getSettings().isHideShowTime(); if (showTime != null) { hide = showTime.equalsIgnoreCase("hide"); } @@ -826,7 +510,7 @@ String title, String message, String description, Exception e) throws IOException { - if (this.settings.isManageExceptions()) { + if (this.coreUtil.getCore().getSettings().isManageExceptions()) { if (env != null) { env.tryResetResponse(); } else { @@ -884,7 +568,7 @@ String formEncoding = req.getParameter("cocoon-form-encoding"); if (formEncoding == null) { - formEncoding = this.settings.getFormEncoding(); + formEncoding = this.coreUtil.getCore().getSettings().getFormEncoding(); } env = new HttpEnvironment(uri, this.servletContextURL, @@ -898,102 +582,6 @@ return env; } - /** - * Instatiates the parent service manager, as specified in the - * parent-service-manager init parameter. - * - * If none is specified, the method returns <code>null</code>. - * - * @return the parent service manager, or <code>null</code>. - */ - protected synchronized ServiceManager getParentServiceManager() { - // FIXME - move this to CoreUtil! -/* ContainerUtil.dispose(this.parentServiceManager); - - this.parentServiceManager = null; - if (parentServiceManagerClass != null) { - try { - Class pcm = ClassUtils.loadClass(parentServiceManagerClass); - Constructor pcmc = pcm.getConstructor(new Class[]{String.class}); - parentServiceManager = (ServiceManager) pcmc.newInstance(new Object[]{parentServiceManagerInitParam}); - - ContainerUtil.enableLogging(parentServiceManager, getLogger()); - ContainerUtil.contextualize(parentServiceManager, this.appContext); - ContainerUtil.initialize(parentServiceManager); - } catch (Exception e) { - if (getLogger().isErrorEnabled()) { - getLogger().error("Could not initialize parent component manager.", e); - } - } - }*/ - return parentServiceManager; - } - - /** - * Creates the Cocoon object and handles exception handling. - */ - private synchronized void createCocoon() - throws ServletException { - - /* HACK for reducing class loader problems. */ - /* example: xalan extensions fail if someone adds xalan jars in tomcat3.2.1/lib */ - if (this.settings.isInitClassloader()) { - try { - Thread.currentThread().setContextClassLoader(this.classLoader); - } catch (Exception e) { - // ignore - } - } - - updateEnvironment(); - forceLoad(); - forceProperty(); - - try { - this.exception = null; - if (getLogger().isInfoEnabled()) { - getLogger().info("Reloading from: " + this.settings.getConfiguration()); - } - Cocoon c = (Cocoon) ClassUtils.newInstance("org.apache.cocoon.Cocoon"); - ContainerUtil.enableLogging(c, getCocoonLogger()); - c.setLoggerManager(getLoggerManager()); - ContainerUtil.contextualize(c, this.appContext); - final ServiceManager parent = this.getParentServiceManager(); - if (parent != null) { - ContainerUtil.service(c, parent); - } - ContainerUtil.initialize(c); - this.creationTime = System.currentTimeMillis(); - - disposeCocoon(); - this.cocoon = c; - } catch (Exception e) { - getLogger().error("Exception reloading", e); - this.exception = e; - disposeCocoon(); - } - } - - private Logger getCocoonLogger() { - final String rootlogger = this.settings.getCocoonLogger(); - if (rootlogger != null) { - return this.getLoggerManager().getLoggerForCategory(rootlogger); - } - return getLogger(); - } - - /** - * 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). - */ - protected void updateEnvironment() throws ServletException { - this.appContext.put(Constants.CONTEXT_CLASS_LOADER, classLoader); - this.appContext.put(Constants.CONTEXT_CLASSPATH, getClassPath()); - } - private String processTime(long time) { StringBuffer out = new StringBuffer(PROCESSED_BY); if (time <= SECOND) { @@ -1013,51 +601,6 @@ } /** - * Gets the current cocoon object. Reload cocoon if configuration - * changed or we are reloading. - */ - private void getCocoon(final String pathInfo, final String reloadParam) - throws ServletException { - if (this.settings.isAllowReload()) { - boolean reload = false; - - if (this.cocoon != null) { - if (this.cocoon.modifiedSince(this.creationTime)) { - if (getLogger().isInfoEnabled()) { - getLogger().info("Configuration changed reload attempt"); - } - reload = true; - } else if (pathInfo == null && reloadParam != null) { - if (getLogger().isInfoEnabled()) { - getLogger().info("Forced reload attempt"); - } - reload = true; - } - } else if (pathInfo == null && reloadParam != null) { - if (getLogger().isInfoEnabled()) { - getLogger().info("Invalid configurations reload"); - } - reload = true; - } - - if (reload) { - initLogger(); - createCocoon(); - } - } - } - - /** - * Destroy Cocoon - */ - private final void disposeCocoon() { - if (this.cocoon != null) { - ContainerUtil.dispose(this.cocoon); - this.cocoon = null; - } - } - - /** * Get an initialisation parameter. The value is trimmed, and null is returned if the trimmed value * is empty. */ @@ -1089,17 +632,14 @@ return this.log; } - protected LoggerManager getLoggerManager() { - return this.loggerManager; - } - protected static final class ServletBootstrapEnvironment - implements Core.BootstrapEnvironment { + implements BootstrapEnvironment { private final ServletConfig config; private final ClassLoader classLoader; private final File writeableContextPath; private final String contextPath; + public Logger logger; public ServletBootstrapEnvironment(ServletConfig config, ClassLoader cl, @@ -1116,28 +656,35 @@ } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#log(java.lang.String) + * @see org.apache.cocoon.core.BootstrapEnvironment#log(java.lang.String) */ public void log(String message) { this.config.getServletContext().log(message); } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#log(java.lang.String, java.lang.Throwable) + * @see org.apache.cocoon.core.BootstrapEnvironment#log(java.lang.String, java.lang.Throwable) */ public void log(String message, Throwable error) { this.config.getServletContext().log(message, error); } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getInputStream(java.lang.String) + * @see org.apache.cocoon.core.BootstrapEnvironment#setLogger(org.apache.avalon.framework.logger.Logger) + */ + public void setLogger(Logger rootLogger) { + this.logger = rootLogger; + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getInputStream(java.lang.String) */ public InputStream getInputStream(String path) { return this.config.getServletContext().getResourceAsStream(path); } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#configure(org.apache.cocoon.configuration.Settings) + * @see org.apache.cocoon.core.BootstrapEnvironment#configure(org.apache.cocoon.configuration.Settings) */ public void configure(Settings settings) { // fill from the servlet parameters @@ -1149,21 +696,21 @@ } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getInitClassLoader() + * @see org.apache.cocoon.core.BootstrapEnvironment#getInitClassLoader() */ public ClassLoader getInitClassLoader() { return this.classLoader; } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getEnvironmentContext() + * @see org.apache.cocoon.core.BootstrapEnvironment#getEnvironmentContext() */ public Context getEnvironmentContext() { return new HttpContext(this.config.getServletContext()); } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getContextURL() + * @see org.apache.cocoon.core.BootstrapEnvironment#getContextURL() */ public String getContextURL() { return this.contextPath; @@ -1171,13 +718,14 @@ /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getContextForWriting() + * @see org.apache.cocoon.core.BootstrapEnvironment#getContextForWriting() */ public File getContextForWriting() { return this.writeableContextPath; } + /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getDefaultLogTarget() + * @see org.apache.cocoon.core.BootstrapEnvironment#getDefaultLogTarget() */ public LogTarget getDefaultLogTarget() { final CocoonLogFormatter formatter = new CocoonLogFormatter(); @@ -1188,41 +736,37 @@ } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#configureLoggingContext(org.apache.avalon.framework.context.DefaultContext) + * @see org.apache.cocoon.core.BootstrapEnvironment#configureLoggingContext(org.apache.avalon.framework.context.DefaultContext) */ public void configureLoggingContext(DefaultContext context) { context.put("servlet-context", this.config.getServletContext()); } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#configure(org.apache.avalon.framework.context.DefaultContext) + * @see org.apache.cocoon.core.BootstrapEnvironment#configure(org.apache.avalon.framework.context.DefaultContext) */ public void configure(DefaultContext context) { context.put(CONTEXT_SERVLET_CONFIG, this.config); - // TODO - move the following into CoreUtil - context.put(Constants.CONTEXT_CLASS_LOADER, classLoader); - // TODO: - //context.put(Constants.CONTEXT_CLASSPATH, getClassPath()); } /** - * @see org.apache.cocoon.core.Core.BootstrapEnvironment#getConfigFile(org.apache.avalon.framework.logger.Logger, java.lang.String) + * @see org.apache.cocoon.core.BootstrapEnvironment#getConfigFile(java.lang.String) */ - public URL getConfigFile(final Logger logger, final String configFileName) + public URL getConfigFile(final String configFileName) throws Exception { final String usedFileName; if (configFileName == null) { - if (logger.isWarnEnabled()) { - logger.warn("Servlet initialization argument 'configurations' not specified, attempting to use '/WEB-INF/cocoon.xconf'"); + if (this.logger.isWarnEnabled()) { + this.logger.warn("Servlet initialization argument 'configurations' not specified, attempting to use '/WEB-INF/cocoon.xconf'"); } usedFileName = "/WEB-INF/cocoon.xconf"; } else { usedFileName = configFileName; } - if (logger.isDebugEnabled()) { - logger.debug("Using configuration file: " + usedFileName); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Using configuration file: " + usedFileName); } URL result; @@ -1235,7 +779,7 @@ } } catch (Exception mue) { String msg = "Init parameter 'configurations' is invalid : " + usedFileName; - logger.error(msg, mue); + this.logger.error(msg, mue); throw new ServletException(msg, mue); } @@ -1246,7 +790,7 @@ result = resultFile.getCanonicalFile().toURL(); } catch (Exception e) { String msg = "Init parameter 'configurations' is invalid : " + usedFileName; - logger.error(msg, e); + this.logger.error(msg, e); throw new ServletException(msg, e); } } @@ -1254,10 +798,170 @@ if (result == null) { String msg = "Init parameter 'configuration' doesn't name an existing resource : " + usedFileName; - logger.error(msg); + this.logger.error(msg); throw new ServletException(msg); } return result; + } + + /** + * This builds the important ClassPath used by this Servlet. It + * does so in a Servlet Engine neutral way. It uses the + * <code>ServletContext</code>'s <code>getRealPath</code> 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. + * + * @throws ServletException + */ + public String getClassPath(Settings settings) { + StringBuffer buildClassPath = new StringBuffer(); + + File root = null; + if (this.getContextForWriting() != null) { + // Old method. There *MUST* be a better method than this... + + String classDir = this.config.getServletContext().getRealPath("/WEB-INF/classes"); + String libDir = this.config.getServletContext().getRealPath("/WEB-INF/lib"); + + if (libDir != null) { + root = new File(libDir); + } + + if (classDir != null) { + buildClassPath.append(classDir); + } + } else { + // New(ish) method for war'd deployments + URL classDirURL = null; + URL libDirURL = null; + + try { + classDirURL = this.config.getServletContext().getResource("/WEB-INF/classes"); + } catch (MalformedURLException me) { + this.logger.warn("Unable to add WEB-INF/classes to the classpath", me); + } + + try { + libDirURL = this.config.getServletContext().getResource("/WEB-INF/lib"); + } catch (MalformedURLException me) { + this.logger.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()); + } + } + + // Unable to find lib directory. Going the hard way. + if (root == null) { + root = this.extractLibraries(settings); + } + + 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); + } + } + + buildClassPath.append(File.pathSeparatorChar) + .append(SystemUtils.JAVA_CLASS_PATH); + + return buildClassPath.toString(); + } + + private File extractLibraries(Settings settings) { + try { + URL manifestURL = this.config.getServletContext().getResource("/META-INF/MANIFEST.MF"); + if (manifestURL == null) { + this.logger.fatalError("Unable to get Manifest"); + return null; + } + + Manifest mf = new Manifest(manifestURL.openStream()); + Attributes attr = mf.getMainAttributes(); + String libValue = attr.getValue("Cocoon-Libs"); + if (libValue == null) { + this.logger.fatalError("Unable to get 'Cocoon-Libs' attribute from the Manifest"); + return null; + } + + List libList = new ArrayList(); + for (StringTokenizer st = new StringTokenizer(libValue, " "); st.hasMoreTokens();) { + libList.add(st.nextToken()); + } + + File root = new File(settings.getWorkDirectory(), "lib"); + root.mkdirs(); + + File[] oldLibs = root.listFiles(); + for (int i = 0; i < oldLibs.length; i++) { + String oldLib = oldLibs[i].getName(); + if (!libList.contains(oldLib)) { + this.logger.debug("Removing old library " + oldLibs[i]); + oldLibs[i].delete(); + } + } + + this.logger.warn("Extracting libraries into " + root); + byte[] buffer = new byte[65536]; + for (Iterator i = libList.iterator(); i.hasNext();) { + String libName = (String) i.next(); + + long lastModified = -1; + try { + lastModified = Long.parseLong(attr.getValue("Cocoon-Lib-" + libName.replace('.', '_'))); + } catch (Exception e) { + this.logger.debug("Failed to parse lastModified: " + attr.getValue("Cocoon-Lib-" + libName.replace('.', '_'))); + } + + File lib = new File(root, libName); + if (lib.exists() && lib.lastModified() != lastModified) { + this.logger.debug("Removing modified library " + lib); + lib.delete(); + } + + InputStream is = this.config.getServletContext().getResourceAsStream("/WEB-INF/lib/" + libName); + if (is == null) { + this.logger.warn("Skipping " + libName); + } else { + this.logger.debug("Extracting " + libName); + OutputStream os = null; + try { + os = new FileOutputStream(lib); + int count; + while ((count = is.read(buffer)) > 0) { + os.write(buffer, 0, count); + } + } finally { + if (is != null) is.close(); + if (os != null) os.close(); + } + } + + if (lastModified != -1) { + lib.setLastModified(lastModified); + } + } + + return root; + } catch (IOException e) { + this.logger.fatalError("Exception while processing Manifest file", e); + return null; + } } }