KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > core > StandardServer


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
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.net.InetAddress JavaDoc;
27 import java.net.ServerSocket JavaDoc;
28 import java.net.Socket JavaDoc;
29 import java.security.AccessControlException JavaDoc;
30 import java.util.Random JavaDoc;
31
32 import javax.management.MBeanRegistration JavaDoc;
33 import javax.management.MBeanServer JavaDoc;
34 import javax.management.ObjectName JavaDoc;
35
36 import org.apache.catalina.Context;
37 import org.apache.catalina.Lifecycle;
38 import org.apache.catalina.LifecycleException;
39 import org.apache.catalina.LifecycleListener;
40 import org.apache.catalina.Server;
41 import org.apache.catalina.ServerFactory;
42 import org.apache.catalina.Service;
43 import org.apache.catalina.deploy.NamingResources;
44 import org.apache.catalina.util.LifecycleSupport;
45 import org.apache.catalina.util.StringManager;
46 import org.apache.catalina.util.ServerInfo;
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49 import org.apache.tomcat.util.buf.StringCache;
50 import org.apache.tomcat.util.modeler.Registry;
51
52
53
54 /**
55  * Standard implementation of the <b>Server</b> interface, available for use
56  * (but not required) when deploying and starting Catalina.
57  *
58  * @author Craig R. McClanahan
59  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
60  */

61 public final class StandardServer
62     implements Lifecycle, Server JavaDoc, MBeanRegistration JavaDoc
63  {
64     private static Log log = LogFactory.getLog(StandardServer.class);
65    
66
67     // -------------------------------------------------------------- Constants
68

69
70     /**
71      * ServerLifecycleListener classname.
72      */

73     private static String JavaDoc SERVER_LISTENER_CLASS_NAME =
74         "org.apache.catalina.mbeans.ServerLifecycleListener";
75
76
77     // ------------------------------------------------------------ Constructor
78

79
80     /**
81      * Construct a default instance of this class.
82      */

83     public StandardServer() {
84
85         super();
86         ServerFactory.setServer(this);
87
88         globalNamingResources = new NamingResources();
89         globalNamingResources.setContainer(this);
90
91         if (isUseNaming()) {
92             if (namingContextListener == null) {
93                 namingContextListener = new NamingContextListener();
94                 addLifecycleListener(namingContextListener);
95             }
96         }
97
98     }
99
100
101     // ----------------------------------------------------- Instance Variables
102

103
104     /**
105      * Global naming resources context.
106      */

107     private javax.naming.Context JavaDoc globalNamingContext = null;
108
109
110     /**
111      * Global naming resources.
112      */

113     private NamingResources globalNamingResources = null;
114
115
116     /**
117      * Descriptive information about this Server implementation.
118      */

119     private static final String JavaDoc info =
120         "org.apache.catalina.core.StandardServer/1.0";
121
122
123     /**
124      * The lifecycle event support for this component.
125      */

126     private LifecycleSupport lifecycle = new LifecycleSupport(this);
127
128
129     /**
130      * The naming context listener for this web application.
131      */

132     private NamingContextListener namingContextListener = null;
133
134
135     /**
136      * The port number on which we wait for shutdown commands.
137      */

138     private int port = 8005;
139
140
141     /**
142      * A random number generator that is <strong>only</strong> used if
143      * the shutdown command string is longer than 1024 characters.
144      */

145     private Random JavaDoc random = null;
146
147
148     /**
149      * The set of Services associated with this Server.
150      */

151     private Service services[] = new Service[0];
152
153
154     /**
155      * The shutdown command string we are looking for.
156      */

157     private String JavaDoc shutdown = "SHUTDOWN";
158
159
160     /**
161      * The string manager for this package.
162      */

163     private static final StringManager sm =
164         StringManager.getManager(Constants.Package);
165
166
167     /**
168      * Has this component been started?
169      */

170     private boolean started = false;
171
172
173     /**
174      * Has this component been initialized?
175      */

176     private boolean initialized = false;
177
178
179     /**
180      * The property change support for this component.
181      */

182     protected PropertyChangeSupport JavaDoc support = new PropertyChangeSupport JavaDoc(this);
183
184     private boolean stopAwait = false;
185
186     // ------------------------------------------------------------- Properties
187

188
189     /**
190      * Return the global naming resources context.
191      */

192     public javax.naming.Context JavaDoc getGlobalNamingContext() {
193
194         return (this.globalNamingContext);
195
196     }
197
198
199     /**
200      * Set the global naming resources context.
201      *
202      * @param globalNamingContext The new global naming resource context
203      */

204     public void setGlobalNamingContext
205         (javax.naming.Context JavaDoc globalNamingContext) {
206
207         this.globalNamingContext = globalNamingContext;
208
209     }
210
211
212     /**
213      * Return the global naming resources.
214      */

215     public NamingResources getGlobalNamingResources() {
216
217         return (this.globalNamingResources);
218
219     }
220
221
222     /**
223      * Set the global naming resources.
224      *
225      * @param globalNamingResources The new global naming resources
226      */

227     public void setGlobalNamingResources
228         (NamingResources globalNamingResources) {
229
230         NamingResources oldGlobalNamingResources =
231             this.globalNamingResources;
232         this.globalNamingResources = globalNamingResources;
233         this.globalNamingResources.setContainer(this);
234         support.firePropertyChange("globalNamingResources",
235                                    oldGlobalNamingResources,
236                                    this.globalNamingResources);
237
238     }
239
240
241     /**
242      * Return descriptive information about this Server implementation and
243      * the corresponding version number, in the format
244      * <code>&lt;description&gt;/&lt;version&gt;</code>.
245      */

246     public String JavaDoc getInfo() {
247
248         return (info);
249
250     }
251
252     /**
253      * Report the current Tomcat Server Release number
254      * @return Tomcat release identifier
255      */

256     public String JavaDoc getServerInfo() {
257
258         return ServerInfo.getServerInfo();
259     }
260
261     /**
262      * Return the port number we listen to for shutdown commands.
263      */

264     public int getPort() {
265
266         return (this.port);
267
268     }
269
270
271     /**
272      * Set the port number we listen to for shutdown commands.
273      *
274      * @param port The new port number
275      */

276     public void setPort(int port) {
277
278         this.port = port;
279
280     }
281
282
283     /**
284      * Return the shutdown command string we are waiting for.
285      */

286     public String JavaDoc getShutdown() {
287
288         return (this.shutdown);
289
290     }
291
292
293     /**
294      * Set the shutdown command we are waiting for.
295      *
296      * @param shutdown The new shutdown command
297      */

298     public void setShutdown(String JavaDoc shutdown) {
299
300         this.shutdown = shutdown;
301
302     }
303
304
305     // --------------------------------------------------------- Server Methods
306

307
308     /**
309      * Add a new Service to the set of defined Services.
310      *
311      * @param service The Service to be added
312      */

313     public void addService(Service service) {
314
315         service.setServer(this);
316
317         synchronized (services) {
318             Service results[] = new Service[services.length + 1];
319             System.arraycopy(services, 0, results, 0, services.length);
320             results[services.length] = service;
321             services = results;
322
323             if (initialized) {
324                 try {
325                     service.initialize();
326                 } catch (LifecycleException e) {
327                     log.error(e);
328                 }
329             }
330
331             if (started && (service instanceof Lifecycle)) {
332                 try {
333                     ((Lifecycle) service).start();
334                 } catch (LifecycleException e) {
335                     ;
336                 }
337             }
338
339             // Report this property change to interested listeners
340
support.firePropertyChange("service", null, service);
341         }
342
343     }
344
345     public void stopAwait() {
346         stopAwait=true;
347     }
348
349     /**
350      * Wait until a proper shutdown command is received, then return.
351      * This keeps the main thread alive - the thread pool listening for http
352      * connections is daemon threads.
353      */

354     public void await() {
355         // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
356
if( port == -2 ) {
357             // undocumented yet - for embedding apps that are around, alive.
358
return;
359         }
360         if( port==-1 ) {
361             while( true ) {
362                 try {
363                     Thread.sleep( 100000 );
364                 } catch( InterruptedException JavaDoc ex ) {
365                 }
366                 if( stopAwait ) return;
367             }
368         }
369         
370         // Set up a server socket to wait on
371
ServerSocket JavaDoc serverSocket = null;
372         try {
373             serverSocket =
374                 new ServerSocket JavaDoc(port, 1,
375                                  InetAddress.getByName("127.0.0.1"));
376         } catch (IOException JavaDoc e) {
377             log.error("StandardServer.await: create[" + port
378                                + "]: ", e);
379             System.exit(1);
380         }
381
382         // Loop waiting for a connection and a valid command
383
while (true) {
384
385             // Wait for the next connection
386
Socket JavaDoc socket = null;
387             InputStream JavaDoc stream = null;
388             try {
389                 socket = serverSocket.accept();
390                 socket.setSoTimeout(10 * 1000); // Ten seconds
391
stream = socket.getInputStream();
392             } catch (AccessControlException JavaDoc ace) {
393                 log.warn("StandardServer.accept security exception: "
394                                    + ace.getMessage(), ace);
395                 continue;
396             } catch (IOException JavaDoc e) {
397                 log.error("StandardServer.await: accept: ", e);
398                 System.exit(1);
399             }
400
401             // Read a set of characters from the socket
402
StringBuffer JavaDoc command = new StringBuffer JavaDoc();
403             int expected = 1024; // Cut off to avoid DoS attack
404
while (expected < shutdown.length()) {
405                 if (random == null)
406                     random = new Random JavaDoc(System.currentTimeMillis());
407                 expected += (random.nextInt() % 1024);
408             }
409             while (expected > 0) {
410                 int ch = -1;
411                 try {
412                     ch = stream.read();
413                 } catch (IOException JavaDoc e) {
414                     log.warn("StandardServer.await: read: ", e);
415                     ch = -1;
416                 }
417                 if (ch < 32) // Control character or EOF terminates loop
418
break;
419                 command.append((char) ch);
420                 expected--;
421             }
422
423             // Close the socket now that we are done with it
424
try {
425                 socket.close();
426             } catch (IOException JavaDoc e) {
427                 ;
428             }
429
430             // Match against our command string
431
boolean match = command.toString().equals(shutdown);
432             if (match) {
433                 break;
434             } else
435                 log.warn("StandardServer.await: Invalid command '" +
436                                    command.toString() + "' received");
437
438         }
439
440         // Close the server socket and return
441
try {
442             serverSocket.close();
443         } catch (IOException JavaDoc e) {
444             ;
445         }
446
447     }
448
449
450     /**
451      * Return the specified Service (if it exists); otherwise return
452      * <code>null</code>.
453      *
454      * @param name Name of the Service to be returned
455      */

456     public Service findService(String JavaDoc name) {
457
458         if (name == null) {
459             return (null);
460         }
461         synchronized (services) {
462             for (int i = 0; i < services.length; i++) {
463                 if (name.equals(services[i].getName())) {
464                     return (services[i]);
465                 }
466             }
467         }
468         return (null);
469
470     }
471
472
473     /**
474      * Return the set of Services defined within this Server.
475      */

476     public Service[] findServices() {
477
478         return (services);
479
480     }
481     
482     /**
483      * Return the JMX service names.
484      */

485     public ObjectName JavaDoc[] getServiceNames() {
486         ObjectName JavaDoc onames[]=new ObjectName JavaDoc[ services.length ];
487         for( int i=0; i<services.length; i++ ) {
488             onames[i]=((StandardService)services[i]).getObjectName();
489         }
490         return onames;
491     }
492
493
494     /**
495      * Remove the specified Service from the set associated from this
496      * Server.
497      *
498      * @param service The Service to be removed
499      */

500     public void removeService(Service service) {
501
502         synchronized (services) {
503             int j = -1;
504             for (int i = 0; i < services.length; i++) {
505                 if (service == services[i]) {
506                     j = i;
507                     break;
508                 }
509             }
510             if (j < 0)
511                 return;
512             if (services[j] instanceof Lifecycle) {
513                 try {
514                     ((Lifecycle) services[j]).stop();
515                 } catch (LifecycleException e) {
516                     ;
517                 }
518             }
519             int k = 0;
520             Service results[] = new Service[services.length - 1];
521             for (int i = 0; i < services.length; i++) {
522                 if (i != j)
523                     results[k++] = services[i];
524             }
525             services = results;
526
527             // Report this property change to interested listeners
528
support.firePropertyChange("service", service, null);
529         }
530
531     }
532
533
534     // --------------------------------------------------------- Public Methods
535

536
537     /**
538      * Add a property change listener to this component.
539      *
540      * @param listener The listener to add
541      */

542     public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
543
544         support.addPropertyChangeListener(listener);
545
546     }
547
548
549     /**
550      * Remove a property change listener from this component.
551      *
552      * @param listener The listener to remove
553      */

554     public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
555
556         support.removePropertyChangeListener(listener);
557
558     }
559
560
561     /**
562      * Return a String representation of this component.
563      */

564     public String JavaDoc toString() {
565
566         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("StandardServer[");
567         sb.append(getPort());
568         sb.append("]");
569         return (sb.toString());
570
571     }
572
573
574     /**
575      * Write the configuration information for this entire <code>Server</code>
576      * out to the server.xml configuration file.
577      *
578      * @exception javax.management.InstanceNotFoundException if the managed resource object
579      * cannot be found
580      * @exception javax.management.MBeanException if the initializer of the object throws
581      * an exception, or persistence is not supported
582      * @exception javax.management.RuntimeOperationsException if an exception is reported
583      * by the persistence mechanism
584      */

585     public synchronized void storeConfig() throws Exception JavaDoc {
586
587         ObjectName JavaDoc sname = null;
588         try {
589            sname = new ObjectName JavaDoc("Catalina:type=StoreConfig");
590            if(mserver.isRegistered(sname)) {
591                mserver.invoke(sname, "storeConfig", null, null);
592            } else
593                log.error("StoreConfig mbean not registered" + sname);
594         } catch (Throwable JavaDoc t) {
595             log.error(t);
596         }
597
598     }
599
600
601     /**
602      * Write the configuration information for <code>Context</code>
603      * out to the specified configuration file.
604      *
605      * @exception javax.management.InstanceNotFoundException if the managed resource object
606      * cannot be found
607      * @exception javax.management.MBeanException if the initializer of the object throws
608      * an exception, or persistence is not supported
609      * @exception javax.management.RuntimeOperationsException if an exception is reported
610      * by the persistence mechanism
611      */

612     public synchronized void storeContext(Context context) throws Exception JavaDoc {
613         
614         ObjectName JavaDoc sname = null;
615         try {
616            sname = new ObjectName JavaDoc("Catalina:type=StoreConfig");
617            if(mserver.isRegistered(sname)) {
618                mserver.invoke(sname, "store",
619                    new Object JavaDoc[] {context},
620                    new String JavaDoc [] { "java.lang.String"});
621            } else
622                log.error("StoreConfig mbean not registered" + sname);
623         } catch (Throwable JavaDoc t) {
624             log.error(t);
625         }
626  
627     }
628
629
630     /**
631      * Return true if naming should be used.
632      */

633     private boolean isUseNaming() {
634         boolean useNaming = true;
635         // Reading the "catalina.useNaming" environment variable
636
String JavaDoc useNamingProperty = System.getProperty("catalina.useNaming");
637         if ((useNamingProperty != null)
638             && (useNamingProperty.equals("false"))) {
639             useNaming = false;
640         }
641         return useNaming;
642     }
643
644
645     // ------------------------------------------------------ Lifecycle Methods
646

647
648     /**
649      * Add a LifecycleEvent listener to this component.
650      *
651      * @param listener The listener to add
652      */

653     public void addLifecycleListener(LifecycleListener listener) {
654
655         lifecycle.addLifecycleListener(listener);
656
657     }
658
659
660     /**
661      * Get the lifecycle listeners associated with this lifecycle. If this
662      * Lifecycle has no listeners registered, a zero-length array is returned.
663      */

664     public LifecycleListener[] findLifecycleListeners() {
665
666         return lifecycle.findLifecycleListeners();
667
668     }
669
670
671     /**
672      * Remove a LifecycleEvent listener from this component.
673      *
674      * @param listener The listener to remove
675      */

676     public void removeLifecycleListener(LifecycleListener listener) {
677
678         lifecycle.removeLifecycleListener(listener);
679
680     }
681
682
683     /**
684      * Prepare for the beginning of active use of the public methods of this
685      * component. This method should be called before any of the public
686      * methods of this component are utilized. It should also send a
687      * LifecycleEvent of type START_EVENT to any registered listeners.
688      *
689      * @exception LifecycleException if this component detects a fatal error
690      * that prevents this component from being used
691      */

692     public void start() throws LifecycleException {
693
694         // Validate and update our current component state
695
if (started) {
696             log.debug(sm.getString("standardServer.start.started"));
697             return;
698         }
699
700         // Notify our interested LifecycleListeners
701
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
702
703         lifecycle.fireLifecycleEvent(START_EVENT, null);
704         started = true;
705
706         // Start our defined Services
707
synchronized (services) {
708             for (int i = 0; i < services.length; i++) {
709                 if (services[i] instanceof Lifecycle)
710                     ((Lifecycle) services[i]).start();
711             }
712         }
713
714         // Notify our interested LifecycleListeners
715
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
716
717     }
718
719
720     /**
721      * Gracefully terminate the active use of the public methods of this
722      * component. This method should be the last one called on a given
723      * instance of this component. It should also send a LifecycleEvent
724      * of type STOP_EVENT to any registered listeners.
725      *
726      * @exception LifecycleException if this component detects a fatal error
727      * that needs to be reported
728      */

729     public void stop() throws LifecycleException {
730
731         // Validate and update our current component state
732
if (!started)
733             return;
734
735         // Notify our interested LifecycleListeners
736
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
737
738         lifecycle.fireLifecycleEvent(STOP_EVENT, null);
739         started = false;
740
741         // Stop our defined Services
742
for (int i = 0; i < services.length; i++) {
743             if (services[i] instanceof Lifecycle)
744                 ((Lifecycle) services[i]).stop();
745         }
746
747         // Notify our interested LifecycleListeners
748
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
749
750     }
751
752     public void init() throws Exception JavaDoc {
753         initialize();
754     }
755     
756     /**
757      * Invoke a pre-startup initialization. This is used to allow connectors
758      * to bind to restricted ports under Unix operating environments.
759      */

760     public void initialize()
761         throws LifecycleException
762     {
763         if (initialized) {
764                 log.info(sm.getString("standardServer.initialize.initialized"));
765             return;
766         }
767         lifecycle.fireLifecycleEvent(INIT_EVENT, null);
768         initialized = true;
769
770         if( oname==null ) {
771             try {
772                 oname=new ObjectName JavaDoc( "Catalina:type=Server");
773                 Registry.getRegistry(null, null)
774                     .registerComponent(this, oname, null );
775             } catch (Exception JavaDoc e) {
776                 log.error("Error registering ",e);
777             }
778         }
779         
780         // Register global String cache
781
try {
782             ObjectName JavaDoc oname2 =
783                 new ObjectName JavaDoc(oname.getDomain() + ":type=StringCache");
784             Registry.getRegistry(null, null)
785                 .registerComponent(new StringCache(), oname2, null );
786         } catch (Exception JavaDoc e) {
787             log.error("Error registering ",e);
788         }
789
790         // Initialize our defined Services
791
for (int i = 0; i < services.length; i++) {
792             services[i].initialize();
793         }
794     }
795     
796     protected String JavaDoc type;
797     protected String JavaDoc domain;
798     protected String JavaDoc suffix;
799     protected ObjectName JavaDoc oname;
800     protected MBeanServer JavaDoc mserver;
801
802     public ObjectName JavaDoc getObjectName() {
803         return oname;
804     }
805
806     public String JavaDoc getDomain() {
807         return domain;
808     }
809
810     public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server,
811                                   ObjectName JavaDoc name) throws Exception JavaDoc {
812         oname=name;
813         mserver=server;
814         domain=name.getDomain();
815         return name;
816     }
817
818     public void postRegister(Boolean JavaDoc registrationDone) {
819     }
820
821     public void preDeregister() throws Exception JavaDoc {
822     }
823
824     public void postDeregister() {
825     }
826     
827 }
828
Popular Tags