1 16 package org.apache.cocoon.servlet; 17 18 import org.apache.avalon.excalibur.logger.Log4JLoggerManager; 19 import org.apache.avalon.excalibur.logger.LogKitLoggerManager; 20 import org.apache.avalon.excalibur.logger.LoggerManager; 21 import org.apache.avalon.framework.activity.Disposable; 22 import org.apache.avalon.framework.activity.Initializable; 23 import org.apache.avalon.framework.component.ComponentManager; 24 import org.apache.avalon.framework.configuration.Configurable; 25 import org.apache.avalon.framework.configuration.Configuration; 26 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 27 import org.apache.avalon.framework.container.ContainerUtil; 28 import org.apache.avalon.framework.context.Contextualizable; 29 import org.apache.avalon.framework.context.DefaultContext; 30 import org.apache.avalon.framework.logger.LogEnabled; 31 import org.apache.avalon.framework.logger.LogKitLogger; 32 import org.apache.avalon.framework.logger.Logger; 33 34 import org.apache.cocoon.Cocoon; 35 import org.apache.cocoon.ConnectionResetException; 36 import org.apache.cocoon.Constants; 37 import org.apache.cocoon.ResourceNotFoundException; 38 import org.apache.cocoon.components.notification.DefaultNotifyingBuilder; 39 import org.apache.cocoon.components.notification.Notifier; 40 import org.apache.cocoon.components.notification.Notifying; 41 import org.apache.cocoon.environment.Environment; 42 import org.apache.cocoon.environment.http.HttpContext; 43 import org.apache.cocoon.environment.http.HttpEnvironment; 44 import org.apache.cocoon.servlet.multipart.MultipartHttpServletRequest; 45 import org.apache.cocoon.servlet.multipart.RequestFactory; 46 import org.apache.cocoon.util.ClassUtils; 47 import org.apache.cocoon.util.Deprecation; 48 import org.apache.cocoon.util.IOUtils; 49 import org.apache.cocoon.util.StringUtils; 50 import org.apache.cocoon.util.log.CocoonLogFormatter; 51 import org.apache.cocoon.util.log.Log4JConfigurator; 52 53 import org.apache.commons.lang.BooleanUtils; 54 import org.apache.commons.lang.SystemUtils; 55 import org.apache.commons.lang.time.StopWatch; 56 import org.apache.excalibur.instrument.InstrumentManager; 57 import org.apache.excalibur.instrument.manager.impl.DefaultInstrumentManagerImpl; 58 import org.apache.log.ContextMap; 59 import org.apache.log.ErrorHandler; 60 import org.apache.log.Hierarchy; 61 import org.apache.log.Priority; 62 import org.apache.log.output.ServletOutputLogTarget; 63 import org.apache.log.util.DefaultErrorHandler; 64 import org.apache.log4j.LogManager; 65 66 import javax.servlet.ServletConfig ; 67 import javax.servlet.ServletContext ; 68 import javax.servlet.ServletException ; 69 import javax.servlet.ServletOutputStream ; 70 import javax.servlet.http.HttpServlet ; 71 import javax.servlet.http.HttpServletRequest ; 72 import javax.servlet.http.HttpServletResponse ; 73 import java.io.File ; 74 import java.io.FileInputStream ; 75 import java.io.FileOutputStream ; 76 import java.io.IOException ; 77 import java.io.InputStream ; 78 import java.io.OutputStream ; 79 import java.lang.reflect.Constructor ; 80 import java.net.MalformedURLException ; 81 import java.net.SocketException ; 82 import java.net.URL ; 83 import java.util.ArrayList ; 84 import java.util.Arrays ; 85 import java.util.HashMap ; 86 import java.util.Iterator ; 87 import java.util.List ; 88 import java.util.StringTokenizer ; 89 import java.util.jar.Attributes ; 90 import java.util.jar.Manifest ; 91 92 104 public class CocoonServlet extends HttpServlet { 105 106 110 public static final String CONTEXT_SERVLET_CONFIG = "servlet-config"; 111 112 protected static final String PROCESSED_BY = "Processed by " 114 + Constants.COMPLETE_NAME + " in "; 115 116 static final float SECOND = 1000; 118 static final float MINUTE = 60 * SECOND; 119 static final float HOUR = 60 * MINUTE; 120 121 private Logger log; 122 private LoggerManager loggerManager; 123 124 127 protected long creationTime; 128 129 132 protected Cocoon cocoon; 133 134 137 protected Exception exception; 138 139 142 protected DefaultContext appContext = new DefaultContext(); 143 144 145 148 protected static final boolean ALLOW_RELOAD = false; 149 150 154 protected boolean allowReload; 155 156 157 160 protected boolean showTime; 161 162 165 protected boolean hiddenShowTime; 166 167 168 private boolean showCocoonVersion; 169 170 173 private static final boolean ENABLE_UPLOADS = false; 174 private static final boolean SAVE_UPLOADS_TO_DISK = true; 175 private static final int MAX_UPLOAD_SIZE = 10000000; 177 180 private boolean enableUploads; 181 private boolean autoSaveUploads; 182 private boolean allowOverwrite; 183 private boolean silentlyRename; 184 private int maxUploadSize; 185 186 private File uploadDir; 187 private File workDir; 188 private File cacheDir; 189 private String containerEncoding; 190 private String defaultFormEncoding; 191 192 protected ServletContext servletContext; 193 194 195 protected ClassLoader classLoader = this.getClass().getClassLoader(); 196 protected boolean initClassLoader = false; 197 198 private String parentComponentManagerClass; 199 private String parentComponentManagerInitParam; 200 201 202 private ComponentManager parentComponentManager; 203 204 protected String forceLoadParameter; 205 protected String forceSystemProperty; 206 207 211 private boolean manageExceptions; 212 213 216 private boolean enableInstrumentation; 217 218 221 private InstrumentManager instrumentManager; 222 223 228 protected String servletContextPath; 229 230 233 protected String servletContextURL; 234 235 239 protected RequestFactory requestFactory; 240 241 253 public void init(ServletConfig conf) 254 throws ServletException { 255 256 super.init(conf); 257 258 if (!this.initClassLoader) { 262 this.initClassLoader = getInitParameterAsBoolean("init-classloader", false); 263 } 264 265 if (this.initClassLoader) { 266 try { 269 Thread.currentThread().setContextClassLoader(this.classLoader); 270 } catch (Exception e) { 271 } 273 } 274 275 try { 276 String value = System.getProperty("javax.xml.parsers.SAXParserFactory"); 280 if (value != null && value.startsWith("weblogic")) { 281 System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl"); 282 System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); 283 } 284 } catch (Exception e) { 285 System.out.println("CocoonServlet: Could not check system properties, got: " + e); 287 } 288 289 this.servletContext = conf.getServletContext(); 290 this.appContext.put(Constants.CONTEXT_ENVIRONMENT_CONTEXT, new HttpContext(this.servletContext)); 291 this.servletContextPath = this.servletContext.getRealPath("/"); 292 293 final String workDirParam = getInitParameter("work-directory"); 296 if (workDirParam != null) { 297 if (this.servletContextPath == null) { 298 this.workDir = new File (workDirParam); 300 } else { 301 File workDirParamFile = new File (workDirParam); 303 if (workDirParamFile.isAbsolute()) { 304 this.workDir = workDirParamFile; 306 } else { 307 this.workDir = new File (servletContextPath, workDirParam); 309 } 310 } 311 } else { 312 this.workDir = (File ) this.servletContext.getAttribute("javax.servlet.context.tempdir"); 313 this.workDir = new File (workDir, "cocoon-files"); 314 } 315 this.workDir.mkdirs(); 316 this.appContext.put(Constants.CONTEXT_WORK_DIR, workDir); 317 318 String path = this.servletContextPath; 319 String debugPathOne = null, debugPathTwo = null; 322 if (path == null) { 323 try { 325 path = this.servletContext.getResource("/WEB-INF").toString(); 326 } catch (MalformedURLException me) { 327 throw new ServletException ("Unable to get resource 'WEB-INF'.", me); 328 } 329 debugPathOne = path; 330 path = path.substring(0, path.length() - "WEB-INF".length()); 331 debugPathTwo = path; 332 } 333 try { 334 if (path.indexOf(':') > 1) { 335 this.servletContextURL = path; 336 } else { 337 this.servletContextURL = new File (path).toURL().toExternalForm(); 338 } 339 } catch (MalformedURLException me) { 340 try { 344 this.servletContextURL = new File (path).toURL().toExternalForm(); 345 } catch (MalformedURLException ignored) { 346 throw new ServletException ("Unable to determine servlet context URL.", me); 347 } 348 } 349 try { 350 this.appContext.put("context-root", new URL (this.servletContextURL)); 351 } catch (MalformedURLException ignore) { 352 } 354 355 initLogger(); 357 358 if (getLogger().isDebugEnabled()) { 359 getLogger().debug("getRealPath for /: " + this.servletContextPath); 360 if (this.servletContextPath == null) { 361 getLogger().debug("getResource for /WEB-INF: " + debugPathOne); 362 getLogger().debug("Path for Root: " + debugPathTwo); 363 } 364 } 365 366 this.forceLoadParameter = getInitParameter("load-class", null); 367 this.forceSystemProperty = getInitParameter("force-property", null); 368 369 if (getLogger().isDebugEnabled()) { 371 getLogger().debug("Servlet Context URL: " + this.servletContextURL); 372 if (workDirParam != null) { 373 getLogger().debug("Using work-directory " + this.workDir); 374 } else { 375 getLogger().debug("Using default work-directory " + this.workDir); 376 } 377 } 378 379 final String uploadDirParam = conf.getInitParameter("upload-directory"); 380 if (uploadDirParam != null) { 381 if (this.servletContextPath == null) { 382 this.uploadDir = new File (uploadDirParam); 383 } else { 384 File uploadDirParamFile = new File (uploadDirParam); 386 if (uploadDirParamFile.isAbsolute()) { 387 this.uploadDir = uploadDirParamFile; 389 } else { 390 this.uploadDir = new File (servletContextPath, uploadDirParam); 392 } 393 } 394 if (getLogger().isDebugEnabled()) { 395 getLogger().debug("Using upload-directory " + this.uploadDir); 396 } 397 } else { 398 this.uploadDir = new File (workDir, "upload-dir" + File.separator); 399 if (getLogger().isDebugEnabled()) { 400 getLogger().debug("Using default upload-directory " + this.uploadDir); 401 } 402 } 403 this.uploadDir.mkdirs(); 404 this.appContext.put(Constants.CONTEXT_UPLOAD_DIR, this.uploadDir); 405 406 this.enableUploads = getInitParameterAsBoolean("enable-uploads", ENABLE_UPLOADS); 407 408 this.autoSaveUploads = getInitParameterAsBoolean("autosave-uploads", SAVE_UPLOADS_TO_DISK); 409 410 String overwriteParam = getInitParameter("overwrite-uploads", "rename"); 411 if ("deny".equalsIgnoreCase(overwriteParam)) { 413 this.allowOverwrite = false; 414 this.silentlyRename = false; 415 } else if ("allow".equalsIgnoreCase(overwriteParam)) { 416 this.allowOverwrite = true; 417 this.silentlyRename = false; } else { 419 this.allowOverwrite = false; 421 this.silentlyRename = true; 422 } 423 424 this.maxUploadSize = getInitParameterAsInteger("upload-max-size", MAX_UPLOAD_SIZE); 425 426 String cacheDirParam = conf.getInitParameter("cache-directory"); 427 if (cacheDirParam != null) { 428 if (this.servletContextPath == null) { 429 this.cacheDir = new File (cacheDirParam); 430 } else { 431 File cacheDirParamFile = new File (cacheDirParam); 433 if (cacheDirParamFile.isAbsolute()) { 434 this.cacheDir = cacheDirParamFile; 436 } else { 437 this.cacheDir = new File (servletContextPath, cacheDirParam); 439 } 440 } 441 if (getLogger().isDebugEnabled()) { 442 getLogger().debug("Using cache-directory " + this.cacheDir); 443 } 444 } else { 445 this.cacheDir = IOUtils.createFile(workDir, "cache-dir" + File.separator); 446 if (getLogger().isDebugEnabled()) { 447 getLogger().debug("cache-directory was not set - defaulting to " + this.cacheDir); 448 } 449 } 450 this.cacheDir.mkdirs(); 451 this.appContext.put(Constants.CONTEXT_CACHE_DIR, this.cacheDir); 452 453 this.appContext.put(Constants.CONTEXT_CONFIG_URL, 454 getConfigFile(conf.getInitParameter("configurations"))); 455 if (conf.getInitParameter("configurations") == null) { 456 if (getLogger().isDebugEnabled()) { 457 getLogger().debug("configurations was not set - defaulting to... ?"); 458 } 459 } 460 461 this.allowReload = getInitParameterAsBoolean("allow-reload", ALLOW_RELOAD); 463 464 String value = conf.getInitParameter("show-time"); 465 this.showTime = BooleanUtils.toBoolean(value) || (this.hiddenShowTime = "hide".equals(value)); 466 if (value == null) { 467 if (getLogger().isDebugEnabled()) { 468 getLogger().debug("show-time was not set - defaulting to false"); 469 } 470 } 471 472 this.showCocoonVersion = getInitParameterAsBoolean("show-cocoon-version", true); 473 474 parentComponentManagerClass = getInitParameter("parent-component-manager", null); 475 if (parentComponentManagerClass != null) { 476 int dividerPos = parentComponentManagerClass.indexOf('/'); 477 if (dividerPos != -1) { 478 parentComponentManagerInitParam = parentComponentManagerClass.substring(dividerPos + 1); 479 parentComponentManagerClass = parentComponentManagerClass.substring(0, dividerPos); 480 } 481 } 482 483 this.containerEncoding = getInitParameter("container-encoding", "ISO-8859-1"); 484 this.defaultFormEncoding = getInitParameter("form-encoding", "ISO-8859-1"); 485 this.appContext.put(Constants.CONTEXT_DEFAULT_ENCODING, this.defaultFormEncoding); 486 487 this.manageExceptions = getInitParameterAsBoolean("manage-exceptions", true); 488 489 this.enableInstrumentation = getInitParameterAsBoolean("enable-instrumentation", false); 490 491 this.requestFactory = new RequestFactory(this.autoSaveUploads, 492 this.uploadDir, 493 this.allowOverwrite, 494 this.silentlyRename, 495 this.maxUploadSize, 496 this.containerEncoding); 497 this.appContext.put(CONTEXT_SERVLET_CONFIG, conf); 499 this.createCocoon(); 500 } 501 502 505 public void destroy() { 506 if (this.initClassLoader) { 507 try { 508 Thread.currentThread().setContextClassLoader(this.classLoader); 509 } catch (Exception e) { 510 } 512 } 513 514 if (this.cocoon != null) { 515 if (getLogger().isDebugEnabled()) { 516 getLogger().debug("Servlet destroyed - disposing Cocoon"); 517 } 518 disposeCocoon(); 519 } 520 521 if (this.instrumentManager instanceof Disposable) { 522 ((Disposable) this.instrumentManager).dispose(); 523 } 524 525 if (this.parentComponentManager != null && this.parentComponentManager instanceof Disposable) { 526 ((Disposable) this.parentComponentManager).dispose(); 527 } 528 529 this.appContext = null; 530 this.classLoader = null; 531 this.log = null; 532 this.loggerManager = null; 533 } 534 535 539 protected void addClassLoaderURL(URL URL) { 540 } 542 543 547 protected void addClassLoaderDirectory(String dir) { 548 } 550 551 567 protected String getClassPath() throws ServletException { 568 StringBuffer buildClassPath = new StringBuffer (); 569 570 File root = null; 571 if (servletContextPath != null) { 572 574 String classDir = this.servletContext.getRealPath("/WEB-INF/classes"); 575 String libDir = this.servletContext.getRealPath("/WEB-INF/lib"); 576 577 if (libDir != null) { 578 root = new File (libDir); 579 } 580 581 if (classDir != null) { 582 buildClassPath.append(classDir); 583 584 addClassLoaderDirectory(classDir); 585 } 586 } else { 587 URL classDirURL = null; 589 URL libDirURL = null; 590 591 try { 592 classDirURL = this.servletContext.getResource("/WEB-INF/classes"); 593 } catch (MalformedURLException me) { 594 if (getLogger().isWarnEnabled()) { 595 this.getLogger().warn("Unable to add WEB-INF/classes to the classpath", me); 596 } 597 } 598 599 try { 600 libDirURL = this.servletContext.getResource("/WEB-INF/lib"); 601 } catch (MalformedURLException me) { 602 if (getLogger().isWarnEnabled()) { 603 this.getLogger().warn("Unable to add WEB-INF/lib to the classpath", me); 604 } 605 } 606 607 if (libDirURL != null && libDirURL.toExternalForm().startsWith("file:")) { 608 root = new File (libDirURL.toExternalForm().substring("file:".length())); 609 } 610 611 if (classDirURL != null) { 612 buildClassPath.append(classDirURL.toExternalForm()); 613 614 addClassLoaderURL(classDirURL); 615 } 616 } 617 618 if (root == null) { 620 root = extractLibraries(); 621 } 622 623 if (root != null && root.isDirectory()) { 624 File [] libraries = root.listFiles(); 625 Arrays.sort(libraries); 626 for (int i = 0; i < libraries.length; i++) { 627 String fullName = IOUtils.getFullFilename(libraries[i]); 628 buildClassPath.append(File.pathSeparatorChar).append(fullName); 629 630 addClassLoaderDirectory(fullName); 631 } 632 } 633 634 buildClassPath.append(File.pathSeparatorChar) 635 .append(SystemUtils.JAVA_CLASS_PATH); 636 637 buildClassPath.append(File.pathSeparatorChar) 638 .append(getExtraClassPath()); 639 return buildClassPath.toString(); 640 } 641 642 private File extractLibraries() { 643 try { 644 URL manifestURL = this.servletContext.getResource("/META-INF/MANIFEST.MF"); 645 if (manifestURL == null) { 646 this.getLogger().fatalError("Unable to get Manifest"); 647 return null; 648 } 649 650 Manifest mf = new Manifest (manifestURL.openStream()); 651 Attributes attr = mf.getMainAttributes(); 652 String libValue = attr.getValue("Cocoon-Libs"); 653 if (libValue == null) { 654 this.getLogger().fatalError("Unable to get 'Cocoon-Libs' attribute from the Manifest"); 655 return null; 656 } 657 658 List libList = new ArrayList (); 659 for (StringTokenizer st = new StringTokenizer (libValue, " "); st.hasMoreTokens();) { 660 libList.add(st.nextToken()); 661 } 662 663 File root = new File (this.workDir, "lib"); 664 root.mkdirs(); 665 666 File [] oldLibs = root.listFiles(); 667 for (int i = 0; i < oldLibs.length; i++) { 668 String oldLib = oldLibs[i].getName(); 669 if (!libList.contains(oldLib)) { 670 this.getLogger().debug("Removing old library " + oldLibs[i]); 671 oldLibs[i].delete(); 672 } 673 } 674 675 this.getLogger().warn("Extracting libraries into " + root); 676 byte[] buffer = new byte[65536]; 677 for (Iterator i = libList.iterator(); i.hasNext();) { 678 String libName = (String ) i.next(); 679 680 long lastModified = -1; 681 try { 682 lastModified = Long.parseLong(attr.getValue("Cocoon-Lib-" + libName.replace('.', '_'))); 683 } catch (Exception e) { 684 this.getLogger().debug("Failed to parse lastModified: " + attr.getValue("Cocoon-Lib-" + libName.replace('.', '_'))); 685 } 686 687 File lib = new File (root, libName); 688 if (lib.exists() && lib.lastModified() != lastModified) { 689 this.getLogger().debug("Removing modified library " + lib); 690 lib.delete(); 691 } 692 693 InputStream is = this.servletContext.getResourceAsStream("/WEB-INF/lib/" + libName); 694 if (is == null) { 695 this.getLogger().warn("Skipping " + libName); 696 } else { 697 this.getLogger().debug("Extracting " + libName); 698 OutputStream os = null; 699 try { 700 os = new FileOutputStream (lib); 701 int count; 702 while ((count = is.read(buffer)) > 0) { 703 os.write(buffer, 0, count); 704 } 705 } finally { 706 if (is != null) is.close(); 707 if (os != null) os.close(); 708 } 709 } 710 711 if (lastModified != -1) { 712 lib.setLastModified(lastModified); 713 } 714 } 715 716 return root; 717 } catch (IOException e) { 718 this.getLogger().fatalError("Exception while processing Manifest file", e); 719 return null; 720 } 721 } 722 723 724 730 protected String getExtraClassPath() throws ServletException { 731 String extraClassPath = this.getInitParameter("extra-classpath"); 732 if (extraClassPath != null) { 733 StringBuffer sb = new StringBuffer (); 734 StringTokenizer st = new StringTokenizer (extraClassPath, SystemUtils.PATH_SEPARATOR, false); 735 int i = 0; 736 while (st.hasMoreTokens()) { 737 String s = st.nextToken(); 738 if (i++ > 0) { 739 sb.append(File.pathSeparatorChar); 740 } 741 if ((s.charAt(0) == File.separatorChar) || 742 (s.charAt(1) == ':')) { 743 if (getLogger().isDebugEnabled()) { 744 getLogger().debug("extraClassPath is absolute: " + s); 745 } 746 sb.append(s); 747 748 addClassLoaderDirectory(s); 749 } else { 750 if (s.indexOf("${") != -1) { 751 String path = StringUtils.replaceToken(s); 752 sb.append(path); 753 if (getLogger().isDebugEnabled()) { 754 getLogger().debug("extraClassPath is not absolute replacing using token: [" + s + "] : " + path); 755 } 756 addClassLoaderDirectory(path); 757 } else { 758 String path = null; 759 if (this.servletContextPath != null) { 760 path = this.servletContextPath + s; 761 if (getLogger().isDebugEnabled()) { 762 getLogger().debug("extraClassPath is not absolute pre-pending context path: " + path); 763 } 764 } else { 765 path = this.workDir.toString() + s; 766 if (getLogger().isDebugEnabled()) { 767 getLogger().debug("extraClassPath is not absolute pre-pending work-directory: " + path); 768 } 769 } 770 sb.append(path); 771 addClassLoaderDirectory(path); 772 } 773 } 774 } 775 return sb.toString(); 776 } 777 return ""; 778 } 779 780 790 protected void initLogger() { 791 final String logLevel = getInitParameter("log-level", "INFO"); 792 793 final String accesslogger = getInitParameter("servlet-logger", "cocoon"); 794 795 final Priority logPriority = Priority.getPriorityForName(logLevel); 796 797 final CocoonLogFormatter formatter = new CocoonLogFormatter(); 798 formatter.setFormat("%7.7{priority} %{time} [%8.8{category}] " + 799 "(%{uri}) %{thread}/%{class:short}: %{message}\\n%{throwable}"); 800 final ServletOutputLogTarget servTarget = new ServletOutputLogTarget(this.servletContext, formatter); 801 802 final Hierarchy defaultHierarchy = Hierarchy.getDefaultHierarchy(); 803 final ErrorHandler errorHandler = new DefaultErrorHandler(); 804 defaultHierarchy.setErrorHandler(errorHandler); 805 defaultHierarchy.setDefaultLogTarget(servTarget); 806 defaultHierarchy.setDefaultPriority(logPriority); 807 final Logger logger = new LogKitLogger(Hierarchy.getDefaultHierarchy().getLoggerFor("")); 808 final String loggerManagerClass = 809 this.getInitParameter("logger-class", LogKitLoggerManager.class.getName()); 810 811 813 final LoggerManager loggerManager = 814 newLoggerManager(loggerManagerClass, defaultHierarchy); 815 ContainerUtil.enableLogging(loggerManager, logger); 816 817 final DefaultContext subcontext = new DefaultContext(this.appContext); 818 subcontext.put("servlet-context", this.servletContext); 819 subcontext.put("context-work", this.workDir); 820 if (this.servletContextPath == null) { 821 File logSCDir = new File (this.workDir, "log"); 822 logSCDir.mkdirs(); 823 if (logger.isWarnEnabled()) { 824 logger.warn("Setting context-root for LogKit to " + logSCDir); 825 } 826 subcontext.put("context-root", logSCDir.toString()); 827 } else { 828 subcontext.put("context-root", this.servletContextPath); 829 } 830 831 try { 832 ContainerUtil.contextualize(loggerManager, subcontext); 833 this.loggerManager = loggerManager; 834 835 if (loggerManager instanceof Configurable) { 836 String logkitConfig = getInitParameter("logkit-config", "/WEB-INF/logkit.xconf"); 838 839 InputStream is = null; 841 if (logkitConfig.indexOf(':') == -1) { 842 is = this.servletContext.getResourceAsStream(logkitConfig); 843 if (is == null) is = new FileInputStream (logkitConfig); 844 } else { 845 URL logkitURL = new URL (logkitConfig); 846 is = logkitURL.openStream(); 847 } 848 final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 849 final Configuration conf = builder.build(is); 850 ContainerUtil.configure(loggerManager, conf); 851 } 852 853 final String log4jConfig = getInitParameter("log4j-config", null); 855 if ( log4jConfig != null ) { 856 final Log4JConfigurator configurator = new Log4JConfigurator(subcontext); 857 858 InputStream is = null; 860 if ( log4jConfig.indexOf(':') == -1) { 861 is = this.servletContext.getResourceAsStream(log4jConfig); 862 if (is == null) is = new FileInputStream (log4jConfig); 863 } else { 864 final URL log4jURL = new URL (log4jConfig); 865 is = log4jURL.openStream(); 866 } 867 configurator.doConfigure(is, LogManager.getLoggerRepository()); 868 } 869 870 ContainerUtil.initialize(loggerManager); 871 } catch (Exception e) { 872 errorHandler.error("Could not set up Cocoon Logger, will use screen instead", e, null); 873 } 874 875 this.log = this.loggerManager.getLoggerForCategory(accesslogger); 876 877 final String deprecationLevel = getInitParameter("forbidden-deprecation-level", "ERROR"); 878 Deprecation.setForbiddenLevel(Deprecation.LogLevel.getLevel(deprecationLevel)); 879 } 880 881 private LoggerManager newLoggerManager(String loggerManagerClass, Hierarchy hierarchy) { 882 if (loggerManagerClass.equals(LogKitLoggerManager.class.getName())) { 883 return new LogKitLoggerManager(hierarchy); 884 } else if (loggerManagerClass.equals(Log4JLoggerManager.class.getName()) || 885 loggerManagerClass.equalsIgnoreCase("LOG4J")) { 886 return new Log4JLoggerManager(); 887 } else { 888 try { 889 Class clazz = Class.forName(loggerManagerClass); 890 return (LoggerManager)clazz.newInstance(); 891 } catch (Exception e) { 892 return new LogKitLoggerManager(hierarchy); 893 } 894 } 895 } 896 897 904 private URL getConfigFile(final String configFileName) 905 throws ServletException { 906 final String usedFileName; 907 908 if (configFileName == null) { 909 if (getLogger().isWarnEnabled()) { 910 getLogger().warn("Servlet initialization argument 'configurations' not specified, attempting to use '/WEB-INF/cocoon.xconf'"); 911 } 912 usedFileName = "/WEB-INF/cocoon.xconf"; 913 } else { 914 usedFileName = configFileName; 915 } 916 917 if (getLogger().isDebugEnabled()) { 918 getLogger().debug("Using configuration file: " + usedFileName); 919 } 920 921 URL result; 922 try { 923 if (usedFileName.indexOf(':') == -1) { 925 result = this.servletContext.getResource(usedFileName); 926 } else { 927 result = new URL (usedFileName); 928 } 929 } catch (Exception mue) { 930 String msg = "Init parameter 'configurations' is invalid : " + usedFileName; 931 getLogger().error(msg, mue); 932 throw new ServletException (msg, mue); 933 } 934 935 if (result == null) { 936 File resultFile = new File (usedFileName); 937 if (resultFile.isFile()) { 938 try { 939 result = resultFile.getCanonicalFile().toURL(); 940 } catch (Exception e) { 941 String msg = "Init parameter 'configurations' is invalid : " + usedFileName; 942 getLogger().error(msg, e); 943 throw new ServletException (msg, e); 944 } 945 } 946 } 947 948 if (result == null) { 949 String msg = "Init parameter 'configuration' doesn't name an existing resource : " + usedFileName; 950 getLogger().error(msg); 951 throw new ServletException (msg); 952 } 953 return result; 954 } 955 956 968 private void forceLoad() { 969 if (this.forceLoadParameter != null) { 970 StringTokenizer fqcnTokenizer = new StringTokenizer (forceLoadParameter, " \t\r\n\f;,", false); 971 972 while (fqcnTokenizer.hasMoreTokens()) { 973 final String fqcn = fqcnTokenizer.nextToken().trim(); 974 975 try { 976 if (getLogger().isDebugEnabled()) { 977 getLogger().debug("Loading: " + fqcn); 978 } 979 ClassUtils.loadClass(fqcn).newInstance(); 980 } catch (Exception e) { 981 if (getLogger().isWarnEnabled()) { 982 getLogger().warn("Could not load class: " + fqcn, e); 983 } 984 } 986 } 987 } 988 } 989 990 997 private void forceProperty() { 998 if (this.forceSystemProperty != null) { 999 StringTokenizer tokenizer = new StringTokenizer (forceSystemProperty, " \t\r\n\f;,", false); 1000 1001 while (tokenizer.hasMoreTokens()) { 1002 final String property = tokenizer.nextToken().trim(); 1003 if (property.indexOf('=') == -1) { 1004 continue; 1005 } 1006 try { 1007 String key = property.substring(0, property.indexOf('=')); 1008 String value = property.substring(property.indexOf('=') + 1); 1009 if (value.indexOf("${") != -1) { 1010 value = StringUtils.replaceToken(value); 1011 } 1012 if (getLogger().isDebugEnabled()) { 1013 getLogger().debug("Setting " + key + "=" + value); 1014 } 1015 System.setProperty(key, value); 1016 } catch (Exception e) { 1017 if (getLogger().isWarnEnabled()) { 1018 getLogger().warn("Could not set property: " + property, e); 1019 } 1020 } 1022 } 1023 } 1024 } 1025 1026 1030 public void service(HttpServletRequest req, HttpServletResponse res) 1031 throws ServletException , IOException { 1032 1033 1034 1035 if (this.initClassLoader) { 1036 try { 1037 Thread.currentThread().setContextClassLoader(this.classLoader); 1038 } catch (Exception e) { 1039 } 1040 } 1041 1042 StopWatch stopWatch = new StopWatch(); 1044 stopWatch.start(); 1045 1046 if (this.showCocoonVersion) { 1048 res.addHeader("X-Cocoon-Version", Constants.VERSION); 1049 } 1050 1051 HttpServletRequest request; 1053 try{ 1054 if (this.enableUploads) { 1055 request = requestFactory.getServletRequest(req); 1056 } else { 1057 request = req; 1058 } 1059 } catch (Exception e) { 1060 if (getLogger().isErrorEnabled()) { 1061 getLogger().error("Problem with Cocoon servlet", e); 1062 } 1063 1064 manageException(req, res, null, null, 1065 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1066 "Problem in creating the Request", null, null, e); 1067 return; 1068 } 1069 1070 1072 if (reloadCocoon(request.getPathInfo(), request.getParameter(Constants.RELOAD_PARAM))) { 1073 disposeCocoon(); 1074 initLogger(); 1075 createCocoon(); 1076 } 1077 1078 if (this.cocoon == null) { 1080 manageException(request, res, null, null, 1081 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1082 "Initialization Problem", 1083 null , 1084 null , 1085 this.exception); 1086 return; 1087 } 1088 1089 String uri = request.getServletPath(); 1091 if (uri == null) { 1092 uri = ""; 1093 } 1094 String pathInfo = request.getPathInfo(); 1095 if (pathInfo != null) { 1096 if (uri.length() > 0 && uri.charAt(0) == '/') { 1099 uri = uri.substring(1); 1100 } 1101 uri += pathInfo; 1102 } 1103 1104 if (uri.length() == 0) { 1105 1111 String prefix = request.getRequestURI(); 1112 if (prefix == null) { 1113 prefix = ""; 1114 } 1115 1116 res.sendRedirect(res.encodeRedirectURL(prefix + "/")); 1117 return; 1118 } 1119 1120 String contentType = null; 1121 ContextMap ctxMap = null; 1122 1123 Environment env; 1124 try{ 1125 if (uri.charAt(0) == '/') { 1126 uri = uri.substring(1); 1127 } 1128 env = getEnvironment(uri, request, res); 1130 } catch (Exception e) { 1131 if (getLogger().isErrorEnabled()) { 1132 getLogger().error("Problem with Cocoon servlet", e); 1133 } 1134 1135 manageException(request, res, null, uri, 1136 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1137 "Problem in creating the Environment", null, null, e); 1138 return; 1139 } 1140 1141 try { 1142 try { 1143 ctxMap = ContextMap.getCurrentContext(); 1146 String threadName = Thread.currentThread().getName(); 1148 ctxMap.set("threadName", threadName); 1149 ctxMap.set("objectModel", env.getObjectModel()); 1151 ctxMap.set("request-id", threadName + System.currentTimeMillis()); 1153 1154 if (this.cocoon.process(env)) { 1155 contentType = env.getContentType(); 1156 } else { 1157 getLogger().fatalError("The Cocoon engine failed to process the request."); 1160 manageException(request, res, env, uri, 1161 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1162 "Request Processing Failed", 1163 "Cocoon engine failed in process the request", 1164 "The processing engine failed to process the request. This could be due to lack of matching or bugs in the pipeline engine.", 1165 null); 1166 return; 1167 } 1168 } catch (ResourceNotFoundException e) { 1169 if (getLogger().isDebugEnabled()) { 1170 getLogger().warn(e.getMessage(), e); 1171 } else if (getLogger().isWarnEnabled()) { 1172 getLogger().warn(e.getMessage()); 1173 } 1174 1175 manageException(request, res, env, uri, 1176 HttpServletResponse.SC_NOT_FOUND, 1177 "Resource Not Found", 1178 "Resource Not Found", 1179 "The requested resource \"" + request.getRequestURI() + "\" could not be found", 1180 e); 1181 return; 1182 1183 } catch (ConnectionResetException e) { 1184 if (getLogger().isDebugEnabled()) { 1185 getLogger().debug(e.toString(), e); 1186 } else if (getLogger().isWarnEnabled()) { 1187 getLogger().warn(e.toString()); 1188 } 1189 1190 } catch (IOException e) { 1191 if (getLogger().isDebugEnabled()) { 1193 getLogger().debug(e.toString(), e); 1194 } else if (getLogger().isWarnEnabled()) { 1195 getLogger().warn(e.toString()); 1196 } 1197 1198 } catch (Exception e) { 1199 if (getLogger().isErrorEnabled()) { 1200 getLogger().error("Internal Cocoon Problem", e); 1201 } 1202 1203 manageException(request, res, env, uri, 1204 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1205 "Internal Server Error", null, null, e); 1206 return; 1207 } 1208 1209 stopWatch.stop(); 1210 String timeString = null; 1211 if (getLogger().isInfoEnabled()) { 1212 timeString = processTime(stopWatch.getTime()); 1213 getLogger().info("'" + uri + "' " + timeString); 1214 } 1215 1216 if (contentType != null && contentType.equals("text/html")) { 1217 String showTime = request.getParameter(Constants.SHOWTIME_PARAM); 1218 boolean show = this.showTime; 1219 if (showTime != null) { 1220 show = !showTime.equalsIgnoreCase("no"); 1221 } 1222 if (show) { 1223 if (timeString == null) { 1224 timeString = processTime(stopWatch.getTime()); 1225 } 1226 boolean hide = this.hiddenShowTime; 1227 if (showTime != null) { 1228 hide = showTime.equalsIgnoreCase("hide"); 1229 } 1230 ServletOutputStream out = res.getOutputStream(); 1231 out.print((hide) ? "<!-- " : "<p>"); 1232 out.print(timeString); 1233 out.println((hide) ? " -->" : "</p>"); 1234 } 1235 } 1236 } finally { 1237 if (ctxMap != null) { 1238 ctxMap.clear(); 1239 } 1240 1241 try { 1242 if (request instanceof MultipartHttpServletRequest) { 1243 if (getLogger().isDebugEnabled()) { 1244 getLogger().debug("Deleting uploaded file(s)."); 1245 } 1246 ((MultipartHttpServletRequest) request).cleanup(); 1247 } 1248 } catch (IOException e) { 1249 getLogger().error("Cocoon got an Exception while trying to cleanup the uploaded files.", e); 1250 } 1251 1252 1269 } 1270 } 1271 1272 protected void manageException(HttpServletRequest req, HttpServletResponse res, Environment env, 1273 String uri, int errorStatus, 1274 String title, String message, String description, 1275 Exception e) 1276 throws IOException { 1277 if (this.manageExceptions) { 1278 if (env != null) { 1279 env.tryResetResponse(); 1280 } else { 1281 res.reset(); 1282 } 1283 1284 String type = Notifying.FATAL_NOTIFICATION; 1285 HashMap extraDescriptions = null; 1286 1287 if (errorStatus == HttpServletResponse.SC_NOT_FOUND) { 1288 type = "resource-not-found"; 1289 e = null; 1291 } else { 1292 extraDescriptions = new HashMap (2); 1293 extraDescriptions.put(Notifying.EXTRA_REQUESTURI, req.getRequestURI()); 1294 if (uri != null) { 1295 extraDescriptions.put("Request URI", uri); 1296 } 1297 1298 if (!getLogger().isInfoEnabled()) { 1300 Throwable t = DefaultNotifyingBuilder.getRootCause(e); 1301 if (t != null) extraDescriptions.put(Notifying.EXTRA_CAUSE, t.getMessage()); 1302 e = null; 1303 } 1304 } 1305 1306 Notifying n = new DefaultNotifyingBuilder().build(this, 1307 e, 1308 type, 1309 title, 1310 "Cocoon Servlet", 1311 message, 1312 description, 1313 extraDescriptions); 1314 1315 res.setContentType("text/html"); 1316 res.setStatus(errorStatus); 1317 Notifier.notify(n, res.getOutputStream(), "text/html"); 1318 } else { 1319 res.sendError(errorStatus, title); 1320 res.flushBuffer(); 1321 } 1322 } 1323 1324 1327 protected Environment getEnvironment(String uri, 1328 HttpServletRequest req, 1329 HttpServletResponse res) 1330 throws Exception { 1331 HttpEnvironment env; 1332 1333 String formEncoding = req.getParameter("cocoon-form-encoding"); 1334 if (formEncoding == null) { 1335 formEncoding = this.defaultFormEncoding; 1336 } 1337 env = new HttpEnvironment(uri, 1338 this.servletContextURL, 1339 req, 1340 res, 1341 this.servletContext, 1342 (HttpContext) this.appContext.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT), 1343 this.containerEncoding, 1344 formEncoding); 1345 env.enableLogging(getLogger()); 1346 return env; 1347 } 1348 1349 1357 protected synchronized ComponentManager getParentComponentManager() { 1358 if (parentComponentManager != null && parentComponentManager instanceof Disposable) { 1359 ((Disposable) parentComponentManager).dispose(); 1360 } 1361 1362 parentComponentManager = null; 1363 if (parentComponentManagerClass != null) { 1364 try { 1365 Class pcm = ClassUtils.loadClass(parentComponentManagerClass); 1366 Constructor pcmc = pcm.getConstructor(new Class []{String .class}); 1367 parentComponentManager = (ComponentManager) pcmc.newInstance(new Object []{parentComponentManagerInitParam}); 1368 1369 if (parentComponentManager instanceof LogEnabled) { 1370 ((LogEnabled) parentComponentManager).enableLogging(getLogger()); 1371 } 1372 if (parentComponentManager instanceof Contextualizable) { 1373 ((Contextualizable) parentComponentManager).contextualize(this.appContext); 1374 } 1375 if (parentComponentManager instanceof Initializable) { 1376 ((Initializable) parentComponentManager).initialize(); 1377 } 1378 } catch (Exception e) { 1379 if (getLogger().isErrorEnabled()) { 1380 getLogger().error("Could not initialize parent component manager.", e); 1381 } 1382 } 1383 } 1384 return parentComponentManager; 1385 } 1386 1387 1390 protected synchronized void createCocoon() 1391 throws ServletException { 1392 1393 if (this.cocoon != null) { 1396 return; 1397 } 1398 1399 1400 1401 if (this.initClassLoader) { 1402 try { 1403 Thread.currentThread().setContextClassLoader(this.classLoader); 1404 } catch (Exception e) { 1405 } 1406 } 1407 1408 updateEnvironment(); 1409 forceLoad(); 1410 forceProperty(); 1411 1412 try { 1413 this.exception = null; 1414 URL configFile = (URL ) this.appContext.get(Constants.CONTEXT_CONFIG_URL); 1415 if (getLogger().isInfoEnabled()) { 1416 getLogger().info("Reloading from: " + configFile.toExternalForm()); 1417 } 1418 Cocoon c = (Cocoon) ClassUtils.newInstance("org.apache.cocoon.Cocoon"); 1419 ContainerUtil.enableLogging(c, getCocoonLogger()); 1420 c.setLoggerManager(getLoggerManager()); 1421 ContainerUtil.contextualize(c, this.appContext); 1422 final ComponentManager parent = this.getParentComponentManager(); 1423 if (parent != null) { 1424 ContainerUtil.compose(c, parent); 1425 } 1426 if (this.enableInstrumentation) { 1427 c.setInstrumentManager(getInstrumentManager()); 1428 } 1429 ContainerUtil.initialize(c); 1430 this.creationTime = System.currentTimeMillis(); 1431 1432 this.cocoon = c; 1433 } catch (Exception e) { 1434 if (getLogger().isErrorEnabled()) { 1435 getLogger().error("Exception reloading", e); 1436 } 1437 this.exception = e; 1438 disposeCocoon(); 1439 } 1440 } 1441 1442 private Logger getCocoonLogger() { 1443 final String rootlogger = getInitParameter("cocoon-logger"); 1444 if (rootlogger != null) { 1445 return this.getLoggerManager().getLoggerForCategory(rootlogger); 1446 } else { 1447 return getLogger(); 1448 } 1449 } 1450 1451 1458 protected void updateEnvironment() throws ServletException { 1459 this.appContext.put(Constants.CONTEXT_CLASS_LOADER, classLoader); 1460 this.appContext.put(Constants.CONTEXT_CLASSPATH, getClassPath()); 1461 } 1462 1463 1468 private InstrumentManager getInstrumentManager() 1469 throws Exception { 1470 String imConfig = getInitParameter("instrumentation-config"); 1471 if (imConfig == null) { 1472 throw new ServletException ("Please define the init-param 'instrumentation-config' in your web.xml"); 1473 } 1474 1475 final InputStream is = this.servletContext.getResourceAsStream(imConfig); 1476 final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 1477 final Configuration conf = builder.build(is); 1478 1479 final String imLoggerCategory = conf.getAttribute("logger", "core.instrument"); 1481 Logger imLogger = this.loggerManager.getLoggerForCategory(imLoggerCategory); 1482 1483 DefaultInstrumentManagerImpl instrumentManager = new DefaultInstrumentManagerImpl(); 1485 instrumentManager.enableLogging(imLogger); 1486 instrumentManager.configure(conf); 1487 instrumentManager.initialize(); 1488 1489 if (getLogger().isDebugEnabled()) { 1490 getLogger().debug("Instrument manager created " + instrumentManager); 1491 } 1492 1493 this.instrumentManager = instrumentManager; 1494 return instrumentManager; 1495 } 1496 1497 private String processTime(long time) { 1498 StringBuffer out = new StringBuffer (PROCESSED_BY); 1499 if (time <= SECOND) { 1500 out.append(time); 1501 out.append(" milliseconds."); 1502 } else if (time <= MINUTE) { 1503 out.append(time / SECOND); 1504 out.append(" seconds."); 1505 } else if (time <= HOUR) { 1506 out.append(time / MINUTE); 1507 out.append(" minutes."); 1508 } else { 1509 out.append(time / HOUR); 1510 out.append(" hours."); 1511 } 1512 return out.toString(); 1513 } 1514 1515 1519 private boolean reloadCocoon(final String pathInfo, final String reloadParam) 1520 throws ServletException { 1521 if (this.allowReload) { 1522 boolean reload = false; 1523 1524 if (this.cocoon != null) { 1525 if (this.cocoon.modifiedSince(this.creationTime)) { 1526 if (getLogger().isInfoEnabled()) { 1527 getLogger().info("Configuration changed reload attempt"); 1528 } 1529 reload = true; 1530 } else if (pathInfo == null && reloadParam != null) { 1531 if (getLogger().isInfoEnabled()) { 1532 getLogger().info("Forced reload attempt"); 1533 } 1534 reload = true; 1535 } 1536 } else if (pathInfo == null && reloadParam != null) { 1537 if (getLogger().isInfoEnabled()) { 1538 getLogger().info("Invalid configurations reload"); 1539 } 1540 reload = true; 1541 } 1542 1543 return reload; 1544 } else { 1545 return false; 1546 } 1547 } 1548 1549 1552 protected final void disposeCocoon() { 1553 if (this.cocoon != null) { 1554 ContainerUtil.dispose(this.cocoon); 1555 this.cocoon = null; 1556 } 1557 } 1558 1559 1563 public String getInitParameter(String name) { 1564 String result = super.getInitParameter(name); 1565 if (result != null) { 1566 result = result.trim(); 1567 if (result.length() == 0) { 1568 result = null; 1569 } 1570 } 1571 1572 return result; 1573 } 1574 1575 1576 protected String getInitParameter(String name, String defaultValue) { 1577 String result = getInitParameter(name); 1578 if (result == null) { 1579 if (getLogger() != null && getLogger().isDebugEnabled()) { 1580 getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'"); 1581 } 1582 return defaultValue; 1583 } else { 1584 return result; 1585 } 1586 } 1587 1588 1589 protected boolean getInitParameterAsBoolean(String name, boolean defaultValue) { 1590 String value = getInitParameter(name); 1591 if (value == null) { 1592 if (getLogger() != null && getLogger().isDebugEnabled()) { 1593 getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'"); 1594 } 1595 return defaultValue; 1596 } 1597 1598 return BooleanUtils.toBoolean(value); 1599 } 1600 1601 protected int getInitParameterAsInteger(String name, int defaultValue) { 1602 String value = getInitParameter(name); 1603 if (value == null) { 1604 if (getLogger() != null && getLogger().isDebugEnabled()) { 1605 getLogger().debug(name + " was not set - defaulting to '" + defaultValue + "'"); 1606 } 1607 return defaultValue; 1608 } else { 1609 return Integer.parseInt(value); 1610 } 1611 } 1612 1613 protected Logger getLogger() { 1614 return this.log; 1615 } 1616 1617 protected LoggerManager getLoggerManager() { 1618 return this.loggerManager; 1619 } 1620} 1621 | Popular Tags |