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