001: /*
002: * Copyright 1999-2001,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.core;
018:
019: import javax.management.MBeanServer;
020: import javax.management.MalformedObjectNameException;
021: import javax.management.ObjectName;
022: import org.apache.catalina.Container;
023: import org.apache.catalina.Context;
024: import org.apache.catalina.DefaultContext;
025: import org.apache.catalina.Engine;
026: import org.apache.catalina.Host;
027: import org.apache.catalina.LifecycleException;
028: import org.apache.catalina.Realm;
029: import org.apache.catalina.Service;
030: import org.apache.catalina.realm.JAASRealm;
031: import org.apache.catalina.util.ServerInfo;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.apache.commons.modeler.Registry;
035: import org.apache.commons.modeler.modules.MbeansSource;
036: import java.io.File;
037: import java.util.List;
038:
039: /**
040: * Standard implementation of the <b>Engine</b> interface. Each
041: * child container must be a Host implementation to process the specific
042: * fully qualified host name of that virtual host.
043: *
044: * @author Craig R. McClanahan
045: * @version $Revision: 1.24 $ $Date: 2004/02/27 14:58:42 $
046: */
047:
048: public class StandardEngine extends ContainerBase implements Engine {
049:
050: private static Log log = LogFactory.getLog(StandardEngine.class);
051:
052: // ----------------------------------------------------------- Constructors
053:
054: /**
055: * Create a new StandardEngine component with the default basic Valve.
056: */
057: public StandardEngine() {
058:
059: super ();
060: pipeline.setBasic(new StandardEngineValve());
061: /* Set the jmvRoute using the system property jvmRoute */
062: try {
063: setJvmRoute(System.getProperty("jvmRoute"));
064: } catch (Exception ex) {
065: }
066: // By default, the engine will hold the reloading thread
067: backgroundProcessorDelay = 10;
068:
069: }
070:
071: // ----------------------------------------------------- Instance Variables
072:
073: /**
074: * Host name to use when no server host, or an unknown host,
075: * is specified in the request.
076: */
077: private String defaultHost = null;
078:
079: /**
080: * The descriptive information string for this implementation.
081: */
082: private static final String info = "org.apache.catalina.core.StandardEngine/1.0";
083:
084: /**
085: * The <code>Service</code> that owns this Engine, if any.
086: */
087: private Service service = null;
088:
089: /** Allow the base dir to be specified explicitely for
090: * each engine. In time we should stop using catalina.base property -
091: * otherwise we loose some flexibility.
092: */
093: private String baseDir = null;
094:
095: /** Optional mbeans config file. This will replace the "hacks" in
096: * jk and ServerListener. The mbeans file will support (transparent)
097: * persistence - soon. It'll probably replace jk2.properties and could
098: * replace server.xml. Of course - the same beans could be loaded and
099: * managed by an external entity - like the embedding app - which
100: * can use a different persistence mechanism.
101: */
102: private String mbeansFile = null;
103:
104: /** Mbeans loaded by the engine.
105: */
106: private List mbeans;
107:
108: /**
109: * DefaultContext config
110: */
111: private DefaultContext defaultContext;
112:
113: /**
114: * The JVM Route ID for this Tomcat instance. All Route ID's must be unique
115: * across the cluster.
116: */
117: private String jvmRouteId;
118:
119: // ------------------------------------------------------------- Properties
120:
121: /** Provide a default in case no explicit configuration is set
122: *
123: * @return configured realm, or a JAAS realm by default
124: */
125: public Realm getRealm() {
126: Realm configured = super .getRealm();
127: // If no set realm has been called - default to JAAS
128: // This can be overriden at engine, context and host level
129: if (configured == null) {
130: configured = new JAASRealm();
131: this .setRealm(configured);
132: }
133: return configured;
134: }
135:
136: /**
137: * Return the default host.
138: */
139: public String getDefaultHost() {
140:
141: return (defaultHost);
142:
143: }
144:
145: /**
146: * Set the default host.
147: *
148: * @param host The new default host
149: */
150: public void setDefaultHost(String host) {
151:
152: String oldDefaultHost = this .defaultHost;
153: if (host == null) {
154: this .defaultHost = null;
155: } else {
156: this .defaultHost = host.toLowerCase();
157: }
158: support.firePropertyChange("defaultHost", oldDefaultHost,
159: this .defaultHost);
160:
161: }
162:
163: public void setName(String name) {
164: if (domain != null) {
165: // keep name==domain, ignore override
166: // we are already registered
167: super .setName(domain);
168: return;
169: }
170: // The engine name is used as domain
171: domain = name; // XXX should we set it in init() ? It shouldn't matter
172: super .setName(name);
173: }
174:
175: /**
176: * Set the cluster-wide unique identifier for this Engine.
177: * This value is only useful in a load-balancing scenario.
178: * <p>
179: * This property should not be changed once it is set.
180: */
181: public void setJvmRoute(String routeId) {
182: jvmRouteId = routeId;
183: }
184:
185: /**
186: * Retrieve the cluster-wide unique identifier for this Engine.
187: * This value is only useful in a load-balancing scenario.
188: */
189: public String getJvmRoute() {
190: return jvmRouteId;
191: }
192:
193: /**
194: * Set the DefaultContext
195: * for new web applications.
196: *
197: * @param defaultContext The new DefaultContext
198: */
199: public void addDefaultContext(DefaultContext defaultContext) {
200:
201: DefaultContext oldDefaultContext = this .defaultContext;
202: this .defaultContext = defaultContext;
203: support.firePropertyChange("defaultContext", oldDefaultContext,
204: this .defaultContext);
205:
206: }
207:
208: /**
209: * Retrieve the DefaultContext for new web applications.
210: */
211: public DefaultContext getDefaultContext() {
212: return (this .defaultContext);
213: }
214:
215: /**
216: * Return the <code>Service</code> with which we are associated (if any).
217: */
218: public Service getService() {
219:
220: return (this .service);
221:
222: }
223:
224: /**
225: * Set the <code>Service</code> with which we are associated (if any).
226: *
227: * @param service The service that owns this Engine
228: */
229: public void setService(Service service) {
230: this .service = service;
231: }
232:
233: public String getMbeansFile() {
234: return mbeansFile;
235: }
236:
237: public void setMbeansFile(String mbeansFile) {
238: this .mbeansFile = mbeansFile;
239: }
240:
241: public String getBaseDir() {
242: if (baseDir == null) {
243: baseDir = System.getProperty("catalina.base");
244: }
245: if (baseDir == null) {
246: baseDir = System.getProperty("catalina.home");
247: }
248: return baseDir;
249: }
250:
251: public void setBaseDir(String baseDir) {
252: this .baseDir = baseDir;
253: }
254:
255: // --------------------------------------------------------- Public Methods
256:
257: /**
258: * Install the StandardContext portion of the DefaultContext
259: * configuration into current Context.
260: *
261: * @param context current web application context
262: */
263: public void installDefaultContext(Context context) {
264:
265: if (defaultContext != null
266: && defaultContext instanceof StandardDefaultContext) {
267:
268: ((StandardDefaultContext) defaultContext)
269: .installDefaultContext(context);
270: }
271: }
272:
273: /**
274: * Import the DefaultContext config into a web application context.
275: *
276: * @param context web application context to import default context
277: */
278: public void importDefaultContext(Context context) {
279:
280: if (this .defaultContext != null)
281: this .defaultContext.importDefaultContext(context);
282:
283: }
284:
285: /**
286: * Add a child Container, only if the proposed child is an implementation
287: * of Host.
288: *
289: * @param child Child container to be added
290: */
291: public void addChild(Container child) {
292:
293: if (!(child instanceof Host))
294: throw new IllegalArgumentException(sm
295: .getString("standardEngine.notHost"));
296: super .addChild(child);
297:
298: }
299:
300: /**
301: * Return descriptive information about this Container implementation and
302: * the corresponding version number, in the format
303: * <code><description>/<version></code>.
304: */
305: public String getInfo() {
306:
307: return (info);
308:
309: }
310:
311: /**
312: * Disallow any attempt to set a parent for this Container, since an
313: * Engine is supposed to be at the top of the Container hierarchy.
314: *
315: * @param container Proposed parent Container
316: */
317: public void setParent(Container container) {
318:
319: throw new IllegalArgumentException(sm
320: .getString("standardEngine.notParent"));
321:
322: }
323:
324: private boolean initialized = false;
325:
326: public void init() {
327: if (initialized)
328: return;
329: initialized = true;
330:
331: if (oname == null) {
332: // not registered in JMX yet - standalone mode
333: try {
334: if (domain == null) {
335: domain = getName();
336: }
337: log.debug("Register " + domain);
338: oname = new ObjectName(domain + ":type=Engine");
339: controller = oname;
340: Registry.getRegistry(null, null).registerComponent(
341: this , oname, null);
342: } catch (Throwable t) {
343: log.info("Error registering ", t);
344: }
345: }
346:
347: if (mbeansFile == null) {
348: String defaultMBeansFile = getBaseDir()
349: + "/conf/tomcat5-mbeans.xml";
350: File f = new File(defaultMBeansFile);
351: if (f.exists())
352: mbeansFile = f.getAbsolutePath();
353: }
354: if (mbeansFile != null) {
355: readEngineMbeans();
356: }
357: if (mbeans != null) {
358: try {
359: Registry.getRegistry(null, null).invoke(mbeans, "init",
360: false);
361: } catch (Exception e) {
362: log.error("Error in init() for " + mbeansFile, e);
363: }
364: }
365:
366: // not needed since the following if statement does the same thing the right way
367: // remove later after checking
368: //if( service==null ) {
369: // try {
370: // ObjectName serviceName=getParentName();
371: // if( mserver.isRegistered( serviceName )) {
372: // log.info("Registering with the service ");
373: // try {
374: // mserver.invoke( serviceName, "setContainer",
375: // new Object[] { this },
376: // new String[] { "org.apache.catalina.Container" } );
377: // } catch( Exception ex ) {
378: // ex.printStackTrace();
379: // }
380: // }
381: // } catch( Exception ex ) {
382: // log.error("Error registering with service ");
383: // }
384: //}
385:
386: if (service == null) {
387: // for consistency...: we are probably in embeded mode
388: try {
389: service = new StandardService();
390: service.setContainer(this );
391: service.initialize();
392: } catch (Throwable t) {
393: t.printStackTrace();
394: }
395: }
396:
397: }
398:
399: public void destroy() throws LifecycleException {
400: if (!initialized)
401: return;
402: initialized = false;
403:
404: // if we created it, make sure it's also destroyed
405: ((StandardService) service).destroy();
406:
407: if (mbeans != null) {
408: try {
409: Registry.getRegistry(null, null).invoke(mbeans,
410: "destroy", false);
411: } catch (Exception e) {
412: log.error("Error in destroy() for " + mbeansFile, e);
413: }
414: }
415: //
416: if (mbeans != null) {
417: try {
418: for (int i = 0; i < mbeans.size(); i++) {
419: Registry.getRegistry(null, null)
420: .unregisterComponent(
421: (ObjectName) mbeans.get(i));
422: }
423: } catch (Exception e) {
424: log.error("Error in destroy() for " + mbeansFile, e);
425: }
426: }
427:
428: // force all metadata to be reloaded.
429: // That doesn't affect existing beans. We should make it per
430: // registry - and stop using the static.
431: Registry.getRegistry(null, null).resetMetadata();
432:
433: }
434:
435: /**
436: * Start this Engine component.
437: *
438: * @exception LifecycleException if a startup error occurs
439: */
440: public void start() throws LifecycleException {
441: if (started) {
442: return;
443: }
444: if (!initialized) {
445: init();
446: }
447: // Log our server identification information
448: //System.out.println(ServerInfo.getServerInfo());
449: log.info("Starting Servlet Engine: "
450: + ServerInfo.getServerInfo());
451: if (mbeans != null) {
452: try {
453: Registry.getRegistry(null, null).invoke(mbeans,
454: "start", false);
455: } catch (Exception e) {
456: log.error("Error in start() for " + mbeansFile, e);
457: }
458: }
459:
460: // Standard container startup
461: super .start();
462:
463: }
464:
465: public void stop() throws LifecycleException {
466: super .stop();
467: if (mbeans != null) {
468: try {
469: Registry.getRegistry(null, null).invoke(mbeans, "stop",
470: false);
471: } catch (Exception e) {
472: log.error("Error in stop() for " + mbeansFile, e);
473: }
474: }
475: }
476:
477: /**
478: * Return a String representation of this component.
479: */
480: public String toString() {
481:
482: StringBuffer sb = new StringBuffer("StandardEngine[");
483: sb.append(getName());
484: sb.append("]");
485: return (sb.toString());
486:
487: }
488:
489: // ------------------------------------------------------ Protected Methods
490:
491: // -------------------- JMX registration --------------------
492:
493: public ObjectName preRegister(MBeanServer server, ObjectName name)
494: throws Exception {
495: super .preRegister(server, name);
496:
497: this .setName(name.getDomain());
498:
499: return name;
500: }
501:
502: // FIXME Remove -- not used
503: public ObjectName getParentName()
504: throws MalformedObjectNameException {
505: if (getService() == null) {
506: return null;
507: }
508: String name = getService().getName();
509: ObjectName serviceName = new ObjectName(domain
510: + ":type=Service,serviceName=" + name);
511: return serviceName;
512: }
513:
514: public ObjectName createObjectName(String domain, ObjectName parent)
515: throws Exception {
516: if (log.isDebugEnabled())
517: log.debug("Create ObjectName " + domain + " " + parent);
518: return new ObjectName(domain + ":type=Engine");
519: }
520:
521: private void readEngineMbeans() {
522: try {
523: MbeansSource mbeansMB = new MbeansSource();
524: File mbeansF = new File(mbeansFile);
525: mbeansMB.setSource(mbeansF);
526:
527: Registry.getRegistry(null, null).registerComponent(
528: mbeansMB, domain + ":type=MbeansFile", null);
529: mbeansMB.load();
530: mbeansMB.init();
531: mbeansMB.setRegistry(Registry.getRegistry(null, null));
532: mbeans = mbeansMB.getMBeans();
533:
534: } catch (Throwable t) {
535: log.error("Error loading " + mbeansFile, t);
536: }
537:
538: }
539:
540: public String getDomain() {
541: if (domain != null) {
542: return domain;
543: } else {
544: return getName();
545: }
546: }
547:
548: public void setDomain(String domain) {
549: this.domain = domain;
550: }
551:
552: }
|