1 // ========================================================================
2 // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.webapp;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19 import java.security.PermissionCollection;
20 import java.util.EventListener;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 import javax.servlet.ServletContext;
25 import javax.servlet.ServletException;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28 import javax.servlet.http.HttpSessionActivationListener;
29 import javax.servlet.http.HttpSessionAttributeListener;
30 import javax.servlet.http.HttpSessionBindingListener;
31 import javax.servlet.http.HttpSessionListener;
32
33 import org.eclipse.jetty.security.SecurityHandler;
34 import org.eclipse.jetty.server.Connector;
35 import org.eclipse.jetty.server.HandlerContainer;
36 import org.eclipse.jetty.server.handler.ContextHandler;
37 import org.eclipse.jetty.server.handler.ErrorHandler;
38 import org.eclipse.jetty.server.session.SessionHandler;
39 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
40 import org.eclipse.jetty.servlet.ServletContextHandler;
41 import org.eclipse.jetty.servlet.ServletHandler;
42 import org.eclipse.jetty.util.IO;
43 import org.eclipse.jetty.util.LazyList;
44 import org.eclipse.jetty.util.Loader;
45 import org.eclipse.jetty.util.StringUtil;
46 import org.eclipse.jetty.util.URIUtil;
47 import org.eclipse.jetty.util.log.Log;
48 import org.eclipse.jetty.util.resource.JarResource;
49 import org.eclipse.jetty.util.resource.Resource;
50
51 /* ------------------------------------------------------------ */
52 /** Web Application Context Handler.
53 * The WebAppContext handler is an extension of ContextHandler that
54 * coordinates the construction and configuration of nested handlers:
55 * {@link org.eclipse.jetty.security.ConstraintSecurityHandler}, {@link org.eclipse.jetty.server.session.SessionHandler}
56 * and {@link org.eclipse.jetty.servlet.ServletHandler}.
57 * The handlers are configured by pluggable configuration classes, with
58 * the default being {@link org.eclipse.jetty.server.server.webapp.WebXmlConfiguration} and
59 * {@link org.eclipse.jetty.server.server.webapp.JettyWebXmlConfiguration}.
60 *
61 * @org.apache.xbean.XBean description="Creates a servlet web application at a given context from a resource base"
62 *
63 *
64 *
65 */
66 public class WebAppContext extends ServletContextHandler
67 {
68 public static final String TEMPDIR = "javax.servlet.context.tempdir";
69 public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml";
70 public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
71
72 private static String[] __dftConfigurationClasses =
73 {
74 "org.eclipse.jetty.webapp.WebInfConfiguration",
75 "org.eclipse.jetty.webapp.WebXmlConfiguration",
76 "org.eclipse.jetty.webapp.MetaInfConfiguration",
77 "org.eclipse.jetty.webapp.FragmentConfiguration",
78 "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
79 "org.eclipse.jetty.webapp.TagLibConfiguration"
80 } ;
81 private String[] _configurationClasses=__dftConfigurationClasses;
82 private Configuration[] _configurations;
83 private String _defaultsDescriptor=WEB_DEFAULTS_XML;
84 private String _descriptor=null;
85 private String _overrideDescriptor=null;
86 private boolean _distributable=false;
87 private boolean _extractWAR=true;
88 private boolean _copyDir=false;
89 private boolean _logUrlOnStart =false;
90 private boolean _parentLoaderPriority= Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority");
91 private PermissionCollection _permissions;
92 private String[] _systemClasses = {
93 "java.",
94 "javax.servlet.",
95 "javax.xml.",
96 "org.xml.",
97 "org.w3c.",
98 "org.apache.commons.logging.",
99 "org.apache.log4j.",
100 "org.eclipse.jetty.servlet.", // webapp cannot change default servlets
101 "org.eclipse.jetty.continuation.", // webapp cannot change continuation classes
102 "org.eclipse.jetty.naming." // webapp cannot change naming classes
103 };
104 private String[] _serverClasses = {
105 "-org.eclipse.jetty.jndi.", // don't hide naming classes
106 "-org.eclipse.jetty.continuation.", // don't hide continuation classes
107 "-org.eclipse.jetty.plus.jaas.", // don't hide jaas modules
108 "org.eclipse.jetty.", // hide rest of jetty classes
109 "org.slf4j." // hide slf4j
110 };
111 private File _tmpDir;
112 private String _war;
113 private String _extraClasspath;
114 private Throwable _unavailableException;
115
116 private Map _resourceAliases;
117 private boolean _ownClassLoader=false;
118 private boolean _configurationDiscovered=false;
119
120 public static ContextHandler getCurrentWebAppContext()
121 {
122 ContextHandler.Context context=ContextHandler.getCurrentContext();
123 if (context!=null)
124 {
125 ContextHandler handler = context.getContextHandler();
126 if (handler instanceof WebAppContext)
127 return (ContextHandler)handler;
128 }
129 return null;
130 }
131
132 /* ------------------------------------------------------------ */
133 public WebAppContext()
134 {
135 super(SESSIONS|SECURITY);
136 }
137
138 /* ------------------------------------------------------------ */
139 /**
140 * @param contextPath The context path
141 * @param webApp The URL or filename of the webapp directory or war file.
142 */
143 public WebAppContext(String webApp,String contextPath)
144 {
145 super(null,contextPath,SESSIONS|SECURITY);
146 setContextPath(contextPath);
147 setWar(webApp);
148 setErrorHandler(new ErrorPageErrorHandler());
149 }
150
151 /* ------------------------------------------------------------ */
152 /**
153 * @param parent The parent HandlerContainer.
154 * @param contextPath The context path
155 * @param webApp The URL or filename of the webapp directory or war file.
156 */
157 public WebAppContext(HandlerContainer parent, String webApp, String contextPath)
158 {
159 super(parent,contextPath,SESSIONS|SECURITY);
160 setWar(webApp);
161 setErrorHandler(new ErrorPageErrorHandler());
162 }
163
164 /* ------------------------------------------------------------ */
165 /**
166 */
167 public WebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
168 {
169 super(null,sessionHandler,securityHandler,servletHandler,errorHandler);
170
171 setErrorHandler(errorHandler!=null?errorHandler:new ErrorPageErrorHandler());
172 }
173
174 /* ------------------------------------------------------------ */
175 /**
176 * @param servletContextName The servletContextName to set.
177 */
178 public void setDisplayName(String servletContextName)
179 {
180 super.setDisplayName(servletContextName);
181 ClassLoader cl = getClassLoader();
182 if (cl!=null && cl instanceof WebAppClassLoader)
183 ((WebAppClassLoader)cl).setName(servletContextName);
184 }
185
186 /* ------------------------------------------------------------ */
187 /** Get an exception that caused the webapp to be unavailable
188 * @return A throwable if the webapp is unavailable or null
189 */
190 public Throwable getUnavailableException()
191 {
192 return _unavailableException;
193 }
194
195
196 /* ------------------------------------------------------------ */
197 /** Set Resource Alias.
198 * Resource aliases map resource uri's within a context.
199 * They may optionally be used by a handler when looking for
200 * a resource.
201 * @param alias
202 * @param uri
203 */
204 public void setResourceAlias(String alias, String uri)
205 {
206 if (_resourceAliases == null)
207 _resourceAliases= new HashMap(5);
208 _resourceAliases.put(alias, uri);
209 }
210
211 /* ------------------------------------------------------------ */
212 public Map getResourceAliases()
213 {
214 if (_resourceAliases == null)
215 return null;
216 return _resourceAliases;
217 }
218
219 /* ------------------------------------------------------------ */
220 public void setResourceAliases(Map map)
221 {
222 _resourceAliases = map;
223 }
224
225 /* ------------------------------------------------------------ */
226 public String getResourceAlias(String alias)
227 {
228 if (_resourceAliases == null)
229 return null;
230 return (String)_resourceAliases.get(alias);
231 }
232
233 /* ------------------------------------------------------------ */
234 public String removeResourceAlias(String alias)
235 {
236 if (_resourceAliases == null)
237 return null;
238 return (String)_resourceAliases.remove(alias);
239 }
240
241 /* ------------------------------------------------------------ */
242 /* (non-Javadoc)
243 * @see org.eclipse.jetty.server.server.handler.ContextHandler#setClassLoader(java.lang.ClassLoader)
244 */
245 public void setClassLoader(ClassLoader classLoader)
246 {
247 super.setClassLoader(classLoader);
248 if (classLoader!=null && classLoader instanceof WebAppClassLoader)
249 ((WebAppClassLoader)classLoader).setName(getDisplayName());
250 }
251
252 /* ------------------------------------------------------------ */
253 public Resource getResource(String uriInContext) throws MalformedURLException
254 {
255 IOException ioe= null;
256 Resource resource= null;
257 int loop=0;
258 while (uriInContext!=null && loop++<100)
259 {
260 try
261 {
262 resource= super.getResource(uriInContext);
263 if (resource != null && resource.exists())
264 return resource;
265
266 uriInContext = getResourceAlias(uriInContext);
267 }
268 catch (IOException e)
269 {
270 Log.ignore(e);
271 if (ioe==null)
272 ioe= e;
273 }
274 }
275
276 if (ioe != null && ioe instanceof MalformedURLException)
277 throw (MalformedURLException)ioe;
278
279 return resource;
280 }
281
282
283 /* ------------------------------------------------------------ */
284 /** Is the context Automatically configured.
285 *
286 * @return true if configuration discovery.
287 */
288 public boolean isConfigurationDiscovered()
289 {
290 return _configurationDiscovered;
291 }
292
293 /* ------------------------------------------------------------ */
294 /** Set the configuration discovery mode.
295 * If configuration discovery is set to true, then the JSR315
296 * servlet 3.0 discovered configuration features are enabled.
297 * These are:<ul>
298 * <li>Web Fragments</li>
299 * <li>META-INF/resource directories</li>
300 * </ul>
301 * @param servlet3autoConfig the servlet3autoConfig to set
302 */
303 public void setConfigurationDiscovered(boolean discovered)
304 {
305 _configurationDiscovered = discovered;
306 }
307
308 /* ------------------------------------------------------------ */
309 /*
310 * @see org.eclipse.thread.AbstractLifeCycle#doStart()
311 */
312 protected void doStart() throws Exception
313 {
314 try
315 {
316 // Setup configurations
317 loadConfigurations();
318
319
320 // Configure classloader
321 _ownClassLoader=false;
322 if (getClassLoader()==null)
323 {
324 WebAppClassLoader classLoader = new WebAppClassLoader(this);
325 setClassLoader(classLoader);
326 _ownClassLoader=true;
327 }
328
329 if (Log.isDebugEnabled())
330 {
331 ClassLoader loader = getClassLoader();
332 Log.debug("Thread Context class loader is: " + loader);
333 loader=loader.getParent();
334 while(loader!=null)
335 {
336 Log.debug("Parent class loader is: " + loader);
337 loader=loader.getParent();
338 }
339 }
340
341 // Prepare for configuration
342 for (int i=0;i<_configurations.length;i++)
343 _configurations[i].preConfigure(this);
344
345 super.doStart();
346
347 // Clean up after configuration
348 for (int i=0;i<_configurations.length;i++)
349 _configurations[i].postConfigure(this);
350
351
352 if (isLogUrlOnStart())
353 dumpUrl();
354 }
355 catch (Exception e)
356 {
357 //start up of the webapp context failed, make sure it is not started
358 Log.warn("Failed startup of context "+this, e);
359 _unavailableException=e;
360 setAvailable(false);
361 }
362 }
363
364 /* ------------------------------------------------------------ */
365 /*
366 * Dumps the current web app name and URL to the log
367 */
368 public void dumpUrl()
369 {
370 Connector[] connectors = getServer().getConnectors();
371 for (int i=0;i<connectors.length;i++)
372 {
373 String connectorName = connectors[i].getName();
374 String displayName = getDisplayName();
375 if (displayName == null)
376 displayName = "WebApp@"+connectors.hashCode();
377
378 Log.info(displayName + " at http://" + connectorName + getContextPath());
379 }
380 }
381
382 /* ------------------------------------------------------------ */
383 /*
384 * @see org.eclipse.thread.AbstractLifeCycle#doStop()
385 */
386 protected void doStop() throws Exception
387 {
388 super.doStop();
389
390 try
391 {
392 for (int i=_configurations.length;i-->0;)
393 _configurations[i].deconfigure(this);
394
395 _configurations=null;
396
397 // restore security handler
398 if (_securityHandler != null && _securityHandler.getHandler()==null)
399 {
400 _sessionHandler.setHandler(_securityHandler);
401 _securityHandler.setHandler(_servletHandler);
402 }
403 }
404 finally
405 {
406 if (_ownClassLoader)
407 setClassLoader(null);
408
409 setAvailable(true);
410 _unavailableException=null;
411 }
412 }
413
414 /* ------------------------------------------------------------ */
415 /**
416 * @return Returns the configurations.
417 */
418 public String[] getConfigurationClasses()
419 {
420 return _configurationClasses;
421 }
422
423 /* ------------------------------------------------------------ */
424 /**
425 * @return Returns the configurations.
426 */
427 public Configuration[] getConfigurations()
428 {
429 return _configurations;
430 }
431
432 /* ------------------------------------------------------------ */
433 /**
434 * The default descriptor is a web.xml format file that is applied to the context before the standard WEB-INF/web.xml
435 * @return Returns the defaultsDescriptor.
436 */
437 public String getDefaultsDescriptor()
438 {
439 return _defaultsDescriptor;
440 }
441
442 /* ------------------------------------------------------------ */
443 /**
444 * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
445 * @return Returns the Override Descriptor.
446 */
447 public String getOverrideDescriptor()
448 {
449 return _overrideDescriptor;
450 }
451
452 /* ------------------------------------------------------------ */
453 /**
454 * @return Returns the permissions.
455 */
456 public PermissionCollection getPermissions()
457 {
458 return _permissions;
459 }
460
461
462 /* ------------------------------------------------------------ */
463 /**
464 * @see #setServerClasses(String[])
465 * @return Returns the serverClasses.
466 */
467 public String[] getServerClasses()
468 {
469 return _serverClasses;
470 }
471
472
473 /* ------------------------------------------------------------ */
474 /**
475 * @see #setSystemClasses(String[])
476 * @return Returns the systemClasses.
477 */
478 public String[] getSystemClasses()
479 {
480 return _systemClasses;
481 }
482
483
484
485 /* ------------------------------------------------------------ */
486 public boolean isServerClass(String name)
487 {
488 name=name.replace('/','.');
489 while(name.startsWith("."))
490 name=name.substring(1);
491
492 String[] server_classes = getServerClasses();
493 if (server_classes!=null)
494 {
495 for (int i=0;i<server_classes.length;i++)
496 {
497 boolean result=true;
498 String c=server_classes[i];
499 if (c.startsWith("-"))
500 {
501 c=c.substring(1); // TODO cache
502 result=false;
503 }
504
505 if (c.endsWith("."))
506 {
507 if (name.startsWith(c))
508 return result;
509 }
510 else if (name.equals(c))
511 return result;
512 }
513 }
514 return false;
515 }
516
517 /* ------------------------------------------------------------ */
518 public boolean isSystemClass(String name)
519 {
520 name=name.replace('/','.');
521 while(name.startsWith("."))
522 name=name.substring(1);
523 String[] system_classes = getSystemClasses();
524 if (system_classes!=null)
525 {
526 for (int i=0;i<system_classes.length;i++)
527 {
528 boolean result=true;
529 String c=system_classes[i];
530
531 if (c.startsWith("-"))
532 {
533 c=c.substring(1); // TODO cache
534 result=false;
535 }
536
537 if (c.endsWith("."))
538 {
539 if (name.startsWith(c))
540 return result;
541 }
542 else if (name.equals(c))
543 return result;
544 }
545 }
546
547 return false;
548
549 }
550
551
552
553
554 /* ------------------------------------------------------------ */
555 /**
556 * @return Returns the war as a file or URL string (Resource)
557 */
558 public String getWar()
559 {
560 if (_war==null)
561 _war=getResourceBase();
562 return _war;
563 }
564
565 /* ------------------------------------------------------------ */
566 public Resource getWebInf() throws IOException
567 {
568 if (super.getBaseResource() == null)
569 return null;
570
571 // Iw there a WEB-INF directory?
572 Resource web_inf= super.getBaseResource().addPath("WEB-INF/");
573 if (!web_inf.exists() || !web_inf.isDirectory())
574 return null;
575
576 return web_inf;
577 }
578
579 /* ------------------------------------------------------------ */
580 /**
581 * @return Returns the distributable.
582 */
583 public boolean isDistributable()
584 {
585 return _distributable;
586 }
587
588 /* ------------------------------------------------------------ */
589 /**
590 * @return Returns the extractWAR.
591 */
592 public boolean isExtractWAR()
593 {
594 return _extractWAR;
595 }
596
597 /* ------------------------------------------------------------ */
598 /**
599 * @return True if the webdir is copied (to allow hot replacement of jars)
600 */
601 public boolean isCopyWebDir()
602 {
603 return _copyDir;
604 }
605
606 /* ------------------------------------------------------------ */
607 /**
608 * @return Returns the java2compliant.
609 */
610 public boolean isParentLoaderPriority()
611 {
612 return _parentLoaderPriority;
613 }
614
615 /* ------------------------------------------------------------ */
616 protected void loadConfigurations()
617 throws Exception
618 {
619 if (_configurations!=null)
620 return;
621 if (_configurationClasses==null)
622 _configurationClasses=__dftConfigurationClasses;
623
624 _configurations = new Configuration[_configurationClasses.length];
625 for (int i=0;i<_configurations.length;i++)
626 {
627 _configurations[i]=(Configuration)Loader.loadClass(this.getClass(), _configurationClasses[i]).newInstance();
628 }
629 }
630
631 /* ------------------------------------------------------------ */
632 protected boolean isProtectedTarget(String target)
633 {
634 while (target.startsWith("//"))
635 target=URIUtil.compactPath(target);
636
637 return StringUtil.startsWithIgnoreCase(target, "/web-inf") || StringUtil.startsWithIgnoreCase(target, "/meta-inf");
638 }
639
640
641 /* ------------------------------------------------------------ */
642 public String toString()
643 {
644 return super.toString()+(_war==null?"":(","+_war));
645 }
646
647
648
649
650 /* ------------------------------------------------------------ */
651 /**
652 * @param configurations The configuration class names. If setConfigurations is not called
653 * these classes are used to create a configurations array.
654 */
655 public void setConfigurationClasses(String[] configurations)
656 {
657 _configurationClasses = configurations==null?null:(String[])configurations.clone();
658 }
659
660 /* ------------------------------------------------------------ */
661 /**
662 * @param configurations The configurations to set.
663 */
664 public void setConfigurations(Configuration[] configurations)
665 {
666 _configurations = configurations==null?null:(Configuration[])configurations.clone();
667 }
668
669 /* ------------------------------------------------------------ */
670 /**
671 * The default descriptor is a web.xml format file that is applied to the context before the standard WEB-INF/web.xml
672 * @param defaultsDescriptor The defaultsDescriptor to set.
673 */
674 public void setDefaultsDescriptor(String defaultsDescriptor)
675 {
676 _defaultsDescriptor = defaultsDescriptor;
677 }
678
679 /* ------------------------------------------------------------ */
680 /**
681 * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
682 * @param overrideDescriptor The overrideDescritpor to set.
683 */
684 public void setOverrideDescriptor(String overrideDescriptor)
685 {
686 _overrideDescriptor = overrideDescriptor;
687 }
688
689 /* ------------------------------------------------------------ */
690 /**
691 * @return the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists.
692 */
693 public String getDescriptor()
694 {
695 return _descriptor;
696 }
697
698 /* ------------------------------------------------------------ */
699 /**
700 * @param descriptor the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists.
701 */
702 public void setDescriptor(String descriptor)
703 {
704 _descriptor=descriptor;
705 }
706
707 /* ------------------------------------------------------------ */
708 /**
709 * @param distributable The distributable to set.
710 */
711 public void setDistributable(boolean distributable)
712 {
713 this._distributable = distributable;
714 }
715
716 /* ------------------------------------------------------------ */
717 public void setEventListeners(EventListener[] eventListeners)
718 {
719 if (_sessionHandler!=null)
720 _sessionHandler.clearEventListeners();
721
722 super.setEventListeners(eventListeners);
723
724 for (int i=0; eventListeners!=null && i<eventListeners.length;i ++)
725 {
726 EventListener listener = eventListeners[i];
727
728 if ((listener instanceof HttpSessionActivationListener)
729 || (listener instanceof HttpSessionAttributeListener)
730 || (listener instanceof HttpSessionBindingListener)
731 || (listener instanceof HttpSessionListener))
732 {
733 if (_sessionHandler!=null)
734 _sessionHandler.addEventListener(listener);
735 }
736
737 }
738 }
739
740 /* ------------------------------------------------------------ */
741 /** Add EventListener
742 * Conveniance method that calls {@link #setEventListeners(EventListener[])}
743 * @param listener
744 */
745 public void addEventListener(EventListener listener)
746 {
747 setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(), listener, EventListener.class));
748 }
749
750
751 /* ------------------------------------------------------------ */
752 /**
753 * @param extractWAR True if war files are extracted
754 */
755 public void setExtractWAR(boolean extractWAR)
756 {
757 _extractWAR = extractWAR;
758 }
759
760 /* ------------------------------------------------------------ */
761 /**
762 *
763 * @param copy True if the webdir is copied (to allow hot replacement of jars)
764 */
765 public void setCopyWebDir(boolean copy)
766 {
767 _copyDir = copy;
768 }
769
770 /* ------------------------------------------------------------ */
771 /**
772 * @param java2compliant The java2compliant to set.
773 */
774 public void setParentLoaderPriority(boolean java2compliant)
775 {
776 _parentLoaderPriority = java2compliant;
777 }
778
779 /* ------------------------------------------------------------ */
780 /**
781 * @param permissions The permissions to set.
782 */
783 public void setPermissions(PermissionCollection permissions)
784 {
785 _permissions = permissions;
786 }
787
788 /* ------------------------------------------------------------ */
789 /**
790 * Set the server classes patterns.
791 * <p>
792 * Server classes/packages are classes used to implement the server and are hidden
793 * from the context. If the context needs to load these classes, it must have its
794 * own copy of them in WEB-INF/lib or WEB-INF/classes.
795 * A class pattern is a string of one of the forms:<dl>
796 * <dt>org.package.Classname</dt><dd>Match a specific class</dd>
797 * <dt>org.package.</dt><dd>Match a specific package hierarchy</dd>
798 * <dt>-org.package.Classname</dt><dd>Exclude a specific class</dd>
799 * <dt>-org.package.</dt><dd>Exclude a specific package hierarchy</dd>
800 * </dl>
801 * @param serverClasses The serverClasses to set.
802 */
803 public void setServerClasses(String[] serverClasses)
804 {
805 _serverClasses = serverClasses==null?null:(String[])serverClasses.clone();
806 }
807
808 /* ------------------------------------------------------------ */
809 /**
810 * Set the system classes patterns.
811 * <p>
812 * System classes/packages are classes provided by the JVM and that
813 * cannot be replaced by classes of the same name from WEB-INF,
814 * regardless of the value of {@link #setParentLoaderPriority(boolean)}.
815 * A class pattern is a string of one of the forms:<dl>
816 * <dt>org.package.Classname</dt><dd>Match a specific class</dd>
817 * <dt>org.package.</dt><dd>Match a specific package hierarchy</dd>
818 * <dt>-org.package.Classname</dt><dd>Exclude a specific class</dd>
819 * <dt>-org.package.</dt><dd>Exclude a specific package hierarchy</dd>
820 * </dl>
821 * @param systemClasses The systemClasses to set.
822 */
823 public void setSystemClasses(String[] systemClasses)
824 {
825 _systemClasses = systemClasses==null?null:(String[])systemClasses.clone();
826 }
827
828
829 /* ------------------------------------------------------------ */
830 /** Set temporary directory for context.
831 * The javax.servlet.context.tempdir attribute is also set.
832 * @param dir Writable temporary directory.
833 */
834 public void setTempDirectory(File dir)
835 {
836 if (isStarted())
837 throw new IllegalStateException("Started");
838
839 if (dir!=null)
840 {
841 try{dir=new File(dir.getCanonicalPath());}
842 catch (IOException e){Log.warn(Log.EXCEPTION,e);}
843 }
844
845 if (dir!=null && !dir.exists())
846 {
847 dir.mkdir();
848 dir.deleteOnExit();
849 }
850
851 if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite()))
852 throw new IllegalArgumentException("Bad temp directory: "+dir);
853
854 _tmpDir=dir;
855 setAttribute(TEMPDIR,_tmpDir);
856 }
857
858 public File getTempDirectory ()
859 {
860 return _tmpDir;
861 }
862
863 /* ------------------------------------------------------------ */
864 /**
865 * @param war The war to set as a file name or URL
866 */
867 public void setWar(String war)
868 {
869 _war = war;
870 }
871
872
873 /* ------------------------------------------------------------ */
874 /**
875 * @return Comma or semicolon separated path of filenames or URLs
876 * pointing to directories or jar files. Directories should end
877 * with '/'.
878 */
879 public String getExtraClasspath()
880 {
881 return _extraClasspath;
882 }
883
884 /* ------------------------------------------------------------ */
885 /**
886 * @param extraClasspath Comma or semicolon separated path of filenames or URLs
887 * pointing to directories or jar files. Directories should end
888 * with '/'.
889 */
890 public void setExtraClasspath(String extraClasspath)
891 {
892 _extraClasspath=extraClasspath;
893 }
894
895 /* ------------------------------------------------------------ */
896 public boolean isLogUrlOnStart()
897 {
898 return _logUrlOnStart;
899 }
900
901 /* ------------------------------------------------------------ */
902 /**
903 * Sets whether or not the web app name and URL is logged on startup
904 *
905 * @param logOnStart whether or not the log message is created
906 */
907 public void setLogUrlOnStart(boolean logOnStart)
908 {
909 this._logUrlOnStart = logOnStart;
910 }
911
912 /* ------------------------------------------------------------ */
913 protected void startContext()
914 throws Exception
915 {
916
917
918 // Configure webapp
919 for (int i=0;i<_configurations.length;i++)
920 _configurations[i].configure(this);
921
922
923 super.startContext();
924 }
925
926 }