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