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
18
19 package org.apache.catalina.core;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.ObjectOutputStream;
29 import java.io.Serializable;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Hashtable;
33 import java.util.Iterator;
34 import java.util.Stack;
35 import java.util.TreeMap;
36
37 import javax.management.AttributeNotFoundException;
38 import javax.management.ListenerNotFoundException;
39 import javax.management.MBeanNotificationInfo;
40 import javax.management.MBeanRegistrationException;
41 import javax.management.MBeanServer;
42 import javax.management.MalformedObjectNameException;
43 import javax.management.Notification;
44 import javax.management.NotificationBroadcasterSupport;
45 import javax.management.NotificationEmitter;
46 import javax.management.NotificationFilter;
47 import javax.management.NotificationListener;
48 import javax.management.ObjectName;
49 import javax.naming.NamingException;
50 import javax.naming.directory.DirContext;
51 import javax.servlet.FilterConfig;
52 import javax.servlet.ServletContext;
53 import javax.servlet.ServletContextAttributeListener;
54 import javax.servlet.ServletContextEvent;
55 import javax.servlet.ServletContextListener;
56 import javax.servlet.ServletException;
57 import javax.servlet.ServletRequestAttributeListener;
58 import javax.servlet.ServletRequestListener;
59 import javax.servlet.http.HttpSessionAttributeListener;
60 import javax.servlet.http.HttpSessionListener;
61
62 import org.apache.AnnotationProcessor;
63 import org.apache.catalina.Container;
64 import org.apache.catalina.ContainerListener;
65 import org.apache.catalina.Context;
66 import org.apache.catalina.Engine;
67 import org.apache.catalina.Globals;
68 import org.apache.catalina.Host;
69 import org.apache.catalina.InstanceListener;
70 import org.apache.catalina.Lifecycle;
71 import org.apache.catalina.LifecycleException;
72 import org.apache.catalina.LifecycleListener;
73 import org.apache.catalina.Loader;
74 import org.apache.catalina.Manager;
75 import org.apache.catalina.Wrapper;
76 import org.apache.catalina.deploy.ApplicationParameter;
77 import org.apache.catalina.deploy.ErrorPage;
78 import org.apache.catalina.deploy.FilterDef;
79 import org.apache.catalina.deploy.FilterMap;
80 import org.apache.catalina.deploy.LoginConfig;
81 import org.apache.catalina.deploy.MessageDestination;
82 import org.apache.catalina.deploy.MessageDestinationRef;
83 import org.apache.catalina.deploy.NamingResources;
84 import org.apache.catalina.deploy.SecurityCollection;
85 import org.apache.catalina.deploy.SecurityConstraint;
86 import org.apache.catalina.loader.WebappLoader;
87 import org.apache.catalina.session.StandardManager;
88 import org.apache.catalina.startup.ContextConfig;
89 import org.apache.catalina.startup.TldConfig;
90 import org.apache.catalina.util.CharsetMapper;
91 import org.apache.catalina.util.DefaultAnnotationProcessor;
92 import org.apache.catalina.util.ExtensionValidator;
93 import org.apache.catalina.util.RequestUtil;
94 import org.apache.catalina.util.URLEncoder;
95 import org.apache.juli.logging.Log;
96 import org.apache.juli.logging.LogFactory;
97 import org.apache.naming.ContextBindings;
98 import org.apache.naming.resources.BaseDirContext;
99 import org.apache.naming.resources.DirContextURLStreamHandler;
100 import org.apache.naming.resources.FileDirContext;
101 import org.apache.naming.resources.ProxyDirContext;
102 import org.apache.naming.resources.WARDirContext;
103 import org.apache.tomcat.util.modeler.Registry;
104
105 /**
106 * Standard implementation of the <b>Context</b> interface. Each
107 * child container must be a Wrapper implementation to process the
108 * requests directed to a particular servlet.
109 *
110 * @author Craig R. McClanahan
111 * @author Remy Maucherat
112 * @version $Revision: 893564 $ $Date: 2009-12-23 17:31:31 +0100 (Wed, 23 Dec 2009) $
113 */
114
115 public class StandardContext
116 extends ContainerBase
117 implements Context, Serializable, NotificationEmitter
118 {
119 private static transient Log log = LogFactory.getLog(StandardContext.class);
120
121
122 // ----------------------------------------------------------- Constructors
123
124
125 /**
126 * Create a new StandardContext component with the default basic Valve.
127 */
128 public StandardContext() {
129
130 super();
131 pipeline.setBasic(new StandardContextValve());
132 broadcaster = new NotificationBroadcasterSupport();
133
134 }
135
136
137 // ----------------------------------------------------- Class Variables
138
139
140 /**
141 * The descriptive information string for this implementation.
142 */
143 private static final String info =
144 "org.apache.catalina.core.StandardContext/1.0";
145
146
147 /**
148 * Array containing the safe characters set.
149 */
150 protected static URLEncoder urlEncoder;
151
152
153 /**
154 * GMT timezone - all HTTP dates are on GMT
155 */
156 static {
157 urlEncoder = new URLEncoder();
158 urlEncoder.addSafeCharacter('~');
159 urlEncoder.addSafeCharacter('-');
160 urlEncoder.addSafeCharacter('_');
161 urlEncoder.addSafeCharacter('.');
162 urlEncoder.addSafeCharacter('*');
163 urlEncoder.addSafeCharacter('/');
164 }
165
166
167 // ----------------------------------------------------- Instance Variables
168
169
170 /**
171 * The alternate deployment descriptor name.
172 */
173 private String altDDName = null;
174
175
176 /**
177 * Annotation processor.
178 */
179 private AnnotationProcessor annotationProcessor = null;
180
181
182 /**
183 * Associated host name.
184 */
185 private String hostName;
186
187
188 /**
189 * The antiJARLocking flag for this Context.
190 */
191 private boolean antiJARLocking = false;
192
193
194 /**
195 * The antiResourceLocking flag for this Context.
196 */
197 private boolean antiResourceLocking = false;
198
199
200 /**
201 * The set of application listener class names configured for this
202 * application, in the order they were encountered in the web.xml file.
203 */
204 private String applicationListeners[] = new String[0];
205
206 private final Object applicationListenersLock = new Object();
207
208
209 /**
210 * The set of instantiated application event listener objects</code>.
211 */
212 private transient Object applicationEventListenersObjects[] =
213 new Object[0];
214
215
216 /**
217 * The set of instantiated application lifecycle listener objects</code>.
218 */
219 private transient Object applicationLifecycleListenersObjects[] =
220 new Object[0];
221
222
223 /**
224 * The set of application parameters defined for this application.
225 */
226 private ApplicationParameter applicationParameters[] =
227 new ApplicationParameter[0];
228
229 private final Object applicationParametersLock = new Object();
230
231
232 /**
233 * The application available flag for this Context.
234 */
235 private boolean available = false;
236
237 /**
238 * The broadcaster that sends j2ee notifications.
239 */
240 private NotificationBroadcasterSupport broadcaster = null;
241
242 /**
243 * The Locale to character set mapper for this application.
244 */
245 private transient CharsetMapper charsetMapper = null;
246
247
248 /**
249 * The Java class name of the CharsetMapper class to be created.
250 */
251 private String charsetMapperClass =
252 "org.apache.catalina.util.CharsetMapper";
253
254
255 /**
256 * The path to a file to save this Context information.
257 */
258 private String configFile = null;
259
260
261 /**
262 * The "correctly configured" flag for this Context.
263 */
264 private boolean configured = false;
265
266
267 /**
268 * The security constraints for this web application.
269 */
270 private SecurityConstraint constraints[] = new SecurityConstraint[0];
271
272 private final Object constraintsLock = new Object();
273
274
275 /**
276 * The ServletContext implementation associated with this Context.
277 */
278 protected transient ApplicationContext context = null;
279
280
281 /**
282 * Compiler classpath to use.
283 */
284 private String compilerClasspath = null;
285
286
287 /**
288 * Should we attempt to use cookies for session id communication?
289 */
290 private boolean cookies = true;
291
292
293 /**
294 * Should we allow the <code>ServletContext.getContext()</code> method
295 * to access the context of other web applications in this server?
296 */
297 private boolean crossContext = false;
298
299
300 /**
301 * Encoded path.
302 */
303 private String encodedPath = null;
304
305
306 /**
307 * The "follow standard delegation model" flag that will be used to
308 * configure our ClassLoader.
309 */
310 private boolean delegate = false;
311
312
313 /**
314 * The display name of this web application.
315 */
316 private String displayName = null;
317
318
319 /**
320 * Override the default context xml location.
321 */
322 private String defaultContextXml;
323
324
325 /**
326 * Override the default web xml location.
327 */
328 private String defaultWebXml;
329
330
331 /**
332 * The distributable flag for this web application.
333 */
334 private boolean distributable = false;
335
336
337 /**
338 * The document root for this web application.
339 */
340 private String docBase = null;
341
342
343 /**
344 * The exception pages for this web application, keyed by fully qualified
345 * class name of the Java exception.
346 */
347 private HashMap exceptionPages = new HashMap();
348
349
350 /**
351 * The set of filter configurations (and associated filter instances) we
352 * have initialized, keyed by filter name.
353 */
354 private HashMap filterConfigs = new HashMap();
355
356
357 /**
358 * The set of filter definitions for this application, keyed by
359 * filter name.
360 */
361 private HashMap filterDefs = new HashMap();
362
363
364 /**
365 * The set of filter mappings for this application, in the order
366 * they were defined in the deployment descriptor.
367 */
368 private FilterMap filterMaps[] = new FilterMap[0];
369
370 private final Object filterMapsLock = new Object();
371
372
373 /**
374 * Ignore annotations.
375 */
376 private boolean ignoreAnnotations = false;
377
378
379 /**
380 * The set of classnames of InstanceListeners that will be added
381 * to each newly created Wrapper by <code>createWrapper()</code>.
382 */
383 private String instanceListeners[] = new String[0];
384
385 private final Object instanceListenersLock = new Object();
386
387
388 /**
389 * The login configuration descriptor for this web application.
390 */
391 private LoginConfig loginConfig = null;
392
393
394 /**
395 * The mapper associated with this context.
396 */
397 private org.apache.tomcat.util.http.mapper.Mapper mapper =
398 new org.apache.tomcat.util.http.mapper.Mapper();
399
400
401 /**
402 * The naming context listener for this web application.
403 */
404 private transient NamingContextListener namingContextListener = null;
405
406
407 /**
408 * The naming resources for this web application.
409 */
410 private NamingResources namingResources = null;
411
412
413 /**
414 * The message destinations for this web application.
415 */
416 private HashMap messageDestinations = new HashMap();
417
418
419 /**
420 * The MIME mappings for this web application, keyed by extension.
421 */
422 private HashMap mimeMappings = new HashMap();
423
424
425 /**
426 * Special case: error page for status 200.
427 */
428 private ErrorPage okErrorPage = null;
429
430
431 /**
432 * The context initialization parameters for this web application,
433 * keyed by name.
434 */
435 private HashMap parameters = new HashMap();
436
437
438 /**
439 * The request processing pause flag (while reloading occurs)
440 */
441 private boolean paused = false;
442
443
444 /**
445 * The public identifier of the DTD for the web application deployment
446 * descriptor version we are currently parsing. This is used to support
447 * relaxed validation rules when processing version 2.2 web.xml files.
448 */
449 private String publicId = null;
450
451
452 /**
453 * The reloadable flag for this web application.
454 */
455 private boolean reloadable = false;
456
457
458 /**
459 * Unpack WAR property.
460 */
461 private boolean unpackWAR = true;
462
463
464 /**
465 * The DefaultContext override flag for this web application.
466 */
467 private boolean override = false;
468
469
470 /**
471 * The original document root for this web application.
472 */
473 private String originalDocBase = null;
474
475
476 /**
477 * The privileged flag for this web application.
478 */
479 private boolean privileged = false;
480
481
482 /**
483 * Should the next call to <code>addWelcomeFile()</code> cause replacement
484 * of any existing welcome files? This will be set before processing the
485 * web application's deployment descriptor, so that application specified
486 * choices <strong>replace</strong>, rather than append to, those defined
487 * in the global descriptor.
488 */
489 private boolean replaceWelcomeFiles = false;
490
491
492 /**
493 * The security role mappings for this application, keyed by role
494 * name (as used within the application).
495 */
496 private HashMap roleMappings = new HashMap();
497
498
499 /**
500 * The security roles for this application, keyed by role name.
501 */
502 private String securityRoles[] = new String[0];
503
504 private final Object securityRolesLock = new Object();
505
506
507 /**
508 * The servlet mappings for this web application, keyed by
509 * matching pattern.
510 */
511 private HashMap servletMappings = new HashMap();
512
513 private final Object servletMappingsLock = new Object();
514
515
516 /**
517 * The session timeout (in minutes) for this web application.
518 */
519 private int sessionTimeout = 30;
520
521 /**
522 * The notification sequence number.
523 */
524 private long sequenceNumber = 0;
525
526 /**
527 * The status code error pages for this web application, keyed by
528 * HTTP status code (as an Integer).
529 */
530 private HashMap statusPages = new HashMap();
531
532
533 /**
534 * Set flag to true to cause the system.out and system.err to be redirected
535 * to the logger when executing a servlet.
536 */
537 private boolean swallowOutput = false;
538
539
540 /**
541 * The JSP tag libraries for this web application, keyed by URI
542 */
543 private HashMap taglibs = new HashMap();
544
545
546 /**
547 * Amount of ms that the container will wait for servlets to unload.
548 */
549 private long unloadDelay = 2000;
550
551
552 /**
553 * The watched resources for this application.
554 */
555 private String watchedResources[] = new String[0];
556
557 private final Object watchedResourcesLock = new Object();
558
559
560 /**
561 * The welcome files for this application.
562 */
563 private String welcomeFiles[] = new String[0];
564
565 private final Object welcomeFilesLock = new Object();
566
567
568 /**
569 * The set of classnames of LifecycleListeners that will be added
570 * to each newly created Wrapper by <code>createWrapper()</code>.
571 */
572 private String wrapperLifecycles[] = new String[0];
573
574 private final Object wrapperLifecyclesLock = new Object();
575
576
577 /**
578 * The set of classnames of ContainerListeners that will be added
579 * to each newly created Wrapper by <code>createWrapper()</code>.
580 */
581 private String wrapperListeners[] = new String[0];
582
583 private final Object wrapperListenersLock = new Object();
584
585
586 /**
587 * The pathname to the work directory for this context (relative to
588 * the server's home if not absolute).
589 */
590 private String workDir = null;
591
592
593 /**
594 * Java class name of the Wrapper class implementation we use.
595 */
596 private String wrapperClassName = StandardWrapper.class.getName();
597 private Class wrapperClass = null;
598
599
600 /**
601 * JNDI use flag.
602 */
603 private boolean useNaming = true;
604
605
606 /**
607 * Filesystem based flag.
608 */
609 private boolean filesystemBased = false;
610
611
612 /**
613 * Name of the associated naming context.
614 */
615 private String namingContextName = null;
616
617
618 /**
619 * Caching allowed flag.
620 */
621 private boolean cachingAllowed = true;
622
623
624 /**
625 * Case sensitivity.
626 */
627 protected boolean caseSensitive = true;
628
629
630 /**
631 * Allow linking.
632 */
633 protected boolean allowLinking = false;
634
635
636 /**
637 * Cache max size in KB.
638 */
639 protected int cacheMaxSize = 10240; // 10 MB
640
641
642 /**
643 * Cache object max size in KB.
644 */
645 protected int cacheObjectMaxSize = 512; // 512K
646
647
648 /**
649 * Cache TTL in ms.
650 */
651 protected int cacheTTL = 5000;
652
653
654 private boolean lazy=true;
655
656 /**
657 * Non proxied resources.
658 */
659 private transient DirContext webappResources = null;
660
661 private long startupTime;
662 private long startTime;
663 private long tldScanTime;
664
665 /**
666 * Name of the engine. If null, the domain is used.
667 */
668 private String engineName = null;
669 private String j2EEApplication="none";
670 private String j2EEServer="none";
671
672
673 /**
674 * Attribute value used to turn on/off XML validation
675 */
676 private boolean webXmlValidation = false;
677
678
679 /**
680 * Attribute value used to turn on/off XML namespace validation
681 */
682 private boolean webXmlNamespaceAware = false;
683
684 /**
685 * Attribute value used to turn on/off TLD processing
686 */
687 private boolean processTlds = true;
688
689 /**
690 * Attribute value used to turn on/off XML validation
691 */
692 private boolean tldValidation = false;
693
694
695 /**
696 * Attribute value used to turn on/off TLD XML namespace validation
697 */
698 private boolean tldNamespaceAware = false;
699
700
701 /**
702 * Should we save the configuration.
703 */
704 private boolean saveConfig = true;
705
706 /**
707 * The flag that indicates that session cookies should use HttpOnly
708 */
709 private boolean useHttpOnly = false;
710
711 /**
712 * Should Tomcat attempt to terminate threads that have been started by the
713 * web application? Stopping threads is performed via the deprecated (for
714 * good reason) <code>Thread.stop()</code> method and is likely to result in
715 * instability. As such, enabling this should be viewed as an option of last
716 * resort in a development environment and is not recommended in a
717 * production environment. If not specified, the default value of
718 * <code>false</code> will be used.
719 */
720 private boolean clearReferencesStopThreads = false;
721
722 // ----------------------------------------------------- Context Properties
723
724
725 public AnnotationProcessor getAnnotationProcessor() {
726 return annotationProcessor;
727 }
728
729
730 public void setAnnotationProcessor(AnnotationProcessor annotationProcessor) {
731 this.annotationProcessor = annotationProcessor;
732 }
733
734
735 public String getEncodedPath() {
736 return encodedPath;
737 }
738
739
740 public void setName( String name ) {
741 super.setName( name );
742 encodedPath = urlEncoder.encode(name);
743 }
744
745
746 /**
747 * Is caching allowed ?
748 */
749 public boolean isCachingAllowed() {
750 return cachingAllowed;
751 }
752
753
754 /**
755 * Set caching allowed flag.
756 */
757 public void setCachingAllowed(boolean cachingAllowed) {
758 this.cachingAllowed = cachingAllowed;
759 }
760
761
762 /**
763 * Set case sensitivity.
764 */
765 public void setCaseSensitive(boolean caseSensitive) {
766 this.caseSensitive = caseSensitive;
767 }
768
769
770 /**
771 * Is case sensitive ?
772 */
773 public boolean isCaseSensitive() {
774 return caseSensitive;
775 }
776
777
778 /**
779 * Set allow linking.
780 */
781 public void setAllowLinking(boolean allowLinking) {
782 this.allowLinking = allowLinking;
783 }
784
785
786 /**
787 * Is linking allowed.
788 */
789 public boolean isAllowLinking() {
790 return allowLinking;
791 }
792
793
794 /**
795 * Set cache TTL.
796 */
797 public void setCacheTTL(int cacheTTL) {
798 this.cacheTTL = cacheTTL;
799 }
800
801
802 /**
803 * Get cache TTL.
804 */
805 public int getCacheTTL() {
806 return cacheTTL;
807 }
808
809
810 /**
811 * Return the maximum size of the cache in KB.
812 */
813 public int getCacheMaxSize() {
814 return cacheMaxSize;
815 }
816
817
818 /**
819 * Set the maximum size of the cache in KB.
820 */
821 public void setCacheMaxSize(int cacheMaxSize) {
822 this.cacheMaxSize = cacheMaxSize;
823 }
824
825
826 /**
827 * Return the maximum size of objects to be cached in KB.
828 */
829 public int getCacheObjectMaxSize() {
830 return cacheObjectMaxSize;
831 }
832
833
834 /**
835 * Set the maximum size of objects to be placed the cache in KB.
836 */
837 public void setCacheObjectMaxSize(int cacheObjectMaxSize) {
838 this.cacheObjectMaxSize = cacheObjectMaxSize;
839 }
840
841
842 /**
843 * Return the "follow standard delegation model" flag used to configure
844 * our ClassLoader.
845 */
846 public boolean getDelegate() {
847
848 return (this.delegate);
849
850 }
851
852
853 /**
854 * Set the "follow standard delegation model" flag used to configure
855 * our ClassLoader.
856 *
857 * @param delegate The new flag
858 */
859 public void setDelegate(boolean delegate) {
860
861 boolean oldDelegate = this.delegate;
862 this.delegate = delegate;
863 support.firePropertyChange("delegate", oldDelegate,
864 this.delegate);
865
866 }
867
868
869 /**
870 * Returns true if the internal naming support is used.
871 */
872 public boolean isUseNaming() {
873
874 return (useNaming);
875
876 }
877
878
879 /**
880 * Enables or disables naming.
881 */
882 public void setUseNaming(boolean useNaming) {
883 this.useNaming = useNaming;
884 }
885
886
887 /**
888 * Returns true if the resources associated with this context are
889 * filesystem based.
890 */
891 public boolean isFilesystemBased() {
892
893 return (filesystemBased);
894
895 }
896
897
898 /**
899 * Return the set of initialized application event listener objects,
900 * in the order they were specified in the web application deployment
901 * descriptor, for this application.
902 *
903 * @exception IllegalStateException if this method is called before
904 * this application has started, or after it has been stopped
905 */
906 public Object[] getApplicationEventListeners() {
907 return (applicationEventListenersObjects);
908 }
909
910
911 /**
912 * Store the set of initialized application event listener objects,
913 * in the order they were specified in the web application deployment
914 * descriptor, for this application.
915 *
916 * @param listeners The set of instantiated listener objects.
917 */
918 public void setApplicationEventListeners(Object listeners[]) {
919 applicationEventListenersObjects = listeners;
920 }
921
922
923 /**
924 * Return the set of initialized application lifecycle listener objects,
925 * in the order they were specified in the web application deployment
926 * descriptor, for this application.
927 *
928 * @exception IllegalStateException if this method is called before
929 * this application has started, or after it has been stopped
930 */
931 public Object[] getApplicationLifecycleListeners() {
932 return (applicationLifecycleListenersObjects);
933 }
934
935
936 /**
937 * Store the set of initialized application lifecycle listener objects,
938 * in the order they were specified in the web application deployment
939 * descriptor, for this application.
940 *
941 * @param listeners The set of instantiated listener objects.
942 */
943 public void setApplicationLifecycleListeners(Object listeners[]) {
944 applicationLifecycleListenersObjects = listeners;
945 }
946
947
948 /**
949 * Return the antiJARLocking flag for this Context.
950 */
951 public boolean getAntiJARLocking() {
952
953 return (this.antiJARLocking);
954
955 }
956
957
958 /**
959 * Return the antiResourceLocking flag for this Context.
960 */
961 public boolean getAntiResourceLocking() {
962
963 return (this.antiResourceLocking);
964
965 }
966
967
968 /**
969 * Set the antiJARLocking feature for this Context.
970 *
971 * @param antiJARLocking The new flag value
972 */
973 public void setAntiJARLocking(boolean antiJARLocking) {
974
975 boolean oldAntiJARLocking = this.antiJARLocking;
976 this.antiJARLocking = antiJARLocking;
977 support.firePropertyChange("antiJARLocking",
978 oldAntiJARLocking,
979 this.antiJARLocking);
980
981 }
982
983
984 /**
985 * Set the antiResourceLocking feature for this Context.
986 *
987 * @param antiResourceLocking The new flag value
988 */
989 public void setAntiResourceLocking(boolean antiResourceLocking) {
990
991 boolean oldAntiResourceLocking = this.antiResourceLocking;
992 this.antiResourceLocking = antiResourceLocking;
993 support.firePropertyChange("antiResourceLocking",
994 oldAntiResourceLocking,
995 this.antiResourceLocking);
996
997 }
998
999
1000 /**
1001 * Return the application available flag for this Context.
1002 */
1003 public boolean getAvailable() {
1004
1005 return (this.available);
1006
1007 }
1008
1009
1010 /**
1011 * Set the application available flag for this Context.
1012 *
1013 * @param available The new application available flag
1014 */
1015 public void setAvailable(boolean available) {
1016
1017 boolean oldAvailable = this.available;
1018 this.available = available;
1019 support.firePropertyChange("available",
1020 oldAvailable,
1021 this.available);
1022
1023 }
1024
1025
1026 /**
1027 * Return the Locale to character set mapper for this Context.
1028 */
1029 public CharsetMapper getCharsetMapper() {
1030
1031 // Create a mapper the first time it is requested
1032 if (this.charsetMapper == null) {
1033 try {
1034 Class clazz = Class.forName(charsetMapperClass);
1035 this.charsetMapper =
1036 (CharsetMapper) clazz.newInstance();
1037 } catch (Throwable t) {
1038 this.charsetMapper = new CharsetMapper();
1039 }
1040 }
1041
1042 return (this.charsetMapper);
1043
1044 }
1045
1046
1047 /**
1048 * Set the Locale to character set mapper for this Context.
1049 *
1050 * @param mapper The new mapper
1051 */
1052 public void setCharsetMapper(CharsetMapper mapper) {
1053
1054 CharsetMapper oldCharsetMapper = this.charsetMapper;
1055 this.charsetMapper = mapper;
1056 if( mapper != null )
1057 this.charsetMapperClass= mapper.getClass().getName();
1058 support.firePropertyChange("charsetMapper", oldCharsetMapper,
1059 this.charsetMapper);
1060
1061 }
1062
1063 /**
1064 * Return the path to a file to save this Context information.
1065 */
1066 public String getConfigFile() {
1067
1068 return (this.configFile);
1069
1070 }
1071
1072
1073 /**
1074 * Set the path to a file to save this Context information.
1075 *
1076 * @param configFile The path to a file to save this Context information.
1077 */
1078 public void setConfigFile(String configFile) {
1079
1080 this.configFile = configFile;
1081 }
1082
1083
1084 /**
1085 * Return the "correctly configured" flag for this Context.
1086 */
1087 public boolean getConfigured() {
1088
1089 return (this.configured);
1090
1091 }
1092
1093
1094 /**
1095 * Set the "correctly configured" flag for this Context. This can be
1096 * set to false by startup listeners that detect a fatal configuration
1097 * error to avoid the application from being made available.
1098 *
1099 * @param configured The new correctly configured flag
1100 */
1101 public void setConfigured(boolean configured) {
1102
1103 boolean oldConfigured = this.configured;
1104 this.configured = configured;
1105 support.firePropertyChange("configured",
1106 oldConfigured,
1107 this.configured);
1108
1109 }
1110
1111
1112 /**
1113 * Return the "use cookies for session ids" flag.
1114 */
1115 public boolean getCookies() {
1116
1117 return (this.cookies);
1118
1119 }
1120
1121
1122 /**
1123 * Set the "use cookies for session ids" flag.
1124 *
1125 * @param cookies The new flag
1126 */
1127 public void setCookies(boolean cookies) {
1128
1129 boolean oldCookies = this.cookies;
1130 this.cookies = cookies;
1131 support.firePropertyChange("cookies",
1132 oldCookies,
1133 this.cookies);
1134
1135 }
1136
1137 /**
1138 * Gets the value of the use HttpOnly cookies for session cookies flag.
1139 *
1140 * @return <code>true</code> if the HttpOnly flag should be set on session
1141 * cookies
1142 */
1143 public boolean getUseHttpOnly() {
1144 return useHttpOnly;
1145 }
1146
1147
1148 /**
1149 * Sets the use HttpOnly cookies for session cookies flag.
1150 *
1151 * @param useHttpOnly Set to <code>true</code> to use HttpOnly cookies
1152 * for session cookies
1153 */
1154 public void setUseHttpOnly(boolean useHttpOnly) {
1155 boolean oldUseHttpOnly = this.useHttpOnly;
1156 this.useHttpOnly = useHttpOnly;
1157 support.firePropertyChange("useHttpOnly",
1158 oldUseHttpOnly,
1159 this.useHttpOnly);
1160 }
1161
1162
1163
1164
1165 /**
1166 * Return the "allow crossing servlet contexts" flag.
1167 */
1168 public boolean getCrossContext() {
1169
1170 return (this.crossContext);
1171
1172 }
1173
1174
1175 /**
1176 * Set the "allow crossing servlet contexts" flag.
1177 *
1178 * @param crossContext The new cross contexts flag
1179 */
1180 public void setCrossContext(boolean crossContext) {
1181
1182 boolean oldCrossContext = this.crossContext;
1183 this.crossContext = crossContext;
1184 support.firePropertyChange("crossContext",
1185 oldCrossContext,
1186 this.crossContext);
1187
1188 }
1189
1190 public String getDefaultContextXml() {
1191 return defaultContextXml;
1192 }
1193
1194 /**
1195 * Set the location of the default context xml that will be used.
1196 * If not absolute, it'll be made relative to the engine's base dir
1197 * ( which defaults to catalina.base system property ).
1198 *
1199 * @param defaultContextXml The default web xml
1200 */
1201 public void setDefaultContextXml(String defaultContextXml) {
1202 this.defaultContextXml = defaultContextXml;
1203 }
1204
1205 public String getDefaultWebXml() {
1206 return defaultWebXml;
1207 }
1208
1209 /**
1210 * Set the location of the default web xml that will be used.
1211 * If not absolute, it'll be made relative to the engine's base dir
1212 * ( which defaults to catalina.base system property ).
1213 *
1214 * @param defaultWebXml The default web xml
1215 */
1216 public void setDefaultWebXml(String defaultWebXml) {
1217 this.defaultWebXml = defaultWebXml;
1218 }
1219
1220 /**
1221 * Gets the time (in milliseconds) it took to start this context.
1222 *
1223 * @return Time (in milliseconds) it took to start this context.
1224 */
1225 public long getStartupTime() {
1226 return startupTime;
1227 }
1228
1229 public void setStartupTime(long startupTime) {
1230 this.startupTime = startupTime;
1231 }
1232
1233 public long getTldScanTime() {
1234 return tldScanTime;
1235 }
1236
1237 public void setTldScanTime(long tldScanTime) {
1238 this.tldScanTime = tldScanTime;
1239 }
1240
1241 /**
1242 * Return the display name of this web application.
1243 */
1244 public String getDisplayName() {
1245
1246 return (this.displayName);
1247
1248 }
1249
1250
1251 /**
1252 * Return the alternate Deployment Descriptor name.
1253 */
1254 public String getAltDDName(){
1255 return altDDName;
1256 }
1257
1258
1259 /**
1260 * Set an alternate Deployment Descriptor name.
1261 */
1262 public void setAltDDName(String altDDName) {
1263 this.altDDName = altDDName;
1264 if (context != null) {
1265 context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
1266 }
1267 }
1268
1269
1270 /**
1271 * Return the compiler classpath.
1272 */
1273 public String getCompilerClasspath(){
1274 return compilerClasspath;
1275 }
1276
1277
1278 /**
1279 * Set the compiler classpath.
1280 */
1281 public void setCompilerClasspath(String compilerClasspath) {
1282 this.compilerClasspath = compilerClasspath;
1283 }
1284
1285
1286 /**
1287 * Set the display name of this web application.
1288 *
1289 * @param displayName The new display name
1290 */
1291 public void setDisplayName(String displayName) {
1292
1293 String oldDisplayName = this.displayName;
1294 this.displayName = displayName;
1295 support.firePropertyChange("displayName", oldDisplayName,
1296 this.displayName);
1297 }
1298
1299
1300 /**
1301 * Return the distributable flag for this web application.
1302 */
1303 public boolean getDistributable() {
1304
1305 return (this.distributable);
1306
1307 }
1308
1309 /**
1310 * Set the distributable flag for this web application.
1311 *
1312 * @param distributable The new distributable flag
1313 */
1314 public void setDistributable(boolean distributable) {
1315 boolean oldDistributable = this.distributable;
1316 this.distributable = distributable;
1317 support.firePropertyChange("distributable",
1318 oldDistributable,
1319 this.distributable);
1320
1321 // Bugzilla 32866
1322 if(getManager() != null) {
1323 if(log.isDebugEnabled()) {
1324 log.debug("Propagating distributable=" + distributable
1325 + " to manager");
1326 }
1327 getManager().setDistributable(distributable);
1328 }
1329 }
1330
1331
1332 /**
1333 * Return the document root for this Context. This can be an absolute
1334 * pathname, a relative pathname, or a URL.
1335 */
1336 public String getDocBase() {
1337
1338 return (this.docBase);
1339
1340 }
1341
1342
1343 /**
1344 * Set the document root for this Context. This can be an absolute
1345 * pathname, a relative pathname, or a URL.
1346 *
1347 * @param docBase The new document root
1348 */
1349 public void setDocBase(String docBase) {
1350
1351 this.docBase = docBase;
1352
1353 }
1354
1355 // experimental
1356 public boolean isLazy() {
1357 return lazy;
1358 }
1359
1360 public void setLazy(boolean lazy) {
1361 this.lazy = lazy;
1362 }
1363
1364
1365 /**
1366 * Return descriptive information about this Container implementation and
1367 * the corresponding version number, in the format
1368 * <code><description>/<version></code>.
1369 */
1370 public String getInfo() {
1371
1372 return (info);
1373
1374 }
1375
1376 public String getEngineName() {
1377 if( engineName != null ) return engineName;
1378 return domain;
1379 }
1380
1381 public void setEngineName(String engineName) {
1382 this.engineName = engineName;
1383 }
1384
1385 public String getJ2EEApplication() {
1386 return j2EEApplication;
1387 }
1388
1389 public void setJ2EEApplication(String j2EEApplication) {
1390 this.j2EEApplication = j2EEApplication;
1391 }
1392
1393 public String getJ2EEServer() {
1394 return j2EEServer;
1395 }
1396
1397 public void setJ2EEServer(String j2EEServer) {
1398 this.j2EEServer = j2EEServer;
1399 }
1400
1401
1402 /**
1403 * Set the Loader with which this Context is associated.
1404 *
1405 * @param loader The newly associated loader
1406 */
1407 public synchronized void setLoader(Loader loader) {
1408
1409 super.setLoader(loader);
1410
1411 }
1412
1413
1414 /**
1415 * Return the boolean on the annotations parsing.
1416 */
1417 public boolean getIgnoreAnnotations() {
1418 return this.ignoreAnnotations;
1419 }
1420
1421
1422 /**
1423 * Set the boolean on the annotations parsing for this web
1424 * application.
1425 *
1426 * @param ignoreAnnotations The boolean on the annotations parsing
1427 */
1428 public void setIgnoreAnnotations(boolean ignoreAnnotations) {
1429 boolean oldIgnoreAnnotations = this.ignoreAnnotations;
1430 this.ignoreAnnotations = ignoreAnnotations;
1431 support.firePropertyChange("ignoreAnnotations", oldIgnoreAnnotations,
1432 this.ignoreAnnotations);
1433 }
1434
1435
1436 /**
1437 * Return the login configuration descriptor for this web application.
1438 */
1439 public LoginConfig getLoginConfig() {
1440
1441 return (this.loginConfig);
1442
1443 }
1444
1445
1446 /**
1447 * Set the login configuration descriptor for this web application.
1448 *
1449 * @param config The new login configuration
1450 */
1451 public void setLoginConfig(LoginConfig config) {
1452
1453 // Validate the incoming property value
1454 if (config == null)
1455 throw new IllegalArgumentException
1456 (sm.getString("standardContext.loginConfig.required"));
1457 String loginPage = config.getLoginPage();
1458 if ((loginPage != null) && !loginPage.startsWith("/")) {
1459 if (isServlet22()) {
1460 if(log.isDebugEnabled())
1461 log.debug(sm.getString("standardContext.loginConfig.loginWarning",
1462 loginPage));
1463 config.setLoginPage("/" + loginPage);
1464 } else {
1465 throw new IllegalArgumentException
1466 (sm.getString("standardContext.loginConfig.loginPage",
1467 loginPage));
1468 }
1469 }
1470 String errorPage = config.getErrorPage();
1471 if ((errorPage != null) && !errorPage.startsWith("/")) {
1472 if (isServlet22()) {
1473 if(log.isDebugEnabled())
1474 log.debug(sm.getString("standardContext.loginConfig.errorWarning",
1475 errorPage));
1476 config.setErrorPage("/" + errorPage);
1477 } else {
1478 throw new IllegalArgumentException
1479 (sm.getString("standardContext.loginConfig.errorPage",
1480 errorPage));
1481 }
1482 }
1483
1484 // Process the property setting change
1485 LoginConfig oldLoginConfig = this.loginConfig;
1486 this.loginConfig = config;
1487 support.firePropertyChange("loginConfig",
1488 oldLoginConfig, this.loginConfig);
1489
1490 }
1491
1492
1493 /**
1494 * Get the mapper associated with the context.
1495 */
1496 public org.apache.tomcat.util.http.mapper.Mapper getMapper() {
1497 return (mapper);
1498 }
1499
1500
1501 /**
1502 * Return the naming resources associated with this web application.
1503 */
1504 public NamingResources getNamingResources() {
1505
1506 if (namingResources == null) {
1507 setNamingResources(new NamingResources());
1508 }
1509 return (namingResources);
1510
1511 }
1512
1513
1514 /**
1515 * Set the naming resources for this web application.
1516 *
1517 * @param namingResources The new naming resources
1518 */
1519 public void setNamingResources(NamingResources namingResources) {
1520
1521 // Process the property setting change
1522 NamingResources oldNamingResources = this.namingResources;
1523 this.namingResources = namingResources;
1524 namingResources.setContainer(this);
1525 support.firePropertyChange("namingResources",
1526 oldNamingResources, this.namingResources);
1527
1528 }
1529
1530
1531 /**
1532 * Return the context path for this Context.
1533 */
1534 public String getPath() {
1535
1536 return (getName());
1537
1538 }
1539
1540
1541 /**
1542 * Set the context path for this Context.
1543 * <p>
1544 * <b>IMPLEMENTATION NOTE</b>: The context path is used as the "name" of
1545 * a Context, because it must be unique.
1546 *
1547 * @param path The new context path
1548 */
1549 public void setPath(String path) {
1550 // XXX Use host in name
1551 setName(path);
1552
1553 }
1554
1555
1556 /**
1557 * Return the public identifier of the deployment descriptor DTD that is
1558 * currently being parsed.
1559 */
1560 public String getPublicId() {
1561
1562 return (this.publicId);
1563
1564 }
1565
1566
1567 /**
1568 * Set the public identifier of the deployment descriptor DTD that is
1569 * currently being parsed.
1570 *
1571 * @param publicId The public identifier
1572 */
1573 public void setPublicId(String publicId) {
1574
1575 if (log.isDebugEnabled())
1576 log.debug("Setting deployment descriptor public ID to '" +
1577 publicId + "'");
1578
1579 String oldPublicId = this.publicId;
1580 this.publicId = publicId;
1581 support.firePropertyChange("publicId", oldPublicId, publicId);
1582
1583 }
1584
1585
1586 /**
1587 * Return the reloadable flag for this web application.
1588 */
1589 public boolean getReloadable() {
1590
1591 return (this.reloadable);
1592
1593 }
1594
1595
1596 /**
1597 * Return the DefaultContext override flag for this web application.
1598 */
1599 public boolean getOverride() {
1600
1601 return (this.override);
1602
1603 }
1604
1605
1606 /**
1607 * Return the original document root for this Context. This can be an absolute
1608 * pathname, a relative pathname, or a URL.
1609 * Is only set as deployment has change docRoot!
1610 */
1611 public String getOriginalDocBase() {
1612
1613 return (this.originalDocBase);
1614
1615 }
1616
1617 /**
1618 * Set the original document root for this Context. This can be an absolute
1619 * pathname, a relative pathname, or a URL.
1620 *
1621 * @param docBase The orginal document root
1622 */
1623 public void setOriginalDocBase(String docBase) {
1624
1625 this.originalDocBase = docBase;
1626 }
1627
1628
1629 /**
1630 * Return the parent class loader (if any) for this web application.
1631 * This call is meaningful only <strong>after</strong> a Loader has
1632 * been configured.
1633 */
1634 public ClassLoader getParentClassLoader() {
1635 if (parentClassLoader != null)
1636 return (parentClassLoader);
1637 if (getPrivileged()) {
1638 return this.getClass().getClassLoader();
1639 } else if (parent != null) {
1640 return (parent.getParentClassLoader());
1641 }
1642 return (ClassLoader.getSystemClassLoader());
1643 }
1644
1645
1646 /**
1647 * Return the privileged flag for this web application.
1648 */
1649 public boolean getPrivileged() {
1650
1651 return (this.privileged);
1652
1653 }
1654
1655
1656 /**
1657 * Set the privileged flag for this web application.
1658 *
1659 * @param privileged The new privileged flag
1660 */
1661 public void setPrivileged(boolean privileged) {
1662
1663 boolean oldPrivileged = this.privileged;
1664 this.privileged = privileged;
1665 support.firePropertyChange("privileged",
1666 oldPrivileged,
1667 this.privileged);
1668
1669 }
1670
1671
1672 /**
1673 * Set the reloadable flag for this web application.
1674 *
1675 * @param reloadable The new reloadable flag
1676 */
1677 public void setReloadable(boolean reloadable) {
1678
1679 boolean oldReloadable = this.reloadable;
1680 this.reloadable = reloadable;
1681 support.firePropertyChange("reloadable",
1682 oldReloadable,
1683 this.reloadable);
1684
1685 }
1686
1687
1688 /**
1689 * Set the DefaultContext override flag for this web application.
1690 *
1691 * @param override The new override flag
1692 */
1693 public void setOverride(boolean override) {
1694
1695 boolean oldOverride = this.override;
1696 this.override = override;
1697 support.firePropertyChange("override",
1698 oldOverride,
1699 this.override);
1700
1701 }
1702
1703
1704 /**
1705 * Return the "replace welcome files" property.
1706 */
1707 public boolean isReplaceWelcomeFiles() {
1708
1709 return (this.replaceWelcomeFiles);
1710
1711 }
1712
1713
1714 /**
1715 * Set the "replace welcome files" property.
1716 *
1717 * @param replaceWelcomeFiles The new property value
1718 */
1719 public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
1720
1721 boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
1722 this.replaceWelcomeFiles = replaceWelcomeFiles;
1723 support.firePropertyChange("replaceWelcomeFiles",
1724 oldReplaceWelcomeFiles,
1725 this.replaceWelcomeFiles);
1726
1727 }
1728
1729
1730 /**
1731 * Return the servlet context for which this Context is a facade.
1732 */
1733 public ServletContext getServletContext() {
1734
1735 if (context == null) {
1736 context = new ApplicationContext(getBasePath(), this);
1737 if (altDDName != null)
1738 context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
1739 }
1740 return (context.getFacade());
1741
1742 }
1743
1744
1745 /**
1746 * Return the default session timeout (in minutes) for this
1747 * web application.
1748 */
1749 public int getSessionTimeout() {
1750
1751 return (this.sessionTimeout);
1752
1753 }
1754
1755
1756 /**
1757 * Set the default session timeout (in minutes) for this
1758 * web application.
1759 *
1760 * @param timeout The new default session timeout
1761 */
1762 public void setSessionTimeout(int timeout) {
1763
1764 int oldSessionTimeout = this.sessionTimeout;
1765 /*
1766 * SRV.13.4 ("Deployment Descriptor"):
1767 * If the timeout is 0 or less, the container ensures the default
1768 * behaviour of sessions is never to time out.
1769 */
1770 this.sessionTimeout = (timeout == 0) ? -1 : timeout;
1771 support.firePropertyChange("sessionTimeout",
1772 oldSessionTimeout,
1773 this.sessionTimeout);
1774
1775 }
1776
1777
1778 /**
1779 * Return the value of the swallowOutput flag.
1780 */
1781 public boolean getSwallowOutput() {
1782
1783 return (this.swallowOutput);
1784
1785 }
1786
1787
1788 /**
1789 * Set the value of the swallowOutput flag. If set to true, the system.out
1790 * and system.err will be redirected to the logger during a servlet
1791 * execution.
1792 *
1793 * @param swallowOutput The new value
1794 */
1795 public void setSwallowOutput(boolean swallowOutput) {
1796
1797 boolean oldSwallowOutput = this.swallowOutput;
1798 this.swallowOutput = swallowOutput;
1799 support.firePropertyChange("swallowOutput",
1800 oldSwallowOutput,
1801 this.swallowOutput);
1802
1803 }
1804
1805
1806 /**
1807 * Return the value of the unloadDelay flag.
1808 */
1809 public long getUnloadDelay() {
1810
1811 return (this.unloadDelay);
1812
1813 }
1814
1815
1816 /**
1817 * Set the value of the unloadDelay flag, which represents the amount
1818 * of ms that the container will wait when unloading servlets.
1819 * Setting this to a small value may cause more requests to fail
1820 * to complete when stopping a web application.
1821 *
1822 * @param unloadDelay The new value
1823 */
1824 public void setUnloadDelay(long unloadDelay) {
1825
1826 long oldUnloadDelay = this.unloadDelay;
1827 this.unloadDelay = unloadDelay;
1828 support.firePropertyChange("unloadDelay",
1829 Long.valueOf(oldUnloadDelay),
1830 Long.valueOf(this.unloadDelay));
1831
1832 }
1833
1834
1835 /**
1836 * Unpack WAR flag accessor.
1837 */
1838 public boolean getUnpackWAR() {
1839
1840 return (unpackWAR);
1841
1842 }
1843
1844
1845 /**
1846 * Unpack WAR flag mutator.
1847 */
1848 public void setUnpackWAR(boolean unpackWAR) {
1849
1850 this.unpackWAR = unpackWAR;
1851
1852 }
1853
1854 /**
1855 * Return the Java class name of the Wrapper implementation used
1856 * for servlets registered in this Context.
1857 */
1858 public String getWrapperClass() {
1859
1860 return (this.wrapperClassName);
1861
1862 }
1863
1864
1865 /**
1866 * Set the Java class name of the Wrapper implementation used
1867 * for servlets registered in this Context.
1868 *
1869 * @param wrapperClassName The new wrapper class name
1870 *
1871 * @throws IllegalArgumentException if the specified wrapper class
1872 * cannot be found or is not a subclass of StandardWrapper
1873 */
1874 public void setWrapperClass(String wrapperClassName) {
1875
1876 this.wrapperClassName = wrapperClassName;
1877
1878 try {
1879 wrapperClass = Class.forName(wrapperClassName);
1880 if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) {
1881 throw new IllegalArgumentException(
1882 sm.getString("standardContext.invalidWrapperClass",
1883 wrapperClassName));
1884 }
1885 } catch (ClassNotFoundException cnfe) {
1886 throw new IllegalArgumentException(cnfe.getMessage());
1887 }
1888 }
1889
1890
1891 /**
1892 * Set the resources DirContext object with which this Container is
1893 * associated.
1894 *
1895 * @param resources The newly associated DirContext
1896 */
1897 public synchronized void setResources(DirContext resources) {
1898
1899 if (started) {
1900 throw new IllegalStateException
1901 (sm.getString("standardContext.resources.started"));
1902 }
1903
1904 DirContext oldResources = this.webappResources;
1905 if (oldResources == resources)
1906 return;
1907
1908 if (resources instanceof BaseDirContext) {
1909 ((BaseDirContext) resources).setCached(isCachingAllowed());
1910 ((BaseDirContext) resources).setCacheTTL(getCacheTTL());
1911 ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize());
1912 ((BaseDirContext) resources).setCacheObjectMaxSize(
1913 getCacheObjectMaxSize());
1914 }
1915 if (resources instanceof FileDirContext) {
1916 filesystemBased = true;
1917 ((FileDirContext) resources).setCaseSensitive(isCaseSensitive());
1918 ((FileDirContext) resources).setAllowLinking(isAllowLinking());
1919 }
1920 this.webappResources = resources;
1921
1922 // The proxied resources will be refreshed on start
1923 this.resources = null;
1924
1925 support.firePropertyChange("resources", oldResources,
1926 this.webappResources);
1927
1928 }
1929
1930
1931 // ------------------------------------------------------ Public Properties
1932
1933
1934 /**
1935 * Return the Locale to character set mapper class for this Context.
1936 */
1937 public String getCharsetMapperClass() {
1938
1939 return (this.charsetMapperClass);
1940
1941 }
1942
1943
1944 /**
1945 * Set the Locale to character set mapper class for this Context.
1946 *
1947 * @param mapper The new mapper class
1948 */
1949 public void setCharsetMapperClass(String mapper) {
1950
1951 String oldCharsetMapperClass = this.charsetMapperClass;
1952 this.charsetMapperClass = mapper;
1953 support.firePropertyChange("charsetMapperClass",
1954 oldCharsetMapperClass,
1955 this.charsetMapperClass);
1956
1957 }
1958
1959
1960 /** Get the absolute path to the work dir.
1961 * To avoid duplication.
1962 *
1963 * @return The work path
1964 */
1965 public String getWorkPath() {
1966 if (getWorkDir() == null) {
1967 return null;
1968 }
1969 File workDir = new File(getWorkDir());
1970 if (!workDir.isAbsolute()) {
1971 File catalinaHome = engineBase();
1972 String catalinaHomePath = null;
1973 try {
1974 catalinaHomePath = catalinaHome.getCanonicalPath();
1975 workDir = new File(catalinaHomePath,
1976 getWorkDir());
1977 } catch (IOException e) {
1978 log.warn("Exception obtaining work path for " + getPath());
1979 }
1980 }
1981 return workDir.getAbsolutePath();
1982 }
1983
1984 /**
1985 * Return the work directory for this Context.
1986 */
1987 public String getWorkDir() {
1988
1989 return (this.workDir);
1990
1991 }
1992
1993
1994 /**
1995 * Set the work directory for this Context.
1996 *
1997 * @param workDir The new work directory
1998 */
1999 public void setWorkDir(String workDir) {
2000
2001 this.workDir = workDir;
2002
2003 if (started) {
2004 postWorkDirectory();
2005 }
2006 }
2007
2008
2009 /**
2010 * Save config ?
2011 */
2012 public boolean isSaveConfig() {
2013 return saveConfig;
2014 }
2015
2016
2017 /**
2018 * Set save config flag.
2019 */
2020 public void setSaveConfig(boolean saveConfig) {
2021 this.saveConfig = saveConfig;
2022 }
2023
2024
2025 /**
2026 * Return the clearReferencesStopThreads flag for this Context.
2027 */
2028 public boolean getClearReferencesStopThreads() {
2029
2030 return (this.clearReferencesStopThreads);
2031
2032 }
2033
2034
2035 /**
2036 * Set the clearReferencesStopThreads feature for this Context.
2037 *
2038 * @param clearReferencesStopThreads The new flag value
2039 */
2040 public void setClearReferencesStopThreads(
2041 boolean clearReferencesStopThreads) {
2042
2043 boolean oldClearReferencesStopThreads = this.clearReferencesStopThreads;
2044 this.clearReferencesStopThreads = clearReferencesStopThreads;
2045 support.firePropertyChange("clearReferencesStopThreads",
2046 oldClearReferencesStopThreads,
2047 this.clearReferencesStopThreads);
2048
2049 }
2050
2051
2052 // -------------------------------------------------------- Context Methods
2053
2054
2055 /**
2056 * Add a new Listener class name to the set of Listeners
2057 * configured for this application.
2058 *
2059 * @param listener Java class name of a listener class
2060 */
2061 public void addApplicationListener(String listener) {
2062
2063 synchronized (applicationListenersLock) {
2064 String results[] =new String[applicationListeners.length + 1];
2065 for (int i = 0; i < applicationListeners.length; i++) {
2066 if (listener.equals(applicationListeners[i])) {
2067 log.info(sm.getString(
2068 "standardContext.duplicateListener",listener));
2069 return;
2070 }
2071 results[i] = applicationListeners[i];
2072 }
2073 results[applicationListeners.length] = listener;
2074 applicationListeners = results;
2075 }
2076 fireContainerEvent("addApplicationListener", listener);
2077
2078 // FIXME - add instance if already started?
2079
2080 }
2081
2082
2083 /**
2084 * Add a new application parameter for this application.
2085 *
2086 * @param parameter The new application parameter
2087 */
2088 public void addApplicationParameter(ApplicationParameter parameter) {
2089
2090 synchronized (applicationParametersLock) {
2091 String newName = parameter.getName();
2092 for (int i = 0; i < applicationParameters.length; i++) {
2093 if (newName.equals(applicationParameters[i].getName()) &&
2094 !applicationParameters[i].getOverride())
2095 return;
2096 }
2097 ApplicationParameter results[] =
2098 new ApplicationParameter[applicationParameters.length + 1];
2099 System.arraycopy(applicationParameters, 0, results, 0,
2100 applicationParameters.length);
2101 results[applicationParameters.length] = parameter;
2102 applicationParameters = results;
2103 }
2104 fireContainerEvent("addApplicationParameter", parameter);
2105
2106 }
2107
2108
2109 /**
2110 * Add a child Container, only if the proposed child is an implementation
2111 * of Wrapper.
2112 *
2113 * @param child Child container to be added
2114 *
2115 * @exception IllegalArgumentException if the proposed container is
2116 * not an implementation of Wrapper
2117 */
2118 public void addChild(Container child) {
2119
2120 // Global JspServlet
2121 Wrapper oldJspServlet = null;
2122
2123 if (!(child instanceof Wrapper)) {
2124 throw new IllegalArgumentException
2125 (sm.getString("standardContext.notWrapper"));
2126 }
2127
2128 Wrapper wrapper = (Wrapper) child;
2129 boolean isJspServlet = "jsp".equals(child.getName());
2130
2131 // Allow webapp to override JspServlet inherited from global web.xml.
2132 if (isJspServlet) {
2133 oldJspServlet = (Wrapper) findChild("jsp");
2134 if (oldJspServlet != null) {
2135 removeChild(oldJspServlet);
2136 }
2137 }
2138
2139 String jspFile = wrapper.getJspFile();
2140 if ((jspFile != null) && !jspFile.startsWith("/")) {
2141 if (isServlet22()) {
2142 if(log.isDebugEnabled())
2143 log.debug(sm.getString("standardContext.wrapper.warning",
2144 jspFile));
2145 wrapper.setJspFile("/" + jspFile);
2146 } else {
2147 throw new IllegalArgumentException
2148 (sm.getString("standardContext.wrapper.error", jspFile));
2149 }
2150 }
2151
2152 super.addChild(child);
2153
2154 if (isJspServlet && oldJspServlet != null) {
2155 /*
2156 * The webapp-specific JspServlet inherits all the mappings
2157 * specified in the global web.xml, and may add additional ones.
2158 */
2159 String[] jspMappings = oldJspServlet.findMappings();
2160 for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
2161 addServletMapping(jspMappings[i], child.getName());
2162 }
2163 }
2164 }
2165
2166
2167 /**
2168 * Add a security constraint to the set for this web application.
2169 */
2170 public void addConstraint(SecurityConstraint constraint) {
2171
2172 // Validate the proposed constraint
2173 SecurityCollection collections[] = constraint.findCollections();
2174 for (int i = 0; i < collections.length; i++) {
2175 String patterns[] = collections[i].findPatterns();
2176 for (int j = 0; j < patterns.length; j++) {
2177 patterns[j] = adjustURLPattern(patterns[j]);
2178 if (!validateURLPattern(patterns[j]))
2179 throw new IllegalArgumentException
2180 (sm.getString
2181 ("standardContext.securityConstraint.pattern",
2182 patterns[j]));
2183 }
2184 }
2185
2186 // Add this constraint to the set for our web application
2187 synchronized (constraintsLock) {
2188 SecurityConstraint results[] =
2189 new SecurityConstraint[constraints.length + 1];
2190 for (int i = 0; i < constraints.length; i++)
2191 results[i] = constraints[i];
2192 results[constraints.length] = constraint;
2193 constraints = results;
2194 }
2195
2196 }
2197
2198
2199
2200 /**
2201 * Add an error page for the specified error or Java exception.
2202 *
2203 * @param errorPage The error page definition to be added
2204 */
2205 public void addErrorPage(ErrorPage errorPage) {
2206 // Validate the input parameters
2207 if (errorPage == null)
2208 throw new IllegalArgumentException
2209 (sm.getString("standardContext.errorPage.required"));
2210 String location = errorPage.getLocation();
2211 if ((location != null) && !location.startsWith("/")) {
2212 if (isServlet22()) {
2213 if(log.isDebugEnabled())
2214 log.debug(sm.getString("standardContext.errorPage.warning",
2215 location));
2216 errorPage.setLocation("/" + location);
2217 } else {
2218 throw new IllegalArgumentException
2219 (sm.getString("standardContext.errorPage.error",
2220 location));
2221 }
2222 }
2223
2224 // Add the specified error page to our internal collections
2225 String exceptionType = errorPage.getExceptionType();
2226 if (exceptionType != null) {
2227 synchronized (exceptionPages) {
2228 exceptionPages.put(exceptionType, errorPage);
2229 }
2230 } else {
2231 synchronized (statusPages) {
2232 if (errorPage.getErrorCode() == 200) {
2233 this.okErrorPage = errorPage;
2234 }
2235 statusPages.put(Integer.valueOf(errorPage.getErrorCode()),
2236 errorPage);
2237 }
2238 }
2239 fireContainerEvent("addErrorPage", errorPage);
2240
2241 }
2242
2243
2244 /**
2245 * Add a filter definition to this Context.
2246 *
2247 * @param filterDef The filter definition to be added
2248 */
2249 public void addFilterDef(FilterDef filterDef) {
2250
2251 synchronized (filterDefs) {
2252 filterDefs.put(filterDef.getFilterName(), filterDef);
2253 }
2254 fireContainerEvent("addFilterDef", filterDef);
2255
2256 }
2257
2258
2259 /**
2260 * Add a filter mapping to this Context.
2261 *
2262 * @param filterMap The filter mapping to be added
2263 *
2264 * @exception IllegalArgumentException if the specified filter name
2265 * does not match an existing filter definition, or the filter mapping
2266 * is malformed
2267 */
2268 public void addFilterMap(FilterMap filterMap) {
2269
2270 // Validate the proposed filter mapping
2271 String filterName = filterMap.getFilterName();
2272 String[] servletNames = filterMap.getServletNames();
2273 String[] urlPatterns = filterMap.getURLPatterns();
2274 if (findFilterDef(filterName) == null)
2275 throw new IllegalArgumentException
2276 (sm.getString("standardContext.filterMap.name", filterName));
2277 // <= Servlet API 2.4
2278 // if ((servletNames.length == 0) && (urlPatterns.length == 0))
2279 // Servlet API 2.5 (FIX 43338)
2280 // SRV 6.2.5 says supporting for '*' as the servlet-name in filter-mapping.
2281 if (!filterMap.getMatchAllServletNames() &&
2282 !filterMap.getMatchAllUrlPatterns() &&
2283 (servletNames.length == 0) && (urlPatterns.length == 0))
2284 throw new IllegalArgumentException
2285 (sm.getString("standardContext.filterMap.either"));
2286 // FIXME: Older spec revisions may still check this
2287 /*
2288 if ((servletNames.length != 0) && (urlPatterns.length != 0))
2289 throw new IllegalArgumentException
2290 (sm.getString("standardContext.filterMap.either"));
2291 */
2292 // Because filter-pattern is new in 2.3, no need to adjust
2293 // for 2.2 backwards compatibility
2294 for (int i = 0; i < urlPatterns.length; i++) {
2295 if (!validateURLPattern(urlPatterns[i])) {
2296 throw new IllegalArgumentException
2297 (sm.getString("standardContext.filterMap.pattern",
2298 urlPatterns[i]));
2299 }
2300 }
2301
2302 // Add this filter mapping to our registered set
2303 synchronized (filterMaps) {
2304 FilterMap results[] =new FilterMap[filterMaps.length + 1];
2305 System.arraycopy(filterMaps, 0, results, 0, filterMaps.length);
2306 results[filterMaps.length] = filterMap;
2307 filterMaps = results;
2308 }
2309 fireContainerEvent("addFilterMap", filterMap);
2310
2311 }
2312
2313
2314 /**
2315 * Add the classname of an InstanceListener to be added to each
2316 * Wrapper appended to this Context.
2317 *
2318 * @param listener Java class name of an InstanceListener class
2319 */
2320 public void addInstanceListener(String listener) {
2321
2322 synchronized (instanceListenersLock) {
2323 String results[] =new String[instanceListeners.length + 1];
2324 for (int i = 0; i < instanceListeners.length; i++)
2325 results[i] = instanceListeners[i];
2326 results[instanceListeners.length] = listener;
2327 instanceListeners = results;
2328 }
2329 fireContainerEvent("addInstanceListener", listener);
2330
2331 }
2332
2333 /**
2334 * Add the given URL pattern as a jsp-property-group. This maps
2335 * resources that match the given pattern so they will be passed
2336 * to the JSP container. Though there are other elements in the
2337 * property group, we only care about the URL pattern here. The
2338 * JSP container will parse the rest.
2339 *
2340 * @param pattern URL pattern to be mapped
2341 */
2342 public void addJspMapping(String pattern) {
2343 String servletName = findServletMapping("*.jsp");
2344 if (servletName == null) {
2345 servletName = "jsp";
2346 }
2347
2348 if( findChild(servletName) != null) {
2349 addServletMapping(pattern, servletName, true);
2350 } else {
2351 if(log.isDebugEnabled())
2352 log.debug("Skiping " + pattern + " , no servlet " + servletName);
2353 }
2354 }
2355
2356
2357 /**
2358 * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
2359 *
2360 * @param locale locale to map an encoding for
2361 * @param encoding encoding to be used for a give locale
2362 */
2363 public void addLocaleEncodingMappingParameter(String locale, String encoding){
2364 getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding);
2365 }
2366
2367
2368 /**
2369 * Add a message destination for this web application.
2370 *
2371 * @param md New message destination
2372 */
2373 public void addMessageDestination(MessageDestination md) {
2374
2375 synchronized (messageDestinations) {
2376 messageDestinations.put(md.getName(), md);
2377 }
2378 fireContainerEvent("addMessageDestination", md.getName());
2379
2380 }
2381
2382
2383 /**
2384 * Add a message destination reference for this web application.
2385 *
2386 * @param mdr New message destination reference
2387 */
2388 public void addMessageDestinationRef
2389 (MessageDestinationRef mdr) {
2390
2391 namingResources.addMessageDestinationRef(mdr);
2392 fireContainerEvent("addMessageDestinationRef", mdr.getName());
2393
2394 }
2395
2396
2397 /**
2398 * Add a new MIME mapping, replacing any existing mapping for
2399 * the specified extension.
2400 *
2401 * @param extension Filename extension being mapped
2402 * @param mimeType Corresponding MIME type
2403 */
2404 public void addMimeMapping(String extension, String mimeType) {
2405
2406 synchronized (mimeMappings) {
2407 mimeMappings.put(extension, mimeType);
2408 }
2409 fireContainerEvent("addMimeMapping", extension);
2410
2411 }
2412
2413
2414 /**
2415 * Add a new context initialization parameter.
2416 *
2417 * @param name Name of the new parameter
2418 * @param value Value of the new parameter
2419 *
2420 * @exception IllegalArgumentException if the name or value is missing,
2421 * or if this context initialization parameter has already been
2422 * registered
2423 */
2424 public void addParameter(String name, String value) {
2425 // Validate the proposed context initialization parameter
2426 if ((name == null) || (value == null))
2427 throw new IllegalArgumentException
2428 (sm.getString("standardContext.parameter.required"));
2429 if (parameters.get(name) != null)
2430 throw new IllegalArgumentException
2431 (sm.getString("standardContext.parameter.duplicate", name));
2432
2433 // Add this parameter to our defined set
2434 synchronized (parameters) {
2435 parameters.put(name, value);
2436 }
2437 fireContainerEvent("addParameter", name);
2438
2439 }
2440
2441
2442 /**
2443 * Add a security role reference for this web application.
2444 *
2445 * @param role Security role used in the application
2446 * @param link Actual security role to check for
2447 */
2448 public void addRoleMapping(String role, String link) {
2449
2450 synchronized (roleMappings) {
2451 roleMappings.put(role, link);
2452 }
2453 fireContainerEvent("addRoleMapping", role);
2454
2455 }
2456
2457
2458 /**
2459 * Add a new security role for this web application.
2460 *
2461 * @param role New security role
2462 */
2463 public void addSecurityRole(String role) {
2464
2465 synchronized (securityRolesLock) {
2466 String results[] =new String[securityRoles.length + 1];
2467 for (int i = 0; i < securityRoles.length; i++)
2468 results[i] = securityRoles[i];
2469 results[securityRoles.length] = role;
2470 securityRoles = results;
2471 }
2472 fireContainerEvent("addSecurityRole", role);
2473
2474 }
2475
2476
2477 /**
2478 * Add a new servlet mapping, replacing any existing mapping for
2479 * the specified pattern.
2480 *
2481 * @param pattern URL pattern to be mapped
2482 * @param name Name of the corresponding servlet to execute
2483 *
2484 * @exception IllegalArgumentException if the specified servlet name
2485 * is not known to this Context
2486 */
2487 public void addServletMapping(String pattern, String name) {
2488 addServletMapping(pattern, name, false);
2489 }
2490
2491
2492 /**
2493 * Add a new servlet mapping, replacing any existing mapping for
2494 * the specified pattern.
2495 *
2496 * @param pattern URL pattern to be mapped
2497 * @param name Name of the corresponding servlet to execute
2498 * @param jspWildCard true if name identifies the JspServlet
2499 * and pattern contains a wildcard; false otherwise
2500 *
2501 * @exception IllegalArgumentException if the specified servlet name
2502 * is not known to this Context
2503 */
2504 public void addServletMapping(String pattern, String name,
2505 boolean jspWildCard) {
2506 // Validate the proposed mapping
2507 if (findChild(name) == null)
2508 throw new IllegalArgumentException
2509 (sm.getString("standardContext.servletMap.name", name));
2510 pattern = adjustURLPattern(RequestUtil.URLDecode(pattern));
2511 if (!validateURLPattern(pattern))
2512 throw new IllegalArgumentException
2513 (sm.getString("standardContext.servletMap.pattern", pattern));
2514
2515 // Add this mapping to our registered set
2516 synchronized (servletMappingsLock) {
2517 String name2 = (String) servletMappings.get(pattern);
2518 if (name2 != null) {
2519 // Don't allow more than one servlet on the same pattern
2520 Wrapper wrapper = (Wrapper) findChild(name2);
2521 wrapper.removeMapping(pattern);
2522 mapper.removeWrapper(pattern);
2523 }
2524 servletMappings.put(pattern, name);
2525 }
2526 Wrapper wrapper = (Wrapper) findChild(name);
2527 wrapper.addMapping(pattern);
2528
2529 // Update context mapper
2530 mapper.addWrapper(pattern, wrapper, jspWildCard);
2531
2532 fireContainerEvent("addServletMapping", pattern);
2533
2534 }
2535
2536
2537 /**
2538 * Add a JSP tag library for the specified URI.
2539 *
2540 * @param uri URI, relative to the web.xml file, of this tag library
2541 * @param location Location of the tag library descriptor
2542 */
2543 public void addTaglib(String uri, String location) {
2544
2545 synchronized (taglibs) {
2546 taglibs.put(uri, location);
2547 }
2548 fireContainerEvent("addTaglib", uri);
2549
2550 }
2551
2552
2553 /**
2554 * Add a new watched resource to the set recognized by this Context.
2555 *
2556 * @param name New watched resource file name
2557 */
2558 public void addWatchedResource(String name) {
2559
2560 synchronized (watchedResourcesLock) {
2561 String results[] = new String[watchedResources.length + 1];
2562 for (int i = 0; i < watchedResources.length; i++)
2563 results[i] = watchedResources[i];
2564 results[watchedResources.length] = name;
2565 watchedResources = results;
2566 }
2567 fireContainerEvent("addWatchedResource", name);
2568
2569 }
2570
2571
2572 /**
2573 * Add a new welcome file to the set recognized by this Context.
2574 *
2575 * @param name New welcome file name
2576 */
2577 public void addWelcomeFile(String name) {
2578
2579 synchronized (welcomeFilesLock) {
2580 // Welcome files from the application deployment descriptor
2581 // completely replace those from the default conf/web.xml file
2582 if (replaceWelcomeFiles) {
2583 welcomeFiles = new String[0];
2584 setReplaceWelcomeFiles(false);
2585 }
2586 String results[] =new String[welcomeFiles.length + 1];
2587 for (int i = 0; i < welcomeFiles.length; i++)
2588 results[i] = welcomeFiles[i];
2589 results[welcomeFiles.length] = name;
2590 welcomeFiles = results;
2591 }
2592 postWelcomeFiles();
2593 fireContainerEvent("addWelcomeFile", name);
2594
2595 }
2596
2597
2598 /**
2599 * Add the classname of a LifecycleListener to be added to each
2600 * Wrapper appended to this Context.
2601 *
2602 * @param listener Java class name of a LifecycleListener class
2603 */
2604 public void addWrapperLifecycle(String listener) {
2605
2606 synchronized (wrapperLifecyclesLock) {
2607 String results[] =new String[wrapperLifecycles.length + 1];
2608 for (int i = 0; i < wrapperLifecycles.length; i++)
2609 results[i] = wrapperLifecycles[i];
2610 results[wrapperLifecycles.length] = listener;
2611 wrapperLifecycles = results;
2612 }
2613 fireContainerEvent("addWrapperLifecycle", listener);
2614
2615 }
2616
2617
2618 /**
2619 * Add the classname of a ContainerListener to be added to each
2620 * Wrapper appended to this Context.
2621 *
2622 * @param listener Java class name of a ContainerListener class
2623 */
2624 public void addWrapperListener(String listener) {
2625
2626 synchronized (wrapperListenersLock) {
2627 String results[] =new String[wrapperListeners.length + 1];
2628 for (int i = 0; i < wrapperListeners.length; i++)
2629 results[i] = wrapperListeners[i];
2630 results[wrapperListeners.length] = listener;
2631 wrapperListeners = results;
2632 }
2633 fireContainerEvent("addWrapperListener", listener);
2634
2635 }
2636
2637
2638 /**
2639 * Factory method to create and return a new Wrapper instance, of
2640 * the Java implementation class appropriate for this Context
2641 * implementation. The constructor of the instantiated Wrapper
2642 * will have been called, but no properties will have been set.
2643 */
2644 public Wrapper createWrapper() {
2645
2646 Wrapper wrapper = null;
2647 if (wrapperClass != null) {
2648 try {
2649 wrapper = (Wrapper) wrapperClass.newInstance();
2650 } catch (Throwable t) {
2651 log.error("createWrapper", t);
2652 return (null);
2653 }
2654 } else {
2655 wrapper = new StandardWrapper();
2656 }
2657
2658 synchronized (instanceListenersLock) {
2659 for (int i = 0; i < instanceListeners.length; i++) {
2660 try {
2661 Class clazz = Class.forName(instanceListeners[i]);
2662 InstanceListener listener =
2663 (InstanceListener) clazz.newInstance();
2664 wrapper.addInstanceListener(listener);
2665 } catch (Throwable t) {
2666 log.error("createWrapper", t);
2667 return (null);
2668 }
2669 }
2670 }
2671
2672 synchronized (wrapperLifecyclesLock) {
2673 for (int i = 0; i < wrapperLifecycles.length; i++) {
2674 try {
2675 Class clazz = Class.forName(wrapperLifecycles[i]);
2676 LifecycleListener listener =
2677 (LifecycleListener) clazz.newInstance();
2678 if (wrapper instanceof Lifecycle)
2679 ((Lifecycle) wrapper).addLifecycleListener(listener);
2680 } catch (Throwable t) {
2681 log.error("createWrapper", t);
2682 return (null);
2683 }
2684 }
2685 }
2686
2687 synchronized (wrapperListenersLock) {
2688 for (int i = 0; i < wrapperListeners.length; i++) {
2689 try {
2690 Class clazz = Class.forName(wrapperListeners[i]);
2691 ContainerListener listener =
2692 (ContainerListener) clazz.newInstance();
2693 wrapper.addContainerListener(listener);
2694 } catch (Throwable t) {
2695 log.error("createWrapper", t);
2696 return (null);
2697 }
2698 }
2699 }
2700
2701 return (wrapper);
2702
2703 }
2704
2705
2706 /**
2707 * Return the set of application listener class names configured
2708 * for this application.
2709 */
2710 public String[] findApplicationListeners() {
2711
2712 return (applicationListeners);
2713
2714 }
2715
2716
2717 /**
2718 * Return the set of application parameters for this application.
2719 */
2720 public ApplicationParameter[] findApplicationParameters() {
2721
2722 synchronized (applicationParametersLock) {
2723 return (applicationParameters);
2724 }
2725
2726 }
2727
2728
2729 /**
2730 * Return the security constraints for this web application.
2731 * If there are none, a zero-length array is returned.
2732 */
2733 public SecurityConstraint[] findConstraints() {
2734
2735 return (constraints);
2736
2737 }
2738
2739
2740 /**
2741 * Return the error page entry for the specified HTTP error code,
2742 * if any; otherwise return <code>null</code>.
2743 *
2744 * @param errorCode Error code to look up
2745 */
2746 public ErrorPage findErrorPage(int errorCode) {
2747 if (errorCode == 200) {
2748 return (okErrorPage);
2749 } else {
2750 return ((ErrorPage) statusPages.get(new Integer(errorCode)));
2751 }
2752
2753 }
2754
2755
2756 /**
2757 * Return the error page entry for the specified Java exception type,
2758 * if any; otherwise return <code>null</code>.
2759 *
2760 * @param exceptionType Exception type to look up
2761 */
2762 public ErrorPage findErrorPage(String exceptionType) {
2763
2764 synchronized (exceptionPages) {
2765 return ((ErrorPage) exceptionPages.get(exceptionType));
2766 }
2767
2768 }
2769
2770
2771 /**
2772 * Return the set of defined error pages for all specified error codes
2773 * and exception types.
2774 */
2775 public ErrorPage[] findErrorPages() {
2776
2777 synchronized(exceptionPages) {
2778 synchronized(statusPages) {
2779 ErrorPage results1[] = new ErrorPage[exceptionPages.size()];
2780 results1 =
2781 (ErrorPage[]) exceptionPages.values().toArray(results1);
2782 ErrorPage results2[] = new ErrorPage[statusPages.size()];
2783 results2 =
2784 (ErrorPage[]) statusPages.values().toArray(results2);
2785 ErrorPage results[] =
2786 new ErrorPage[results1.length + results2.length];
2787 for (int i = 0; i < results1.length; i++)
2788 results[i] = results1[i];
2789 for (int i = results1.length; i < results.length; i++)
2790 results[i] = results2[i - results1.length];
2791 return (results);
2792 }
2793 }
2794
2795 }
2796
2797
2798 /**
2799 * Return the filter definition for the specified filter name, if any;
2800 * otherwise return <code>null</code>.
2801 *
2802 * @param filterName Filter name to look up
2803 */
2804 public FilterDef findFilterDef(String filterName) {
2805
2806 synchronized (filterDefs) {
2807 return ((FilterDef) filterDefs.get(filterName));
2808 }
2809
2810 }
2811
2812
2813 /**
2814 * Return the set of defined filters for this Context.
2815 */
2816 public FilterDef[] findFilterDefs() {
2817
2818 synchronized (filterDefs) {
2819 FilterDef results[] = new FilterDef[filterDefs.size()];
2820 return ((FilterDef[]) filterDefs.values().toArray(results));
2821 }
2822
2823 }
2824
2825
2826 /**
2827 * Return the set of filter mappings for this Context.
2828 */
2829 public FilterMap[] findFilterMaps() {
2830
2831 return (filterMaps);
2832
2833 }
2834
2835
2836 /**
2837 * Return the set of InstanceListener classes that will be added to
2838 * newly created Wrappers automatically.
2839 */
2840 public String[] findInstanceListeners() {
2841
2842 synchronized (instanceListenersLock) {
2843 return (instanceListeners);
2844 }
2845
2846 }
2847
2848
2849 /**
2850 * FIXME: Fooling introspection ...
2851 */
2852 public Context findMappingObject() {
2853 return (Context) getMappingObject();
2854 }
2855
2856
2857 /**
2858 * Return the message destination with the specified name, if any;
2859 * otherwise, return <code>null</code>.
2860 *
2861 * @param name Name of the desired message destination
2862 */
2863 public MessageDestination findMessageDestination(String name) {
2864
2865 synchronized (messageDestinations) {
2866 return ((MessageDestination) messageDestinations.get(name));
2867 }
2868
2869 }
2870
2871
2872 /**
2873 * Return the set of defined message destinations for this web
2874 * application. If none have been defined, a zero-length array
2875 * is returned.
2876 */
2877 public MessageDestination[] findMessageDestinations() {
2878
2879 synchronized (messageDestinations) {
2880 MessageDestination results[] =
2881 new MessageDestination[messageDestinations.size()];
2882 return ((MessageDestination[])
2883 messageDestinations.values().toArray(results));
2884 }
2885
2886 }
2887
2888
2889 /**
2890 * Return the message destination ref with the specified name, if any;
2891 * otherwise, return <code>null</code>.
2892 *
2893 * @param name Name of the desired message destination ref
2894 */
2895 public MessageDestinationRef
2896 findMessageDestinationRef(String name) {
2897
2898 return namingResources.findMessageDestinationRef(name);
2899
2900 }
2901
2902
2903 /**
2904 * Return the set of defined message destination refs for this web
2905 * application. If none have been defined, a zero-length array
2906 * is returned.
2907 */
2908 public MessageDestinationRef[]
2909 findMessageDestinationRefs() {
2910
2911 return namingResources.findMessageDestinationRefs();
2912
2913 }
2914
2915
2916 /**
2917 * Return the MIME type to which the specified extension is mapped,
2918 * if any; otherwise return <code>null</code>.
2919 *
2920 * @param extension Extension to map to a MIME type
2921 */
2922 public String findMimeMapping(String extension) {
2923
2924 return ((String) mimeMappings.get(extension));
2925
2926 }
2927
2928
2929 /**
2930 * Return the extensions for which MIME mappings are defined. If there
2931 * are none, a zero-length array is returned.
2932 */
2933 public String[] findMimeMappings() {
2934
2935 synchronized (mimeMappings) {
2936 String results[] = new String[mimeMappings.size()];
2937 return
2938 ((String[]) mimeMappings.keySet().toArray(results));
2939 }
2940
2941 }
2942
2943
2944 /**
2945 * Return the value for the specified context initialization
2946 * parameter name, if any; otherwise return <code>null</code>.
2947 *
2948 * @param name Name of the parameter to return
2949 */
2950 public String findParameter(String name) {
2951
2952 synchronized (parameters) {
2953 return ((String) parameters.get(name));
2954 }
2955
2956 }
2957
2958
2959 /**
2960 * Return the names of all defined context initialization parameters
2961 * for this Context. If no parameters are defined, a zero-length
2962 * array is returned.
2963 */
2964 public String[] findParameters() {
2965
2966 synchronized (parameters) {
2967 String results[] = new String[parameters.size()];
2968 return ((String[]) parameters.keySet().toArray(results));
2969 }
2970
2971 }
2972
2973
2974 /**
2975 * For the given security role (as used by an application), return the
2976 * corresponding role name (as defined by the underlying Realm) if there
2977 * is one. Otherwise, return the specified role unchanged.
2978 *
2979 * @param role Security role to map
2980 */
2981 public String findRoleMapping(String role) {
2982
2983 String realRole = null;
2984 synchronized (roleMappings) {
2985 realRole = (String) roleMappings.get(role);
2986 }
2987 if (realRole != null)
2988 return (realRole);
2989 else
2990 return (role);
2991
2992 }
2993
2994
2995 /**
2996 * Return <code>true</code> if the specified security role is defined
2997 * for this application; otherwise return <code>false</code>.
2998 *
2999 * @param role Security role to verify
3000 */
3001 public boolean findSecurityRole(String role) {
3002
3003 synchronized (securityRolesLock) {
3004 for (int i = 0; i < securityRoles.length; i++) {
3005 if (role.equals(securityRoles[i]))
3006 return (true);
3007 }
3008 }
3009 return (false);
3010
3011 }
3012
3013
3014 /**
3015 * Return the security roles defined for this application. If none
3016 * have been defined, a zero-length array is returned.
3017 */
3018 public String[] findSecurityRoles() {
3019
3020 synchronized (securityRolesLock) {
3021 return (securityRoles);
3022 }
3023
3024 }
3025
3026
3027 /**
3028 * Return the servlet name mapped by the specified pattern (if any);
3029 * otherwise return <code>null</code>.
3030 *
3031 * @param pattern Pattern for which a mapping is requested
3032 */
3033 public String findServletMapping(String pattern) {
3034
3035 synchronized (servletMappingsLock) {
3036 return ((String) servletMappings.get(pattern));
3037 }
3038
3039 }
3040
3041
3042 /**
3043 * Return the patterns of all defined servlet mappings for this
3044 * Context. If no mappings are defined, a zero-length array is returned.
3045 */
3046 public String[] findServletMappings() {
3047
3048 synchronized (servletMappingsLock) {
3049 String results[] = new String[servletMappings.size()];
3050 return
3051 ((String[]) servletMappings.keySet().toArray(results));
3052 }
3053
3054 }
3055
3056
3057 /**
3058 * Return the context-relative URI of the error page for the specified
3059 * HTTP status code, if any; otherwise return <code>null</code>.
3060 *
3061 * @param status HTTP status code to look up
3062 */
3063 public String findStatusPage(int status) {
3064
3065 ErrorPage errorPage = (ErrorPage)statusPages.get(new Integer(status));
3066 if (errorPage!=null) {
3067 return errorPage.getLocation();
3068 }
3069 return null;
3070
3071 }
3072
3073
3074 /**
3075 * Return the set of HTTP status codes for which error pages have
3076 * been specified. If none are specified, a zero-length array
3077 * is returned.
3078 */
3079 public int[] findStatusPages() {
3080
3081 synchronized (statusPages) {
3082 int results[] = new int[statusPages.size()];
3083 Iterator elements = statusPages.keySet().iterator();
3084 int i = 0;
3085 while (elements.hasNext())
3086 results[i++] = ((Integer) elements.next()).intValue();
3087 return (results);
3088 }
3089
3090 }
3091
3092
3093 /**
3094 * Return the tag library descriptor location for the specified taglib
3095 * URI, if any; otherwise, return <code>null</code>.
3096 *
3097 * @param uri URI, relative to the web.xml file
3098 */
3099 public String findTaglib(String uri) {
3100
3101 synchronized (taglibs) {
3102 return ((String) taglibs.get(uri));
3103 }
3104
3105 }
3106
3107
3108 /**
3109 * Return the URIs of all tag libraries for which a tag library
3110 * descriptor location has been specified. If none are specified,
3111 * a zero-length array is returned.
3112 */
3113 public String[] findTaglibs() {
3114
3115 synchronized (taglibs) {
3116 String results[] = new String[taglibs.size()];
3117 return ((String[]) taglibs.keySet().toArray(results));
3118 }
3119
3120 }
3121
3122
3123 /**
3124 * Return <code>true</code> if the specified welcome file is defined
3125 * for this Context; otherwise return <code>false</code>.
3126 *
3127 * @param name Welcome file to verify
3128 */
3129 public boolean findWelcomeFile(String name) {
3130
3131 synchronized (welcomeFilesLock) {
3132 for (int i = 0; i < welcomeFiles.length; i++) {
3133 if (name.equals(welcomeFiles[i]))
3134 return (true);
3135 }
3136 }
3137 return (false);
3138
3139 }
3140
3141
3142 /**
3143 * Return the set of watched resources for this Context. If none are
3144 * defined, a zero length array will be returned.
3145 */
3146 public String[] findWatchedResources() {
3147 synchronized (watchedResourcesLock) {
3148 return watchedResources;
3149 }
3150 }
3151
3152
3153 /**
3154 * Return the set of welcome files defined for this Context. If none are
3155 * defined, a zero-length array is returned.
3156 */
3157 public String[] findWelcomeFiles() {
3158
3159 synchronized (welcomeFilesLock) {
3160 return (welcomeFiles);
3161 }
3162
3163 }
3164
3165
3166 /**
3167 * Return the set of LifecycleListener classes that will be added to
3168 * newly created Wrappers automatically.
3169 */
3170 public String[] findWrapperLifecycles() {
3171
3172 synchronized (wrapperLifecyclesLock) {
3173 return (wrapperLifecycles);
3174 }
3175
3176 }
3177
3178
3179 /**
3180 * Return the set of ContainerListener classes that will be added to
3181 * newly created Wrappers automatically.
3182 */
3183 public String[] findWrapperListeners() {
3184
3185 synchronized (wrapperListenersLock) {
3186 return (wrapperListeners);
3187 }
3188
3189 }
3190
3191
3192 /**
3193 * Reload this web application, if reloading is supported.
3194 * <p>
3195 * <b>IMPLEMENTATION NOTE</b>: This method is designed to deal with
3196 * reloads required by changes to classes in the underlying repositories
3197 * of our class loader. It does not handle changes to the web application
3198 * deployment descriptor. If that has occurred, you should stop this
3199 * Context and create (and start) a new Context instance instead.
3200 *
3201 * @exception IllegalStateException if the <code>reloadable</code>
3202 * property is set to <code>false</code>.
3203 */
3204 public synchronized void reload() {
3205
3206 // Validate our current component state
3207 if (!started)
3208 throw new IllegalStateException
3209 (sm.getString("containerBase.notStarted", logName()));
3210
3211 // Make sure reloading is enabled
3212 // if (!reloadable)
3213 // throw new IllegalStateException
3214 // (sm.getString("standardContext.notReloadable"));
3215 if(log.isInfoEnabled())
3216 log.info(sm.getString("standardContext.reloadingStarted"));
3217
3218 // Stop accepting requests temporarily
3219 setPaused(true);
3220
3221 try {
3222 stop();
3223 } catch (LifecycleException e) {
3224 log.error(sm.getString("standardContext.stoppingContext"), e);
3225 }
3226
3227 try {
3228 start();
3229 } catch (LifecycleException e) {
3230 log.error(sm.getString("standardContext.startingContext"), e);
3231 }
3232
3233 setPaused(false);
3234
3235 }
3236
3237
3238 /**
3239 * Remove the specified application listener class from the set of
3240 * listeners for this application.
3241 *
3242 * @param listener Java class name of the listener to be removed
3243 */
3244 public void removeApplicationListener(String listener) {
3245
3246 synchronized (applicationListenersLock) {
3247
3248 // Make sure this welcome file is currently present
3249 int n = -1;
3250 for (int i = 0; i < applicationListeners.length; i++) {
3251 if (applicationListeners[i].equals(listener)) {
3252 n = i;
3253 break;
3254 }
3255 }
3256 if (n < 0)
3257 return;
3258
3259 // Remove the specified constraint
3260 int j = 0;
3261 String results[] = new String[applicationListeners.length - 1];
3262 for (int i = 0; i < applicationListeners.length; i++) {
3263 if (i != n)
3264 results[j++] = applicationListeners[i];
3265 }
3266 applicationListeners = results;
3267
3268 }
3269
3270 // Inform interested listeners
3271 fireContainerEvent("removeApplicationListener", listener);
3272
3273 // FIXME - behavior if already started?
3274
3275 }
3276
3277
3278 /**
3279 * Remove the application parameter with the specified name from
3280 * the set for this application.
3281 *
3282 * @param name Name of the application parameter to remove
3283 */
3284 public void removeApplicationParameter(String name) {
3285
3286 synchronized (applicationParametersLock) {
3287
3288 // Make sure this parameter is currently present
3289 int n = -1;
3290 for (int i = 0; i < applicationParameters.length; i++) {
3291 if (name.equals(applicationParameters[i].getName())) {
3292 n = i;
3293 break;
3294 }
3295 }
3296 if (n < 0)
3297 return;
3298
3299 // Remove the specified parameter
3300 int j = 0;
3301 ApplicationParameter results[] =
3302 new ApplicationParameter[applicationParameters.length - 1];
3303 for (int i = 0; i < applicationParameters.length; i++) {
3304 if (i != n)
3305 results[j++] = applicationParameters[i];
3306 }
3307 applicationParameters = results;
3308
3309 }
3310
3311 // Inform interested listeners
3312 fireContainerEvent("removeApplicationParameter", name);
3313
3314 }
3315
3316
3317 /**
3318 * Add a child Container, only if the proposed child is an implementation
3319 * of Wrapper.
3320 *
3321 * @param child Child container to be added
3322 *
3323 * @exception IllegalArgumentException if the proposed container is
3324 * not an implementation of Wrapper
3325 */
3326 public void removeChild(Container child) {
3327
3328 if (!(child instanceof Wrapper)) {
3329 throw new IllegalArgumentException
3330 (sm.getString("standardContext.notWrapper"));
3331 }
3332
3333 super.removeChild(child);
3334
3335 }
3336
3337
3338 /**
3339 * Remove the specified security constraint from this web application.
3340 *
3341 * @param constraint Constraint to be removed
3342 */
3343 public void removeConstraint(SecurityConstraint constraint) {
3344
3345 synchronized (constraintsLock) {
3346
3347 // Make sure this constraint is currently present
3348 int n = -1;
3349 for (int i = 0; i < constraints.length; i++) {
3350 if (constraints[i].equals(constraint)) {
3351 n = i;
3352 break;
3353 }
3354 }
3355 if (n < 0)
3356 return;
3357
3358 // Remove the specified constraint
3359 int j = 0;
3360 SecurityConstraint results[] =
3361 new SecurityConstraint[constraints.length - 1];
3362 for (int i = 0; i < constraints.length; i++) {
3363 if (i != n)
3364 results[j++] = constraints[i];
3365 }
3366 constraints = results;
3367
3368 }
3369
3370 // Inform interested listeners
3371 fireContainerEvent("removeConstraint", constraint);
3372
3373 }
3374
3375
3376 /**
3377 * Remove the error page for the specified error code or
3378 * Java language exception, if it exists; otherwise, no action is taken.
3379 *
3380 * @param errorPage The error page definition to be removed
3381 */
3382 public void removeErrorPage(ErrorPage errorPage) {
3383
3384 String exceptionType = errorPage.getExceptionType();
3385 if (exceptionType != null) {
3386 synchronized (exceptionPages) {
3387 exceptionPages.remove(exceptionType);
3388 }
3389 } else {
3390 synchronized (statusPages) {
3391 if (errorPage.getErrorCode() == 200) {
3392 this.okErrorPage = null;
3393 }
3394 statusPages.remove(Integer.valueOf(errorPage.getErrorCode()));
3395 }
3396 }
3397 fireContainerEvent("removeErrorPage", errorPage);
3398
3399 }
3400
3401
3402 /**
3403 * Remove the specified filter definition from this Context, if it exists;
3404 * otherwise, no action is taken.
3405 *
3406 * @param filterDef Filter definition to be removed
3407 */
3408 public void removeFilterDef(FilterDef filterDef) {
3409
3410 synchronized (filterDefs) {
3411 filterDefs.remove(filterDef.getFilterName());
3412 }
3413 fireContainerEvent("removeFilterDef", filterDef);
3414
3415 }
3416
3417
3418 /**
3419 * Remove a filter mapping from this Context.
3420 *
3421 * @param filterMap The filter mapping to be removed
3422 */
3423 public void removeFilterMap(FilterMap filterMap) {
3424
3425 synchronized (filterMapsLock) {
3426
3427 // Make sure this filter mapping is currently present
3428 int n = -1;
3429 for (int i = 0; i < filterMaps.length; i++) {
3430 if (filterMaps[i] == filterMap) {
3431 n = i;
3432 break;
3433 }
3434 }
3435 if (n < 0)
3436 return;
3437
3438 // Remove the specified filter mapping
3439 FilterMap results[] = new FilterMap[filterMaps.length - 1];
3440 System.arraycopy(filterMaps, 0, results, 0, n);
3441 System.arraycopy(filterMaps, n + 1, results, n,
3442 (filterMaps.length - 1) - n);
3443 filterMaps = results;
3444
3445 }
3446
3447 // Inform interested listeners
3448 fireContainerEvent("removeFilterMap", filterMap);
3449
3450 }
3451
3452
3453 /**
3454 * Remove a class name from the set of InstanceListener classes that
3455 * will be added to newly created Wrappers.
3456 *
3457 * @param listener Class name of an InstanceListener class to be removed
3458 */
3459 public void removeInstanceListener(String listener) {
3460
3461 synchronized (instanceListenersLock) {
3462
3463 // Make sure this welcome file is currently present
3464 int n = -1;
3465 for (int i = 0; i < instanceListeners.length; i++) {
3466 if (instanceListeners[i].equals(listener)) {
3467 n = i;
3468 break;
3469 }
3470 }
3471 if (n < 0)
3472 return;
3473
3474 // Remove the specified constraint
3475 int j = 0;
3476 String results[] = new String[instanceListeners.length - 1];
3477 for (int i = 0; i < instanceListeners.length; i++) {
3478 if (i != n)
3479 results[j++] = instanceListeners[i];
3480 }
3481 instanceListeners = results;
3482
3483 }
3484
3485 // Inform interested listeners
3486 fireContainerEvent("removeInstanceListener", listener);
3487
3488 }
3489
3490
3491 /**
3492 * Remove any message destination with the specified name.
3493 *
3494 * @param name Name of the message destination to remove
3495 */
3496 public void removeMessageDestination(String name) {
3497
3498 synchronized (messageDestinations) {
3499 messageDestinations.remove(name);
3500 }
3501 fireContainerEvent("removeMessageDestination", name);
3502
3503 }
3504
3505
3506 /**
3507 * Remove any message destination ref with the specified name.
3508 *
3509 * @param name Name of the message destination ref to remove
3510 */
3511 public void removeMessageDestinationRef(String name) {
3512
3513 namingResources.removeMessageDestinationRef(name);
3514 fireContainerEvent("removeMessageDestinationRef", name);
3515
3516 }
3517
3518
3519 /**
3520 * Remove the MIME mapping for the specified extension, if it exists;
3521 * otherwise, no action is taken.
3522 *
3523 * @param extension Extension to remove the mapping for
3524 */
3525 public void removeMimeMapping(String extension) {
3526
3527 synchronized (mimeMappings) {
3528 mimeMappings.remove(extension);
3529 }
3530 fireContainerEvent("removeMimeMapping", extension);
3531
3532 }
3533
3534
3535 /**
3536 * Remove the context initialization parameter with the specified
3537 * name, if it exists; otherwise, no action is taken.
3538 *
3539 * @param name Name of the parameter to remove
3540 */
3541 public void removeParameter(String name) {
3542
3543 synchronized (parameters) {
3544 parameters.remove(name);
3545 }
3546 fireContainerEvent("removeParameter", name);
3547
3548 }
3549
3550
3551 /**
3552 * Remove any security role reference for the specified name
3553 *
3554 * @param role Security role (as used in the application) to remove
3555 */
3556 public void removeRoleMapping(String role) {
3557
3558 synchronized (roleMappings) {
3559 roleMappings.remove(role);
3560 }
3561 fireContainerEvent("removeRoleMapping", role);
3562
3563 }
3564
3565
3566 /**
3567 * Remove any security role with the specified name.
3568 *
3569 * @param role Security role to remove
3570 */
3571 public void removeSecurityRole(String role) {
3572
3573 synchronized (securityRolesLock) {
3574
3575 // Make sure this security role is currently present
3576 int n = -1;
3577 for (int i = 0; i < securityRoles.length; i++) {
3578 if (role.equals(securityRoles[i])) {
3579 n = i;
3580 break;
3581 }
3582 }
3583 if (n < 0)
3584 return;
3585
3586 // Remove the specified security role
3587 int j = 0;
3588 String results[] = new String[securityRoles.length - 1];
3589 for (int i = 0; i < securityRoles.length; i++) {
3590 if (i != n)
3591 results[j++] = securityRoles[i];
3592 }
3593 securityRoles = results;
3594
3595 }
3596
3597 // Inform interested listeners
3598 fireContainerEvent("removeSecurityRole", role);
3599
3600 }
3601
3602
3603 /**
3604 * Remove any servlet mapping for the specified pattern, if it exists;
3605 * otherwise, no action is taken.
3606 *
3607 * @param pattern URL pattern of the mapping to remove
3608 */
3609 public void removeServletMapping(String pattern) {
3610
3611 String name = null;
3612 synchronized (servletMappingsLock) {
3613 name = (String) servletMappings.remove(pattern);
3614 }
3615 Wrapper wrapper = (Wrapper) findChild(name);
3616 if( wrapper != null ) {
3617 wrapper.removeMapping(pattern);
3618 }
3619 mapper.removeWrapper(pattern);
3620 fireContainerEvent("removeServletMapping", pattern);
3621
3622 }
3623
3624
3625 /**
3626 * Remove the tag library location forthe specified tag library URI.
3627 *
3628 * @param uri URI, relative to the web.xml file
3629 */
3630 public void removeTaglib(String uri) {
3631
3632 synchronized (taglibs) {
3633 taglibs.remove(uri);
3634 }
3635 fireContainerEvent("removeTaglib", uri);
3636 }
3637
3638
3639 /**
3640 * Remove the specified watched resource name from the list associated
3641 * with this Context.
3642 *
3643 * @param name Name of the watched resource to be removed
3644 */
3645 public void removeWatchedResource(String name) {
3646
3647 synchronized (watchedResourcesLock) {
3648
3649 // Make sure this watched resource is currently present
3650 int n = -1;
3651 for (int i = 0; i < watchedResources.length; i++) {
3652 if (watchedResources[i].equals(name)) {
3653 n = i;
3654 break;
3655 }
3656 }
3657 if (n < 0)
3658 return;
3659
3660 // Remove the specified watched resource
3661 int j = 0;
3662 String results[] = new String[watchedResources.length - 1];
3663 for (int i = 0; i < watchedResources.length; i++) {
3664 if (i != n)
3665 results[j++] = watchedResources[i];
3666 }
3667 watchedResources = results;
3668
3669 }
3670
3671 fireContainerEvent("removeWatchedResource", name);
3672
3673 }
3674
3675
3676 /**
3677 * Remove the specified welcome file name from the list recognized
3678 * by this Context.
3679 *
3680 * @param name Name of the welcome file to be removed
3681 */
3682 public void removeWelcomeFile(String name) {
3683
3684 synchronized (welcomeFilesLock) {
3685
3686 // Make sure this welcome file is currently present
3687 int n = -1;
3688 for (int i = 0; i < welcomeFiles.length; i++) {
3689 if (welcomeFiles[i].equals(name)) {
3690 n = i;
3691 break;
3692 }
3693 }
3694 if (n < 0)
3695 return;
3696
3697 // Remove the specified constraint
3698 int j = 0;
3699 String results[] = new String[welcomeFiles.length - 1];
3700 for (int i = 0; i < welcomeFiles.length; i++) {
3701 if (i != n)
3702 results[j++] = welcomeFiles[i];
3703 }
3704 welcomeFiles = results;
3705
3706 }
3707
3708 // Inform interested listeners
3709 postWelcomeFiles();
3710 fireContainerEvent("removeWelcomeFile", name);
3711
3712 }
3713
3714
3715 /**
3716 * Remove a class name from the set of LifecycleListener classes that
3717 * will be added to newly created Wrappers.
3718 *
3719 * @param listener Class name of a LifecycleListener class to be removed
3720 */
3721 public void removeWrapperLifecycle(String listener) {
3722
3723
3724 synchronized (wrapperLifecyclesLock) {
3725
3726 // Make sure this welcome file is currently present
3727 int n = -1;
3728 for (int i = 0; i < wrapperLifecycles.length; i++) {
3729 if (wrapperLifecycles[i].equals(listener)) {
3730 n = i;
3731 break;
3732 }
3733 }
3734 if (n < 0)
3735 return;
3736
3737 // Remove the specified constraint
3738 int j = 0;
3739 String results[] = new String[wrapperLifecycles.length - 1];
3740 for (int i = 0; i < wrapperLifecycles.length; i++) {
3741 if (i != n)
3742 results[j++] = wrapperLifecycles[i];
3743 }
3744 wrapperLifecycles = results;
3745
3746 }
3747
3748 // Inform interested listeners
3749 fireContainerEvent("removeWrapperLifecycle", listener);
3750
3751 }
3752
3753
3754 /**
3755 * Remove a class name from the set of ContainerListener classes that
3756 * will be added to newly created Wrappers.
3757 *
3758 * @param listener Class name of a ContainerListener class to be removed
3759 */
3760 public void removeWrapperListener(String listener) {
3761
3762
3763 synchronized (wrapperListenersLock) {
3764
3765 // Make sure this welcome file is currently present
3766 int n = -1;
3767 for (int i = 0; i < wrapperListeners.length; i++) {
3768 if (wrapperListeners[i].equals(listener)) {
3769 n = i;
3770 break;
3771 }
3772 }
3773 if (n < 0)
3774 return;
3775
3776 // Remove the specified constraint
3777 int j = 0;
3778 String results[] = new String[wrapperListeners.length - 1];
3779 for (int i = 0; i < wrapperListeners.length; i++) {
3780 if (i != n)
3781 results[j++] = wrapperListeners[i];
3782 }
3783 wrapperListeners = results;
3784
3785 }
3786
3787 // Inform interested listeners
3788 fireContainerEvent("removeWrapperListener", listener);
3789
3790 }
3791
3792
3793 /**
3794 * Gets the cumulative processing times of all servlets in this
3795 * StandardContext.
3796 *
3797 * @return Cumulative processing times of all servlets in this
3798 * StandardContext
3799 */
3800 public long getProcessingTime() {
3801
3802 long result = 0;
3803
3804 Container[] children = findChildren();
3805 if (children != null) {
3806 for( int i=0; i< children.length; i++ ) {
3807 result += ((StandardWrapper)children[i]).getProcessingTime();
3808 }
3809 }
3810
3811 return result;
3812 }
3813
3814
3815 // --------------------------------------------------------- Public Methods
3816
3817
3818 /**
3819 * Configure and initialize the set of filters for this Context.
3820 * Return <code>true</code> if all filter initialization completed
3821 * successfully, or <code>false</code> otherwise.
3822 */
3823 public boolean filterStart() {
3824
3825 if (getLogger().isDebugEnabled())
3826 getLogger().debug("Starting filters");
3827 // Instantiate and record a FilterConfig for each defined filter
3828 boolean ok = true;
3829 synchronized (filterConfigs) {
3830 filterConfigs.clear();
3831 Iterator names = filterDefs.keySet().iterator();
3832 while (names.hasNext()) {
3833 String name = (String) names.next();
3834 if (getLogger().isDebugEnabled())
3835 getLogger().debug(" Starting filter '" + name + "'");
3836 ApplicationFilterConfig filterConfig = null;
3837 try {
3838 filterConfig = new ApplicationFilterConfig
3839 (this, (FilterDef) filterDefs.get(name));
3840 filterConfigs.put(name, filterConfig);
3841 } catch (Throwable t) {
3842 getLogger().error
3843 (sm.getString("standardContext.filterStart", name), t);
3844 ok = false;
3845 }
3846 }
3847 }
3848
3849 return (ok);
3850
3851 }
3852
3853
3854 /**
3855 * Finalize and release the set of filters for this Context.
3856 * Return <code>true</code> if all filter finalization completed
3857 * successfully, or <code>false</code> otherwise.
3858 */
3859 public boolean filterStop() {
3860
3861 if (getLogger().isDebugEnabled())
3862 getLogger().debug("Stopping filters");
3863
3864 // Release all Filter and FilterConfig instances
3865 synchronized (filterConfigs) {
3866 Iterator names = filterConfigs.keySet().iterator();
3867 while (names.hasNext()) {
3868 String name = (String) names.next();
3869 if (getLogger().isDebugEnabled())
3870 getLogger().debug(" Stopping filter '" + name + "'");
3871 ApplicationFilterConfig filterConfig =
3872 (ApplicationFilterConfig) filterConfigs.get(name);
3873 filterConfig.release();
3874 }
3875 filterConfigs.clear();
3876 }
3877 return (true);
3878
3879 }
3880
3881
3882 /**
3883 * Find and return the initialized <code>FilterConfig</code> for the
3884 * specified filter name, if any; otherwise return <code>null</code>.
3885 *
3886 * @param name Name of the desired filter
3887 */
3888 public FilterConfig findFilterConfig(String name) {
3889
3890 return ((FilterConfig) filterConfigs.get(name));
3891
3892 }
3893
3894
3895 /**
3896 * Configure the set of instantiated application event listeners
3897 * for this Context. Return <code>true</code> if all listeners wre
3898 * initialized successfully, or <code>false</code> otherwise.
3899 */
3900 public boolean listenerStart() {
3901
3902 if (log.isDebugEnabled())
3903 log.debug("Configuring application event listeners");
3904
3905 // Instantiate the required listeners
3906 ClassLoader loader = getLoader().getClassLoader();
3907 String listeners[] = findApplicationListeners();
3908 Object results[] = new Object[listeners.length];
3909 boolean ok = true;
3910 for (int i = 0; i < results.length; i++) {
3911 if (getLogger().isDebugEnabled())
3912 getLogger().debug(" Configuring event listener class '" +
3913 listeners[i] + "'");
3914 try {
3915 Class clazz = loader.loadClass(listeners[i]);
3916 results[i] = clazz.newInstance();
3917 // Annotation processing
3918 if (!getIgnoreAnnotations()) {
3919 getAnnotationProcessor().processAnnotations(results[i]);
3920 getAnnotationProcessor().postConstruct(results[i]);
3921 }
3922 } catch (Throwable t) {
3923 getLogger().error
3924 (sm.getString("standardContext.applicationListener",
3925 listeners[i]), t);
3926 ok = false;
3927 }
3928 }
3929 if (!ok) {
3930 getLogger().error(sm.getString("standardContext.applicationSkipped"));
3931 return (false);
3932 }
3933
3934 // Sort listeners in two arrays
3935 ArrayList eventListeners = new ArrayList();
3936 ArrayList lifecycleListeners = new ArrayList();
3937 for (int i = 0; i < results.length; i++) {
3938 if ((results[i] instanceof ServletContextAttributeListener)
3939 || (results[i] instanceof ServletRequestAttributeListener)
3940 || (results[i] instanceof ServletRequestListener)
3941 || (results[i] instanceof HttpSessionAttributeListener)) {
3942 eventListeners.add(results[i]);
3943 }
3944 if ((results[i] instanceof ServletContextListener)
3945 || (results[i] instanceof HttpSessionListener)) {
3946 lifecycleListeners.add(results[i]);
3947 }
3948 }
3949
3950 setApplicationEventListeners(eventListeners.toArray());
3951 setApplicationLifecycleListeners(lifecycleListeners.toArray());
3952
3953 // Send application start events
3954
3955 if (getLogger().isDebugEnabled())
3956 getLogger().debug("Sending application start events");
3957
3958 Object instances[] = getApplicationLifecycleListeners();
3959 if (instances == null)
3960 return (ok);
3961 ServletContextEvent event =
3962 new ServletContextEvent(getServletContext());
3963 for (int i = 0; i < instances.length; i++) {
3964 if (instances[i] == null)
3965 continue;
3966 if (!(instances[i] instanceof ServletContextListener))
3967 continue;
3968 ServletContextListener listener =
3969 (ServletContextListener) instances[i];
3970 try {
3971 fireContainerEvent("beforeContextInitialized", listener);
3972 listener.contextInitialized(event);
3973 fireContainerEvent("afterContextInitialized", listener);
3974 } catch (Throwable t) {
3975 fireContainerEvent("afterContextInitialized", listener);
3976 getLogger().error
3977 (sm.getString("standardContext.listenerStart",
3978 instances[i].getClass().getName()), t);
3979 ok = false;
3980 }
3981 }
3982 return (ok);
3983
3984 }
3985
3986
3987 /**
3988 * Send an application stop event to all interested listeners.
3989 * Return <code>true</code> if all events were sent successfully,
3990 * or <code>false</code> otherwise.
3991 */
3992 public boolean listenerStop() {
3993
3994 if (log.isDebugEnabled())
3995 log.debug("Sending application stop events");
3996
3997 boolean ok = true;
3998 Object listeners[] = getApplicationLifecycleListeners();
3999 if (listeners != null) {
4000 ServletContextEvent event =
4001 new ServletContextEvent(getServletContext());
4002 for (int i = 0; i < listeners.length; i++) {
4003 int j = (listeners.length - 1) - i;
4004 if (listeners[j] == null)
4005 continue;
4006 if (listeners[j] instanceof ServletContextListener) {
4007 ServletContextListener listener =
4008 (ServletContextListener) listeners[j];
4009 try {
4010 fireContainerEvent("beforeContextDestroyed", listener);
4011 listener.contextDestroyed(event);
4012 fireContainerEvent("afterContextDestroyed", listener);
4013 } catch (Throwable t) {
4014 fireContainerEvent("afterContextDestroyed", listener);
4015 getLogger().error
4016 (sm.getString("standardContext.listenerStop",
4017 listeners[j].getClass().getName()), t);
4018 ok = false;
4019 }
4020 }
4021 // Annotation processing
4022 if (!getIgnoreAnnotations()) {
4023 try {
4024 getAnnotationProcessor().preDestroy(listeners[j]);
4025 } catch (Throwable t) {
4026 getLogger().error
4027 (sm.getString("standardContext.listenerStop",
4028 listeners[j].getClass().getName()), t);
4029 ok = false;
4030 }
4031 }
4032 }
4033 }
4034
4035 // Annotation processing
4036 listeners = getApplicationEventListeners();
4037 if (!getIgnoreAnnotations() && listeners != null) {
4038 for (int i = 0; i < listeners.length; i++) {
4039 int j = (listeners.length - 1) - i;
4040 if (listeners[j] == null)
4041 continue;
4042 try {
4043 getAnnotationProcessor().preDestroy(listeners[j]);
4044 } catch (Throwable t) {
4045 getLogger().error
4046 (sm.getString("standardContext.listenerStop",
4047 listeners[j].getClass().getName()), t);
4048 ok = false;
4049 }
4050 }
4051 }
4052
4053 setApplicationEventListeners(null);
4054 setApplicationLifecycleListeners(null);
4055
4056 return (ok);
4057
4058 }
4059
4060
4061 /**
4062 * Allocate resources, including proxy.
4063 * Return <code>true</code> if initialization was successfull,
4064 * or <code>false</code> otherwise.
4065 */
4066 public boolean resourcesStart() {
4067
4068 boolean ok = true;
4069
4070 Hashtable env = new Hashtable();
4071 if (getParent() != null)
4072 env.put(ProxyDirContext.HOST, getParent().getName());
4073 env.put(ProxyDirContext.CONTEXT, getName());
4074
4075 try {
4076 ProxyDirContext proxyDirContext =
4077 new ProxyDirContext(env, webappResources);
4078 if (webappResources instanceof FileDirContext) {
4079 filesystemBased = true;
4080 ((FileDirContext) webappResources).setCaseSensitive
4081 (isCaseSensitive());
4082 ((FileDirContext) webappResources).setAllowLinking
4083 (isAllowLinking());
4084 }
4085 if (webappResources instanceof BaseDirContext) {
4086 ((BaseDirContext) webappResources).setDocBase(getBasePath());
4087 ((BaseDirContext) webappResources).setCached
4088 (isCachingAllowed());
4089 ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL());
4090 ((BaseDirContext) webappResources).setCacheMaxSize
4091 (getCacheMaxSize());
4092 ((BaseDirContext) webappResources).allocate();
4093 }
4094 // Register the cache in JMX
4095 if (isCachingAllowed()) {
4096 ObjectName resourcesName =
4097 new ObjectName(this.getDomain() + ":type=Cache,host="
4098 + getHostname() + ",path="
4099 + (("".equals(getPath()))?"/":getPath()));
4100 Registry.getRegistry(null, null).registerComponent
4101 (proxyDirContext.getCache(), resourcesName, null);
4102 }
4103 this.resources = proxyDirContext;
4104 } catch (Throwable t) {
4105 log.error(sm.getString("standardContext.resourcesStart"), t);
4106 ok = false;
4107 }
4108
4109 return (ok);
4110
4111 }
4112
4113
4114 /**
4115 * Deallocate resources and destroy proxy.
4116 */
4117 public boolean resourcesStop() {
4118
4119 boolean ok = true;
4120
4121 try {
4122 if (resources != null) {
4123 if (resources instanceof Lifecycle) {
4124 ((Lifecycle) resources).stop();
4125 }
4126 if (webappResources instanceof BaseDirContext) {
4127 ((BaseDirContext) webappResources).release();
4128 }
4129 // Unregister the cache in JMX
4130 if (isCachingAllowed()) {
4131 ObjectName resourcesName =
4132 new ObjectName(this.getDomain()
4133 + ":type=Cache,host="
4134 + getHostname() + ",path="
4135 + (("".equals(getPath()))?"/"
4136 :getPath()));
4137 Registry.getRegistry(null, null)
4138 .unregisterComponent(resourcesName);
4139 }
4140 }
4141 } catch (Throwable t) {
4142 log.error(sm.getString("standardContext.resourcesStop"), t);
4143 ok = false;
4144 }
4145
4146 this.resources = null;
4147
4148 return (ok);
4149
4150 }
4151
4152
4153 /**
4154 * Load and initialize all servlets marked "load on startup" in the
4155 * web application deployment descriptor.
4156 *
4157 * @param children Array of wrappers for all currently defined
4158 * servlets (including those not declared load on startup)
4159 */
4160 public void loadOnStartup(Container children[]) {
4161
4162 // Collect "load on startup" servlets that need to be initialized
4163 TreeMap map = new TreeMap();
4164 for (int i = 0; i < children.length; i++) {
4165 Wrapper wrapper = (Wrapper) children[i];
4166 int loadOnStartup = wrapper.getLoadOnStartup();
4167 if (loadOnStartup < 0)
4168 continue;
4169 Integer key = Integer.valueOf(loadOnStartup);
4170 ArrayList list = (ArrayList) map.get(key);
4171 if (list == null) {
4172 list = new ArrayList();
4173 map.put(key, list);
4174 }
4175 list.add(wrapper);
4176 }
4177
4178 // Load the collected "load on startup" servlets
4179 Iterator keys = map.keySet().iterator();
4180 while (keys.hasNext()) {
4181 Integer key = (Integer) keys.next();
4182 ArrayList list = (ArrayList) map.get(key);
4183 Iterator wrappers = list.iterator();
4184 while (wrappers.hasNext()) {
4185 Wrapper wrapper = (Wrapper) wrappers.next();
4186 try {
4187 wrapper.load();
4188 } catch (ServletException e) {
4189 getLogger().error(sm.getString("standardWrapper.loadException",
4190 getName()), StandardWrapper.getRootCause(e));
4191 // NOTE: load errors (including a servlet that throws
4192 // UnavailableException from tht init() method) are NOT
4193 // fatal to application startup
4194 }
4195 }
4196 }
4197
4198 }
4199
4200
4201 /**
4202 * Start this Context component.
4203 *
4204 * @exception LifecycleException if a startup error occurs
4205 */
4206 public synchronized void start() throws LifecycleException {
4207 //if (lazy ) return;
4208 if (started) {
4209 if(log.isInfoEnabled())
4210 log.info(sm.getString("containerBase.alreadyStarted", logName()));
4211 return;
4212 }
4213 if( !initialized ) {
4214 try {
4215 init();
4216 } catch( Exception ex ) {
4217 throw new LifecycleException("Error initializaing ", ex);
4218 }
4219 }
4220 if(log.isDebugEnabled())
4221 log.debug("Starting " + ("".equals(getName()) ? "ROOT" : getName()));
4222
4223 // Set JMX object name for proper pipeline registration
4224 preRegisterJMX();
4225
4226 if ((oname != null) &&
4227 (Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname))) {
4228 // As things depend on the JMX registration, the context
4229 // must be reregistered again once properly initialized
4230 Registry.getRegistry(null, null).unregisterComponent(oname);
4231 }
4232
4233 // Notify our interested LifecycleListeners
4234 lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
4235
4236 setAvailable(false);
4237 setConfigured(false);
4238 boolean ok = true;
4239
4240 // Add missing components as necessary
4241 if (webappResources == null) { // (1) Required by Loader
4242 if (log.isDebugEnabled())
4243 log.debug("Configuring default Resources");
4244 try {
4245 if ((docBase != null) && (docBase.endsWith(".war")) && (!(new File(getBasePath())).isDirectory()))
4246 setResources(new WARDirContext());
4247 else
4248 setResources(new FileDirContext());
4249 } catch (IllegalArgumentException e) {
4250 log.error("Error initializing resources: " + e.getMessage());
4251 ok = false;
4252 }
4253 }
4254 if (ok) {
4255 if (!resourcesStart()) {
4256 log.error( "Error in resourceStart()");
4257 ok = false;
4258 }
4259 }
4260
4261 // Look for a realm - that may have been configured earlier.
4262 // If the realm is added after context - it'll set itself.
4263 // TODO: what is the use case for this ?
4264 if( realm == null && mserver != null ) {
4265 ObjectName realmName=null;
4266 try {
4267 realmName=new ObjectName( getEngineName() + ":type=Realm,host=" +
4268 getHostname() + ",path=" + getPath());
4269 if( mserver.isRegistered(realmName ) ) {
4270 mserver.invoke(realmName, "init",
4271 new Object[] {},
4272 new String[] {}
4273 );
4274 }
4275 } catch( Throwable t ) {
4276 if(log.isDebugEnabled())
4277 log.debug("No realm for this host " + realmName);
4278 }
4279 }
4280
4281 if (getLoader() == null) {
4282 WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
4283 webappLoader.setDelegate(getDelegate());
4284 setLoader(webappLoader);
4285 }
4286
4287 // Initialize character set mapper
4288 getCharsetMapper();
4289
4290 // Post work directory
4291 postWorkDirectory();
4292
4293 // Validate required extensions
4294 boolean dependencyCheck = true;
4295 try {
4296 dependencyCheck = ExtensionValidator.validateApplication
4297 (getResources(), this);
4298 } catch (IOException ioe) {
4299 log.error("Error in dependencyCheck", ioe);
4300 dependencyCheck = false;
4301 }
4302
4303 if (!dependencyCheck) {
4304 // do not make application available if depency check fails
4305 ok = false;
4306 }
4307
4308 // Reading the "catalina.useNaming" environment variable
4309 String useNamingProperty = System.getProperty("catalina.useNaming");
4310 if ((useNamingProperty != null)
4311 && (useNamingProperty.equals("false"))) {
4312 useNaming = false;
4313 }
4314
4315 if (ok && isUseNaming()) {
4316 if (namingContextListener == null) {
4317 namingContextListener = new NamingContextListener();
4318 namingContextListener.setName(getNamingContextName());
4319 addLifecycleListener(namingContextListener);
4320 }
4321 }
4322
4323 // Standard container startup
4324 if (log.isDebugEnabled())
4325 log.debug("Processing standard container startup");
4326
4327
4328 // Binding thread
4329 ClassLoader oldCCL = bindThread();
4330
4331 boolean mainOk = false;
4332
4333 try {
4334
4335 if (ok) {
4336
4337 started = true;
4338
4339 // Start our subordinate components, if any
4340 if ((loader != null) && (loader instanceof Lifecycle))
4341 ((Lifecycle) loader).start();
4342
4343 // Unbinding thread
4344 unbindThread(oldCCL);
4345
4346 // Binding thread
4347 oldCCL = bindThread();
4348
4349 // Initialize logger again. Other components might have used it too early,
4350 // so it should be reset.
4351 logger = null;
4352 getLogger();
4353 if ((logger != null) && (logger instanceof Lifecycle))
4354 ((Lifecycle) logger).start();
4355
4356 if ((cluster != null) && (cluster instanceof Lifecycle))
4357 ((Lifecycle) cluster).start();
4358 if ((realm != null) && (realm instanceof Lifecycle))
4359 ((Lifecycle) realm).start();
4360 if ((resources != null) && (resources instanceof Lifecycle))
4361 ((Lifecycle) resources).start();
4362
4363 // Start our child containers, if any
4364 Container children[] = findChildren();
4365 for (int i = 0; i < children.length; i++) {
4366 if (children[i] instanceof Lifecycle)
4367 ((Lifecycle) children[i]).start();
4368 }
4369
4370 // Start the Valves in our pipeline (including the basic),
4371 // if any
4372 if (pipeline instanceof Lifecycle) {
4373 ((Lifecycle) pipeline).start();
4374 }
4375
4376 // Notify our interested LifecycleListeners
4377 lifecycle.fireLifecycleEvent(START_EVENT, null);
4378
4379 // Acquire clustered manager
4380 Manager contextManager = null;
4381 if (manager == null) {
4382 if ( (getCluster() != null) && distributable) {
4383 try {
4384 contextManager = getCluster().createManager(getName());
4385 } catch (Exception ex) {
4386 log.error("standardContext.clusterFail", ex);
4387 ok = false;
4388 }
4389 } else {
4390 contextManager = new StandardManager();
4391 }
4392 }
4393
4394 // Configure default manager if none was specified
4395 if (contextManager != null) {
4396 setManager(contextManager);
4397 }
4398
4399 if (manager!=null && (getCluster() != null) && distributable) {
4400 //let the cluster know that there is a context that is distributable
4401 //and that it has its own manager
4402 getCluster().registerManager(manager);
4403 }
4404
4405
4406 mainOk = true;
4407
4408 }
4409
4410 } finally {
4411 // Unbinding thread
4412 unbindThread(oldCCL);
4413 if (!mainOk) {
4414 // An exception occurred
4415 // Register with JMX anyway, to allow management
4416 registerJMX();
4417 }
4418 }
4419
4420 if (!getConfigured()) {
4421 log.error( "Error getConfigured");
4422 ok = false;
4423 }
4424
4425 // We put the resources into the servlet context
4426 if (ok)
4427 getServletContext().setAttribute
4428 (Globals.RESOURCES_ATTR, getResources());
4429
4430 // Initialize associated mapper
4431 mapper.setContext(getPath(), welcomeFiles, resources);
4432
4433 // Binding thread
4434 oldCCL = bindThread();
4435
4436 // Set annotation processing parameter for Jasper (unfortunately, since
4437 // this can be configured in many places and not just in /WEB-INF/web.xml,
4438 // there are not many solutions)
4439 // Initialize annotation processor
4440 if (ok && !getIgnoreAnnotations()) {
4441 if (annotationProcessor == null) {
4442 if (isUseNaming() && namingContextListener != null) {
4443 annotationProcessor =
4444 new DefaultAnnotationProcessor(namingContextListener.getEnvContext());
4445 } else {
4446 annotationProcessor = new DefaultAnnotationProcessor(null);
4447 }
4448 }
4449 getServletContext().setAttribute
4450 (AnnotationProcessor.class.getName(), annotationProcessor);
4451 }
4452
4453 try {
4454
4455 // Create context attributes that will be required
4456 if (ok) {
4457 postWelcomeFiles();
4458 }
4459
4460 if (ok) {
4461 // Notify our interested LifecycleListeners
4462 lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
4463 }
4464
4465 // Configure and call application event listeners
4466 if (ok) {
4467 if (!listenerStart()) {
4468 log.error( "Error listenerStart");
4469 ok = false;
4470 }
4471 }
4472
4473 try {
4474 // Start manager
4475 if ((manager != null) && (manager instanceof Lifecycle)) {
4476 ((Lifecycle) getManager()).start();
4477 }
4478
4479 // Start ContainerBackgroundProcessor thread
4480 super.threadStart();
4481 } catch(Exception e) {
4482 log.error("Error manager.start()", e);
4483 ok = false;
4484 }
4485
4486 // Configure and call application filters
4487 if (ok) {
4488 if (!filterStart()) {
4489 log.error( "Error filterStart");
4490 ok = false;
4491 }
4492 }
4493
4494 // Load and initialize all "load on startup" servlets
4495 if (ok) {
4496 loadOnStartup(findChildren());
4497 }
4498
4499 } finally {
4500 // Unbinding thread
4501 unbindThread(oldCCL);
4502 }
4503
4504 // Set available status depending upon startup success
4505 if (ok) {
4506 if (log.isDebugEnabled())
4507 log.debug("Starting completed");
4508 setAvailable(true);
4509 } else {
4510 log.error(sm.getString("standardContext.startFailed", getName()));
4511 try {
4512 stop();
4513 } catch (Throwable t) {
4514 log.error(sm.getString("standardContext.startCleanup"), t);
4515 }
4516 setAvailable(false);
4517 }
4518
4519 // JMX registration
4520 registerJMX();
4521
4522 startTime=System.currentTimeMillis();
4523
4524 // Send j2ee.state.running notification
4525 if (ok && (this.getObjectName() != null)) {
4526 Notification notification =
4527 new Notification("j2ee.state.running", this.getObjectName(),
4528 sequenceNumber++);
4529 broadcaster.sendNotification(notification);
4530 }
4531
4532 // Close all JARs right away to avoid always opening a peak number
4533 // of files on startup
4534 if (getLoader() instanceof WebappLoader) {
4535 ((WebappLoader) getLoader()).closeJARs(true);
4536 }
4537
4538 // Reinitializing if something went wrong
4539 if (!ok && started) {
4540 stop();
4541 }
4542
4543 //cacheContext();
4544 }
4545
4546
4547 private void cacheContext() {
4548 try {
4549 File workDir=new File( getWorkPath() );
4550
4551 File ctxSer=new File( workDir, "_tomcat_context.ser");
4552 FileOutputStream fos=new FileOutputStream( ctxSer );
4553 ObjectOutputStream oos=new ObjectOutputStream( fos );
4554 oos.writeObject(this);
4555 oos.close();
4556 fos.close();
4557 } catch( Throwable t ) {
4558 if(log.isInfoEnabled())
4559 log.info("Error saving context.ser ", t);
4560 }
4561 }
4562
4563
4564 /**
4565 * Stop this Context component.
4566 *
4567 * @exception LifecycleException if a shutdown error occurs
4568 */
4569 public synchronized void stop() throws LifecycleException {
4570
4571 // Validate and update our current component state
4572 if (!started) {
4573 if(log.isInfoEnabled())
4574 log.info(sm.getString("containerBase.notStarted", logName()));
4575 return;
4576 }
4577
4578 // Notify our interested LifecycleListeners
4579 lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
4580
4581 // Send j2ee.state.stopping notification
4582 if (this.getObjectName() != null) {
4583 Notification notification =
4584 new Notification("j2ee.state.stopping", this.getObjectName(),
4585 sequenceNumber++);
4586 broadcaster.sendNotification(notification);
4587 }
4588
4589 // Mark this application as unavailable while we shut down
4590 setAvailable(false);
4591
4592 // Binding thread
4593 ClassLoader oldCCL = bindThread();
4594
4595 try {
4596
4597 // Stop our child containers, if any
4598 Container[] children = findChildren();
4599 for (int i = 0; i < children.length; i++) {
4600 if (children[i] instanceof Lifecycle)
4601 ((Lifecycle) children[i]).stop();
4602 }
4603
4604 // Stop our filters
4605 filterStop();
4606
4607 // Stop ContainerBackgroundProcessor thread
4608 super.threadStop();
4609
4610 if ((manager != null) && (manager instanceof Lifecycle)) {
4611 ((Lifecycle) manager).stop();
4612 }
4613
4614 // Stop our application listeners
4615 listenerStop();
4616
4617 // Finalize our character set mapper
4618 setCharsetMapper(null);
4619
4620 // Normal container shutdown processing
4621 if (log.isDebugEnabled())
4622 log.debug("Processing standard container shutdown");
4623 // Notify our interested LifecycleListeners
4624 lifecycle.fireLifecycleEvent(STOP_EVENT, null);
4625 started = false;
4626
4627 // Stop the Valves in our pipeline (including the basic), if any
4628 if (pipeline instanceof Lifecycle) {
4629 ((Lifecycle) pipeline).stop();
4630 }
4631
4632 // Clear all application-originated servlet context attributes
4633 if (context != null)
4634 context.clearAttributes();
4635
4636 // Stop resources
4637 resourcesStop();
4638
4639 if ((realm != null) && (realm instanceof Lifecycle)) {
4640 ((Lifecycle) realm).stop();
4641 }
4642 if ((cluster != null) && (cluster instanceof Lifecycle)) {
4643 ((Lifecycle) cluster).stop();
4644 }
4645 if ((logger != null) && (logger instanceof Lifecycle)) {
4646 ((Lifecycle) logger).stop();
4647 }
4648 if ((loader != null) && (loader instanceof Lifecycle)) {
4649 ((Lifecycle) loader).stop();
4650 }
4651
4652 } finally {
4653
4654 // Unbinding thread
4655 unbindThread(oldCCL);
4656
4657 }
4658
4659 // Send j2ee.state.stopped notification
4660 if (this.getObjectName() != null) {
4661 Notification notification =
4662 new Notification("j2ee.state.stopped", this.getObjectName(),
4663 sequenceNumber++);
4664 broadcaster.sendNotification(notification);
4665 }
4666
4667 // Reset application context
4668 context = null;
4669
4670 // This object will no longer be visible or used.
4671 try {
4672 resetContext();
4673 } catch( Exception ex ) {
4674 log.error( "Error reseting context " + this + " " + ex, ex );
4675 }
4676
4677 // Notify our interested LifecycleListeners
4678 lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
4679
4680 if (log.isDebugEnabled())
4681 log.debug("Stopping complete");
4682
4683 }
4684
4685 /** Destroy needs to clean up the context completely.
4686 *
4687 * The problem is that undoing all the config in start() and restoring
4688 * a 'fresh' state is impossible. After stop()/destroy()/init()/start()
4689 * we should have the same state as if a fresh start was done - i.e
4690 * read modified web.xml, etc. This can only be done by completely
4691 * removing the context object and remapping a new one, or by cleaning
4692 * up everything.
4693 *
4694 * XXX Should this be done in stop() ?
4695 *
4696 */
4697 public void destroy() throws Exception {
4698 if( oname != null ) {
4699 // Send j2ee.object.deleted notification
4700 Notification notification =
4701 new Notification("j2ee.object.deleted", this.getObjectName(),
4702 sequenceNumber++);
4703 broadcaster.sendNotification(notification);
4704 }
4705 super.destroy();
4706
4707 // Notify our interested LifecycleListeners
4708 lifecycle.fireLifecycleEvent(DESTROY_EVENT, null);
4709
4710 synchronized (instanceListenersLock) {
4711 instanceListeners = new String[0];
4712 }
4713
4714 }
4715
4716 private void resetContext() throws Exception, MBeanRegistrationException {
4717 // Restore the original state ( pre reading web.xml in start )
4718 // If you extend this - override this method and make sure to clean up
4719 children=new HashMap();
4720 startupTime = 0;
4721 startTime = 0;
4722 tldScanTime = 0;
4723
4724 // Bugzilla 32867
4725 distributable = false;
4726
4727 applicationListeners = new String[0];
4728 applicationEventListenersObjects = new Object[0];
4729 applicationLifecycleListenersObjects = new Object[0];
4730 taglibs = new HashMap<String, String>();
4731
4732 annotationProcessor = null;
4733
4734 if(log.isDebugEnabled())
4735 log.debug("resetContext " + oname);
4736 }
4737
4738 /**
4739 * Return a String representation of this component.
4740 */
4741 public String toString() {
4742
4743 StringBuffer sb = new StringBuffer();
4744 if (getParent() != null) {
4745 sb.append(getParent().toString());
4746 sb.append(".");
4747 }
4748 sb.append("StandardContext[");
4749 sb.append(getName());
4750 sb.append("]");
4751 return (sb.toString());
4752
4753 }
4754
4755
4756 // ------------------------------------------------------ Protected Methods
4757
4758
4759 /**
4760 * Adjust the URL pattern to begin with a leading slash, if appropriate
4761 * (i.e. we are running a servlet 2.2 application). Otherwise, return
4762 * the specified URL pattern unchanged.
4763 *
4764 * @param urlPattern The URL pattern to be adjusted (if needed)
4765 * and returned
4766 */
4767 protected String adjustURLPattern(String urlPattern) {
4768
4769 if (urlPattern == null)
4770 return (urlPattern);
4771 if (urlPattern.startsWith("/") || urlPattern.startsWith("*."))
4772 return (urlPattern);
4773 if (!isServlet22())
4774 return (urlPattern);
4775 if(log.isDebugEnabled())
4776 log.debug(sm.getString("standardContext.urlPattern.patternWarning",
4777 urlPattern));
4778 return ("/" + urlPattern);
4779
4780 }
4781
4782
4783 /**
4784 * Are we processing a version 2.2 deployment descriptor?
4785 */
4786 protected boolean isServlet22() {
4787
4788 if (this.publicId == null)
4789 return (false);
4790 if (this.publicId.equals
4791 (org.apache.catalina.startup.Constants.WebDtdPublicId_22))
4792 return (true);
4793 else
4794 return (false);
4795
4796 }
4797
4798
4799 /**
4800 * Return a File object representing the base directory for the
4801 * entire servlet container (i.e. the Engine container if present).
4802 */
4803 protected File engineBase() {
4804 String base=System.getProperty("catalina.base");
4805 if( base == null ) {
4806 StandardEngine eng=(StandardEngine)this.getParent().getParent();
4807 base=eng.getBaseDir();
4808 }
4809 return (new File(base));
4810 }
4811
4812
4813 // -------------------------------------------------------- Private Methods
4814
4815
4816 /**
4817 * Bind current thread, both for CL purposes and for JNDI ENC support
4818 * during : startup, shutdown and realoading of the context.
4819 *
4820 * @return the previous context class loader
4821 */
4822 private ClassLoader bindThread() {
4823
4824 ClassLoader oldContextClassLoader =
4825 Thread.currentThread().getContextClassLoader();
4826
4827 if (getResources() == null)
4828 return oldContextClassLoader;
4829
4830 if (getLoader().getClassLoader() != null) {
4831 Thread.currentThread().setContextClassLoader
4832 (getLoader().getClassLoader());
4833 }
4834
4835 DirContextURLStreamHandler.bind(getResources());
4836
4837 if (isUseNaming()) {
4838 try {
4839 ContextBindings.bindThread(this, this);
4840 } catch (NamingException e) {
4841 // Silent catch, as this is a normal case during the early
4842 // startup stages
4843 }
4844 }
4845
4846 return oldContextClassLoader;
4847
4848 }
4849
4850
4851 /**
4852 * Unbind thread.
4853 */
4854 private void unbindThread(ClassLoader oldContextClassLoader) {
4855
4856 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
4857
4858 oldContextClassLoader = null;
4859
4860 if (isUseNaming()) {
4861 ContextBindings.unbindThread(this, this);
4862 }
4863
4864 DirContextURLStreamHandler.unbind();
4865
4866 }
4867
4868
4869
4870 /**
4871 * Get base path.
4872 */
4873 protected String getBasePath() {
4874 String docBase = null;
4875 Container container = this;
4876 while (container != null) {
4877 if (container instanceof Host)
4878 break;
4879 container = container.getParent();
4880 }
4881 File file = new File(getDocBase());
4882 if (!file.isAbsolute()) {
4883 if (container == null) {
4884 docBase = (new File(engineBase(), getDocBase())).getPath();
4885 } else {
4886 // Use the "appBase" property of this container
4887 String appBase = ((Host) container).getAppBase();
4888 file = new File(appBase);
4889 if (!file.isAbsolute())
4890 file = new File(engineBase(), appBase);
4891 docBase = (new File(file, getDocBase())).getPath();
4892 }
4893 } else {
4894 docBase = file.getPath();
4895 }
4896 return docBase;
4897 }
4898
4899
4900 /**
4901 * Get app base.
4902 */
4903 protected String getAppBase() {
4904 String appBase = null;
4905 Container container = this;
4906 while (container != null) {
4907 if (container instanceof Host)
4908 break;
4909 container = container.getParent();
4910 }
4911 if (container != null) {
4912 appBase = ((Host) container).getAppBase();
4913 }
4914 return appBase;
4915 }
4916
4917
4918 /**
4919 * Get config base.
4920 */
4921 public File getConfigBase() {
4922 File configBase =
4923 new File(System.getProperty("catalina.base"), "conf");
4924 if (!configBase.exists()) {
4925 return null;
4926 }
4927 Container container = this;
4928 Container host = null;
4929 Container engine = null;
4930 while (container != null) {
4931 if (container instanceof Host)
4932 host = container;
4933 if (container instanceof Engine)
4934 engine = container;
4935 container = container.getParent();
4936 }
4937 if (engine != null) {
4938 configBase = new File(configBase, engine.getName());
4939 }
4940 if (host != null) {
4941 configBase = new File(configBase, host.getName());
4942 }
4943 if (saveConfig) {
4944 configBase.mkdirs();
4945 }
4946 return configBase;
4947 }
4948
4949
4950 /**
4951 * Given a context path, get the config file name.
4952 */
4953 protected String getDefaultConfigFile() {
4954 String basename = null;
4955 String path = getPath();
4956 if (path.equals("")) {
4957 basename = "ROOT";
4958 } else {
4959 basename = path.substring(1).replace('/', '#');
4960 }
4961 return (basename + ".xml");
4962 }
4963
4964
4965 /**
4966 * Copy a file.
4967 */
4968 private boolean copy(File src, File dest) {
4969 FileInputStream is = null;
4970 FileOutputStream os = null;
4971 try {
4972 is = new FileInputStream(src);
4973 os = new FileOutputStream(dest);
4974 byte[] buf = new byte[4096];
4975 while (true) {
4976 int len = is.read(buf);
4977 if (len < 0)
4978 break;
4979 os.write(buf, 0, len);
4980 }
4981 is.close();
4982 os.close();
4983 } catch (IOException e) {
4984 return false;
4985 } finally {
4986 try {
4987 if (is != null) {
4988 is.close();
4989 }
4990 } catch (Exception e) {
4991 // Ignore
4992 }
4993 try {
4994 if (os != null) {
4995 os.close();
4996 }
4997 } catch (Exception e) {
4998 // Ignore
4999 }
5000 }
5001 return true;
5002 }
5003
5004
5005 /**
5006 * Get naming context full name.
5007 */
5008 private String getNamingContextName() {
5009 if (namingContextName == null) {
5010 Container parent = getParent();
5011 if (parent == null) {
5012 namingContextName = getName();
5013 } else {
5014 Stack stk = new Stack();
5015 StringBuffer buff = new StringBuffer();
5016 while (parent != null) {
5017 stk.push(parent.getName());
5018 parent = parent.getParent();
5019 }
5020 while (!stk.empty()) {
5021 buff.append("/" + stk.pop());
5022 }
5023 buff.append(getName());
5024 namingContextName = buff.toString();
5025 }
5026 }
5027 return namingContextName;
5028 }
5029
5030
5031 /**
5032 * Naming context listener accessor.
5033 */
5034 public NamingContextListener getNamingContextListener() {
5035 return namingContextListener;
5036 }
5037
5038
5039 /**
5040 * Naming context listener setter.
5041 */
5042 public void setNamingContextListener(NamingContextListener namingContextListener) {
5043 this.namingContextListener = namingContextListener;
5044 }
5045
5046
5047 /**
5048 * Return the request processing paused flag for this Context.
5049 */
5050 public boolean getPaused() {
5051
5052 return (this.paused);
5053
5054 }
5055
5056
5057 /**
5058 * Post a copy of our web application resources as a servlet context
5059 * attribute.
5060 */
5061 private void postResources() {
5062
5063 getServletContext().setAttribute
5064 (Globals.RESOURCES_ATTR, getResources());
5065
5066 }
5067
5068
5069 /**
5070 * Post a copy of our current list of welcome files as a servlet context
5071 * attribute, so that the default servlet can find them.
5072 */
5073 private void postWelcomeFiles() {
5074
5075 getServletContext().setAttribute("org.apache.catalina.WELCOME_FILES",
5076 welcomeFiles);
5077
5078 }
5079
5080 public String getHostname() {
5081 Container parentHost = getParent();
5082 if (parentHost != null) {
5083 hostName = parentHost.getName();
5084 }
5085 if ((hostName == null) || (hostName.length() < 1))
5086 hostName = "_";
5087 return hostName;
5088 }
5089
5090 /**
5091 * Set the appropriate context attribute for our work directory.
5092 */
5093 private void postWorkDirectory() {
5094
5095 // Acquire (or calculate) the work directory path
5096 String workDir = getWorkDir();
5097 if (workDir == null || workDir.length() == 0) {
5098
5099 // Retrieve our parent (normally a host) name
5100 String hostName = null;
5101 String engineName = null;
5102 String hostWorkDir = null;
5103 Container parentHost = getParent();
5104 if (parentHost != null) {
5105 hostName = parentHost.getName();
5106 if (parentHost instanceof StandardHost) {
5107 hostWorkDir = ((StandardHost)parentHost).getWorkDir();
5108 }
5109 Container parentEngine = parentHost.getParent();
5110 if (parentEngine != null) {
5111 engineName = parentEngine.getName();
5112 }
5113 }
5114 if ((hostName == null) || (hostName.length() < 1))
5115 hostName = "_";
5116 if ((engineName == null) || (engineName.length() < 1))
5117 engineName = "_";
5118
5119 String temp = getPath();
5120 if (temp.startsWith("/"))
5121 temp = temp.substring(1);
5122 temp = temp.replace('/', '_');
5123 temp = temp.replace('\\', '_');
5124 if (temp.length() < 1)
5125 temp = "_";
5126 if (hostWorkDir != null ) {
5127 workDir = hostWorkDir + File.separator + temp;
5128 } else {
5129 workDir = "work" + File.separator + engineName +
5130 File.separator + hostName + File.separator + temp;
5131 }
5132 setWorkDir(workDir);
5133 }
5134
5135 // Create this directory if necessary
5136 File dir = new File(workDir);
5137 if (!dir.isAbsolute()) {
5138 File catalinaHome = engineBase();
5139 String catalinaHomePath = null;
5140 try {
5141 catalinaHomePath = catalinaHome.getCanonicalPath();
5142 dir = new File(catalinaHomePath, workDir);
5143 } catch (IOException e) {
5144 }
5145 }
5146 dir.mkdirs();
5147
5148 // Set the appropriate servlet context attribute
5149 getServletContext().setAttribute(Globals.WORK_DIR_ATTR, dir);
5150 if (getServletContext() instanceof ApplicationContext)
5151 ((ApplicationContext) getServletContext()).setAttributeReadOnly
5152 (Globals.WORK_DIR_ATTR);
5153
5154 }
5155
5156
5157 /**
5158 * Set the request processing paused flag for this Context.
5159 *
5160 * @param paused The new request processing paused flag
5161 */
5162 private void setPaused(boolean paused) {
5163
5164 this.paused = paused;
5165
5166 }
5167
5168
5169 /**
5170 * Validate the syntax of a proposed <code><url-pattern></code>
5171 * for conformance with specification requirements.
5172 *
5173 * @param urlPattern URL pattern to be validated
5174 */
5175 private boolean validateURLPattern(String urlPattern) {
5176
5177 if (urlPattern == null)
5178 return (false);
5179 if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) {
5180 return (false);
5181 }
5182 if (urlPattern.startsWith("*.")) {
5183 if (urlPattern.indexOf('/') < 0) {
5184 checkUnusualURLPattern(urlPattern);
5185 return (true);
5186 } else
5187 return (false);
5188 }
5189 if ( (urlPattern.startsWith("/")) &&
5190 (urlPattern.indexOf("*.") < 0)) {
5191 checkUnusualURLPattern(urlPattern);
5192 return (true);
5193 } else
5194 return (false);
5195
5196 }
5197
5198
5199 /**
5200 * Check for unusual but valid <code><url-pattern></code>s.
5201 * See Bugzilla 34805, 43079 & 43080
5202 */
5203 private void checkUnusualURLPattern(String urlPattern) {
5204 if (log.isInfoEnabled()) {
5205 if(urlPattern.endsWith("*") && (urlPattern.length() < 2 ||
5206 urlPattern.charAt(urlPattern.length()-2) != '/')) {
5207 log.info("Suspicious url pattern: \"" + urlPattern + "\"" +
5208 " in context [" + getName() + "] - see" +
5209 " section SRV.11.2 of the Servlet specification" );
5210 }
5211 }
5212 }
5213
5214
5215 // ------------------------------------------------------------- Operations
5216
5217
5218 /**
5219 * JSR77 deploymentDescriptor attribute
5220 *
5221 * @return string deployment descriptor
5222 */
5223 public String getDeploymentDescriptor() {
5224
5225 InputStream stream = null;
5226 ServletContext servletContext = getServletContext();
5227 if (servletContext != null) {
5228 stream = servletContext.getResourceAsStream(
5229 org.apache.catalina.startup.Constants.ApplicationWebXml);
5230 }
5231 if (stream == null) {
5232 return "";
5233 }
5234 BufferedReader br = new BufferedReader(
5235 new InputStreamReader(stream));
5236 StringBuffer sb = new StringBuffer();
5237 String strRead = "";
5238 try {
5239 while (strRead != null) {
5240 sb.append(strRead);
5241 strRead = br.readLine();
5242 }
5243 } catch (IOException e) {
5244 return "";
5245 }
5246
5247 return sb.toString();
5248
5249 }
5250
5251
5252 /**
5253 * JSR77 servlets attribute
5254 *
5255 * @return list of all servlets ( we know about )
5256 */
5257 public String[] getServlets() {
5258
5259 String[] result = null;
5260
5261 Container[] children = findChildren();
5262 if (children != null) {
5263 result = new String[children.length];
5264 for( int i=0; i< children.length; i++ ) {
5265 result[i] = ((StandardWrapper)children[i]).getObjectName();
5266 }
5267 }
5268
5269 return result;
5270 }
5271
5272
5273 public ObjectName createObjectName(String hostDomain, ObjectName parentName)
5274 throws MalformedObjectNameException
5275 {
5276 String onameStr;
5277 StandardHost hst=(StandardHost)getParent();
5278
5279 String pathName=getName();
5280 String hostName=getParent().getName();
5281 String name= "//" + ((hostName==null)? "DEFAULT" : hostName) +
5282 (("".equals(pathName))?"/":pathName );
5283
5284 String suffix=",J2EEApplication=" +
5285 getJ2EEApplication() + ",J2EEServer=" +
5286 getJ2EEServer();
5287
5288 onameStr="j2eeType=WebModule,name=" + name + suffix;
5289 if( log.isDebugEnabled())
5290 log.debug("Registering " + onameStr + " for " + oname);
5291
5292 // default case - no domain explictely set.
5293 if( getDomain() == null ) domain=hst.getDomain();
5294
5295 ObjectName oname=new ObjectName(getDomain() + ":" + onameStr);
5296 return oname;
5297 }
5298
5299 private void preRegisterJMX() {
5300 try {
5301 StandardHost host = (StandardHost) getParent();
5302 if ((oname == null)
5303 || (oname.getKeyProperty("j2eeType") == null)) {
5304 oname = createObjectName(host.getDomain(), host.getJmxName());
5305 controller = oname;
5306 }
5307 } catch(Exception ex) {
5308 if(log.isInfoEnabled())
5309 log.info("Error registering ctx with jmx " + this + " " +
5310 oname + " " + ex.toString(), ex );
5311 }
5312 }
5313
5314 private void registerJMX() {
5315 try {
5316 if (log.isDebugEnabled()) {
5317 log.debug("Checking for " + oname );
5318 }
5319 if(! Registry.getRegistry(null, null)
5320 .getMBeanServer().isRegistered(oname)) {
5321 controller = oname;
5322 Registry.getRegistry(null, null)
5323 .registerComponent(this, oname, null);
5324
5325 // Send j2ee.object.created notification
5326 if (this.getObjectName() != null) {
5327 Notification notification = new Notification(
5328 "j2ee.object.created",
5329 this.getObjectName(),
5330 sequenceNumber++);
5331 broadcaster.sendNotification(notification);
5332 }
5333 }
5334 Container children[] = findChildren();
5335 for (int i=0; children!=null && i<children.length; i++) {
5336 ((StandardWrapper)children[i]).registerJMX( this );
5337 }
5338 } catch (Exception ex) {
5339 if(log.isInfoEnabled())
5340 log.info("Error registering wrapper with jmx " + this + " " +
5341 oname + " " + ex.toString(), ex );
5342 }
5343 }
5344
5345 /** There are 2 cases:
5346 * 1.The context is created and registered by internal APIS
5347 * 2. The context is created by JMX, and it'll self-register.
5348 *
5349 * @param server The server
5350 * @param name The object name
5351 * @return ObjectName The name of the object
5352 * @throws Exception If an error occurs
5353 */
5354 public ObjectName preRegister(MBeanServer server,
5355 ObjectName name)
5356 throws Exception
5357 {
5358 if( oname != null ) {
5359 //log.info( "Already registered " + oname + " " + name);
5360 // Temporary - /admin uses the old names
5361 return name;
5362 }
5363 ObjectName result=super.preRegister(server,name);
5364 return name;
5365 }
5366
5367 public void preDeregister() throws Exception {
5368 if( started ) {
5369 try {
5370 stop();
5371 } catch( Exception ex ) {
5372 log.error( "error stopping ", ex);
5373 }
5374 }
5375 }
5376
5377 public void init() throws Exception {
5378
5379 if( this.getParent() == null ) {
5380 ObjectName parentName=getParentName();
5381
5382 if( ! mserver.isRegistered(parentName)) {
5383 if(log.isDebugEnabled())
5384 log.debug("No host, creating one " + parentName);
5385 StandardHost host=new StandardHost();
5386 host.setName(hostName);
5387 host.setAutoDeploy(false);
5388 Registry.getRegistry(null, null)
5389 .registerComponent(host, parentName, null);
5390 // We could do it the hard way...
5391 //mserver.invoke(parentName, "init", new Object[] {}, new String[] {} );
5392 // or same thing easier:
5393 host.init();
5394 }
5395
5396 // Add the main configuration listener
5397 LifecycleListener config = null;
5398 try {
5399 String configClassName = null;
5400 try {
5401 configClassName = String.valueOf(mserver.getAttribute(parentName, "configClass"));
5402 } catch (AttributeNotFoundException e) {
5403 // Ignore, it's normal a host may not have this optional attribute
5404 }
5405 if (configClassName != null) {
5406 Class clazz = Class.forName(configClassName);
5407 config = (LifecycleListener) clazz.newInstance();
5408 } else {
5409 config = new ContextConfig();
5410 }
5411 } catch (Exception e) {
5412 log.warn("Error creating ContextConfig for " + parentName, e);
5413 throw e;
5414 }
5415 this.addLifecycleListener(config);
5416
5417 if (log.isDebugEnabled()) {
5418 log.debug("AddChild " + parentName + " " + this);
5419 }
5420 try {
5421 mserver.invoke(parentName, "addChild", new Object[] { this },
5422 new String[] {"org.apache.catalina.Container"});
5423 } catch (Exception e) {
5424 destroy();
5425 throw e;
5426 }
5427 // It's possible that addChild may have started us
5428 if( initialized ) {
5429 return;
5430 }
5431 }
5432 if (processTlds) {
5433 this.addLifecycleListener(new TldConfig());
5434 }
5435
5436 super.init();
5437
5438 // Notify our interested LifecycleListeners
5439 lifecycle.fireLifecycleEvent(INIT_EVENT, null);
5440
5441 // Send j2ee.state.starting notification
5442 if (this.getObjectName() != null) {
5443 Notification notification = new Notification("j2ee.state.starting",
5444 this.getObjectName(),
5445 sequenceNumber++);
5446 broadcaster.sendNotification(notification);
5447 }
5448
5449 }
5450
5451 public ObjectName getParentName() throws MalformedObjectNameException {
5452 // "Life" update
5453 String path=oname.getKeyProperty("name");
5454 if( path == null ) {
5455 log.error( "No name attribute " +name );
5456 return null;
5457 }
5458 if( ! path.startsWith( "//")) {
5459 log.error("Invalid name " + name);
5460 }
5461 path=path.substring(2);
5462 int delim=path.indexOf( "/" );
5463 hostName="localhost"; // Should be default...
5464 if( delim > 0 ) {
5465 hostName=path.substring(0, delim);
5466 path = path.substring(delim);
5467 if (path.equals("/")) {
5468 this.setName("");
5469 } else {
5470 this.setName(path);
5471 }
5472 } else {
5473 if(log.isDebugEnabled())
5474 log.debug("Setting path " + path );
5475 this.setName( path );
5476 }
5477 // XXX The service and domain should be the same.
5478 String parentDomain=getEngineName();
5479 if( parentDomain == null ) parentDomain=domain;
5480 ObjectName parentName=new ObjectName( parentDomain + ":" +
5481 "type=Host,host=" + hostName);
5482 return parentName;
5483 }
5484
5485 public void create() throws Exception{
5486 init();
5487 }
5488
5489 /* Remove a JMX notficationListener
5490 * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
5491 */
5492 public void removeNotificationListener(NotificationListener listener,
5493 NotificationFilter filter, Object object) throws ListenerNotFoundException {
5494 broadcaster.removeNotificationListener(listener,filter,object);
5495
5496 }
5497
5498 private MBeanNotificationInfo[] notificationInfo;
5499
5500 /* Get JMX Broadcaster Info
5501 * @TODO use StringManager for international support!
5502 * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
5503 * @see javax.management.NotificationBroadcaster#getNotificationInfo()
5504 */
5505 public MBeanNotificationInfo[] getNotificationInfo() {
5506 // FIXME: i18n
5507 if(notificationInfo == null) {
5508 notificationInfo = new MBeanNotificationInfo[]{
5509 new MBeanNotificationInfo(new String[] {
5510 "j2ee.object.created"},
5511 Notification.class.getName(),
5512 "web application is created"
5513 ),
5514 new MBeanNotificationInfo(new String[] {
5515 "j2ee.state.starting"},
5516 Notification.class.getName(),
5517 "change web application is starting"
5518 ),
5519 new MBeanNotificationInfo(new String[] {
5520 "j2ee.state.running"},
5521 Notification.class.getName(),
5522 "web application is running"
5523 ),
5524 new MBeanNotificationInfo(new String[] {
5525 "j2ee.state.stopped"},
5526 Notification.class.getName(),
5527 "web application start to stopped"
5528 ),
5529 new MBeanNotificationInfo(new String[] {
5530 "j2ee.object.stopped"},
5531 Notification.class.getName(),
5532 "web application is stopped"
5533 ),
5534 new MBeanNotificationInfo(new String[] {
5535 "j2ee.object.deleted"},
5536 Notification.class.getName(),
5537 "web application is deleted"
5538 )
5539 };
5540
5541 }
5542
5543 return notificationInfo;
5544 }
5545
5546
5547 /* Add a JMX-NotificationListener
5548 * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
5549 */
5550 public void addNotificationListener(NotificationListener listener,
5551 NotificationFilter filter, Object object) throws IllegalArgumentException {
5552 broadcaster.addNotificationListener(listener,filter,object);
5553
5554 }
5555
5556
5557 /**
5558 * Remove a JMX-NotificationListener
5559 * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
5560 */
5561 public void removeNotificationListener(NotificationListener listener)
5562 throws ListenerNotFoundException {
5563 broadcaster.removeNotificationListener(listener);
5564
5565 }
5566
5567
5568 // ------------------------------------------------------------- Attributes
5569
5570
5571 /**
5572 * Return the naming resources associated with this web application.
5573 */
5574 public javax.naming.directory.DirContext getStaticResources() {
5575
5576 return getResources();
5577
5578 }
5579
5580
5581 /**
5582 * Return the naming resources associated with this web application.
5583 * FIXME: Fooling introspection ...
5584 */
5585 public javax.naming.directory.DirContext findStaticResources() {
5586
5587 return getResources();
5588
5589 }
5590
5591
5592 /**
5593 * Return the naming resources associated with this web application.
5594 */
5595 public String[] getWelcomeFiles() {
5596
5597 return findWelcomeFiles();
5598
5599 }
5600
5601 /**
5602 * Set the validation feature of the XML parser used when
5603 * parsing xml instances.
5604 * @param webXmlValidation true to enable xml instance validation
5605 */
5606 public void setXmlValidation(boolean webXmlValidation){
5607
5608 this.webXmlValidation = webXmlValidation;
5609
5610 }
5611
5612 /**
5613 * Get the server.xml <context> attribute's xmlValidation.
5614 * @return true if validation is enabled.
5615 *
5616 */
5617 public boolean getXmlValidation(){
5618 return webXmlValidation;
5619 }
5620
5621
5622 /**
5623 * Get the server.xml <context> attribute's xmlNamespaceAware.
5624 * @return true if namespace awarenes is enabled.
5625 */
5626 public boolean getXmlNamespaceAware(){
5627 return webXmlNamespaceAware;
5628 }
5629
5630
5631 /**
5632 * Set the namespace aware feature of the XML parser used when
5633 * parsing xml instances.
5634 * @param webXmlNamespaceAware true to enable namespace awareness
5635 */
5636 public void setXmlNamespaceAware(boolean webXmlNamespaceAware){
5637 this.webXmlNamespaceAware= webXmlNamespaceAware;
5638 }
5639
5640
5641 /**
5642 * Set the validation feature of the XML parser used when
5643 * parsing tlds files.
5644 * @param tldValidation true to enable xml instance validation
5645 */
5646 public void setTldValidation(boolean tldValidation){
5647
5648 this.tldValidation = tldValidation;
5649
5650 }
5651
5652 /**
5653 * Get the server.xml <context> attribute's webXmlValidation.
5654 * @return true if validation is enabled.
5655 *
5656 */
5657 public boolean getTldValidation(){
5658 return tldValidation;
5659 }
5660
5661 /**
5662 * Sets the process TLDs attribute.
5663 *
5664 * @param newProcessTlds The new value
5665 */
5666 public void setProcessTlds(boolean newProcessTlds) {
5667 processTlds = newProcessTlds;
5668 }
5669
5670 /**
5671 * Returns the processTlds attribute value.
5672 */
5673 public boolean getProcessTlds() {
5674 return processTlds;
5675 }
5676
5677 /**
5678 * Get the server.xml <host> attribute's xmlNamespaceAware.
5679 * @return true if namespace awarenes is enabled.
5680 */
5681 public boolean getTldNamespaceAware(){
5682 return tldNamespaceAware;
5683 }
5684
5685
5686 /**
5687 * Set the namespace aware feature of the XML parser used when
5688 * parsing xml instances.
5689 * @param tldNamespaceAware true to enable namespace awareness
5690 */
5691 public void setTldNamespaceAware(boolean tldNamespaceAware){
5692 this.tldNamespaceAware= tldNamespaceAware;
5693 }
5694
5695
5696 /**
5697 * Support for "stateManageable" JSR77
5698 */
5699 public boolean isStateManageable() {
5700 return true;
5701 }
5702
5703 public void startRecursive() throws LifecycleException {
5704 // nothing to start recursive, the servlets will be started by load-on-startup
5705 start();
5706 }
5707
5708 public int getState() {
5709 if( started ) {
5710 return 1; // RUNNING
5711 }
5712 if( initialized ) {
5713 return 0; // starting ?
5714 }
5715 if( ! available ) {
5716 return 4; //FAILED
5717 }
5718 // 2 - STOPPING
5719 return 3; // STOPPED
5720 }
5721
5722 /**
5723 * The J2EE Server ObjectName this module is deployed on.
5724 */
5725 private String server = null;
5726
5727 /**
5728 * The Java virtual machines on which this module is running.
5729 */
5730 private String[] javaVMs = null;
5731
5732 public String getServer() {
5733 return server;
5734 }
5735
5736 public String setServer(String server) {
5737 return this.server=server;
5738 }
5739
5740 public String[] getJavaVMs() {
5741 return javaVMs;
5742 }
5743
5744 public String[] setJavaVMs(String[] javaVMs) {
5745 return this.javaVMs = javaVMs;
5746 }
5747
5748 /**
5749 * Gets the time this context was started.
5750 *
5751 * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this
5752 * context was started
5753 */
5754 public long getStartTime() {
5755 return startTime;
5756 }
5757
5758 public boolean isEventProvider() {
5759 return false;
5760 }
5761
5762 public boolean isStatisticsProvider() {
5763 return false;
5764 }
5765
5766 }