001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon;
018:
019: import org.apache.avalon.excalibur.component.ComponentProxyGenerator;
020: import org.apache.avalon.excalibur.component.DefaultRoleManager;
021: import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
022: import org.apache.avalon.excalibur.logger.LoggerManager;
023: import org.apache.avalon.framework.activity.Disposable;
024: import org.apache.avalon.framework.activity.Initializable;
025: import org.apache.avalon.framework.component.Component;
026: import org.apache.avalon.framework.component.ComponentException;
027: import org.apache.avalon.framework.component.ComponentManager;
028: import org.apache.avalon.framework.component.Composable;
029: import org.apache.avalon.framework.configuration.Configuration;
030: import org.apache.avalon.framework.configuration.ConfigurationException;
031: import org.apache.avalon.framework.configuration.DefaultConfiguration;
032: import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
033: import org.apache.avalon.framework.container.ContainerUtil;
034: import org.apache.avalon.framework.context.Context;
035: import org.apache.avalon.framework.context.ContextException;
036: import org.apache.avalon.framework.context.Contextualizable;
037: import org.apache.avalon.framework.context.DefaultContext;
038: import org.apache.avalon.framework.logger.AbstractLogEnabled;
039: import org.apache.avalon.framework.logger.Logger;
040: import org.apache.avalon.framework.thread.ThreadSafe;
041:
042: import org.apache.cocoon.components.CocoonComponentManager;
043: import org.apache.cocoon.components.ComponentContext;
044: import org.apache.cocoon.components.PropertyAwareSAXConfigurationHandler;
045: import org.apache.cocoon.components.pipeline.ProcessingPipeline;
046: import org.apache.cocoon.components.source.SourceUtil;
047: import org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper;
048: import org.apache.cocoon.environment.Environment;
049: import org.apache.cocoon.environment.ObjectModelHelper;
050: import org.apache.cocoon.environment.Request;
051: import org.apache.cocoon.environment.Session;
052: import org.apache.cocoon.util.ClassUtils;
053: import org.apache.cocoon.util.Deprecation;
054: import org.apache.cocoon.util.SimpleSourceResolver;
055: import org.apache.cocoon.util.Settings;
056: import org.apache.cocoon.util.SettingsHelper;
057: import org.apache.cocoon.util.location.Location;
058: import org.apache.cocoon.util.location.LocationImpl;
059: import org.apache.cocoon.util.location.LocationUtils;
060:
061: import org.apache.commons.lang.SystemUtils;
062: import org.apache.excalibur.instrument.InstrumentManageable;
063: import org.apache.excalibur.instrument.InstrumentManager;
064: import org.apache.excalibur.source.Source;
065: import org.apache.excalibur.source.SourceResolver;
066: import org.apache.excalibur.source.impl.URLSource;
067: import org.apache.excalibur.xml.impl.XercesParser;
068: import org.apache.excalibur.xml.sax.SAXParser;
069: import org.xml.sax.InputSource;
070:
071: import java.io.BufferedInputStream;
072: import java.io.File;
073: import java.io.IOException;
074: import java.net.URL;
075: import java.util.Collections;
076: import java.util.Enumeration;
077: import java.util.Map;
078: import java.util.ConcurrentModificationException;
079:
080: /**
081: * The Cocoon Object is the main Kernel for the entire Cocoon system.
082: *
083: * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a> (Apache Software Foundation)
084: * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
085: * @author <a href="mailto:leo.sutic@inspireinfrastructure.com">Leo Sutic</a>
086: * @version CVS $Id: Cocoon.java 540711 2007-05-22 19:36:07Z cziegeler $
087: */
088: public class Cocoon extends AbstractLogEnabled implements ThreadSafe,
089: Component, Initializable, Disposable, Modifiable, Processor,
090: Contextualizable, Composable, InstrumentManageable {
091:
092: // Register the location finder for Avalon configuration objects and exceptions
093: // and keep a strong reference to it.
094: private static final LocationUtils.LocationFinder LOCATION_FINDER = new LocationUtils.LocationFinder() {
095: public Location getLocation(Object obj, String description) {
096: if (obj instanceof Configuration) {
097: Configuration config = (Configuration) obj;
098: String locString = config.getLocation();
099: Location result = LocationUtils.parse(locString);
100: if (LocationUtils.isKnown(result)) {
101: // Add description
102: StringBuffer desc = new StringBuffer().append('<');
103: // Unfortunately Configuration.getPrefix() is not public
104: try {
105: if (config.getNamespace().startsWith(
106: "http://apache.org/cocoon/sitemap/")) {
107: desc.append("map:");
108: }
109: } catch (ConfigurationException e) {
110: // no namespace: ignore
111: }
112: desc.append(config.getName()).append('>');
113: return new LocationImpl(desc.toString(), result);
114: } else {
115: return result;
116: }
117: }
118:
119: if (obj instanceof Exception) {
120: // Many exceptions in Cocoon have a message like "blah blah at file://foo/bar.xml:12:1"
121: String msg = ((Exception) obj).getMessage();
122: if (msg == null) {
123: return null;
124: }
125:
126: int pos = msg.lastIndexOf(" at ");
127: if (pos != -1) {
128: return LocationUtils.parse(msg.substring(pos + 4));
129: } else {
130: // Will try other finders
131: return null;
132: }
133: }
134:
135: // Try next finders.
136: return null;
137: }
138: };
139:
140: static {
141: LocationUtils.addFinder(LOCATION_FINDER);
142: }
143:
144: static Cocoon instance;
145:
146: /** The root Cocoon logger */
147: private Logger rootLogger;
148:
149: /** The application context */
150: private Context context;
151:
152: /** The configuration file */
153: private Source configurationFile;
154:
155: /** The configuration tree */
156: private Configuration configuration;
157:
158: /** The logger manager */
159: private LoggerManager loggerManager;
160:
161: /** The instrument manager */
162: private InstrumentManager instrumentManager;
163:
164: /** The classpath (null if not available) */
165: private String classpath;
166:
167: /** The working directory (null if not available) */
168: private File workDir;
169:
170: /** The component manager. */
171: private ExcaliburComponentManager componentManager;
172:
173: /** The parent component manager. */
174: private ComponentManager parentComponentManager;
175:
176: /** Flag for disposed or not */
177: private boolean disposed;
178:
179: /** Active request count */
180: private volatile int activeRequestCount;
181:
182: /** The Processor if it is ThreadSafe */
183: private Processor threadSafeProcessor;
184:
185: /** The source resolver */
186: protected SourceResolver sourceResolver;
187:
188: /** An optional Avalon Component that is called before and after processing all requests. */
189: protected RequestListener requestListener;
190:
191: /**
192: * Creates a new <code>Cocoon</code> instance.
193: *
194: * @exception ConfigurationException if an error occurs
195: */
196: public Cocoon() throws ConfigurationException {
197: // Set the system properties needed by Xalan2.
198: this .setSystemProperties();
199:
200: // HACK: Provide a way to share an instance of Cocoon object between
201: // several servlets/portlets.
202: Cocoon.instance = this ;
203: }
204:
205: public void enableLogging(Logger logger) {
206: this .rootLogger = logger;
207: super .enableLogging(logger.getChildLogger("cocoon"));
208: }
209:
210: /**
211: * Get the parent component manager. For purposes of
212: * avoiding extra method calls, the manager parameter may be null.
213: *
214: * @param manager the parent component manager. May be <code>null</code>
215: */
216: public void compose(ComponentManager manager)
217: throws ComponentException {
218: this .parentComponentManager = manager;
219: }
220:
221: /**
222: * Describe <code>contextualize</code> method here.
223: *
224: * @param context a <code>Context</code> value
225: * @exception ContextException if an error occurs
226: */
227: public void contextualize(Context context) throws ContextException {
228: if (this .context == null) {
229: this .context = new ComponentContext(context);
230: SettingsHelper.createSettings(
231: (DefaultContext) this .context, this .getLogger());
232: ((DefaultContext) this .context).makeReadOnly();
233:
234: this .classpath = (String) context
235: .get(Constants.CONTEXT_CLASSPATH);
236: this .workDir = (File) context
237: .get(Constants.CONTEXT_WORK_DIR);
238: try {
239: // FIXME: add a configuration option for the refresh delay.
240: // for now, hard-coded to 1 second.
241: URLSource urlSource = new URLSource();
242: urlSource.init((URL) context
243: .get(Constants.CONTEXT_CONFIG_URL), null);
244: this .configurationFile = new DelayedRefreshSourceWrapper(
245: urlSource, 1000L);
246:
247: } catch (IOException e) {
248: throw new ContextException(
249: "Could not open configuration file.", e);
250: } catch (Exception e) {
251: throw new ContextException(
252: "contextualize(..) Exception", e);
253: }
254: }
255: }
256:
257: /**
258: * The <code>setLoggerManager</code> method will get a <code>LoggerManager</code>
259: * for further use.
260: *
261: * @param loggerManager a <code>LoggerManager</code> value
262: */
263: public void setLoggerManager(LoggerManager loggerManager) {
264: this .loggerManager = loggerManager;
265: Deprecation.setLogger(this .loggerManager
266: .getLoggerForCategory("deprecation"));
267: }
268:
269: /**
270: * Set the <code>InstrumentManager</code> for this Cocoon instance.
271: *
272: * @param manager an <code>InstrumentManager</code> instance
273: */
274: public void setInstrumentManager(final InstrumentManager manager) {
275: this .instrumentManager = manager;
276: }
277:
278: /**
279: * The <code>initialize</code> method
280: *
281: * @exception Exception if an error occurs
282: */
283: public void initialize() throws Exception {
284: if (this .parentComponentManager != null) {
285: this .componentManager = new CocoonComponentManager(
286: this .parentComponentManager,
287: (ClassLoader) this .context
288: .get(Constants.CONTEXT_CLASS_LOADER));
289: } else {
290: this .componentManager = new CocoonComponentManager(
291: (ClassLoader) this .context
292: .get(Constants.CONTEXT_CLASS_LOADER));
293: }
294: ContainerUtil.enableLogging(this .componentManager,
295: this .rootLogger.getChildLogger("manager"));
296: ContainerUtil
297: .contextualize(this .componentManager, this .context);
298: this .componentManager
299: .setInstrumentManager(this .instrumentManager);
300: this .getLogger().debug("New Cocoon object.");
301:
302: // Log the System Properties.
303: this .dumpSystemProperties();
304:
305: // Setup the default parser, for parsing configuration.
306: // If one need to use a different parser, set the given system property
307: // first check for deprecated property to be compatible:
308: String parser = getSystemProperty(
309: Constants.DEPRECATED_PARSER_PROPERTY,
310: Constants.DEFAULT_PARSER);
311: if (!Constants.DEFAULT_PARSER.equals(parser)) {
312: this .getLogger().warn(
313: "Deprecated property "
314: + Constants.DEPRECATED_PARSER_PROPERTY
315: + " is used. Please use "
316: + Constants.PARSER_PROPERTY + " instead.");
317: if ("org.apache.cocoon.components.parser.XercesParser"
318: .equals(parser)) {
319: parser = XercesParser.class.getName();
320: } else {
321: this
322: .getLogger()
323: .warn(
324: "Unknown value for deprecated property: "
325: + Constants.DEPRECATED_PARSER_PROPERTY
326: + ", value: "
327: + parser
328: + ". If you experience problems during startup, check the parser configuration section of the documentation.");
329: }
330: } else {
331: parser = getSystemProperty(Constants.PARSER_PROPERTY,
332: Constants.DEFAULT_PARSER);
333: }
334: if (this .getLogger().isDebugEnabled()) {
335: this .getLogger().debug("Parser: " + parser);
336: this .getLogger().debug("Classpath: " + this .classpath);
337: this .getLogger().debug(
338: "Work directory: "
339: + this .workDir.getCanonicalPath());
340: }
341:
342: ExcaliburComponentManager startupManager = new ExcaliburComponentManager(
343: (ClassLoader) this .context
344: .get(Constants.CONTEXT_CLASS_LOADER));
345: ContainerUtil.enableLogging(startupManager, this .rootLogger
346: .getChildLogger("startup"));
347: ContainerUtil.contextualize(startupManager, this .context);
348: startupManager.setLoggerManager(this .loggerManager);
349:
350: try {
351: startupManager.addComponent(SAXParser.ROLE, ClassUtils
352: .loadClass(parser), new DefaultConfiguration("",
353: "empty"));
354: } catch (Exception e) {
355: throw new ConfigurationException("Could not load parser "
356: + parser, e);
357: }
358:
359: ContainerUtil.initialize(startupManager);
360: this .configure(startupManager);
361: ContainerUtil.dispose(startupManager);
362: startupManager = null;
363:
364: // add the logger manager to the component locator
365: final ComponentProxyGenerator proxyGenerator = new ComponentProxyGenerator();
366: final Component loggerManagerProxy = proxyGenerator.getProxy(
367: LoggerManager.class.getName(), this .loggerManager);
368: this .componentManager.addComponentInstance(LoggerManager.ROLE,
369: loggerManagerProxy);
370:
371: ContainerUtil.initialize(this .componentManager);
372:
373: // Get the Processor and keep it if it's ThreadSafe
374: Processor processor = (Processor) this .componentManager
375: .lookup(Processor.ROLE);
376: if (processor instanceof ThreadSafe) {
377: if (this .getLogger().isDebugEnabled()) {
378: this .getLogger().debug(
379: "Processor of class "
380: + processor.getClass().getName()
381: + " is ThreadSafe");
382: }
383: this .threadSafeProcessor = processor;
384: } else {
385: if (this .getLogger().isDebugEnabled()) {
386: this
387: .getLogger()
388: .debug(
389: "Processor of class "
390: + processor.getClass()
391: .getName()
392: + " is NOT ThreadSafe -- will be looked up at each request");
393: }
394: this .componentManager.release(processor);
395: }
396:
397: this .sourceResolver = (SourceResolver) this .componentManager
398: .lookup(SourceResolver.ROLE);
399:
400: if (this .componentManager.hasComponent(RequestListener.ROLE)) {
401: this .requestListener = (RequestListener) this .componentManager
402: .lookup(RequestListener.ROLE);
403: }
404: }
405:
406: /** Dump System Properties */
407: private void dumpSystemProperties() {
408: if (this .getLogger().isDebugEnabled()) {
409: try {
410: Enumeration e = System.getProperties().propertyNames();
411: this .getLogger().debug(
412: "===== System Properties Start =====");
413: for (; e.hasMoreElements();) {
414: String key = (String) e.nextElement();
415: this .getLogger().debug(
416: key + "=" + System.getProperty(key));
417: }
418: this .getLogger().debug(
419: "===== System Properties End =====");
420: } catch (SecurityException se) {
421: // Ignore Exceptions.
422: }
423: }
424: }
425:
426: /**
427: * Configure this <code>Cocoon</code> instance.
428: *
429: * @param startupManager an <code>ExcaliburComponentManager</code> value
430: * @exception ConfigurationException if an error occurs
431: * @exception ContextException if an error occurs
432: */
433: public void configure(ExcaliburComponentManager startupManager)
434: throws ConfigurationException, ContextException {
435: SAXParser p = null;
436: Settings settings = SettingsHelper.getSettings(this .context);
437:
438: Configuration roles = null;
439: try {
440: p = (SAXParser) startupManager.lookup(SAXParser.ROLE);
441: SAXConfigurationHandler b = new PropertyAwareSAXConfigurationHandler(
442: settings, this .getLogger());
443: URL url = ClassUtils
444: .getResource("org/apache/cocoon/cocoon.roles");
445: InputSource is = new InputSource(url.openStream());
446: is.setSystemId(url.toString());
447: p.parse(is, b);
448: roles = b.getConfiguration();
449: } catch (Exception e) {
450: throw new ConfigurationException(
451: "Error trying to load configurations", e);
452: } finally {
453: if (p != null)
454: startupManager.release((Component) p);
455: }
456:
457: DefaultRoleManager drm = new DefaultRoleManager();
458: ContainerUtil.enableLogging(drm, this .rootLogger
459: .getChildLogger("roles"));
460: ContainerUtil.configure(drm, roles);
461: roles = null;
462:
463: try {
464: this .configurationFile.refresh();
465: p = (SAXParser) startupManager.lookup(SAXParser.ROLE);
466: SAXConfigurationHandler b = new PropertyAwareSAXConfigurationHandler(
467: settings, this .getLogger());
468: InputSource is = SourceUtil
469: .getInputSource(this .configurationFile);
470: p.parse(is, b);
471: this .configuration = b.getConfiguration();
472: } catch (Exception e) {
473: throw new ConfigurationException(
474: "Error trying to load configurations", e);
475: } finally {
476: if (p != null)
477: startupManager.release((Component) p);
478: }
479:
480: Configuration conf = this .configuration;
481: if (this .getLogger().isDebugEnabled()) {
482: this .getLogger().debug(
483: "Root configuration: " + conf.getName());
484: }
485: if (!"cocoon".equals(conf.getName())) {
486: throw new ConfigurationException(
487: "Invalid configuration file\n" + conf.toString());
488: }
489: if (this .getLogger().isDebugEnabled()) {
490: this .getLogger().debug(
491: "Configuration version: "
492: + conf.getAttribute("version"));
493: }
494: if (!Constants.CONF_VERSION
495: .equals(conf.getAttribute("version"))) {
496: throw new ConfigurationException(
497: "Invalid configuration schema version. Must be '"
498: + Constants.CONF_VERSION + "'.");
499: }
500:
501: String userRoles = conf.getAttribute("user-roles", "");
502: if (!"".equals(userRoles)) {
503: try {
504: p = (SAXParser) startupManager.lookup(SAXParser.ROLE);
505: SAXConfigurationHandler b = new PropertyAwareSAXConfigurationHandler(
506: settings, this .getLogger());
507: org.apache.cocoon.environment.Context context = (org.apache.cocoon.environment.Context) this .context
508: .get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
509: URL url = context.getResource(userRoles);
510: if (url == null) {
511: throw new ConfigurationException(
512: "User-roles configuration '" + userRoles
513: + "' cannot be found.");
514: }
515: InputSource is = new InputSource(
516: new BufferedInputStream(url.openStream()));
517: is.setSystemId(url.toString());
518: p.parse(is, b);
519: roles = b.getConfiguration();
520: } catch (Exception e) {
521: throw new ConfigurationException(
522: "Error trying to load user-roles configuration",
523: e);
524: } finally {
525: startupManager.release((Component) p);
526: }
527:
528: DefaultRoleManager urm = new DefaultRoleManager(drm);
529: ContainerUtil.enableLogging(urm, this .rootLogger
530: .getChildLogger("roles").getChildLogger("user"));
531: ContainerUtil.configure(urm, roles);
532: roles = null;
533: drm = urm;
534: }
535:
536: this .componentManager.setRoleManager(drm);
537: this .componentManager.setLoggerManager(this .loggerManager);
538:
539: this .getLogger().debug("Setting up components...");
540: ContainerUtil.configure(this .componentManager, conf);
541: }
542:
543: /**
544: * Queries the class to estimate its ergodic period termination.
545: *
546: * @param date a <code>long</code> value
547: * @return a <code>boolean</code> value
548: */
549: public boolean modifiedSince(long date) {
550: return date < this .configurationFile.getLastModified();
551: }
552:
553: /**
554: * Helper method to retrieve system property.
555: * Returns default value if SecurityException is caught.
556: */
557: public static String getSystemProperty(String property, String value) {
558: try {
559: return System.getProperty(property, value);
560: } catch (SecurityException e) {
561: System.err
562: .println("Caught a SecurityException reading the system property '"
563: + property
564: + "';"
565: + " Cocoon will default to '"
566: + value
567: + "' value.");
568: return value;
569: }
570: }
571:
572: /**
573: * Sets required system properties.
574: */
575: protected void setSystemProperties() {
576: try {
577: // FIXME We shouldn't have to specify the SAXParser...
578: // This is needed by Xalan2, it is used by org.xml.sax.helpers.XMLReaderFactory
579: // to locate the SAX2 driver.
580: if (getSystemProperty("org.xml.sax.driver", null) == null) {
581: System.setProperty("org.xml.sax.driver",
582: "org.apache.xerces.parsers.SAXParser");
583: }
584: } catch (SecurityException e) {
585: // Ignore security exceptions
586: System.out
587: .println("Caught a SecurityException writing the system property: "
588: + e);
589: }
590:
591: try {
592: // FIXME We shouldn't have to specify these. Needed to override jaxp implementation of weblogic.
593: if (getSystemProperty(
594: "javax.xml.parsers.DocumentBuilderFactory", "")
595: .startsWith("weblogic")) {
596: System
597: .setProperty(
598: "javax.xml.parsers.DocumentBuilderFactory",
599: "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
600: System.setProperty(
601: "javax.xml.parsers.SAXParserFactory",
602: "org.apache.xerces.jaxp.SAXParserFactoryImpl");
603: }
604: } catch (SecurityException e) {
605: // Ignore security exceptions
606: System.out
607: .println("Caught a SecurityException writing the system property: "
608: + e);
609: }
610: }
611:
612: /**
613: * Dispose this instance
614: */
615: public void dispose() {
616: if (this .componentManager != null) {
617: if (this .requestListener != null) {
618: this .componentManager.release(this .requestListener);
619: }
620: this .componentManager.release(this .threadSafeProcessor);
621: this .threadSafeProcessor = null;
622:
623: this .componentManager
624: .release((Component) this .sourceResolver);
625: this .sourceResolver = null;
626:
627: ContainerUtil.dispose(this .componentManager);
628: this .componentManager = null;
629: }
630:
631: this .context = null;
632: if (Cocoon.instance == this ) {
633: Cocoon.instance = null;
634: }
635: this .disposed = true;
636: }
637:
638: /**
639: * Log debug information about the current environment.
640: *
641: * @param environment an <code>Environment</code> value
642: */
643: protected void debug(Environment environment, boolean internal) {
644: String lineSeparator = SystemUtils.LINE_SEPARATOR;
645: Map objectModel = environment.getObjectModel();
646: Request request = ObjectModelHelper.getRequest(objectModel);
647: Session session = request.getSession(false);
648: StringBuffer msg = new StringBuffer(2048);
649: msg.append("DEBUGGING INFORMATION:").append(lineSeparator);
650: if (internal) {
651: msg.append("INTERNAL ");
652: }
653: msg.append("REQUEST: ").append(request.getRequestURI()).append(
654: lineSeparator).append(lineSeparator);
655: msg.append("CONTEXT PATH: ").append(request.getContextPath())
656: .append(lineSeparator);
657: msg.append("SERVLET PATH: ").append(request.getServletPath())
658: .append(lineSeparator);
659: msg.append("PATH INFO: ").append(request.getPathInfo()).append(
660: lineSeparator).append(lineSeparator);
661:
662: msg.append("REMOTE HOST: ").append(request.getRemoteHost())
663: .append(lineSeparator);
664: msg.append("REMOTE ADDRESS: ").append(request.getRemoteAddr())
665: .append(lineSeparator);
666: msg.append("REMOTE USER: ").append(request.getRemoteUser())
667: .append(lineSeparator);
668: msg.append("REQUEST SESSION ID: ").append(
669: request.getRequestedSessionId()).append(lineSeparator);
670: msg.append("REQUEST PREFERRED LOCALE: ").append(
671: request.getLocale().toString()).append(lineSeparator);
672: msg.append("SERVER HOST: ").append(request.getServerName())
673: .append(lineSeparator);
674: msg.append("SERVER PORT: ").append(request.getServerPort())
675: .append(lineSeparator).append(lineSeparator);
676:
677: msg.append("METHOD: ").append(request.getMethod()).append(
678: lineSeparator);
679: msg.append("CONTENT LENGTH: ").append(
680: request.getContentLength()).append(lineSeparator);
681: msg.append("PROTOCOL: ").append(request.getProtocol()).append(
682: lineSeparator);
683: msg.append("SCHEME: ").append(request.getScheme()).append(
684: lineSeparator);
685: msg.append("AUTH TYPE: ").append(request.getAuthType()).append(
686: lineSeparator).append(lineSeparator);
687: msg.append("CURRENT ACTIVE REQUESTS: ").append(
688: this .activeRequestCount).append(lineSeparator);
689:
690: // log all of the request parameters
691: Enumeration e = request.getParameterNames();
692:
693: msg.append("REQUEST PARAMETERS:").append(lineSeparator).append(
694: lineSeparator);
695:
696: while (e.hasMoreElements()) {
697: String p = (String) e.nextElement();
698:
699: msg.append("PARAM: '").append(p).append("' ").append(
700: "VALUES: '");
701: String[] params = request.getParameterValues(p);
702: for (int i = 0; i < params.length; i++) {
703: msg.append("[" + params[i] + "]");
704: if (i != (params.length - 1)) {
705: msg.append(", ");
706: }
707: }
708:
709: msg.append("'").append(lineSeparator);
710: }
711:
712: // log all of the header parameters
713: Enumeration e2 = request.getHeaderNames();
714:
715: msg.append("HEADER PARAMETERS:").append(lineSeparator).append(
716: lineSeparator);
717:
718: while (e2.hasMoreElements()) {
719: String p = (String) e2.nextElement();
720:
721: msg.append("PARAM: '").append(p).append("' ").append(
722: "VALUES: '");
723: Enumeration e3 = request.getHeaders(p);
724: while (e3.hasMoreElements()) {
725: msg.append("[" + e3.nextElement() + "]");
726: if (e3.hasMoreElements()) {
727: msg.append(", ");
728: }
729: }
730:
731: msg.append("'").append(lineSeparator);
732: }
733:
734: msg.append(lineSeparator).append("SESSION ATTRIBUTES:").append(
735: lineSeparator).append(lineSeparator);
736:
737: // log all of the session attributes
738: if (session != null) {
739: StringBuffer buffer = new StringBuffer("");
740: int count = -1;
741: while (count <= 0) {
742: // Fix bug #12139: Session can be modified while still
743: // being enumerated here
744: try {
745: e = session.getAttributeNames();
746: while (e.hasMoreElements()) {
747: String p = (String) e.nextElement();
748: buffer.append("PARAM: '").append(p)
749: .append("' ").append("VALUE: '")
750: .append(session.getAttribute(p))
751: .append("'").append(lineSeparator);
752: }
753: break;
754: } catch (ConcurrentModificationException ex) {
755: buffer = new StringBuffer("");
756: ++count;
757: }
758:
759: }
760: msg.append(buffer.toString());
761: }
762:
763: this .getLogger().debug(msg.toString());
764: }
765:
766: /**
767: * Process the given <code>Environment</code> to produce the output.
768: *
769: * @param environment an <code>Environment</code> value
770: * @return a <code>boolean</code> value
771: * @exception Exception if an error occurs
772: */
773: public boolean process(Environment environment) throws Exception {
774: if (this .disposed) {
775: throw new IllegalStateException(
776: "You cannot process a Disposed Cocoon engine.");
777: }
778:
779: Object key = CocoonComponentManager
780: .startProcessing(environment);
781: final int environmentDepth = CocoonComponentManager
782: .markEnvironment();
783: CocoonComponentManager.enterEnvironment(environment,
784: this .componentManager, this );
785: try {
786: boolean result;
787: if (this .getLogger().isDebugEnabled()) {
788: ++this .activeRequestCount;
789: this .debug(environment, false);
790: }
791:
792: if (this .requestListener != null) {
793: try {
794: this .requestListener.onRequestStart(environment);
795: } catch (Exception e) {
796: this .getLogger().error(
797: "Error encountered monitoring request start: "
798: + e.getMessage());
799: }
800: }
801:
802: if (this .threadSafeProcessor != null) {
803: result = this .threadSafeProcessor.process(environment);
804: if (this .requestListener != null) {
805: try {
806: this .requestListener.onRequestEnd(environment);
807: } catch (Exception e) {
808: this .getLogger().error(
809: "Error encountered monitoring request start: "
810: + e.getMessage());
811: }
812: }
813: } else {
814: Processor processor = (Processor) this .componentManager
815: .lookup(Processor.ROLE);
816: try {
817: result = processor.process(environment);
818: if (this .requestListener != null) {
819: try {
820: this .requestListener
821: .onRequestEnd(environment);
822: } catch (Exception e) {
823: this .getLogger().error(
824: "Error encountered monitoring request start: "
825: + e.getMessage());
826: }
827: }
828: } finally {
829: this .componentManager.release(processor);
830: }
831: }
832: // commit response on success
833: environment.commitResponse();
834:
835: return result;
836: } catch (Exception any) {
837: if (this .requestListener != null) {
838: try {
839: this .requestListener.onRequestException(
840: environment, any);
841: } catch (Exception e) {
842: this .getLogger().error(
843: "Error encountered monitoring request start: "
844: + e.getMessage());
845: }
846: }
847: // reset response on error
848: environment.tryResetResponse();
849: throw any;
850: } finally {
851: CocoonComponentManager.leaveEnvironment();
852: CocoonComponentManager.endProcessing(environment, key);
853: if (this .getLogger().isDebugEnabled()) {
854: --this .activeRequestCount;
855: }
856:
857: // TODO (CZ): This is only for testing - remove it later on
858: CocoonComponentManager.checkEnvironment(environmentDepth,
859: this .getLogger());
860: }
861: }
862:
863: /**
864: * Process the given <code>Environment</code> to assemble
865: * a <code>ProcessingPipeline</code>.
866: * @since 2.1
867: */
868: public ProcessingPipeline buildPipeline(Environment environment)
869: throws Exception {
870: if (this .disposed) {
871: throw new IllegalStateException(
872: "You cannot process a Disposed Cocoon engine.");
873: }
874:
875: try {
876: if (this .getLogger().isDebugEnabled()) {
877: ++this .activeRequestCount;
878: this .debug(environment, true);
879: }
880:
881: if (this .threadSafeProcessor != null) {
882: return this .threadSafeProcessor
883: .buildPipeline(environment);
884: } else {
885: Processor processor = (Processor) this .componentManager
886: .lookup(Processor.ROLE);
887: try {
888: return processor.buildPipeline(environment);
889: } finally {
890: this .componentManager.release(processor);
891: }
892: }
893:
894: } finally {
895: if (this .getLogger().isDebugEnabled()) {
896: --this .activeRequestCount;
897: }
898: }
899: }
900:
901: /**
902: * Get the sitemap component configurations
903: * @since 2.1
904: */
905: public Map getComponentConfigurations() {
906: return Collections.EMPTY_MAP;
907: }
908:
909: /**
910: * Return this (Cocoon is always at the root of the processing chain).
911: * @since 2.1.1
912: */
913: public Processor getRootProcessor() {
914: return this ;
915: }
916:
917: /**
918: * Accessor for active request count
919: */
920: public int getActiveRequestCount() {
921: return this .activeRequestCount;
922: }
923:
924: public ExcaliburComponentManager getComponentManager() {
925: return this .componentManager;
926: }
927:
928: /**
929: * Create a simple source resolver.
930: */
931: protected SourceResolver createSourceResolver(Logger logger)
932: throws ContextException {
933: // Create our own resolver
934: final SimpleSourceResolver resolver = new SimpleSourceResolver();
935: resolver.enableLogging(logger);
936: try {
937: resolver.contextualize(this .context);
938: } catch (ContextException ce) {
939: throw new ContextException("Cannot setup source resolver.",
940: ce);
941: }
942: return resolver;
943: }
944: }
|