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.lang.reflect.Method;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.PrintStream;
25 import java.util.ArrayList;
26 import java.util.Enumeration;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Properties;
30 import java.util.Stack;
31 import java.security.AccessController;
32 import java.security.PrivilegedActionException;
33 import java.security.PrivilegedExceptionAction;
34 import javax.servlet.Servlet;
35 import javax.servlet.ServletConfig;
36 import javax.servlet.ServletContext;
37 import javax.servlet.ServletException;
38 import javax.servlet.ServletRequest;
39 import javax.servlet.ServletResponse;
40 import javax.servlet.SingleThreadModel;
41 import javax.servlet.UnavailableException;
42 import javax.management.ListenerNotFoundException;
43 import javax.management.MBeanNotificationInfo;
44 import javax.management.Notification;
45 import javax.management.NotificationBroadcasterSupport;
46 import javax.management.NotificationEmitter;
47 import javax.management.NotificationFilter;
48 import javax.management.NotificationListener;
49 import javax.management.ObjectName;
50
51 import org.apache.PeriodicEventListener;
52 import org.apache.catalina.Container;
53 import org.apache.catalina.ContainerServlet;
54 import org.apache.catalina.Context;
55 import org.apache.catalina.Globals;
56 import org.apache.catalina.InstanceEvent;
57 import org.apache.catalina.InstanceListener;
58 import org.apache.catalina.LifecycleException;
59 import org.apache.catalina.Loader;
60 import org.apache.catalina.Wrapper;
61 import org.apache.catalina.security.SecurityUtil;
62 import org.apache.catalina.util.Enumerator;
63 import org.apache.catalina.util.InstanceSupport;
64 import org.apache.tomcat.util.log.SystemLogHandler;
65 import org.apache.tomcat.util.modeler.Registry;
66
67 /**
68 * Standard implementation of the <b>Wrapper</b> interface that represents
69 * an individual servlet definition. No child Containers are allowed, and
70 * the parent Container must be a Context.
71 *
72 * @author Craig R. McClanahan
73 * @author Remy Maucherat
74 * @version $Revision: 598795 $ $Date: 2007-11-27 23:43:49 +0100 (mar., 27 nov. 2007) $
75 */
76 public class StandardWrapper
77 extends ContainerBase
78 implements ServletConfig, Wrapper, NotificationEmitter {
79
80 protected static org.apache.juli.logging.Log log=
81 org.apache.juli.logging.LogFactory.getLog( StandardWrapper.class );
82
83 protected static final String[] DEFAULT_SERVLET_METHODS = new String[] {
84 "GET", "HEAD", "POST" };
85
86 // ----------------------------------------------------------- Constructors
87
88
89 /**
90 * Create a new StandardWrapper component with the default basic Valve.
91 */
92 public StandardWrapper() {
93
94 super();
95 swValve=new StandardWrapperValve();
96 pipeline.setBasic(swValve);
97 broadcaster = new NotificationBroadcasterSupport();
98
99 if (restrictedServlets == null) {
100 restrictedServlets = new Properties();
101 try {
102 InputStream is =
103 this.getClass().getClassLoader().getResourceAsStream
104 ("org/apache/catalina/core/RestrictedServlets.properties");
105 if (is != null) {
106 restrictedServlets.load(is);
107 } else {
108 log.error(sm.getString("standardWrapper.restrictedServletsResource"));
109 }
110 } catch (IOException e) {
111 log.error(sm.getString("standardWrapper.restrictedServletsResource"), e);
112 }
113 }
114
115 }
116
117
118 // ----------------------------------------------------- Instance Variables
119
120
121 /**
122 * The date and time at which this servlet will become available (in
123 * milliseconds since the epoch), or zero if the servlet is available.
124 * If this value equals Long.MAX_VALUE, the unavailability of this
125 * servlet is considered permanent.
126 */
127 protected long available = 0L;
128
129 /**
130 * The broadcaster that sends j2ee notifications.
131 */
132 protected NotificationBroadcasterSupport broadcaster = null;
133
134 /**
135 * The count of allocations that are currently active (even if they
136 * are for the same instance, as will be true on a non-STM servlet).
137 */
138 protected int countAllocated = 0;
139
140
141 /**
142 * The facade associated with this wrapper.
143 */
144 protected StandardWrapperFacade facade =
145 new StandardWrapperFacade(this);
146
147
148 /**
149 * The descriptive information string for this implementation.
150 */
151 protected static final String info =
152 "org.apache.catalina.core.StandardWrapper/1.0";
153
154
155 /**
156 * The (single) initialized instance of this servlet.
157 */
158 protected Servlet instance = null;
159
160
161 /**
162 * The support object for our instance listeners.
163 */
164 protected InstanceSupport instanceSupport = new InstanceSupport(this);
165
166
167 /**
168 * The context-relative URI of the JSP file for this servlet.
169 */
170 protected String jspFile = null;
171
172
173 /**
174 * The load-on-startup order value (negative value means load on
175 * first call) for this servlet.
176 */
177 protected int loadOnStartup = -1;
178
179
180 /**
181 * Mappings associated with the wrapper.
182 */
183 protected ArrayList mappings = new ArrayList();
184
185
186 /**
187 * The initialization parameters for this servlet, keyed by
188 * parameter name.
189 */
190 protected HashMap parameters = new HashMap();
191
192
193 /**
194 * The security role references for this servlet, keyed by role name
195 * used in the servlet. The corresponding value is the role name of
196 * the web application itself.
197 */
198 protected HashMap references = new HashMap();
199
200
201 /**
202 * The run-as identity for this servlet.
203 */
204 protected String runAs = null;
205
206 /**
207 * The notification sequence number.
208 */
209 protected long sequenceNumber = 0;
210
211 /**
212 * The fully qualified servlet class name for this servlet.
213 */
214 protected String servletClass = null;
215
216
217 /**
218 * Does this servlet implement the SingleThreadModel interface?
219 */
220 protected boolean singleThreadModel = false;
221
222
223 /**
224 * Are we unloading our servlet instance at the moment?
225 */
226 protected boolean unloading = false;
227
228
229 /**
230 * Maximum number of STM instances.
231 */
232 protected int maxInstances = 20;
233
234
235 /**
236 * Number of instances currently loaded for a STM servlet.
237 */
238 protected int nInstances = 0;
239
240
241 /**
242 * Stack containing the STM instances.
243 */
244 protected Stack instancePool = null;
245
246
247 /**
248 * Wait time for servlet unload in ms.
249 */
250 protected long unloadDelay = 2000;
251
252
253 /**
254 * True if this StandardWrapper is for the JspServlet
255 */
256 protected boolean isJspServlet;
257
258
259 /**
260 * The ObjectName of the JSP monitoring mbean
261 */
262 protected ObjectName jspMonitorON;
263
264
265 /**
266 * Should we swallow System.out
267 */
268 protected boolean swallowOutput = false;
269
270 // To support jmx attributes
271 protected StandardWrapperValve swValve;
272 protected long loadTime=0;
273 protected int classLoadTime=0;
274
275 /**
276 * Static class array used when the SecurityManager is turned on and
277 * <code>Servlet.init</code> is invoked.
278 */
279 protected static Class[] classType = new Class[]{ServletConfig.class};
280
281
282 /**
283 * Static class array used when the SecurityManager is turned on and
284 * <code>Servlet.service</code> is invoked.
285 */
286 protected static Class[] classTypeUsedInService = new Class[]{
287 ServletRequest.class,
288 ServletResponse.class};
289
290 /**
291 * Restricted servlets (which can only be loaded by a privileged webapp).
292 */
293 protected static Properties restrictedServlets = null;
294
295
296 // ------------------------------------------------------------- Properties
297
298
299 /**
300 * Return the available date/time for this servlet, in milliseconds since
301 * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
302 * that unavailability is permanent and any request for this servlet will return
303 * an SC_NOT_FOUND error. If this date/time is in the future, any request for
304 * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero,
305 * the servlet is currently available.
306 */
307 public long getAvailable() {
308
309 return (this.available);
310
311 }
312
313
314 /**
315 * Set the available date/time for this servlet, in milliseconds since the
316 * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
317 * that unavailability is permanent and any request for this servlet will return
318 * an SC_NOT_FOUND error. If this date/time is in the future, any request for
319 * this servlet will return an SC_SERVICE_UNAVAILABLE error.
320 *
321 * @param available The new available date/time
322 */
323 public void setAvailable(long available) {
324
325 long oldAvailable = this.available;
326 if (available > System.currentTimeMillis())
327 this.available = available;
328 else
329 this.available = 0L;
330 support.firePropertyChange("available", new Long(oldAvailable),
331 new Long(this.available));
332
333 }
334
335
336 /**
337 * Return the number of active allocations of this servlet, even if they
338 * are all for the same instance (as will be true for servlets that do
339 * not implement <code>SingleThreadModel</code>.
340 */
341 public int getCountAllocated() {
342
343 return (this.countAllocated);
344
345 }
346
347
348 public String getEngineName() {
349 return ((StandardContext)getParent()).getEngineName();
350 }
351
352
353 /**
354 * Return descriptive information about this Container implementation and
355 * the corresponding version number, in the format
356 * <code><description>/<version></code>.
357 */
358 public String getInfo() {
359
360 return (info);
361
362 }
363
364
365 /**
366 * Return the InstanceSupport object for this Wrapper instance.
367 */
368 public InstanceSupport getInstanceSupport() {
369
370 return (this.instanceSupport);
371
372 }
373
374
375 /**
376 * Return the context-relative URI of the JSP file for this servlet.
377 */
378 public String getJspFile() {
379
380 return (this.jspFile);
381
382 }
383
384
385 /**
386 * Set the context-relative URI of the JSP file for this servlet.
387 *
388 * @param jspFile JSP file URI
389 */
390 public void setJspFile(String jspFile) {
391
392 String oldJspFile = this.jspFile;
393 this.jspFile = jspFile;
394 support.firePropertyChange("jspFile", oldJspFile, this.jspFile);
395
396 // Each jsp-file needs to be represented by its own JspServlet and
397 // corresponding JspMonitoring mbean, because it may be initialized
398 // with its own init params
399 isJspServlet = true;
400
401 }
402
403
404 /**
405 * Return the load-on-startup order value (negative value means
406 * load on first call).
407 */
408 public int getLoadOnStartup() {
409
410 if (isJspServlet && loadOnStartup < 0) {
411 /*
412 * JspServlet must always be preloaded, because its instance is
413 * used during registerJMX (when registering the JSP
414 * monitoring mbean)
415 */
416 return Integer.MAX_VALUE;
417 } else {
418 return (this.loadOnStartup);
419 }
420 }
421
422
423 /**
424 * Set the load-on-startup order value (negative value means
425 * load on first call).
426 *
427 * @param value New load-on-startup value
428 */
429 public void setLoadOnStartup(int value) {
430
431 int oldLoadOnStartup = this.loadOnStartup;
432 this.loadOnStartup = value;
433 support.firePropertyChange("loadOnStartup",
434 new Integer(oldLoadOnStartup),
435 new Integer(this.loadOnStartup));
436
437 }
438
439
440
441 /**
442 * Set the load-on-startup order value from a (possibly null) string.
443 * Per the specification, any missing or non-numeric value is converted
444 * to a zero, so that this servlet will still be loaded at startup
445 * time, but in an arbitrary order.
446 *
447 * @param value New load-on-startup value
448 */
449 public void setLoadOnStartupString(String value) {
450
451 try {
452 setLoadOnStartup(Integer.parseInt(value));
453 } catch (NumberFormatException e) {
454 setLoadOnStartup(0);
455 }
456 }
457
458 public String getLoadOnStartupString() {
459 return Integer.toString( getLoadOnStartup());
460 }
461
462
463 /**
464 * Return maximum number of instances that will be allocated when a single
465 * thread model servlet is used.
466 */
467 public int getMaxInstances() {
468
469 return (this.maxInstances);
470
471 }
472
473
474 /**
475 * Set the maximum number of instances that will be allocated when a single
476 * thread model servlet is used.
477 *
478 * @param maxInstances New value of maxInstances
479 */
480 public void setMaxInstances(int maxInstances) {
481
482 int oldMaxInstances = this.maxInstances;
483 this.maxInstances = maxInstances;
484 support.firePropertyChange("maxInstances", oldMaxInstances,
485 this.maxInstances);
486
487 }
488
489
490 /**
491 * Set the parent Container of this Wrapper, but only if it is a Context.
492 *
493 * @param container Proposed parent Container
494 */
495 public void setParent(Container container) {
496
497 if ((container != null) &&
498 !(container instanceof Context))
499 throw new IllegalArgumentException
500 (sm.getString("standardWrapper.notContext"));
501 if (container instanceof StandardContext) {
502 swallowOutput = ((StandardContext)container).getSwallowOutput();
503 unloadDelay = ((StandardContext)container).getUnloadDelay();
504 }
505 super.setParent(container);
506
507 }
508
509
510 /**
511 * Return the run-as identity for this servlet.
512 */
513 public String getRunAs() {
514
515 return (this.runAs);
516
517 }
518
519
520 /**
521 * Set the run-as identity for this servlet.
522 *
523 * @param runAs New run-as identity value
524 */
525 public void setRunAs(String runAs) {
526
527 String oldRunAs = this.runAs;
528 this.runAs = runAs;
529 support.firePropertyChange("runAs", oldRunAs, this.runAs);
530
531 }
532
533
534 /**
535 * Return the fully qualified servlet class name for this servlet.
536 */
537 public String getServletClass() {
538
539 return (this.servletClass);
540
541 }
542
543
544 /**
545 * Set the fully qualified servlet class name for this servlet.
546 *
547 * @param servletClass Servlet class name
548 */
549 public void setServletClass(String servletClass) {
550
551 String oldServletClass = this.servletClass;
552 this.servletClass = servletClass;
553 support.firePropertyChange("servletClass", oldServletClass,
554 this.servletClass);
555 if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) {
556 isJspServlet = true;
557 }
558 }
559
560
561
562 /**
563 * Set the name of this servlet. This is an alias for the normal
564 * <code>Container.setName()</code> method, and complements the
565 * <code>getServletName()</code> method required by the
566 * <code>ServletConfig</code> interface.
567 *
568 * @param name The new name of this servlet
569 */
570 public void setServletName(String name) {
571
572 setName(name);
573
574 }
575
576
577 /**
578 * Return <code>true</code> if the servlet class represented by this
579 * component implements the <code>SingleThreadModel</code> interface.
580 */
581 public boolean isSingleThreadModel() {
582
583 try {
584 loadServlet();
585 } catch (Throwable t) {
586 ;
587 }
588 return (singleThreadModel);
589
590 }
591
592
593 /**
594 * Is this servlet currently unavailable?
595 */
596 public boolean isUnavailable() {
597
598 if (available == 0L)
599 return (false);
600 else if (available <= System.currentTimeMillis()) {
601 available = 0L;
602 return (false);
603 } else
604 return (true);
605
606 }
607
608
609 /**
610 * Gets the names of the methods supported by the underlying servlet.
611 *
612 * This is the same set of methods included in the Allow response header
613 * in response to an OPTIONS request method processed by the underlying
614 * servlet.
615 *
616 * @return Array of names of the methods supported by the underlying
617 * servlet
618 */
619 public String[] getServletMethods() throws ServletException {
620
621 Class servletClazz = loadServlet().getClass();
622 if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
623 servletClazz)) {
624 return DEFAULT_SERVLET_METHODS;
625 }
626
627 HashSet allow = new HashSet();
628 allow.add("TRACE");
629 allow.add("OPTIONS");
630
631 Method[] methods = getAllDeclaredMethods(servletClazz);
632 for (int i=0; methods != null && i<methods.length; i++) {
633 Method m = methods[i];
634
635 if (m.getName().equals("doGet")) {
636 allow.add("GET");
637 allow.add("HEAD");
638 } else if (m.getName().equals("doPost")) {
639 allow.add("POST");
640 } else if (m.getName().equals("doPut")) {
641 allow.add("PUT");
642 } else if (m.getName().equals("doDelete")) {
643 allow.add("DELETE");
644 }
645 }
646
647 String[] methodNames = new String[allow.size()];
648 return (String[]) allow.toArray(methodNames);
649
650 }
651
652
653 // --------------------------------------------------------- Public Methods
654
655
656 /**
657 * Execute a periodic task, such as reloading, etc. This method will be
658 * invoked inside the classloading context of this container. Unexpected
659 * throwables will be caught and logged.
660 */
661 public void backgroundProcess() {
662 super.backgroundProcess();
663
664 if (!started)
665 return;
666
667 if (getServlet() != null && (getServlet() instanceof PeriodicEventListener)) {
668 ((PeriodicEventListener) getServlet()).periodicEvent();
669 }
670 }
671
672
673 /**
674 * Extract the root cause from a servlet exception.
675 *
676 * @param e The servlet exception
677 */
678 public static Throwable getRootCause(ServletException e) {
679 Throwable rootCause = e;
680 Throwable rootCauseCheck = null;
681 // Extra aggressive rootCause finding
682 int loops = 0;
683 do {
684 loops++;
685 rootCauseCheck = rootCause.getCause();
686 if (rootCauseCheck != null)
687 rootCause = rootCauseCheck;
688 } while (rootCauseCheck != null && (loops < 20));
689 return rootCause;
690 }
691
692
693 /**
694 * Refuse to add a child Container, because Wrappers are the lowest level
695 * of the Container hierarchy.
696 *
697 * @param child Child container to be added
698 */
699 public void addChild(Container child) {
700
701 throw new IllegalStateException
702 (sm.getString("standardWrapper.notChild"));
703
704 }
705
706
707 /**
708 * Add a new servlet initialization parameter for this servlet.
709 *
710 * @param name Name of this initialization parameter to add
711 * @param value Value of this initialization parameter to add
712 */
713 public void addInitParameter(String name, String value) {
714
715 synchronized (parameters) {
716 parameters.put(name, value);
717 }
718 fireContainerEvent("addInitParameter", name);
719
720 }
721
722
723 /**
724 * Add a new listener interested in InstanceEvents.
725 *
726 * @param listener The new listener
727 */
728 public void addInstanceListener(InstanceListener listener) {
729
730 instanceSupport.addInstanceListener(listener);
731
732 }
733
734
735 /**
736 * Add a mapping associated with the Wrapper.
737 *
738 * @param mapping The new wrapper mapping
739 */
740 public void addMapping(String mapping) {
741
742 synchronized (mappings) {
743 mappings.add(mapping);
744 }
745 fireContainerEvent("addMapping", mapping);
746
747 }
748
749
750 /**
751 * Add a new security role reference record to the set of records for
752 * this servlet.
753 *
754 * @param name Role name used within this servlet
755 * @param link Role name used within the web application
756 */
757 public void addSecurityReference(String name, String link) {
758
759 synchronized (references) {
760 references.put(name, link);
761 }
762 fireContainerEvent("addSecurityReference", name);
763
764 }
765
766
767 /**
768 * Return the associated servlet instance.
769 */
770 public Servlet getServlet() {
771 return instance;
772 }
773
774
775 /**
776 * Allocate an initialized instance of this Servlet that is ready to have
777 * its <code>service()</code> method called. If the servlet class does
778 * not implement <code>SingleThreadModel</code>, the (only) initialized
779 * instance may be returned immediately. If the servlet class implements
780 * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
781 * that this instance is not allocated again until it is deallocated by a
782 * call to <code>deallocate()</code>.
783 *
784 * @exception ServletException if the servlet init() method threw
785 * an exception
786 * @exception ServletException if a loading error occurs
787 */
788 public Servlet allocate() throws ServletException {
789
790 // If we are currently unloading this servlet, throw an exception
791 if (unloading)
792 throw new ServletException
793 (sm.getString("standardWrapper.unloading", getName()));
794
795 // If not SingleThreadedModel, return the same instance every time
796 if (!singleThreadModel) {
797
798 // Load and initialize our instance if necessary
799 if (instance == null) {
800 synchronized (this) {
801 if (instance == null) {
802 try {
803 if (log.isDebugEnabled())
804 log.debug("Allocating non-STM instance");
805
806 instance = loadServlet();
807 } catch (ServletException e) {
808 throw e;
809 } catch (Throwable e) {
810 throw new ServletException
811 (sm.getString("standardWrapper.allocate"), e);
812 }
813 }
814 }
815 }
816
817 if (!singleThreadModel) {
818 if (log.isTraceEnabled())
819 log.trace(" Returning non-STM instance");
820 countAllocated++;
821 return (instance);
822 }
823
824 }
825
826 synchronized (instancePool) {
827
828 while (countAllocated >= nInstances) {
829 // Allocate a new instance if possible, or else wait
830 if (nInstances < maxInstances) {
831 try {
832 instancePool.push(loadServlet());
833 nInstances++;
834 } catch (ServletException e) {
835 throw e;
836 } catch (Throwable e) {
837 throw new ServletException
838 (sm.getString("standardWrapper.allocate"), e);
839 }
840 } else {
841 try {
842 instancePool.wait();
843 } catch (InterruptedException e) {
844 ;
845 }
846 }
847 }
848 if (log.isTraceEnabled())
849 log.trace(" Returning allocated STM instance");
850 countAllocated++;
851 return (Servlet) instancePool.pop();
852
853 }
854
855 }
856
857
858 /**
859 * Return this previously allocated servlet to the pool of available
860 * instances. If this servlet class does not implement SingleThreadModel,
861 * no action is actually required.
862 *
863 * @param servlet The servlet to be returned
864 *
865 * @exception ServletException if a deallocation error occurs
866 */
867 public void deallocate(Servlet servlet) throws ServletException {
868
869 // If not SingleThreadModel, no action is required
870 if (!singleThreadModel) {
871 countAllocated--;
872 return;
873 }
874
875 // Unlock and free this instance
876 synchronized (instancePool) {
877 countAllocated--;
878 instancePool.push(servlet);
879 instancePool.notify();
880 }
881
882 }
883
884
885 /**
886 * Return the value for the specified initialization parameter name,
887 * if any; otherwise return <code>null</code>.
888 *
889 * @param name Name of the requested initialization parameter
890 */
891 public String findInitParameter(String name) {
892
893 synchronized (parameters) {
894 return ((String) parameters.get(name));
895 }
896
897 }
898
899
900 /**
901 * Return the names of all defined initialization parameters for this
902 * servlet.
903 */
904 public String[] findInitParameters() {
905
906 synchronized (parameters) {
907 String results[] = new String[parameters.size()];
908 return ((String[]) parameters.keySet().toArray(results));
909 }
910
911 }
912
913
914 /**
915 * Return the mappings associated with this wrapper.
916 */
917 public String[] findMappings() {
918
919 synchronized (mappings) {
920 return (String[]) mappings.toArray(new String[mappings.size()]);
921 }
922
923 }
924
925
926 /**
927 * Return the security role link for the specified security role
928 * reference name, if any; otherwise return <code>null</code>.
929 *
930 * @param name Security role reference used within this servlet
931 */
932 public String findSecurityReference(String name) {
933
934 synchronized (references) {
935 return ((String) references.get(name));
936 }
937
938 }
939
940
941 /**
942 * Return the set of security role reference names associated with
943 * this servlet, if any; otherwise return a zero-length array.
944 */
945 public String[] findSecurityReferences() {
946
947 synchronized (references) {
948 String results[] = new String[references.size()];
949 return ((String[]) references.keySet().toArray(results));
950 }
951
952 }
953
954
955 /**
956 * FIXME: Fooling introspection ...
957 */
958 public Wrapper findMappingObject() {
959 return (Wrapper) getMappingObject();
960 }
961
962
963 /**
964 * Load and initialize an instance of this servlet, if there is not already
965 * at least one initialized instance. This can be used, for example, to
966 * load servlets that are marked in the deployment descriptor to be loaded
967 * at server startup time.
968 * <p>
969 * <b>IMPLEMENTATION NOTE</b>: Servlets whose classnames begin with
970 * <code>org.apache.catalina.</code> (so-called "container" servlets)
971 * are loaded by the same classloader that loaded this class, rather than
972 * the classloader for the current web application.
973 * This gives such classes access to Catalina internals, which are
974 * prevented for classes loaded for web applications.
975 *
976 * @exception ServletException if the servlet init() method threw
977 * an exception
978 * @exception ServletException if some other loading problem occurs
979 */
980 public synchronized void load() throws ServletException {
981 instance = loadServlet();
982 }
983
984
985 /**
986 * Load and initialize an instance of this servlet, if there is not already
987 * at least one initialized instance. This can be used, for example, to
988 * load servlets that are marked in the deployment descriptor to be loaded
989 * at server startup time.
990 */
991 public synchronized Servlet loadServlet() throws ServletException {
992
993 // Nothing to do if we already have an instance or an instance pool
994 if (!singleThreadModel && (instance != null))
995 return instance;
996
997 PrintStream out = System.out;
998 if (swallowOutput) {
999 SystemLogHandler.startCapture();
1000 }
1001
1002 Servlet servlet;
1003 try {
1004 long t1=System.currentTimeMillis();
1005 // If this "servlet" is really a JSP file, get the right class.
1006 // HOLD YOUR NOSE - this is a kludge that avoids having to do special
1007 // case Catalina-specific code in Jasper - it also requires that the
1008 // servlet path be replaced by the <jsp-file> element content in
1009 // order to be completely effective
1010 String actualClass = servletClass;
1011 if ((actualClass == null) && (jspFile != null)) {
1012 Wrapper jspWrapper = (Wrapper)
1013 ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
1014 if (jspWrapper != null) {
1015 actualClass = jspWrapper.getServletClass();
1016 // Merge init parameters
1017 String paramNames[] = jspWrapper.findInitParameters();
1018 for (int i = 0; i < paramNames.length; i++) {
1019 if (parameters.get(paramNames[i]) == null) {
1020 parameters.put
1021 (paramNames[i],
1022 jspWrapper.findInitParameter(paramNames[i]));
1023 }
1024 }
1025 }
1026 }
1027
1028 // Complain if no servlet class has been specified
1029 if (actualClass == null) {
1030 unavailable(null);
1031 throw new ServletException
1032 (sm.getString("standardWrapper.notClass", getName()));
1033 }
1034
1035 // Acquire an instance of the class loader to be used
1036 Loader loader = getLoader();
1037 if (loader == null) {
1038 unavailable(null);
1039 throw new ServletException
1040 (sm.getString("standardWrapper.missingLoader", getName()));
1041 }
1042
1043 ClassLoader classLoader = loader.getClassLoader();
1044
1045 // Special case class loader for a container provided servlet
1046 //
1047 if (isContainerProvidedServlet(actualClass) &&
1048 ! ((Context)getParent()).getPrivileged() ) {
1049 // If it is a priviledged context - using its own
1050 // class loader will work, since it's a child of the container
1051 // loader
1052 classLoader = this.getClass().getClassLoader();
1053 }
1054
1055 // Load the specified servlet class from the appropriate class loader
1056 Class classClass = null;
1057 try {
1058 if (SecurityUtil.isPackageProtectionEnabled()){
1059 final ClassLoader fclassLoader = classLoader;
1060 final String factualClass = actualClass;
1061 try{
1062 classClass = (Class)AccessController.doPrivileged(
1063 new PrivilegedExceptionAction(){
1064 public Object run() throws Exception{
1065 if (fclassLoader != null) {
1066 return fclassLoader.loadClass(factualClass);
1067 } else {
1068 return Class.forName(factualClass);
1069 }
1070 }
1071 });
1072 } catch(PrivilegedActionException pax){
1073 Exception ex = pax.getException();
1074 if (ex instanceof ClassNotFoundException){
1075 throw (ClassNotFoundException)ex;
1076 } else {
1077 getServletContext().log( "Error loading "
1078 + fclassLoader + " " + factualClass, ex );
1079 }
1080 }
1081 } else {
1082 if (classLoader != null) {
1083 classClass = classLoader.loadClass(actualClass);
1084 } else {
1085 classClass = Class.forName(actualClass);
1086 }
1087 }
1088 } catch (ClassNotFoundException e) {
1089 unavailable(null);
1090 getServletContext().log( "Error loading " + classLoader + " " + actualClass, e );
1091 throw new ServletException
1092 (sm.getString("standardWrapper.missingClass", actualClass),
1093 e);
1094 }
1095
1096 if (classClass == null) {
1097 unavailable(null);
1098 throw new ServletException
1099 (sm.getString("standardWrapper.missingClass", actualClass));
1100 }
1101
1102 // Instantiate and initialize an instance of the servlet class itself
1103 try {
1104 servlet = (Servlet) classClass.newInstance();
1105 // Annotation processing
1106 if (!((Context) getParent()).getIgnoreAnnotations()) {
1107 if (getParent() instanceof StandardContext) {
1108 ((StandardContext)getParent()).getAnnotationProcessor().processAnnotations(servlet);
1109 ((StandardContext)getParent()).getAnnotationProcessor().postConstruct(servlet);
1110 }
1111 }
1112 } catch (ClassCastException e) {
1113 unavailable(null);
1114 // Restore the context ClassLoader
1115 throw new ServletException
1116 (sm.getString("standardWrapper.notServlet", actualClass), e);
1117 } catch (Throwable e) {
1118 unavailable(null);
1119
1120 // Added extra log statement for Bugzilla 36630:
1121 // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
1122 if(log.isDebugEnabled()) {
1123 log.debug(sm.getString("standardWrapper.instantiate", actualClass), e);
1124 }
1125
1126 // Restore the context ClassLoader
1127 throw new ServletException
1128 (sm.getString("standardWrapper.instantiate", actualClass), e);
1129 }
1130
1131 // Check if loading the servlet in this web application should be
1132 // allowed
1133 if (!isServletAllowed(servlet)) {
1134 throw new SecurityException
1135 (sm.getString("standardWrapper.privilegedServlet",
1136 actualClass));
1137 }
1138
1139 // Special handling for ContainerServlet instances
1140 if ((servlet instanceof ContainerServlet) &&
1141 (isContainerProvidedServlet(actualClass) ||
1142 ((Context)getParent()).getPrivileged() )) {
1143 ((ContainerServlet) servlet).setWrapper(this);
1144 }
1145
1146 classLoadTime=(int) (System.currentTimeMillis() -t1);
1147 // Call the initialization method of this servlet
1148 try {
1149 instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
1150 servlet);
1151
1152 if( Globals.IS_SECURITY_ENABLED) {
1153
1154 Object[] args = new Object[]{((ServletConfig)facade)};
1155 SecurityUtil.doAsPrivilege("init",
1156 servlet,
1157 classType,
1158 args);
1159 args = null;
1160 } else {
1161 servlet.init(facade);
1162 }
1163
1164 // Invoke jspInit on JSP pages
1165 if ((loadOnStartup >= 0) && (jspFile != null)) {
1166 // Invoking jspInit
1167 DummyRequest req = new DummyRequest();
1168 req.setServletPath(jspFile);
1169 req.setQueryString("jsp_precompile=true");
1170 DummyResponse res = new DummyResponse();
1171
1172 if( Globals.IS_SECURITY_ENABLED) {
1173 Object[] args = new Object[]{req, res};
1174 SecurityUtil.doAsPrivilege("service",
1175 servlet,
1176 classTypeUsedInService,
1177 args);
1178 args = null;
1179 } else {
1180 servlet.service(req, res);
1181 }
1182 }
1183 instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
1184 servlet);
1185 } catch (UnavailableException f) {
1186 instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
1187 servlet, f);
1188 unavailable(f);
1189 throw f;
1190 } catch (ServletException f) {
1191 instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
1192 servlet, f);
1193 // If the servlet wanted to be unavailable it would have
1194 // said so, so do not call unavailable(null).
1195 throw f;
1196 } catch (Throwable f) {
1197 getServletContext().log("StandardWrapper.Throwable", f );
1198 instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
1199 servlet, f);
1200 // If the servlet wanted to be unavailable it would have
1201 // said so, so do not call unavailable(null).
1202 throw new ServletException
1203 (sm.getString("standardWrapper.initException", getName()), f);
1204 }
1205
1206 // Register our newly initialized instance
1207 singleThreadModel = servlet instanceof SingleThreadModel;
1208 if (singleThreadModel) {
1209 if (instancePool == null)
1210 instancePool = new Stack();
1211 }
1212 fireContainerEvent("load", this);
1213
1214 loadTime=System.currentTimeMillis() -t1;
1215 } finally {
1216 if (swallowOutput) {
1217 String log = SystemLogHandler.stopCapture();
1218 if (log != null && log.length() > 0) {
1219 if (getServletContext() != null) {
1220 getServletContext().log(log);
1221 } else {
1222 out.println(log);
1223 }
1224 }
1225 }
1226 }
1227 return servlet;
1228
1229 }
1230
1231
1232 /**
1233 * Remove the specified initialization parameter from this servlet.
1234 *
1235 * @param name Name of the initialization parameter to remove
1236 */
1237 public void removeInitParameter(String name) {
1238
1239 synchronized (parameters) {
1240 parameters.remove(name);
1241 }
1242 fireContainerEvent("removeInitParameter", name);
1243
1244 }
1245
1246
1247 /**
1248 * Remove a listener no longer interested in InstanceEvents.
1249 *
1250 * @param listener The listener to remove
1251 */
1252 public void removeInstanceListener(InstanceListener listener) {
1253
1254 instanceSupport.removeInstanceListener(listener);
1255
1256 }
1257
1258
1259 /**
1260 * Remove a mapping associated with the wrapper.
1261 *
1262 * @param mapping The pattern to remove
1263 */
1264 public void removeMapping(String mapping) {
1265
1266 synchronized (mappings) {
1267 mappings.remove(mapping);
1268 }
1269 fireContainerEvent("removeMapping", mapping);
1270
1271 }
1272
1273
1274 /**
1275 * Remove any security role reference for the specified role name.
1276 *
1277 * @param name Security role used within this servlet to be removed
1278 */
1279 public void removeSecurityReference(String name) {
1280
1281 synchronized (references) {
1282 references.remove(name);
1283 }
1284 fireContainerEvent("removeSecurityReference", name);
1285
1286 }
1287
1288
1289 /**
1290 * Return a String representation of this component.
1291 */
1292 public String toString() {
1293
1294 StringBuffer sb = new StringBuffer();
1295 if (getParent() != null) {
1296 sb.append(getParent().toString());
1297 sb.append(".");
1298 }
1299 sb.append("StandardWrapper[");
1300 sb.append(getName());
1301 sb.append("]");
1302 return (sb.toString());
1303
1304 }
1305
1306
1307 /**
1308 * Process an UnavailableException, marking this servlet as unavailable
1309 * for the specified amount of time.
1310 *
1311 * @param unavailable The exception that occurred, or <code>null</code>
1312 * to mark this servlet as permanently unavailable
1313 */
1314 public void unavailable(UnavailableException unavailable) {
1315 getServletContext().log(sm.getString("standardWrapper.unavailable", getName()));
1316 if (unavailable == null)
1317 setAvailable(Long.MAX_VALUE);
1318 else if (unavailable.isPermanent())
1319 setAvailable(Long.MAX_VALUE);
1320 else {
1321 int unavailableSeconds = unavailable.getUnavailableSeconds();
1322 if (unavailableSeconds <= 0)
1323 unavailableSeconds = 60; // Arbitrary default
1324 setAvailable(System.currentTimeMillis() +
1325 (unavailableSeconds * 1000L));
1326 }
1327
1328 }
1329
1330
1331 /**
1332 * Unload all initialized instances of this servlet, after calling the
1333 * <code>destroy()</code> method for each instance. This can be used,
1334 * for example, prior to shutting down the entire servlet engine, or
1335 * prior to reloading all of the classes from the Loader associated with
1336 * our Loader's repository.
1337 *
1338 * @exception ServletException if an exception is thrown by the
1339 * destroy() method
1340 */
1341 public synchronized void unload() throws ServletException {
1342
1343 // Nothing to do if we have never loaded the instance
1344 if (!singleThreadModel && (instance == null))
1345 return;
1346 unloading = true;
1347
1348 // Loaf a while if the current instance is allocated
1349 // (possibly more than once if non-STM)
1350 if (countAllocated > 0) {
1351 int nRetries = 0;
1352 long delay = unloadDelay / 20;
1353 while ((nRetries < 21) && (countAllocated > 0)) {
1354 if ((nRetries % 10) == 0) {
1355 log.info(sm.getString("standardWrapper.waiting",
1356 new Integer(countAllocated)));
1357 }
1358 try {
1359 Thread.sleep(delay);
1360 } catch (InterruptedException e) {
1361 ;
1362 }
1363 nRetries++;
1364 }
1365 }
1366
1367 PrintStream out = System.out;
1368 if (swallowOutput) {
1369 SystemLogHandler.startCapture();
1370 }
1371
1372 // Call the servlet destroy() method
1373 try {
1374 instanceSupport.fireInstanceEvent
1375 (InstanceEvent.BEFORE_DESTROY_EVENT, instance);
1376
1377 if( Globals.IS_SECURITY_ENABLED) {
1378 SecurityUtil.doAsPrivilege("destroy",
1379 instance);
1380 SecurityUtil.remove(instance);
1381 } else {
1382 instance.destroy();
1383 }
1384
1385 instanceSupport.fireInstanceEvent
1386 (InstanceEvent.AFTER_DESTROY_EVENT, instance);
1387
1388 // Annotation processing
1389 if (!((Context) getParent()).getIgnoreAnnotations()) {
1390 ((StandardContext)getParent()).getAnnotationProcessor().preDestroy(instance);
1391 }
1392
1393 } catch (Throwable t) {
1394 instanceSupport.fireInstanceEvent
1395 (InstanceEvent.AFTER_DESTROY_EVENT, instance, t);
1396 instance = null;
1397 instancePool = null;
1398 nInstances = 0;
1399 fireContainerEvent("unload", this);
1400 unloading = false;
1401 throw new ServletException
1402 (sm.getString("standardWrapper.destroyException", getName()),
1403 t);
1404 } finally {
1405 // Write captured output
1406 if (swallowOutput) {
1407 String log = SystemLogHandler.stopCapture();
1408 if (log != null && log.length() > 0) {
1409 if (getServletContext() != null) {
1410 getServletContext().log(log);
1411 } else {
1412 out.println(log);
1413 }
1414 }
1415 }
1416 }
1417
1418 // Deregister the destroyed instance
1419 instance = null;
1420
1421 if (singleThreadModel && (instancePool != null)) {
1422 try {
1423 while (!instancePool.isEmpty()) {
1424 Servlet s = (Servlet) instancePool.pop();
1425 if (Globals.IS_SECURITY_ENABLED) {
1426 SecurityUtil.doAsPrivilege("destroy", s);
1427 SecurityUtil.remove(instance);
1428 } else {
1429 s.destroy();
1430 }
1431 // Annotation processing
1432 if (!((Context) getParent()).getIgnoreAnnotations()) {
1433 ((StandardContext)getParent()).getAnnotationProcessor().preDestroy(s);
1434 }
1435 }
1436 } catch (Throwable t) {
1437 instancePool = null;
1438 nInstances = 0;
1439 unloading = false;
1440 fireContainerEvent("unload", this);
1441 throw new ServletException
1442 (sm.getString("standardWrapper.destroyException",
1443 getName()), t);
1444 }
1445 instancePool = null;
1446 nInstances = 0;
1447 }
1448
1449 singleThreadModel = false;
1450
1451 unloading = false;
1452 fireContainerEvent("unload", this);
1453
1454 }
1455
1456
1457 // -------------------------------------------------- ServletConfig Methods
1458
1459
1460 /**
1461 * Return the initialization parameter value for the specified name,
1462 * if any; otherwise return <code>null</code>.
1463 *
1464 * @param name Name of the initialization parameter to retrieve
1465 */
1466 public String getInitParameter(String name) {
1467
1468 return (findInitParameter(name));
1469
1470 }
1471
1472
1473 /**
1474 * Return the set of initialization parameter names defined for this
1475 * servlet. If none are defined, an empty Enumeration is returned.
1476 */
1477 public Enumeration getInitParameterNames() {
1478
1479 synchronized (parameters) {
1480 return (new Enumerator(parameters.keySet()));
1481 }
1482
1483 }
1484
1485
1486 /**
1487 * Return the servlet context with which this servlet is associated.
1488 */
1489 public ServletContext getServletContext() {
1490
1491 if (parent == null)
1492 return (null);
1493 else if (!(parent instanceof Context))
1494 return (null);
1495 else
1496 return (((Context) parent).getServletContext());
1497
1498 }
1499
1500
1501 /**
1502 * Return the name of this servlet.
1503 */
1504 public String getServletName() {
1505
1506 return (getName());
1507
1508 }
1509
1510 public long getProcessingTime() {
1511 return swValve.getProcessingTime();
1512 }
1513
1514 public void setProcessingTime(long processingTime) {
1515 swValve.setProcessingTime(processingTime);
1516 }
1517
1518 public long getMaxTime() {
1519 return swValve.getMaxTime();
1520 }
1521
1522 public void setMaxTime(long maxTime) {
1523 swValve.setMaxTime(maxTime);
1524 }
1525
1526 public long getMinTime() {
1527 return swValve.getMinTime();
1528 }
1529
1530 public void setMinTime(long minTime) {
1531 swValve.setMinTime(minTime);
1532 }
1533
1534 public int getRequestCount() {
1535 return swValve.getRequestCount();
1536 }
1537
1538 public void setRequestCount(int requestCount) {
1539 swValve.setRequestCount(requestCount);
1540 }
1541
1542 public int getErrorCount() {
1543 return swValve.getErrorCount();
1544 }
1545
1546 public void setErrorCount(int errorCount) {
1547 swValve.setErrorCount(errorCount);
1548 }
1549
1550 /**
1551 * Increment the error count used for monitoring.
1552 */
1553 public void incrementErrorCount(){
1554 swValve.setErrorCount(swValve.getErrorCount() + 1);
1555 }
1556
1557 public long getLoadTime() {
1558 return loadTime;
1559 }
1560
1561 public void setLoadTime(long loadTime) {
1562 this.loadTime = loadTime;
1563 }
1564
1565 public int getClassLoadTime() {
1566 return classLoadTime;
1567 }
1568
1569 // -------------------------------------------------------- Package Methods
1570
1571
1572 // -------------------------------------------------------- protected Methods
1573
1574
1575 /**
1576 * Add a default Mapper implementation if none have been configured
1577 * explicitly.
1578 *
1579 * @param mapperClass Java class name of the default Mapper
1580 */
1581 protected void addDefaultMapper(String mapperClass) {
1582
1583 ; // No need for a default Mapper on a Wrapper
1584
1585 }
1586
1587
1588 /**
1589 * Return <code>true</code> if the specified class name represents a
1590 * container provided servlet class that should be loaded by the
1591 * server class loader.
1592 *
1593 * @param classname Name of the class to be checked
1594 */
1595 protected boolean isContainerProvidedServlet(String classname) {
1596
1597 if (classname.startsWith("org.apache.catalina.")) {
1598 return (true);
1599 }
1600 try {
1601 Class clazz =
1602 this.getClass().getClassLoader().loadClass(classname);
1603 return (ContainerServlet.class.isAssignableFrom(clazz));
1604 } catch (Throwable t) {
1605 return (false);
1606 }
1607
1608 }
1609
1610
1611 /**
1612 * Return <code>true</code> if loading this servlet is allowed.
1613 */
1614 protected boolean isServletAllowed(Object servlet) {
1615
1616 // Privileged webapps may load all servlets without restriction
1617 if (((Context) getParent()).getPrivileged()) {
1618 return true;
1619 }
1620
1621 if (servlet instanceof ContainerServlet) {
1622 return (false);
1623 }
1624
1625 Class clazz = servlet.getClass();
1626 while (clazz != null && !clazz.getName().equals("javax.servlet.http.HttpServlet")) {
1627 if ("restricted".equals(restrictedServlets.getProperty(clazz.getName()))) {
1628 return (false);
1629 }
1630 clazz = clazz.getSuperclass();
1631 }
1632
1633 return (true);
1634
1635 }
1636
1637
1638 protected Method[] getAllDeclaredMethods(Class c) {
1639
1640 if (c.equals(javax.servlet.http.HttpServlet.class)) {
1641 return null;
1642 }
1643
1644 Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
1645
1646 Method[] thisMethods = c.getDeclaredMethods();
1647 if (thisMethods == null) {
1648 return parentMethods;
1649 }
1650
1651 if ((parentMethods != null) && (parentMethods.length > 0)) {
1652 Method[] allMethods =
1653 new Method[parentMethods.length + thisMethods.length];
1654 System.arraycopy(parentMethods, 0, allMethods, 0,
1655 parentMethods.length);
1656 System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
1657 thisMethods.length);
1658
1659 thisMethods = allMethods;
1660 }
1661
1662 return thisMethods;
1663 }
1664
1665
1666 // ------------------------------------------------------ Lifecycle Methods
1667
1668
1669 /**
1670 * Start this component, pre-loading the servlet if the load-on-startup
1671 * value is set appropriately.
1672 *
1673 * @exception LifecycleException if a fatal error occurs during startup
1674 */
1675 public void start() throws LifecycleException {
1676
1677 // Send j2ee.state.starting notification
1678 if (this.getObjectName() != null) {
1679 Notification notification = new Notification("j2ee.state.starting",
1680 this.getObjectName(),
1681 sequenceNumber++);
1682 broadcaster.sendNotification(notification);
1683 }
1684
1685 // Start up this component
1686 super.start();
1687
1688 if( oname != null )
1689 registerJMX((StandardContext)getParent());
1690
1691 // Load and initialize an instance of this servlet if requested
1692 // MOVED TO StandardContext START() METHOD
1693
1694 setAvailable(0L);
1695
1696 // Send j2ee.state.running notification
1697 if (this.getObjectName() != null) {
1698 Notification notification =
1699 new Notification("j2ee.state.running", this.getObjectName(),
1700 sequenceNumber++);
1701 broadcaster.sendNotification(notification);
1702 }
1703
1704 }
1705
1706
1707 /**
1708 * Stop this component, gracefully shutting down the servlet if it has
1709 * been initialized.
1710 *
1711 * @exception LifecycleException if a fatal error occurs during shutdown
1712 */
1713 public void stop() throws LifecycleException {
1714
1715 setAvailable(Long.MAX_VALUE);
1716
1717 // Send j2ee.state.stopping notification
1718 if (this.getObjectName() != null) {
1719 Notification notification =
1720 new Notification("j2ee.state.stopping", this.getObjectName(),
1721 sequenceNumber++);
1722 broadcaster.sendNotification(notification);
1723 }
1724
1725 // Shut down our servlet instance (if it has been initialized)
1726 try {
1727 unload();
1728 } catch (ServletException e) {
1729 getServletContext().log(sm.getString
1730 ("standardWrapper.unloadException", getName()), e);
1731 }
1732
1733 // Shut down this component
1734 super.stop();
1735
1736 // Send j2ee.state.stoppped notification
1737 if (this.getObjectName() != null) {
1738 Notification notification =
1739 new Notification("j2ee.state.stopped", this.getObjectName(),
1740 sequenceNumber++);
1741 broadcaster.sendNotification(notification);
1742 }
1743
1744 if( oname != null ) {
1745 Registry.getRegistry(null, null).unregisterComponent(oname);
1746
1747 // Send j2ee.object.deleted notification
1748 Notification notification =
1749 new Notification("j2ee.object.deleted", this.getObjectName(),
1750 sequenceNumber++);
1751 broadcaster.sendNotification(notification);
1752 }
1753
1754 if (isJspServlet && jspMonitorON != null ) {
1755 Registry.getRegistry(null, null).unregisterComponent(jspMonitorON);
1756 }
1757
1758 }
1759
1760 protected void registerJMX(StandardContext ctx) {
1761
1762 String parentName = ctx.getName();
1763 parentName = ("".equals(parentName)) ? "/" : parentName;
1764
1765 String hostName = ctx.getParent().getName();
1766 hostName = (hostName==null) ? "DEFAULT" : hostName;
1767
1768 String domain = ctx.getDomain();
1769
1770 String webMod= "//" + hostName + parentName;
1771 String onameStr = domain + ":j2eeType=Servlet,name=" + getName() +
1772 ",WebModule=" + webMod + ",J2EEApplication=" +
1773 ctx.getJ2EEApplication() + ",J2EEServer=" +
1774 ctx.getJ2EEServer();
1775 try {
1776 oname=new ObjectName(onameStr);
1777 controller=oname;
1778 Registry.getRegistry(null, null)
1779 .registerComponent(this, oname, null );
1780
1781 // Send j2ee.object.created notification
1782 if (this.getObjectName() != null) {
1783 Notification notification = new Notification(
1784 "j2ee.object.created",
1785 this.getObjectName(),
1786 sequenceNumber++);
1787 broadcaster.sendNotification(notification);
1788 }
1789 } catch( Exception ex ) {
1790 log.info("Error registering servlet with jmx " + this, ex);
1791 }
1792
1793 if (isJspServlet) {
1794 // Register JSP monitoring mbean
1795 onameStr = domain + ":type=JspMonitor,name=" + getName()
1796 + ",WebModule=" + webMod
1797 + ",J2EEApplication=" + ctx.getJ2EEApplication()
1798 + ",J2EEServer=" + ctx.getJ2EEServer();
1799 try {
1800 jspMonitorON = new ObjectName(onameStr);
1801 Registry.getRegistry(null, null)
1802 .registerComponent(instance, jspMonitorON, null);
1803 } catch( Exception ex ) {
1804 log.info("Error registering JSP monitoring with jmx " +
1805 instance, ex);
1806 }
1807 }
1808 }
1809
1810
1811 /* Remove a JMX notficationListener
1812 * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
1813 */
1814 public void removeNotificationListener(NotificationListener listener,
1815 NotificationFilter filter, Object object) throws ListenerNotFoundException {
1816 broadcaster.removeNotificationListener(listener,filter,object);
1817
1818 }
1819
1820 protected MBeanNotificationInfo[] notificationInfo;
1821
1822 /* Get JMX Broadcaster Info
1823 * @TODO use StringManager for international support!
1824 * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
1825 * @see javax.management.NotificationBroadcaster#getNotificationInfo()
1826 */
1827 public MBeanNotificationInfo[] getNotificationInfo() {
1828
1829 if(notificationInfo == null) {
1830 notificationInfo = new MBeanNotificationInfo[]{
1831 new MBeanNotificationInfo(new String[] {
1832 "j2ee.object.created"},
1833 Notification.class.getName(),
1834 "servlet is created"
1835 ),
1836 new MBeanNotificationInfo(new String[] {
1837 "j2ee.state.starting"},
1838 Notification.class.getName(),
1839 "servlet is starting"
1840 ),
1841 new MBeanNotificationInfo(new String[] {
1842 "j2ee.state.running"},
1843 Notification.class.getName(),
1844 "servlet is running"
1845 ),
1846 new MBeanNotificationInfo(new String[] {
1847 "j2ee.state.stopped"},
1848 Notification.class.getName(),
1849 "servlet start to stopped"
1850 ),
1851 new MBeanNotificationInfo(new String[] {
1852 "j2ee.object.stopped"},
1853 Notification.class.getName(),
1854 "servlet is stopped"
1855 ),
1856 new MBeanNotificationInfo(new String[] {
1857 "j2ee.object.deleted"},
1858 Notification.class.getName(),
1859 "servlet is deleted"
1860 )
1861 };
1862
1863 }
1864
1865 return notificationInfo;
1866 }
1867
1868
1869 /* Add a JMX-NotificationListener
1870 * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
1871 */
1872 public void addNotificationListener(NotificationListener listener,
1873 NotificationFilter filter, Object object) throws IllegalArgumentException {
1874 broadcaster.addNotificationListener(listener,filter,object);
1875 }
1876
1877
1878 /**
1879 * Remove a JMX-NotificationListener
1880 * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
1881 */
1882 public void removeNotificationListener(NotificationListener listener)
1883 throws ListenerNotFoundException {
1884 broadcaster.removeNotificationListener(listener);
1885 }
1886
1887
1888 // ------------------------------------------------------------- Attributes
1889
1890
1891 public boolean isEventProvider() {
1892 return false;
1893 }
1894
1895 public boolean isStateManageable() {
1896 return false;
1897 }
1898
1899 public boolean isStatisticsProvider() {
1900 return false;
1901 }
1902
1903
1904 }