| 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( |