001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardService.java,v 1.11 2002/06/09 02:19:42 remm Exp $
003: * $Revision: 1.11 $
004: * $Date: 2002/06/09 02:19:42 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.core;
065:
066: import java.beans.PropertyChangeListener;
067: import java.beans.PropertyChangeSupport;
068: import org.apache.catalina.Connector;
069: import org.apache.catalina.Container;
070: import org.apache.catalina.Engine;
071: import org.apache.catalina.Lifecycle;
072: import org.apache.catalina.LifecycleEvent;
073: import org.apache.catalina.LifecycleException;
074: import org.apache.catalina.LifecycleListener;
075: import org.apache.catalina.Server;
076: import org.apache.catalina.Service;
077: import org.apache.catalina.util.LifecycleSupport;
078: import org.apache.catalina.util.StringManager;
079:
080: /**
081: * Standard implementation of the <code>Service</code> interface. The
082: * associated Container is generally an instance of Engine, but this is
083: * not required.
084: *
085: * @author Craig R. McClanahan
086: * @version $Revision: 1.11 $ $Date: 2002/06/09 02:19:42 $
087: */
088:
089: public final class StandardService implements Lifecycle, Service {
090:
091: // ----------------------------------------------------- Instance Variables
092:
093: /**
094: * The set of Connectors associated with this Service.
095: */
096: private Connector connectors[] = new Connector[0];
097:
098: /**
099: * The Container associated with this Service.
100: */
101: private Container container = null;
102:
103: /**
104: * The debugging detail level for this component.
105: */
106: private int debug = 0;
107:
108: /**
109: * Descriptive information about this component implementation.
110: */
111: private static final String info = "org.apache.catalina.core.StandardService/1.0";
112:
113: /**
114: * Has this component been initialized?
115: */
116: private boolean initialized = false;
117:
118: /**
119: * The name of this service.
120: */
121: private String name = null;
122:
123: /**
124: * The lifecycle event support for this component.
125: */
126: private LifecycleSupport lifecycle = new LifecycleSupport(this );
127:
128: /**
129: * The string manager for this package.
130: */
131: private static final StringManager sm = StringManager
132: .getManager(Constants.Package);
133:
134: /**
135: * The <code>Server</code> that owns this Service, if any.
136: */
137: private Server server = null;
138:
139: /**
140: * Has this component been started?
141: */
142: private boolean started = false;
143:
144: /**
145: * The property change support for this component.
146: */
147: protected PropertyChangeSupport support = new PropertyChangeSupport(
148: this );
149:
150: // ------------------------------------------------------------- Properties
151:
152: /**
153: * Return the <code>Container</code> that handles requests for all
154: * <code>Connectors</code> associated with this Service.
155: */
156: public Container getContainer() {
157:
158: return (this .container);
159:
160: }
161:
162: /**
163: * Set the <code>Container</code> that handles requests for all
164: * <code>Connectors</code> associated with this Service.
165: *
166: * @param container The new Container
167: */
168: public void setContainer(Container container) {
169:
170: Container oldContainer = this .container;
171: if ((oldContainer != null) && (oldContainer instanceof Engine))
172: ((Engine) oldContainer).setService(null);
173: this .container = container;
174: if ((this .container != null)
175: && (this .container instanceof Engine))
176: ((Engine) this .container).setService(this );
177: if (started && (this .container != null)
178: && (this .container instanceof Lifecycle)) {
179: try {
180: ((Lifecycle) this .container).start();
181: } catch (LifecycleException e) {
182: ;
183: }
184: }
185: synchronized (connectors) {
186: for (int i = 0; i < connectors.length; i++)
187: connectors[i].setContainer(this .container);
188: }
189: if (started && (oldContainer != null)
190: && (oldContainer instanceof Lifecycle)) {
191: try {
192: ((Lifecycle) oldContainer).stop();
193: } catch (LifecycleException e) {
194: ;
195: }
196: }
197:
198: // Report this property change to interested listeners
199: support.firePropertyChange("container", oldContainer,
200: this .container);
201:
202: }
203:
204: /**
205: * Return the debugging detail level of this component.
206: */
207: public int getDebug() {
208:
209: return (this .debug);
210:
211: }
212:
213: /**
214: * Set the debugging detail level of this component.
215: *
216: * @param debug The new debugging detail level
217: */
218: public void setDebug(int debug) {
219:
220: this .debug = debug;
221:
222: }
223:
224: /**
225: * Return descriptive information about this Service implementation and
226: * the corresponding version number, in the format
227: * <code><description>/<version></code>.
228: */
229: public String getInfo() {
230:
231: return (this .info);
232:
233: }
234:
235: /**
236: * Return the name of this Service.
237: */
238: public String getName() {
239:
240: return (this .name);
241:
242: }
243:
244: /**
245: * Set the name of this Service.
246: *
247: * @param name The new service name
248: */
249: public void setName(String name) {
250:
251: this .name = name;
252:
253: }
254:
255: /**
256: * Return the <code>Server</code> with which we are associated (if any).
257: */
258: public Server getServer() {
259:
260: return (this .server);
261:
262: }
263:
264: /**
265: * Set the <code>Server</code> with which we are associated (if any).
266: *
267: * @param server The server that owns this Service
268: */
269: public void setServer(Server server) {
270:
271: this .server = server;
272:
273: }
274:
275: // --------------------------------------------------------- Public Methods
276:
277: /**
278: * Add a new Connector to the set of defined Connectors, and associate it
279: * with this Service's Container.
280: *
281: * @param connector The Connector to be added
282: */
283: public void addConnector(Connector connector) {
284:
285: synchronized (connectors) {
286: connector.setContainer(this .container);
287: connector.setService(this );
288: Connector results[] = new Connector[connectors.length + 1];
289: System.arraycopy(connectors, 0, results, 0,
290: connectors.length);
291: results[connectors.length] = connector;
292: connectors = results;
293:
294: if (initialized) {
295: try {
296: connector.initialize();
297: } catch (LifecycleException e) {
298: e.printStackTrace(System.err);
299: }
300: }
301:
302: if (started && (connector instanceof Lifecycle)) {
303: try {
304: ((Lifecycle) connector).start();
305: } catch (LifecycleException e) {
306: ;
307: }
308: }
309:
310: // Report this property change to interested listeners
311: support.firePropertyChange("connector", null, connector);
312: }
313:
314: }
315:
316: /**
317: * Add a property change listener to this component.
318: *
319: * @param listener The listener to add
320: */
321: public void addPropertyChangeListener(
322: PropertyChangeListener listener) {
323:
324: support.addPropertyChangeListener(listener);
325:
326: }
327:
328: /**
329: * Find and return the set of Connectors associated with this Service.
330: */
331: public Connector[] findConnectors() {
332:
333: return (connectors);
334:
335: }
336:
337: /**
338: * Remove the specified Connector from the set associated from this
339: * Service. The removed Connector will also be disassociated from our
340: * Container.
341: *
342: * @param connector The Connector to be removed
343: */
344: public void removeConnector(Connector connector) {
345:
346: synchronized (connectors) {
347: int j = -1;
348: for (int i = 0; i < connectors.length; i++) {
349: if (connector == connectors[i]) {
350: j = i;
351: break;
352: }
353: }
354: if (j < 0)
355: return;
356: if (started && (connectors[j] instanceof Lifecycle)) {
357: try {
358: ((Lifecycle) connectors[j]).stop();
359: } catch (LifecycleException e) {
360: ;
361: }
362: }
363: connectors[j].setContainer(null);
364: connector.setService(null);
365: int k = 0;
366: Connector results[] = new Connector[connectors.length - 1];
367: for (int i = 0; i < connectors.length; i++) {
368: if (i != j)
369: results[k++] = connectors[i];
370: }
371: connectors = results;
372:
373: // Report this property change to interested listeners
374: support.firePropertyChange("connector", connector, null);
375: }
376:
377: }
378:
379: /**
380: * Remove a property change listener from this component.
381: *
382: * @param listener The listener to remove
383: */
384: public void removePropertyChangeListener(
385: PropertyChangeListener listener) {
386:
387: support.removePropertyChangeListener(listener);
388:
389: }
390:
391: /**
392: * Return a String representation of this component.
393: */
394: public String toString() {
395:
396: StringBuffer sb = new StringBuffer("StandardService[");
397: sb.append(getName());
398: sb.append("]");
399: return (sb.toString());
400:
401: }
402:
403: // ------------------------------------------------------ Lifecycle Methods
404:
405: /**
406: * Add a LifecycleEvent listener to this component.
407: *
408: * @param listener The listener to add
409: */
410: public void addLifecycleListener(LifecycleListener listener) {
411:
412: lifecycle.addLifecycleListener(listener);
413:
414: }
415:
416: /**
417: * Get the lifecycle listeners associated with this lifecycle. If this
418: * Lifecycle has no listeners registered, a zero-length array is returned.
419: */
420: public LifecycleListener[] findLifecycleListeners() {
421:
422: return lifecycle.findLifecycleListeners();
423:
424: }
425:
426: /**
427: * Remove a LifecycleEvent listener from this component.
428: *
429: * @param listener The listener to remove
430: */
431: public void removeLifecycleListener(LifecycleListener listener) {
432:
433: lifecycle.removeLifecycleListener(listener);
434:
435: }
436:
437: /**
438: * Prepare for the beginning of active use of the public methods of this
439: * component. This method should be called before any of the public
440: * methods of this component are utilized. It should also send a
441: * LifecycleEvent of type START_EVENT to any registered listeners.
442: *
443: * @exception LifecycleException if this component detects a fatal error
444: * that prevents this component from being used
445: */
446: public void start() throws LifecycleException {
447:
448: // Validate and update our current component state
449: if (started) {
450: throw new LifecycleException(sm
451: .getString("standardService.start.started"));
452: }
453:
454: // Notify our interested LifecycleListeners
455: lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
456:
457: System.out.println(sm.getString("standardService.start.name",
458: this .name));
459: lifecycle.fireLifecycleEvent(START_EVENT, null);
460: started = true;
461:
462: // Start our defined Container first
463: if (container != null) {
464: synchronized (container) {
465: if (container instanceof Lifecycle) {
466: ((Lifecycle) container).start();
467: }
468: }
469: }
470:
471: // Start our defined Connectors second
472: synchronized (connectors) {
473: for (int i = 0; i < connectors.length; i++) {
474: if (connectors[i] instanceof Lifecycle)
475: ((Lifecycle) connectors[i]).start();
476: }
477: }
478:
479: // Notify our interested LifecycleListeners
480: lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
481:
482: }
483:
484: /**
485: * Gracefully terminate the active use of the public methods of this
486: * component. This method should be the last one called on a given
487: * instance of this component. It should also send a LifecycleEvent
488: * of type STOP_EVENT to any registered listeners.
489: *
490: * @exception LifecycleException if this component detects a fatal error
491: * that needs to be reported
492: */
493: public void stop() throws LifecycleException {
494:
495: // Validate and update our current component state
496: if (!started) {
497: throw new LifecycleException(sm
498: .getString("standardService.stop.notStarted"));
499: }
500:
501: // Notify our interested LifecycleListeners
502: lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
503:
504: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
505:
506: System.out.println(sm.getString("standardService.stop.name",
507: this .name));
508: started = false;
509:
510: // Stop our defined Connectors first
511: synchronized (connectors) {
512: for (int i = 0; i < connectors.length; i++) {
513: if (connectors[i] instanceof Lifecycle)
514: ((Lifecycle) connectors[i]).stop();
515: }
516: }
517:
518: // Stop our defined Container second
519: if (container != null) {
520: synchronized (container) {
521: if (container instanceof Lifecycle) {
522: ((Lifecycle) container).stop();
523: }
524: }
525: }
526:
527: // Notify our interested LifecycleListeners
528: lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
529:
530: }
531:
532: /**
533: * Invoke a pre-startup initialization. This is used to allow connectors
534: * to bind to restricted ports under Unix operating environments.
535: */
536: public void initialize() throws LifecycleException {
537: if (initialized)
538: throw new LifecycleException(
539: sm
540: .getString("standardService.initialize.initialized"));
541: initialized = true;
542:
543: // Initialize our defined Connectors
544: synchronized (connectors) {
545: for (int i = 0; i < connectors.length; i++) {
546: connectors[i].initialize();
547: }
548: }
549: }
550:
551: }
|