Java tutorial
/* * Copyright 1999-2004 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; import org.apache.avalon.excalibur.component.ComponentProxyGenerator; import org.apache.avalon.excalibur.component.DefaultRoleManager; import org.apache.avalon.excalibur.component.ExcaliburComponentManager; import org.apache.avalon.excalibur.logger.LoggerManager; import org.apache.avalon.framework.activity.Disposable; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.component.Component; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.component.Composable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.DefaultConfiguration; import org.apache.avalon.framework.configuration.SAXConfigurationHandler; import org.apache.avalon.framework.container.ContainerUtil; 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.AbstractLogEnabled; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.thread.ThreadSafe; import org.apache.cocoon.components.CocoonComponentManager; import org.apache.cocoon.components.ComponentContext; import org.apache.cocoon.components.PropertyAwareSAXConfigurationHandler; import org.apache.cocoon.components.pipeline.ProcessingPipeline; import org.apache.cocoon.components.source.SourceUtil; import org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper; import org.apache.cocoon.environment.Environment; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Session; import org.apache.cocoon.util.ClassUtils; import org.apache.cocoon.util.Deprecation; import org.apache.cocoon.util.SimpleSourceResolver; import org.apache.cocoon.util.Settings; import org.apache.cocoon.util.PropertySettings; import org.apache.cocoon.util.SettingsHelper; import org.apache.cocoon.util.location.Location; import org.apache.cocoon.util.location.LocationImpl; import org.apache.cocoon.util.location.LocationUtils; import org.apache.commons.lang.SystemUtils; import org.apache.excalibur.instrument.InstrumentManageable; import org.apache.excalibur.instrument.InstrumentManager; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceResolver; import org.apache.excalibur.source.impl.URLSource; import org.apache.excalibur.xml.impl.XercesParser; import org.apache.excalibur.xml.sax.SAXParser; import org.xml.sax.InputSource; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Collections; import java.util.Enumeration; import java.util.Map; /** * The Cocoon Object is the main Kernel for the entire Cocoon system. * * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a> (Apache Software Foundation) * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> * @author <a href="mailto:leo.sutic@inspireinfrastructure.com">Leo Sutic</a> * @version CVS $Id: Cocoon.java 389028 2006-03-27 06:21:40Z rgoers $ */ public class Cocoon extends AbstractLogEnabled implements ThreadSafe, Component, Initializable, Disposable, Modifiable, Processor, Contextualizable, Composable, InstrumentManageable { // Register the location finder for Avalon configuration objects and exceptions // and keep a strong reference to it. private static final LocationUtils.LocationFinder confLocFinder = new LocationUtils.LocationFinder() { public Location getLocation(Object obj, String description) { if (obj instanceof Configuration) { Configuration config = (Configuration) obj; String locString = config.getLocation(); Location result = LocationUtils.parse(locString); if (LocationUtils.isKnown(result)) { // Add description StringBuffer desc = new StringBuffer().append('<'); // Unfortunately Configuration.getPrefix() is not public try { if (config.getNamespace().startsWith("http://apache.org/cocoon/sitemap/")) { desc.append("map:"); } } catch (ConfigurationException e) { // no namespace: ignore } desc.append(config.getName()).append('>'); return new LocationImpl(desc.toString(), result); } else { return result; } } if (obj instanceof Exception) { // Many exceptions in Cocoon have a message like "blah blah at file://foo/bar.xml:12:1" String msg = ((Exception) obj).getMessage(); if (msg == null) return null; int pos = msg.lastIndexOf(" at "); if (pos != -1) { return LocationUtils.parse(msg.substring(pos + 4)); } else { // Will try other finders return null; } } // Try next finders. return null; } }; static { LocationUtils.addFinder(confLocFinder); } static Cocoon instance; /** The root Cocoon logger */ private Logger rootLogger; /** The application context */ private Context context; /** The configuration file */ private Source configurationFile; /** The configuration tree */ private Configuration configuration; /** The logger manager */ private LoggerManager loggerManager; /** The instrument manager */ private InstrumentManager instrumentManager; /** The classpath (null if not available) */ private String classpath; /** The working directory (null if not available) */ private File workDir; /** The component manager. */ private ExcaliburComponentManager componentManager; /** The parent component manager. */ private ComponentManager parentComponentManager; /** Flag for disposed or not */ private boolean disposed; /** Active request count */ private volatile int activeRequestCount; /** The Processor if it is ThreadSafe */ private Processor threadSafeProcessor; /** The source resolver */ protected SourceResolver sourceResolver; /** An optional Avalon Component that is called before and after processing all requests. */ protected RequestListener requestListener; /** * Creates a new <code>Cocoon</code> instance. * * @exception ConfigurationException if an error occurs */ public Cocoon() throws ConfigurationException { // Set the system properties needed by Xalan2. setSystemProperties(); // HACK: Provide a way to share an instance of Cocoon object between // several servlets/portlets. Cocoon.instance = this; } public void enableLogging(Logger logger) { this.rootLogger = logger; super.enableLogging(logger.getChildLogger("cocoon")); } /** * Get the parent component manager. For purposes of * avoiding extra method calls, the manager parameter may be null. * * @param manager the parent component manager. May be <code>null</code> */ public void compose(ComponentManager manager) throws ComponentException { this.parentComponentManager = manager; } /** * Describe <code>contextualize</code> method here. * * @param context a <code>Context</code> value * @exception ContextException if an error occurs */ public void contextualize(Context context) throws ContextException { if (this.context == null) { this.context = new ComponentContext(context); SettingsHelper.createSettings((DefaultContext) this.context, getLogger()); ((DefaultContext) this.context).makeReadOnly(); this.classpath = (String) context.get(Constants.CONTEXT_CLASSPATH); this.workDir = (File) context.get(Constants.CONTEXT_WORK_DIR); try { // FIXME: add a configuration option for the refresh delay. // for now, hard-coded to 1 second. URLSource urlSource = new URLSource(); urlSource.init((URL) context.get(Constants.CONTEXT_CONFIG_URL), null); this.configurationFile = new DelayedRefreshSourceWrapper(urlSource, 1000L); } catch (IOException e) { throw new ContextException("Could not open configuration file.", e); } catch (Exception e) { throw new ContextException("contextualize(..) Exception", e); } } } /** * The <code>setLoggerManager</code> method will get a <code>LoggerManager</code> * for further use. * * @param loggerManager a <code>LoggerManager</code> value */ public void setLoggerManager(LoggerManager loggerManager) { this.loggerManager = loggerManager; Deprecation.setLogger(this.loggerManager.getLoggerForCategory("deprecation")); } /** * Set the <code>InstrumentManager</code> for this Cocoon instance. * * @param manager an <code>InstrumentManager</code> instance */ public void setInstrumentManager(final InstrumentManager manager) { this.instrumentManager = manager; } /** * The <code>initialize</code> method * * @exception Exception if an error occurs */ public void initialize() throws Exception { if (parentComponentManager != null) { this.componentManager = new CocoonComponentManager(parentComponentManager, (ClassLoader) this.context.get(Constants.CONTEXT_CLASS_LOADER)); } else { this.componentManager = new CocoonComponentManager( (ClassLoader) this.context.get(Constants.CONTEXT_CLASS_LOADER)); } ContainerUtil.enableLogging(this.componentManager, this.rootLogger.getChildLogger("manager")); ContainerUtil.contextualize(this.componentManager, this.context); this.componentManager.setInstrumentManager(this.instrumentManager); getLogger().debug("New Cocoon object."); // Log the System Properties. dumpSystemProperties(); // Setup the default parser, for parsing configuration. // If one need to use a different parser, set the given system property // first check for deprecated property to be compatible: String parser = getSystemProperty(Constants.DEPRECATED_PARSER_PROPERTY, Constants.DEFAULT_PARSER); if (!Constants.DEFAULT_PARSER.equals(parser)) { getLogger().warn("Deprecated property " + Constants.DEPRECATED_PARSER_PROPERTY + " is used. Please use " + Constants.PARSER_PROPERTY + " instead."); if ("org.apache.cocoon.components.parser.XercesParser".equals(parser)) { parser = XercesParser.class.getName(); } else { getLogger().warn("Unknown value for deprecated property: " + Constants.DEPRECATED_PARSER_PROPERTY + ", value: " + parser + ". If you experience problems during startup, check the parser configuration section of the documentation."); } } else { parser = getSystemProperty(Constants.PARSER_PROPERTY, Constants.DEFAULT_PARSER); } if (getLogger().isDebugEnabled()) { getLogger().debug("Parser: " + parser); getLogger().debug("Classpath: " + classpath); getLogger().debug("Work directory: " + workDir.getCanonicalPath()); } ExcaliburComponentManager startupManager = new ExcaliburComponentManager( (ClassLoader) this.context.get(Constants.CONTEXT_CLASS_LOADER)); ContainerUtil.enableLogging(startupManager, this.rootLogger.getChildLogger("startup")); ContainerUtil.contextualize(startupManager, this.context); startupManager.setLoggerManager(this.loggerManager); try { startupManager.addComponent(SAXParser.ROLE, ClassUtils.loadClass(parser), new DefaultConfiguration("", "empty")); } catch (Exception e) { throw new ConfigurationException("Could not load parser " + parser, e); } ContainerUtil.initialize(startupManager); configure(startupManager); ContainerUtil.dispose(startupManager); startupManager = null; // add the logger manager to the component locator final ComponentProxyGenerator proxyGenerator = new ComponentProxyGenerator(); final Component loggerManagerProxy = proxyGenerator.getProxy(LoggerManager.class.getName(), loggerManager); componentManager.addComponentInstance(LoggerManager.ROLE, loggerManagerProxy); ContainerUtil.initialize(this.componentManager); // Get the Processor and keep it if it's ThreadSafe Processor processor = (Processor) this.componentManager.lookup(Processor.ROLE); if (processor instanceof ThreadSafe) { if (getLogger().isDebugEnabled()) { getLogger().debug("Processor of class " + processor.getClass().getName() + " is ThreadSafe"); } this.threadSafeProcessor = processor; } else { if (getLogger().isDebugEnabled()) { getLogger().debug("Processor of class " + processor.getClass().getName() + " is NOT ThreadSafe -- will be looked up at each request"); } this.componentManager.release(processor); } this.sourceResolver = (SourceResolver) this.componentManager.lookup(SourceResolver.ROLE); if (this.componentManager.hasComponent(RequestListener.ROLE)) { this.requestListener = (RequestListener) this.componentManager.lookup(RequestListener.ROLE); } } /** Dump System Properties */ private void dumpSystemProperties() { if (getLogger().isDebugEnabled()) { try { Enumeration e = System.getProperties().propertyNames(); getLogger().debug("===== System Properties Start ====="); for (; e.hasMoreElements();) { String key = (String) e.nextElement(); getLogger().debug(key + "=" + System.getProperty(key)); } getLogger().debug("===== System Properties End ====="); } catch (SecurityException se) { // Ignore Exceptions. } } } /** * Configure this <code>Cocoon</code> instance. * * @param startupManager an <code>ExcaliburComponentManager</code> value * @exception ConfigurationException if an error occurs * @exception ContextException if an error occurs */ public void configure(ExcaliburComponentManager startupManager) throws ConfigurationException, ContextException { SAXParser p = null; Settings settings = SettingsHelper.getSettings(this.context); Configuration roles = null; try { p = (SAXParser) startupManager.lookup(SAXParser.ROLE); SAXConfigurationHandler b = new PropertyAwareSAXConfigurationHandler(settings, getLogger()); URL url = ClassUtils.getResource("org/apache/cocoon/cocoon.roles"); InputSource is = new InputSource(url.openStream()); is.setSystemId(url.toString()); p.parse(is, b); roles = b.getConfiguration(); } catch (Exception e) { throw new ConfigurationException("Error trying to load configurations", e); } finally { if (p != null) startupManager.release((Component) p); } DefaultRoleManager drm = new DefaultRoleManager(); ContainerUtil.enableLogging(drm, this.rootLogger.getChildLogger("roles")); ContainerUtil.configure(drm, roles); roles = null; try { this.configurationFile.refresh(); p = (SAXParser) startupManager.lookup(SAXParser.ROLE); SAXConfigurationHandler b = new PropertyAwareSAXConfigurationHandler(settings, getLogger()); InputSource is = SourceUtil.getInputSource(this.configurationFile); p.parse(is, b); this.configuration = b.getConfiguration(); } catch (Exception e) { throw new ConfigurationException("Error trying to load configurations", e); } finally { if (p != null) startupManager.release((Component) p); } Configuration conf = this.configuration; if (getLogger().isDebugEnabled()) { getLogger().debug("Root configuration: " + conf.getName()); } if (!"cocoon".equals(conf.getName())) { throw new ConfigurationException("Invalid configuration file\n" + conf.toString()); } if (getLogger().isDebugEnabled()) { getLogger().debug("Configuration version: " + conf.getAttribute("version")); } if (!Constants.CONF_VERSION.equals(conf.getAttribute("version"))) { throw new ConfigurationException( "Invalid configuration schema version. Must be '" + Constants.CONF_VERSION + "'."); } String userRoles = conf.getAttribute("user-roles", ""); if (!"".equals(userRoles)) { try { p = (SAXParser) startupManager.lookup(SAXParser.ROLE); SAXConfigurationHandler b = new PropertyAwareSAXConfigurationHandler(settings, getLogger()); org.apache.cocoon.environment.Context context = (org.apache.cocoon.environment.Context) this.context .get(Constants.CONTEXT_ENVIRONMENT_CONTEXT); URL url = context.getResource(userRoles); if (url == null) { throw new ConfigurationException( "User-roles configuration '" + userRoles + "' cannot be found."); } InputSource is = new InputSource(new BufferedInputStream(url.openStream())); is.setSystemId(url.toString()); p.parse(is, b); roles = b.getConfiguration(); } catch (Exception e) { throw new ConfigurationException("Error trying to load user-roles configuration", e); } finally { startupManager.release((Component) p); } DefaultRoleManager urm = new DefaultRoleManager(drm); ContainerUtil.enableLogging(urm, this.rootLogger.getChildLogger("roles").getChildLogger("user")); ContainerUtil.configure(urm, roles); roles = null; drm = urm; } this.componentManager.setRoleManager(drm); this.componentManager.setLoggerManager(this.loggerManager); getLogger().debug("Setting up components..."); ContainerUtil.configure(this.componentManager, conf); } /** * Queries the class to estimate its ergodic period termination. * * @param date a <code>long</code> value * @return a <code>boolean</code> value */ public boolean modifiedSince(long date) { return date < this.configurationFile.getLastModified(); } /** * Helper method to retrieve system property. * Returns default value if SecurityException is caught. */ public static String getSystemProperty(String property, String value) { try { return System.getProperty(property, value); } catch (SecurityException e) { System.err.println("Caught a SecurityException reading the system property '" + property + "';" + " Cocoon will default to '" + value + "' value."); return value; } } /** * Sets required system properties. */ protected void setSystemProperties() { try { // FIXME We shouldn't have to specify the SAXParser... // This is needed by Xalan2, it is used by org.xml.sax.helpers.XMLReaderFactory // to locate the SAX2 driver. if (getSystemProperty("org.xml.sax.driver", null) == null) { System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser"); } } catch (SecurityException e) { // Ignore security exceptions System.out.println("Caught a SecurityException writing the system property: " + e); } try { // FIXME We shouldn't have to specify these. Needed to override jaxp implementation of weblogic. if (getSystemProperty("javax.xml.parsers.DocumentBuilderFactory", "").startsWith("weblogic")) { System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl"); } } catch (SecurityException e) { // Ignore security exceptions System.out.println("Caught a SecurityException writing the system property: " + e); } } /** * Dispose this instance */ public void dispose() { if (this.componentManager != null) { if (this.requestListener != null) { this.componentManager.release(this.requestListener); } this.componentManager.release(this.threadSafeProcessor); this.threadSafeProcessor = null; this.componentManager.release(this.sourceResolver); this.sourceResolver = null; ContainerUtil.dispose(this.componentManager); this.componentManager = null; } this.context = null; if (Cocoon.instance == this) { Cocoon.instance = null; } this.disposed = true; } /** * Log debug information about the current environment. * * @param environment an <code>Environment</code> value */ protected void debug(Environment environment, boolean internal) { String lineSeparator = SystemUtils.LINE_SEPARATOR; Map objectModel = environment.getObjectModel(); Request request = ObjectModelHelper.getRequest(objectModel); Session session = request.getSession(false); StringBuffer msg = new StringBuffer(); msg.append("DEBUGGING INFORMATION:").append(lineSeparator); if (internal) { msg.append("INTERNAL "); } msg.append("REQUEST: ").append(request.getRequestURI()).append(lineSeparator).append(lineSeparator); msg.append("CONTEXT PATH: ").append(request.getContextPath()).append(lineSeparator); msg.append("SERVLET PATH: ").append(request.getServletPath()).append(lineSeparator); msg.append("PATH INFO: ").append(request.getPathInfo()).append(lineSeparator).append(lineSeparator); msg.append("REMOTE HOST: ").append(request.getRemoteHost()).append(lineSeparator); msg.append("REMOTE ADDRESS: ").append(request.getRemoteAddr()).append(lineSeparator); msg.append("REMOTE USER: ").append(request.getRemoteUser()).append(lineSeparator); msg.append("REQUEST SESSION ID: ").append(request.getRequestedSessionId()).append(lineSeparator); msg.append("REQUEST PREFERRED LOCALE: ").append(request.getLocale().toString()).append(lineSeparator); msg.append("SERVER HOST: ").append(request.getServerName()).append(lineSeparator); msg.append("SERVER PORT: ").append(request.getServerPort()).append(lineSeparator).append(lineSeparator); msg.append("METHOD: ").append(request.getMethod()).append(lineSeparator); msg.append("CONTENT LENGTH: ").append(request.getContentLength()).append(lineSeparator); msg.append("PROTOCOL: ").append(request.getProtocol()).append(lineSeparator); msg.append("SCHEME: ").append(request.getScheme()).append(lineSeparator); msg.append("AUTH TYPE: ").append(request.getAuthType()).append(lineSeparator).append(lineSeparator); msg.append("CURRENT ACTIVE REQUESTS: ").append(activeRequestCount).append(lineSeparator); // log all of the request parameters Enumeration e = request.getParameterNames(); msg.append("REQUEST PARAMETERS:").append(lineSeparator).append(lineSeparator); while (e.hasMoreElements()) { String p = (String) e.nextElement(); msg.append("PARAM: '").append(p).append("' ").append("VALUES: '"); String[] params = request.getParameterValues(p); for (int i = 0; i < params.length; i++) { msg.append("[" + params[i] + "]"); if (i != (params.length - 1)) { msg.append(", "); } } msg.append("'").append(lineSeparator); } // log all of the header parameters Enumeration e2 = request.getHeaderNames(); msg.append("HEADER PARAMETERS:").append(lineSeparator).append(lineSeparator); while (e2.hasMoreElements()) { String p = (String) e2.nextElement(); msg.append("PARAM: '").append(p).append("' ").append("VALUES: '"); Enumeration e3 = request.getHeaders(p); while (e3.hasMoreElements()) { msg.append("[" + e3.nextElement() + "]"); if (e3.hasMoreElements()) { msg.append(", "); } } msg.append("'").append(lineSeparator); } msg.append(lineSeparator).append("SESSION ATTRIBUTES:").append(lineSeparator).append(lineSeparator); // log all of the session attributes if (session != null) { // Fix bug #12139: Session can be modified while still // being enumerated here synchronized (session) { e = session.getAttributeNames(); while (e.hasMoreElements()) { String p = (String) e.nextElement(); msg.append("PARAM: '").append(p).append("' ").append("VALUE: '").append(session.getAttribute(p)) .append("'").append(lineSeparator); } } } getLogger().debug(msg.toString()); } /** * Process the given <code>Environment</code> to produce the output. * * @param environment an <code>Environment</code> value * @return a <code>boolean</code> value * @exception Exception if an error occurs */ public boolean process(Environment environment) throws Exception { if (this.disposed) { throw new IllegalStateException("You cannot process a Disposed Cocoon engine."); } Object key = CocoonComponentManager.startProcessing(environment); final int environmentDepth = CocoonComponentManager.markEnvironment(); CocoonComponentManager.enterEnvironment(environment, this.componentManager, this); try { boolean result; if (getLogger().isDebugEnabled()) { ++activeRequestCount; debug(environment, false); } if (this.requestListener != null) { try { requestListener.onRequestStart(environment); } catch (Exception e) { getLogger().error("Error encountered monitoring request start: " + e.getMessage()); } } if (this.threadSafeProcessor != null) { result = this.threadSafeProcessor.process(environment); if (this.requestListener != null) { try { requestListener.onRequestEnd(environment); } catch (Exception e) { getLogger().error("Error encountered monitoring request start: " + e.getMessage()); } } } else { Processor processor = (Processor) this.componentManager.lookup(Processor.ROLE); try { result = processor.process(environment); if (this.requestListener != null) { try { requestListener.onRequestEnd(environment); } catch (Exception e) { getLogger().error("Error encountered monitoring request start: " + e.getMessage()); } } } finally { this.componentManager.release(processor); } } // commit response on success environment.commitResponse(); return result; } catch (Exception any) { if (this.requestListener != null) { try { requestListener.onRequestException(environment, any); } catch (Exception e) { getLogger().error("Error encountered monitoring request start: " + e.getMessage()); } } // reset response on error environment.tryResetResponse(); throw any; } finally { CocoonComponentManager.leaveEnvironment(); CocoonComponentManager.endProcessing(environment, key); if (getLogger().isDebugEnabled()) { --activeRequestCount; } // TODO (CZ): This is only for testing - remove it later on CocoonComponentManager.checkEnvironment(environmentDepth, getLogger()); } } /** * Process the given <code>Environment</code> to assemble * a <code>ProcessingPipeline</code>. * @since 2.1 */ public ProcessingPipeline buildPipeline(Environment environment) throws Exception { if (disposed) { throw new IllegalStateException("You cannot process a Disposed Cocoon engine."); } try { if (getLogger().isDebugEnabled()) { ++activeRequestCount; debug(environment, true); } if (this.threadSafeProcessor != null) { return this.threadSafeProcessor.buildPipeline(environment); } else { Processor processor = (Processor) this.componentManager.lookup(Processor.ROLE); try { return processor.buildPipeline(environment); } finally { this.componentManager.release(processor); } } } finally { if (getLogger().isDebugEnabled()) { --activeRequestCount; } } } /** * Get the sitemap component configurations * @since 2.1 */ public Map getComponentConfigurations() { return Collections.EMPTY_MAP; } /** * Return this (Cocoon is always at the root of the processing chain). * @since 2.1.1 */ public Processor getRootProcessor() { return this; } /** * Accessor for active request count */ public int getActiveRequestCount() { return activeRequestCount; } public ExcaliburComponentManager getComponentManager() { return this.componentManager; } /** * Create a simple source resolver. */ protected SourceResolver createSourceResolver(Logger logger) throws ContextException { // Create our own resolver final SimpleSourceResolver resolver = new SimpleSourceResolver(); resolver.enableLogging(logger); try { resolver.contextualize(this.context); } catch (ContextException ce) { throw new ContextException("Cannot setup source resolver.", ce); } return resolver; } }