Author: cziegeler Date: Thu Apr 21 13:43:19 2005 New Revision: 164118 URL: http://svn.apache.org/viewcvs?rev=164118&view=rev Log: Start using CoreUtil
Modified: cocoon/blocks/supported/portal/trunk/java/org/apache/cocoon/portlet/CocoonPortlet.java Modified: cocoon/blocks/supported/portal/trunk/java/org/apache/cocoon/portlet/CocoonPortlet.java URL: http://svn.apache.org/viewcvs/cocoon/blocks/supported/portal/trunk/java/org/apache/cocoon/portlet/CocoonPortlet.java?rev=164118&r1=164117&r2=164118&view=diff ============================================================================== --- cocoon/blocks/supported/portal/trunk/java/org/apache/cocoon/portlet/CocoonPortlet.java (original) +++ cocoon/blocks/supported/portal/trunk/java/org/apache/cocoon/portlet/CocoonPortlet.java Thu Apr 21 13:43:19 2005 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-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. @@ -15,74 +15,59 @@ */ package org.apache.cocoon.portlet; -import org.apache.avalon.excalibur.logger.Log4JLoggerManager; -import org.apache.avalon.excalibur.logger.LogKitLoggerManager; -import org.apache.avalon.excalibur.logger.LoggerManager; -import org.apache.avalon.framework.configuration.Configurable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; -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.io.PrintStream; +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.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.GenericPortlet; +import javax.portlet.PortletConfig; +import javax.portlet.PortletException; +import javax.portlet.PortletRequest; +import javax.portlet.PortletSession; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; +import javax.servlet.ServletException; + import org.apache.avalon.framework.context.DefaultContext; -import org.apache.avalon.framework.logger.LogKitLogger; 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; import org.apache.cocoon.ResourceNotFoundException; -import org.apache.cocoon.components.ContextHelper; import org.apache.cocoon.components.notification.DefaultNotifyingBuilder; 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.BootstrapEnvironment; +import org.apache.cocoon.core.CoreUtil; +import org.apache.cocoon.environment.Context; import org.apache.cocoon.environment.Environment; import org.apache.cocoon.environment.portlet.PortletContext; import org.apache.cocoon.environment.portlet.PortletEnvironment; import org.apache.cocoon.portlet.multipart.MultipartActionRequest; import org.apache.cocoon.portlet.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.Log4JConfigurator; - import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.SystemUtils; import org.apache.log.ContextMap; -import org.apache.log.ErrorHandler; -import org.apache.log.Hierarchy; -import org.apache.log.Priority; -import org.apache.log.util.DefaultErrorHandler; -import org.apache.log4j.LogManager; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.GenericPortlet; -import javax.portlet.PortletConfig; -import javax.portlet.PortletException; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.PortletRequest; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.lang.reflect.Constructor; -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 org.apache.log.LogTarget; /** * This is the entry point for Cocoon execution as an JSR-168 Portlet. @@ -107,12 +92,6 @@ static final float HOUR = 60 * MINUTE; private Logger log; - private LoggerManager loggerManager; - - /** - * The time the cocoon instance was created - */ - protected long creationTime = 0; /** * The <code>Cocoon</code> instance @@ -127,73 +106,15 @@ /** * Avalon application context */ - protected DefaultContext appContext = new DefaultContext(); - + protected org.apache.avalon.framework.context.Context appContext; - /** - * Default value for [EMAIL PROTECTED] #allowReload} parameter (false) - */ - protected static final boolean ALLOW_RELOAD = false; - - /** - * Allow reloading of cocoon by specifying the <code>cocoon-reload=true</code> parameter with a request - */ - protected boolean allowReload; - - /** - * Allow adding processing time to the response - */ - protected boolean showTime; - - /** - * If true, processing time will be added as an HTML comment - */ - protected boolean hiddenShowTime; - - - /** - * Default value for [EMAIL PROTECTED] #enableUploads} parameter (false) - */ - private static final boolean ENABLE_UPLOADS = false; - private static final boolean SAVE_UPLOADS_TO_DISK = true; - private static final int MAX_UPLOAD_SIZE = 10000000; // 10Mb - - /** - * Allow processing of upload requests (mime/multipart) - */ - private boolean enableUploads; - private boolean autoSaveUploads; - private boolean allowOverwrite; - private boolean silentlyRename; - private int maxUploadSize; - - private File uploadDir; - private File workDir; - private File cacheDir; private String containerEncoding; - private String defaultFormEncoding; protected javax.portlet.PortletContext portletContext; /** The classloader that will be set as the context classloader if init-classloader is true */ protected ClassLoader classLoader = this.getClass().getClassLoader(); - protected boolean initClassLoader = false; - - private String parentServiceManagerClass; - private String parentServiceManagerInitParam; - - /** The parent ServiceManager, if any. Stored here in order to be able to dispose it in destroy(). */ - private ServiceManager parentServiceManager; - - protected String forceLoadParameter; - protected String forceSystemProperty; - - /** - * If true or not set, this class will try to catch and handle all Cocoon exceptions. - * If false, it will rethrow them to the portlet container. - */ - private boolean manageExceptions; /** * This is the path to the portlet context (or the result @@ -236,6 +157,12 @@ */ protected boolean storeSessionPath; + /** CoreUtil */ + protected CoreUtil coreUtil; + + /** Settings */ + protected Settings settings; + /** * Initialize this <code>CocoonPortlet</code> instance. * @@ -257,71 +184,9 @@ public void init(PortletConfig conf) throws PortletException { super.init(conf); - - // Check the init-classloader parameter only if it's not already true. - // This is useful for subclasses of this portlet 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 - } - } - - 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 (SecurityException e) { - // Ignore security exception - System.out.println("CocoonPortlet: Could not check system properties, got: " + e); - } - this.portletContext = conf.getPortletContext(); - this.appContext.put(Constants.CONTEXT_ENVIRONMENT_CONTEXT, new PortletContext(this.portletContext)); this.portletContextPath = this.portletContext.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.portletContextPath == 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(portletContextPath, workDirParam); - } - } - } else { - // TODO: Check portlet specification - this.workDir = (File) this.portletContext.getAttribute("javax.servlet.context.tempdir"); - if (this.workDir == null) { - this.workDir = new File(this.portletContext.getRealPath("/WEB-INF/work")); - } - this.workDir = new File(workDir, "cocoon-files"); - } - this.workDir.mkdirs(); - this.appContext.put(Constants.CONTEXT_WORK_DIR, workDir); - String path = this.portletContextPath; // these two variables are just for debugging. We can't log at this point // as the logger isn't initialized yet. @@ -338,702 +203,93 @@ debugPathTwo = path; } - try { - if (path.indexOf(':') > 1) { - this.portletContextURL = path; - } else { - this.portletContextURL = 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.portletContextURL = new File(path).toURL().toExternalForm(); - } catch (MalformedURLException ignored) { - throw new PortletException("Unable to determine portlet context URL.", me); - } - } - try { - this.appContext.put("context-root", new URL(this.portletContextURL)); - } catch (MalformedURLException ignore) { - // we simply ignore this - } - - // Init logger - initLogger(); - - if (getLogger().isDebugEnabled()) { - getLogger().debug("getRealPath for /: " + this.portletContextPath); - if (this.portletContextPath == 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("Portlet Context URL: " + this.portletContextURL); - if (workDirParam != null) { - getLogger().debug("Using work-directory " + this.workDir); - } else { - getLogger().debug("Using default work-directory " + this.workDir); - } - } - try { - this.appContext.put(ContextHelper.CONTEXT_ROOT_URL, new URL(this.portletContextURL)); - } catch (MalformedURLException ignore) { - // we simply ignore this - } - - final String uploadDirParam = conf.getInitParameter("upload-directory"); - if (uploadDirParam != null) { - if (this.portletContextPath == 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(portletContextPath, 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.portletContextPath == 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(portletContextPath, 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"); - } - } - - parentServiceManagerClass = getInitParameter("parent-service-manager", null); - if (parentServiceManagerClass != null) { - int dividerPos = parentServiceManagerClass.indexOf('/'); - if (dividerPos != -1) { - parentServiceManagerInitParam = parentServiceManagerClass.substring(dividerPos + 1); - parentServiceManagerClass = parentServiceManagerClass.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.requestFactory = new RequestFactory(this.autoSaveUploads, - this.uploadDir, - this.allowOverwrite, - this.silentlyRename, - this.maxUploadSize, - this.defaultFormEncoding); - - this.servletPath = getInitParameter("servlet-path", null); - if (this.servletPath != null) { - if (this.servletPath.startsWith("/")) { - this.servletPath = this.servletPath.substring(1); - } - if (this.servletPath.endsWith("/")) { - this.servletPath = servletPath.substring(0, servletPath.length() - 1); - } - } - - final String sessionScopeParam = getInitParameter("default-session-scope", "portlet"); - if ("application".equalsIgnoreCase(sessionScopeParam)) { - this.defaultSessionScope = javax.portlet.PortletSession.APPLICATION_SCOPE; - } else { - this.defaultSessionScope = javax.portlet.PortletSession.PORTLET_SCOPE; - } - - // Add the portlet configuration - this.appContext.put(CONTEXT_PORTLET_CONFIG, conf); - this.createCocoon(); - } - - /** - * Dispose Cocoon when portlet is destroyed - */ - public void destroy() { - if (this.initClassLoader) { - try { - Thread.currentThread().setContextClassLoader(this.classLoader); - } catch (Exception e) { - } - } - - if (this.cocoon != null) { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Portlet destroyed - disposing Cocoon"); - } - this.disposeCocoon(); - } - - ContainerUtil.dispose(this.parentServiceManager); - } - - /** - * Adds an URL to the classloader. Does nothing here, but can - * be overriden. - */ - protected void addClassLoaderURL(URL URL) { - // Nothing - } - - /** - * Adds a directory to the classloader. Does nothing here, but can - * be overriden. - */ - protected void addClassLoaderDirectory(String dir) { - // Nothing - } - - /** - * This builds the important ClassPath used by this Portlet. It - * does so in a Portlet Engine neutral way. It uses the - * <code>PortletContext</code>'s <code>getRealPath</code> method - * to get the Portlet 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 PortletException - */ - protected String getClassPath() throws PortletException { - StringBuffer buildClassPath = new StringBuffer(); - - File root = null; - if (portletContextPath != null) { - // Old method. There *MUST* be a better method than this... - - String classDir = this.portletContext.getRealPath("/WEB-INF/classes"); - String libDir = this.portletContext.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.portletContext.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.portletContext.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(); - } - - private File extractLibraries() { - try { - URL manifestURL = this.portletContext.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.workDir, "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.portletContext.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 PortletException - */ - protected String getExtraClassPath() throws PortletException { - 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.portletContextPath != null) { - path = this.portletContextPath + 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 ""; - } - - /** - * 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 Portlet - * container's log system. Only messages that are Priority.ERROR - * and above go to the portlet 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 initLogger() { - final String logLevel = getInitParameter("log-level", "INFO"); - - final String accesslogger = getInitParameter("portlet-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 PortletOutputLogTarget servTarget = new PortletOutputLogTarget(this.portletContext, 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("portlet-context", this.portletContext); - if (this.portletContextPath == null) { - File logSCDir = new File(this.workDir, "log"); - logSCDir.mkdirs(); - if (getLogger().isWarnEnabled()) { - getLogger().warn("Setting context-root for LogKit to " + logSCDir); - } - subcontext.put("context-root", logSCDir.toString()); - } else { - subcontext.put("context-root", this.portletContextPath); - } - - 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.portletContext.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.portletContext.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); - } - - private LoggerManager newLoggerManager(String loggerManagerClass, Hierarchy hierarchy) { - if (loggerManagerClass.equals(LogKitLoggerManager.class.getName())) { - return new LogKitLoggerManager(hierarchy); - } else if (loggerManagerClass.equals(Log4JLoggerManager.class.getName()) || - loggerManagerClass.equalsIgnoreCase("LOG4J")) { - return new Log4JLoggerManager(); - } else { + try { + if (path.indexOf(':') > 1) { + this.portletContextURL = path; + } else { + this.portletContextURL = 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 { - Class clazz = Class.forName(loggerManagerClass); - return (LoggerManager)clazz.newInstance(); - } catch (Exception e) { - return new LogKitLoggerManager(hierarchy); + this.portletContextURL = new File(path).toURL().toExternalForm(); + } catch (MalformedURLException ignored) { + throw new PortletException("Unable to determine portlet context URL.", me); } } - } - - /** - * Set the ConfigFile for the Cocoon object. - * - * @param configFileName The file location for the cocoon.xconf - * - * @throws PortletException - */ - private URL getConfigFile(final String configFileName) - throws PortletException { - final String usedFileName; - if (configFileName == null) { - if (getLogger().isWarnEnabled()) { - getLogger().warn("Portlet initialization argument 'configurations' not specified, attempting to use '/WEB-INF/cocoon.xconf'"); + 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"); } - usedFileName = "/WEB-INF/cocoon.xconf"; - } else { - usedFileName = configFileName; + } catch (SecurityException e) { + // Ignore security exception + this.portletContext.log("CocoonPortlet: Could not check system properties, got: " + e); } - if (getLogger().isDebugEnabled()) { - getLogger().debug("Using configuration file: " + usedFileName); - } + // initialize settings + PortletBootstrapEnvironment env = new PortletBootstrapEnvironment(conf, this.classLoader, this.portletContextPath, this.portletContextURL); - URL result; try { - // test if this is a qualified url - if (usedFileName.indexOf(':') == -1) { - result = this.portletContext.getResource(usedFileName); - } else { - result = new URL(usedFileName); + this.coreUtil = new CoreUtil(env); + this.appContext = coreUtil.getCore().getContext(); + this.log = env.logger; + } catch (Exception e) { + if ( e instanceof PortletException ) { + throw (PortletException)e; } - } catch (Exception mue) { - String msg = "Init parameter 'configurations' is invalid : " + usedFileName; - getLogger().error(msg, mue); - throw new PortletException(msg, mue); + throw new PortletException(e); } - if (result == null) { - File resultFile = new File(usedFileName); - if (resultFile.isFile()) { - try { - result = resultFile.getCanonicalFile().toURL(); - } catch (Exception e) { - String msg = "Init parameter 'configurations' is invalid : " + usedFileName; - getLogger().error(msg, e); - throw new PortletException(msg, e); - } + if (getLogger().isDebugEnabled()) { + getLogger().debug("getRealPath for /: " + this.portletContextPath); + if (this.portletContextPath == null) { + getLogger().debug("getResource for /WEB-INF: " + debugPathOne); + getLogger().debug("Path for Root: " + debugPathTwo); } } - if (result == null) { - String msg = "Init parameter 'configuration' doesn't name an existing resource : " + usedFileName; - getLogger().error(msg); - throw new PortletException(msg); - } - return result; - } - - /** - * 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() { - if (this.forceLoadParameter != null) { - StringTokenizer fqcnTokenizer = new StringTokenizer(forceLoadParameter, " \t\r\n\f;,", false); + this.containerEncoding = getInitParameter("container-encoding", "ISO-8859-1"); + this.settings = this.coreUtil.getCore().getSettings(); + this.requestFactory = new RequestFactory(this.settings.isAutosaveUploads(), + new File(this.settings.getUploadDirectory()), + this.settings.isAllowOverwrite(), + this.settings.isSilentlyRename(), + this.settings.getMaxUploadSize(), + this.settings.getFormEncoding()); - while (fqcnTokenizer.hasMoreTokens()) { - final String fqcn = fqcnTokenizer.nextToken().trim(); + final String sessionScopeParam = getInitParameter("default-session-scope", "portlet"); + if ("application".equalsIgnoreCase(sessionScopeParam)) { + this.defaultSessionScope = javax.portlet.PortletSession.APPLICATION_SCOPE; + } else { + this.defaultSessionScope = javax.portlet.PortletSession.PORTLET_SCOPE; + } - try { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Trying to load class: " + fqcn); - } - ClassUtils.loadClass(fqcn).newInstance(); - } catch (Exception e) { - if (getLogger().isWarnEnabled()) { - getLogger().warn("Could not force-load class: " + fqcn, e); - } - // Do not throw an exception, because it is not a fatal error. - } - } + try { + this.exception = null; + this.cocoon = this.coreUtil.createCocoon(); + } catch (Exception e) { + this.exception = e; } } /** - * 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. + * Dispose Cocoon when portlet is destroyed */ - private void forceProperty() { - if (this.forceSystemProperty != null) { - StringTokenizer tokenizer = new StringTokenizer(forceSystemProperty, " \t\r\n\f;,", false); - - java.util.Properties systemProps = System.getProperties(); - while (tokenizer.hasMoreTokens()) { - final String property = tokenizer.nextToken().trim(); - if (property.indexOf('=') == -1) { - continue; - } - try { - String key = property.substring(0, property.indexOf('=')); - String value = property.substring(property.indexOf('=') + 1); - if (value.indexOf("${") != -1) { - value = StringUtils.replaceToken(value); - } - if (getLogger().isDebugEnabled()) { - getLogger().debug("setting " + key + "=" + value); - } - systemProps.setProperty(key, value); - } catch (Exception e) { - if (getLogger().isWarnEnabled()) { - getLogger().warn("Could not set property: " + property, e); - } - // Do not throw an exception, because it is not a fatal error. - } - } - System.setProperties(systemProps); + public void destroy() { + this.portletContext.log("Destroying Cocoon Portlet."); + if ( this.coreUtil != null ) { + this.coreUtil.destroy(); + this.coreUtil = null; } + super.destroy(); } /** @@ -1045,7 +301,7 @@ /* HACK for reducing class loader problems. */ /* example: xalan extensions fail if someone adds xalan jars in tomcat3.2.1/lib */ - if (this.initClassLoader) { + if (this.settings.isInitClassloader()) { try { Thread.currentThread().setContextClassLoader(this.classLoader); } catch (Exception e) { @@ -1061,7 +317,7 @@ // get the request (wrapped if contains multipart-form data) ActionRequest request; try { - if (this.enableUploads) { + if (this.settings.isEnableUploads()) { request = requestFactory.getServletRequest(req); } else { request = req; @@ -1077,7 +333,12 @@ } // Get the cocoon engine instance - getCocoon(request.getParameter(Constants.RELOAD_PARAM)); + try { + this.exception = null; + this.cocoon = this.coreUtil.getCocoon(null, request.getParameter(Constants.RELOAD_PARAM)); + } catch (Exception e) { + this.exception = e; + } // Check if cocoon was initialized if (this.cocoon == null) { @@ -1216,7 +477,7 @@ /* HACK for reducing class loader problems. */ /* example: xalan extensions fail if someone adds xalan jars in tomcat3.2.1/lib */ - if (this.initClassLoader) { + if (this.settings.isInitClassloader()) { try { Thread.currentThread().setContextClassLoader(this.classLoader); } catch (Exception e) { @@ -1233,7 +494,12 @@ RenderRequest request = req; // Get the cocoon engine instance - getCocoon(request.getParameter(Constants.RELOAD_PARAM)); + try { + this.exception = null; + this.cocoon = this.coreUtil.getCocoon(null, request.getParameter(Constants.RELOAD_PARAM)); + } catch (Exception e) { + this.exception = e; + } // Check if cocoon was initialized if (this.cocoon == null) { @@ -1348,12 +614,12 @@ if (contentType != null && contentType.equals("text/html")) { String showTime = request.getParameter(Constants.SHOWTIME_PARAM); - boolean show = this.showTime; + boolean show = this.settings.isShowTime(); if (showTime != null) { show = !showTime.equalsIgnoreCase("no"); } if (show) { - boolean hide = this.hiddenShowTime; + boolean hide = this.settings.isHideShowTime(); if (showTime != null) { hide = showTime.equalsIgnoreCase("hide"); } @@ -1431,7 +697,7 @@ String uri, String title, String message, String description, Exception e) throws IOException, PortletException { - if (this.manageExceptions) { + if (this.settings.isManageExceptions()) { if (env != null) { env.tryResetResponse(); } else { @@ -1484,7 +750,7 @@ String formEncoding = req.getParameter("cocoon-form-encoding"); if (formEncoding == null) { - formEncoding = this.defaultFormEncoding; + formEncoding = this.settings.getFormEncoding(); } env = new PortletEnvironment(servletPath, pathInfo, @@ -1513,7 +779,7 @@ String formEncoding = req.getParameter("cocoon-form-encoding"); if (formEncoding == null) { - formEncoding = this.defaultFormEncoding; + formEncoding = this.settings.getFormEncoding(); } env = new PortletEnvironment(servletPath, pathInfo, @@ -1529,103 +795,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() { - 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(this.parentServiceManager, this.getLogger()); - ContainerUtil.contextualize(this.parentServiceManager, this.appContext); - ContainerUtil.initialize(this.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 PortletException { - - /* 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 { - 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 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) { - if (getLogger().isErrorEnabled()) { - getLogger().error("Exception reloading", e); - } - this.exception = e; - disposeCocoon(); - } - } - - private Logger getCocoonLogger() { - final String rootlogger = getInitParameter("cocoon-logger"); - if (rootlogger != null) { - return this.getLoggerManager().getLoggerForCategory(rootlogger); - } else { - 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 PortletException { - 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) { @@ -1645,51 +814,6 @@ } /** - * Gets the current cocoon object. Reload cocoon if configuration - * changed or we are reloading. - */ - private void getCocoon(final String reloadParam) - throws PortletException { - if (this.allowReload) { - 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 (reloadParam != null) { - if (getLogger().isInfoEnabled()) { - getLogger().info("Forced reload attempt"); - } - reload = true; - } - } else if (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. */ @@ -1706,7 +830,7 @@ } /** Convenience method to access portlet parameters */ - protected String getInitParameter(String name, String defaultValue) { + private String getInitParameter(String name, String defaultValue) { String result = getInitParameter(name); if (result == null) { if (getLogger() != null && getLogger().isDebugEnabled()) { @@ -1719,7 +843,7 @@ } /** Convenience method to access boolean portlet parameters */ - protected boolean getInitParameterAsBoolean(String name, boolean defaultValue) { + private boolean getInitParameterAsBoolean(String name, boolean defaultValue) { String value = getInitParameter(name); if (value == null) { if (getLogger() != null && getLogger().isDebugEnabled()) { @@ -1731,7 +855,7 @@ return BooleanUtils.toBoolean(value); } - protected int getInitParameterAsInteger(String name, int defaultValue) { + private int getInitParameterAsInteger(String name, int defaultValue) { String value = getInitParameter(name); if (value == null) { if (getLogger() != null && getLogger().isDebugEnabled()) { @@ -1747,7 +871,338 @@ return this.log; } - protected LoggerManager getLoggerManager() { - return this.loggerManager; + protected static final class PortletBootstrapEnvironment + implements BootstrapEnvironment { + + private final PortletConfig config; + private final ClassLoader classLoader; + private final File writeableContextPath; + private final String contextPath; + public Logger logger; + + public PortletBootstrapEnvironment(PortletConfig config, + ClassLoader cl, + String writeablePath, + String path) { + this.config = config; + this.classLoader = cl; + if ( writeablePath == null ) { + this.writeableContextPath = null; + } else { + this.writeableContextPath = new File(writeablePath); + } + this.contextPath = path; + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#log(java.lang.String) + */ + public void log(String message) { + this.config.getPortletContext().log(message); + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#log(java.lang.String, java.lang.Throwable) + */ + public void log(String message, Throwable error) { + this.config.getPortletContext().log(message, error); + } + + /** + * @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.getPortletContext().getResourceAsStream(path); + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#configure(org.apache.cocoon.configuration.Settings) + */ + public void configure(Settings settings) { + // fill from the portlet parameters + SettingsHelper.fill(settings, this.config); + if ( settings.getWorkDirectory() == null ) { + final File workDir = (File)this.config.getPortletContext().getAttribute("javax.servlet.context.tempdir"); + settings.setWorkDirectory(workDir.getAbsolutePath()); + } + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getInitClassLoader() + */ + public ClassLoader getInitClassLoader() { + return this.classLoader; + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getEnvironmentContext() + */ + public Context getEnvironmentContext() { + return new PortletContext(this.config.getPortletContext()); + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getContextURL() + */ + public String getContextURL() { + return this.contextPath; + } + + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getContextForWriting() + */ + public File getContextForWriting() { + return this.writeableContextPath; + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getDefaultLogTarget() + */ + public LogTarget getDefaultLogTarget() { + final CocoonLogFormatter formatter = new CocoonLogFormatter(); + formatter.setFormat("%7.7{priority} %{time} [%8.8{category}] " + + "(%{uri}) %{thread}/%{class:short}: %{message}\\n%{throwable}"); + return new PortletOutputLogTarget(this.config.getPortletContext(), formatter); + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#configureLoggingContext(org.apache.avalon.framework.context.DefaultContext) + */ + public void configureLoggingContext(DefaultContext context) { + context.put("servlet-context", this.config.getPortletContext()); + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#configure(org.apache.avalon.framework.context.DefaultContext) + */ + public void configure(DefaultContext context) { + // Add the portlet configuration + context.put(CONTEXT_PORTLET_CONFIG, this.config); + } + + /** + * @see org.apache.cocoon.core.BootstrapEnvironment#getConfigFile(java.lang.String) + */ + public URL getConfigFile(final String configFileName) + throws Exception { + final String usedFileName; + + if (configFileName == null) { + 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 (this.logger.isDebugEnabled()) { + this.logger.debug("Using configuration file: " + usedFileName); + } + + URL result; + try { + // test if this is a qualified url + if (usedFileName.indexOf(':') == -1) { + result = this.config.getPortletContext().getResource(usedFileName); + } else { + result = new URL(usedFileName); + } + } catch (Exception mue) { + String msg = "Init parameter 'configurations' is invalid : " + usedFileName; + this.logger.error(msg, mue); + throw new PortletException(msg, mue); + } + + if (result == null) { + File resultFile = new File(usedFileName); + if (resultFile.isFile()) { + try { + result = resultFile.getCanonicalFile().toURL(); + } catch (Exception e) { + String msg = "Init parameter 'configurations' is invalid : " + usedFileName; + this.logger.error(msg, e); + throw new PortletException(msg, e); + } + } + } + + if (result == null) { + String msg = "Init parameter 'configuration' doesn't name an existing resource : " + usedFileName; + this.logger.error(msg); + throw new PortletException(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.getPortletContext().getRealPath("/WEB-INF/classes"); + String libDir = this.config.getPortletContext().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.getPortletContext().getResource("/WEB-INF/classes"); + } catch (MalformedURLException me) { + this.logger.warn("Unable to add WEB-INF/classes to the classpath", me); + } + + try { + libDirURL = this.config.getPortletContext().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.getPortletContext().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.getPortletContext().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; + } + } + } + }