001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2006 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: DomainMonitor.java 10045 2007-03-02 12:42:35Z danesa $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.management.monitoring;
025:
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.HashMap;
029: import java.util.Iterator;
030: import java.util.LinkedList;
031: import java.util.Vector;
032:
033: import javax.management.JMException;
034: import javax.management.MBeanServer;
035: import javax.management.MalformedObjectNameException;
036: import javax.management.ObjectName;
037:
038: import org.objectweb.jonas_domain.api.DomainMap;
039: import org.objectweb.jonas_domain.api.DomainMapException;
040: import org.objectweb.jonas_domain.lib.wrapper.DomainManagerWrapper;
041: import org.objectweb.jonas_domain.xml.Cluster;
042: import org.objectweb.jonas_domain.xml.ClusterDaemon;
043: import org.objectweb.jonas_domain.xml.Location;
044: import org.objectweb.jonas_domain.xml.Server;
045:
046: import org.objectweb.jonas.common.Log;
047: import org.objectweb.jonas.discovery.DiscEvent;
048: import org.objectweb.jonas.discovery.DiscoveryState;
049: import org.objectweb.jonas.jmx.JmxService;
050: import org.objectweb.jonas.jmx.JonasObjectName;
051: import org.objectweb.jonas.management.cluster.BaseCluster;
052: import org.objectweb.jonas.management.cluster.ClusterFactory;
053: import org.objectweb.jonas.management.cluster.CmiClusterFactory;
054: import org.objectweb.jonas.management.cluster.EjbHaClusterFactory;
055: import org.objectweb.jonas.management.cluster.JkClusterFactory;
056: import org.objectweb.jonas.management.cluster.LogicalCluster;
057: import org.objectweb.jonas.management.cluster.LogicalClusterFactory;
058: import org.objectweb.jonas.management.cluster.TomcatClusterFactory;
059: import org.objectweb.jonas.server.J2EEServer;
060: import org.objectweb.jonas.service.ServiceManager;
061:
062: import org.objectweb.util.monolog.api.BasicLevel;
063: import org.objectweb.util.monolog.api.Logger;
064:
065: /**
066: * This class represents the Master Server of the Domain.
067: * Is created by the DiscoveryService if it detects it is the master.
068: * It is not instanciated for slave servers.
069: * @author danesa
070: * @author durieuxp refactoring
071: */
072: public class DomainMonitor implements DomainMonitorMBean {
073:
074: /**
075: * logger for traces
076: */
077: private static Logger logger = Log
078: .getLogger("org.objectweb.jonas.domain.management");
079:
080: /**
081: * List of known ClusterFactory
082: */
083: private ArrayList clusterFactoryList = new ArrayList(5);
084:
085: /**
086: * List of known ClusterDaemon
087: */
088: private HashMap myclusterdaemons = new HashMap();
089:
090: /**
091: * ref to the Jmx Service
092: */
093: private JmxService jmx = (JmxService) ServiceManager.getInstance()
094: .getJmxService();
095:
096: /**
097: * ref to the MBeanServer.
098: */
099: private MBeanServer mbeanServer;
100:
101: /**
102: * Thread object allowing to check the proxys state in order to detect if
103: * they can be reached using the established connection.
104: */
105: private StateMonitor stateMonitor = null;
106:
107: /**
108: * My Domain Name
109: */
110: private String domainName;
111:
112: /**
113: * The local server name (name of the master)
114: */
115: private String masterName;
116:
117: /**
118: * Domain description string (from domain.xml)
119: */
120: private String description;
121:
122: /**
123: * list of delpoyement operations
124: */
125: private ArrayList deployList = new ArrayList();
126:
127: /**
128: * The LogicalClusterFactory
129: */
130: private LogicalClusterFactory lcl;
131:
132: /**
133: * Constructor
134: */
135: public DomainMonitor(String domain) {
136: domainName = domain;
137: mbeanServer = jmx.getJmxServer();
138:
139: // Create the ClusterFactory objects
140: lcl = new LogicalClusterFactory(this );
141: clusterFactoryList.add(lcl);
142: clusterFactoryList.add(new JkClusterFactory(this ));
143: clusterFactoryList.add(new TomcatClusterFactory(this ));
144: clusterFactoryList.add(new CmiClusterFactory(this ));
145: clusterFactoryList.add(new EjbHaClusterFactory(this ));
146: }
147:
148: public void readDomainConfig() {
149:
150: // Create domain map based on the info contained in domain.xml file.
151: try {
152: createDomainMap();
153: } catch (Exception e) {
154: logger.log(BasicLevel.INFO, "Cannot read domain.xml");
155: if (logger.isLoggable(BasicLevel.DEBUG)) {
156: logger.log(BasicLevel.DEBUG, "Exception raised:" + e);
157: }
158: }
159:
160: // Create state monitor thread
161: stateMonitor = new StateMonitor(this );
162: stateMonitor.start();
163: logger.log(BasicLevel.DEBUG, "State monitor created");
164: }
165:
166: public String getDescription() {
167: return description;
168: }
169:
170: public String getDomainName() {
171: return domainName;
172: }
173:
174: public void setMonitoringPeriod(int sec) {
175: stateMonitor.setSamplingPeriod(sec);
176: }
177:
178: public int getMonitoringPeriod() {
179: return stateMonitor.getSamplingPeriod();
180: }
181:
182: /**
183: * Create the domain representation found in domain.xml
184: * @throws DomainMapException Error reading domain.xml
185: * @throws JMException
186: */
187: private void createDomainMap() throws DomainMapException,
188: JMException {
189:
190: // Parse the domain.xml file.
191: ClassLoader currentLoader = Thread.currentThread()
192: .getContextClassLoader();
193: DomainMap domainMap = DomainManagerWrapper.getDomainMap(null,
194: currentLoader);
195: if (logger.isLoggable(BasicLevel.DEBUG)) {
196: logger.log(BasicLevel.DEBUG, "Domain Map :" + domainMap);
197: }
198:
199: // Check domain name.
200: String definedName = domainMap.getName();
201: if (!domainName.equals(definedName)) {
202: logger.log(BasicLevel.INFO,
203: "Domain name in domain.xml is not the actual domain name: "
204: + domainName);
205: return;
206: }
207:
208: description = domainMap.getDescription();
209:
210: // Get list of clusterdaemons
211: Vector daemons = domainMap.getClusterDaemons();
212: for (int i = 0; i < daemons.size(); i++) {
213: ClusterDaemon cd = (ClusterDaemon) daemons.elementAt(i);
214: String cdname = cd.getName();
215: // Create the proxy and add it to the list
216: Location loc = cd.getLocation();
217: ClusterDaemonProxy cdp = new ClusterDaemonProxy(this ,
218: cdname, loc.getUrlList());
219: if (logger.isLoggable(BasicLevel.DEBUG)) {
220: logger.log(BasicLevel.DEBUG, "Adding clusterdaemon : "
221: + cdname);
222: }
223: // give a name and register mbean
224: ObjectName on = JonasObjectName.clusterDaemonProxy(cdname);
225: cdp.setObjectName(on.toString());
226: // add it to the list
227: myclusterdaemons.put(cdname, cdp);
228: }
229:
230: // Get list of servers
231: Vector servers = domainMap.getServers();
232: for (int i = 0; i < servers.size(); i++) {
233: Server sv = (Server) servers.elementAt(i);
234: String svname = sv.getName();
235: // Check ClusterDaemon attached to this server
236: String cdn = sv.getClusterDaemon();
237: ClusterDaemonProxy cdp = null;
238: if (cdn != null) {
239: cdp = (ClusterDaemonProxy) myclusterdaemons.get(cdn);
240: if (cdp == null) {
241: logger.log(BasicLevel.WARN,
242: "Undeclared ClusterDaemon :" + cdn);
243: }
244: }
245: // Create the proxy and add it to the list
246: Location loc = sv.getLocation();
247: ServerProxy sp = findServerProxy(svname);
248: if (sp == null) {
249: sp = new ServerProxy(this , svname, loc.getUrlList(),
250: cdp);
251: if (logger.isLoggable(BasicLevel.DEBUG)) {
252: logger.log(BasicLevel.DEBUG, "Adding server : "
253: + svname);
254: }
255: // give a name and register mbean
256: ObjectName on = JonasObjectName.serverProxy(svname);
257: sp.setObjectName(on.toString());
258: // add it to the list
259: lcl.notifyServer(sp);
260: } else {
261: logger.log(BasicLevel.WARN, "Server already declared: "
262: + svname);
263: }
264: }
265:
266: // Get list of logical clusters
267: Vector clusters = domainMap.getClusters();
268: for (int i = 0; i < clusters.size(); i++) {
269: Cluster cl = (Cluster) clusters.elementAt(i);
270: String clname = cl.getName();
271: LogicalCluster locl = (LogicalCluster) lcl
272: .getCluster(clname);
273: if (locl == null) {
274: // Create a Logical Cluster
275: locl = createLogicalCluster(clname);
276: }
277: if (locl != null) {
278: // Add servers to the new cluster
279: LinkedList serverList = cl.getServerList();
280: for (int j = 0; j < serverList.size(); j++) {
281: Server sv = (Server) serverList.get(j);
282: String svname = sv.getName();
283: ServerProxy sp = findServerProxy(svname);
284: if (sp == null) {
285: // Server is defined directly in the Cluster
286: String cdn = sv.getClusterDaemon();
287: ClusterDaemonProxy cdp = null;
288: if (cdn != null) {
289: cdp = (ClusterDaemonProxy) myclusterdaemons
290: .get(cdn);
291: if (cdp == null) {
292: logger.log(BasicLevel.WARN,
293: "Undeclared ClusterDaemon :"
294: + cdn);
295: }
296: }
297: // Create the proxy and add it to the list
298: Location loc = sv.getLocation();
299: sp = new ServerProxy(this , svname, loc
300: .getUrlList(), cdp);
301: // give a name and register mbean
302: ObjectName on = JonasObjectName
303: .serverProxy(svname);
304: sp.setObjectName(on.toString());
305: }
306: locl.addServer(svname, sp);
307: // Notify the cluster factories
308: notifyServerProxyRunning(sp);
309: }
310: }
311: }
312:
313: }
314:
315: /**
316: * Add the local J2EEServer to the list of servers
317: */
318: public ServerProxy addLocalServer(String svname, Collection urls) {
319: logger.log(BasicLevel.DEBUG, svname);
320:
321: // Add a ServerProxy even for the local server
322: ServerProxy sp = findServerProxy(svname);
323: if (sp == null) {
324: sp = new ServerProxy(this , svname, urls, null);
325: if (logger.isLoggable(BasicLevel.DEBUG)) {
326: logger.log(BasicLevel.DEBUG, "Adding server : "
327: + svname);
328: }
329: // give a name and register mbean
330: ObjectName on;
331: try {
332: on = JonasObjectName.serverProxy(svname);
333: sp.setObjectName(on.toString());
334: } catch (MalformedObjectNameException e) {
335: logger.log(BasicLevel.ERROR, "MalformedObjectName: "
336: + svname);
337: }
338: // add it to the list
339: lcl.notifyServer(sp);
340: }
341: // remember the master server name
342: masterName = svname;
343: return sp;
344: }
345:
346: /**
347: * Get a Cluster by its name. Look in all cluster factories.
348: * @param name The name of the cluster
349: * @return the Cluster or null if unknown by the domain.
350: */
351: public BaseCluster findCluster(String name) {
352: logger.log(BasicLevel.DEBUG, name);
353: BaseCluster cluster = null;
354: // Look in each cluster factory to find if this cluster exists somewhere
355: for (Iterator it = clusterFactoryList.iterator(); it.hasNext();) {
356: ClusterFactory cf = (ClusterFactory) it.next();
357: cluster = cf.getCluster(name);
358: if (cluster != null) {
359: break;
360: }
361: }
362: return cluster;
363: }
364:
365: /**
366: * Get a Server by its name
367: * @param name The name of the server
368: * @return the Server or null if unknown by the domain.
369: */
370: public J2EEServer findServer(String name) {
371: logger.log(BasicLevel.DEBUG, name);
372: // Look in the domain cluster, holding all servers in the domain.
373: BaseCluster cluster = (BaseCluster) lcl.getCluster(domainName);
374: return cluster.getServer(name);
375: }
376:
377: /**
378: * Get a Server by its name
379: * @param name The name of the server
380: * @return the ServerProxy or null if unknown by the domain.
381: */
382: public ServerProxy findServerProxy(String name) {
383: logger.log(BasicLevel.DEBUG, name);
384: // Look in the domain cluster, holding all servers in the domain.
385: BaseCluster cluster = (BaseCluster) lcl.getCluster(domainName);
386: if (cluster == null) {
387: // Not initialized yet: no server known at this time.
388: return null;
389: }
390: return cluster.getServerProxy(name);
391: }
392:
393: /**
394: * Get a ClusterDaemon by its name
395: * @param name The name of the clusterdaemon
396: * @return the ClusterDaemonProxy or null if unknown by the domain.
397: */
398: public ClusterDaemonProxy findClusterDaemonProxy(String name) {
399: return (ClusterDaemonProxy) myclusterdaemons.get(name);
400: }
401:
402: /**
403: * Get the list of ServerProxy
404: * @return Collection of all ServerProxy in the Domain
405: */
406: public Collection getServerList() {
407:
408: // All servers are set in the Domain Cluster
409: LogicalCluster domaincluster = (LogicalCluster) lcl
410: .getCluster(domainName);
411: if (domaincluster == null) {
412: return new ArrayList();
413: }
414: return domaincluster.getServerProxyList();
415: }
416:
417: /**
418: * Get the list of all ClusterDaemonProxy
419: */
420: public Collection getClusterDaemonList() {
421: return myclusterdaemons.values();
422: }
423:
424: /**
425: * Get the list of all clusters of any type
426: * @return Collection of all Clusters in the domain
427: */
428: public Collection getTotalClusterList() {
429: ArrayList ret = new ArrayList();
430: for (Iterator it = clusterFactoryList.iterator(); it.hasNext();) {
431: ClusterFactory cf = (ClusterFactory) it.next();
432: ret.addAll(cf.getClusterList());
433: }
434: return ret;
435: }
436:
437: /**
438: * Create a logical cluster
439: */
440: public LogicalCluster createLogicalCluster(String name) {
441: return lcl.createLogicalCluster(name);
442: }
443:
444: /**
445: * Get the list of logical clusters
446: */
447: public Collection getLogicalClusterList() {
448: return lcl.getClusterList();
449: }
450:
451: /**
452: * MBean method
453: * To be replaced by J2EEDomain.getServers()
454: * @return Array of OBJECT_NAMEs of all ServerProxy
455: */
456: public String[] getProxys() {
457: // Look in the domain cluster, holding all servers in the domain.
458: BaseCluster cluster = (BaseCluster) lcl.getCluster(domainName);
459: Collection col = cluster.getServerProxyList();
460: String[] ret = new String[col.size()];
461: int i = 0;
462: for (Iterator it = col.iterator(); it.hasNext();) {
463: ServerProxy proxy = (ServerProxy) it.next();
464: ret[i++] = proxy.getObjectName();
465: }
466: return ret;
467: }
468:
469: /**
470: * MBean method
471: * @return Array of OBJECT_NAMEs of all cluster MBeans
472: */
473: public String[] getClusters() {
474: ArrayList al = new ArrayList();
475: for (int i = 0; i < clusterFactoryList.size(); i++) {
476: ClusterFactory clFactory = (ClusterFactory) clusterFactoryList
477: .get(i);
478: Iterator clIt = clFactory.getClusterList().iterator();
479: for (; clIt.hasNext();) {
480: BaseCluster cl = (BaseCluster) clIt.next();
481: al.add(cl.getObjectName());
482: }
483: }
484: String[] ret = new String[al.size()];
485: for (int i = 0; i < al.size(); i++) {
486: ret[i] = (String) al.get(i);
487: }
488: return ret;
489: }
490:
491: /**
492: * Handle Notifications from Discovery Service
493: * @param event
494: */
495: public void discoveryNotification(DiscEvent event) {
496: if (logger.isLoggable(BasicLevel.DEBUG)) {
497: logger.log(BasicLevel.DEBUG, "Get notification:" + event);
498: }
499: if (!event.getDomainName().equals(domainName)) {
500: logger
501: .log(BasicLevel.WARN,
502: "Discovery notification from another domain. Forget it.");
503: if (logger.isLoggable(BasicLevel.DEBUG)) {
504: logger.log(BasicLevel.DEBUG, "Notification Domain = "
505: + event.getDomainName());
506: }
507: return;
508: }
509: String state = event.getState();
510: String svname = event.getServerName();
511:
512: // Look if the server is known
513: ServerProxy proxy = findServerProxy(svname);
514: if (proxy == null) {
515: // Create an entry for this server
516: proxy = new ServerProxy(this , svname);
517: // give a name and register mbean
518: ObjectName on;
519: try {
520: on = JonasObjectName.serverProxy(svname);
521: proxy.setObjectName(on.toString());
522: } catch (MalformedObjectNameException e) {
523: logger.log(BasicLevel.ERROR,
524: "MalformedObjectName - Cannot register MBEAN:"
525: + svname);
526: }
527: }
528:
529: // If server is running, get its urls to establish a connection.
530: if (state.equals(DiscoveryState.RUNNING)) {
531: // If this is myself, just forget it
532: if (svname.equals(masterName)) {
533: logger.log(BasicLevel.DEBUG,
534: "Yes, I'm already running, I knew that.");
535: return;
536: }
537: // Establish the connection
538: ArrayList urls = new ArrayList();
539: String[] urlstr = event.getConnectorURL();
540: for (int i = 0; i < urlstr.length; i++) {
541: urls.add(urlstr[i]);
542: }
543: proxy.notifyStarting(urls);
544: // Notify each ClusterFactory that a server started in the domain
545: notifyServerProxyRunning(proxy);
546: } else if (state.equals(DiscoveryState.STOPPING)) {
547: proxy.notifyStopping();
548: // TODO Notify ClusterFactory's
549: }
550: }
551:
552: /**
553: * Notify to all the cluster factories that a server started in the domain
554: * @param sp the server's proxy
555: */
556: void notifyServerProxyRunning(ServerProxy sp) {
557: for (Iterator it = clusterFactoryList.iterator(); it.hasNext();) {
558: ClusterFactory cf = (ClusterFactory) it.next();
559: cf.notifyServer(sp);
560: }
561: }
562:
563: /**
564: * Register a DeployAction
565: * @return true if correctly aded in the list
566: */
567: public synchronized boolean registerDeployAction(DeployAction action) {
568: // Don't add if already another similar action
569: for (Iterator it = deployList.iterator(); it.hasNext();) {
570: DeployAction act = (DeployAction) it.next();
571: if (act.getFileName().equals(action.getFileName())
572: && act.getServerName().equals(
573: action.getServerName())) {
574: logger
575: .log(BasicLevel.DEBUG,
576: "Already a similar action");
577: return false;
578: }
579: }
580: return deployList.add(action);
581: }
582:
583: /**
584: * Get the list of server where a file is being deployed
585: * @param filename file to deploy
586: * @return server name
587: */
588: public synchronized String[] getDeployServers(String filename) {
589: ArrayList slist = new ArrayList();
590: for (Iterator it = deployList.iterator(); it.hasNext();) {
591: DeployAction act = (DeployAction) it.next();
592: if (act.getFileName().equals(filename)) {
593: slist.add(act.getServerName());
594: }
595: }
596: return (String[]) slist.toArray(new String[0]);
597: }
598:
599: /**
600: * Get the current state (string form) of deployment operation
601: * @param filename file to deploy
602: * @param servername server where deployment is done
603: * @return one of "progress","ok","fail"
604: */
605: public synchronized String getDeployState(String filename,
606: String servername) {
607: String ret = "error";
608: for (Iterator it = deployList.iterator(); it.hasNext();) {
609: DeployAction act = (DeployAction) it.next();
610: if (act.getFileName().equals(filename)
611: && act.getServerName().equals(servername)) {
612: ret = act.getStateAsString();
613: break;
614: }
615: }
616: return ret;
617: }
618:
619: /**
620: * Get the error message associated to the error state
621: * @param filename file to deploy
622: * @param servername server where deployment is done
623: * @return error message
624: */
625: public synchronized String getErrorMessage(String filename,
626: String servername) {
627: String ret = "";
628: for (Iterator it = deployList.iterator(); it.hasNext();) {
629: DeployAction act = (DeployAction) it.next();
630: if (act.getFileName().equals(filename)
631: && act.getServerName().equals(servername)) {
632: ret = act.getErrorMessage();
633: }
634: }
635: return ret;
636: }
637:
638: /**
639: * Forget all deploy information
640: */
641: public synchronized void forgetAllDeploy() {
642: deployList.clear();
643: }
644:
645: /**
646: * Try to refresh the server states
647: * TODO notify thread only.
648: */
649: public void refreshStates() {
650: try {
651: checkServerStates(false);
652: } catch (JMException e) {
653: logger.log(BasicLevel.DEBUG, "Cannot refresh states:", e);
654: }
655: }
656:
657: // ------------------------------------------------------------------------------
658: // Thread associated to the DomainMonitor
659: // ------------------------------------------------------------------------------
660:
661: /**
662: * Check state of all remote servers in the domain
663: * @throws JMException
664: */
665: private synchronized void checkServerStates(boolean readall)
666: throws JMException {
667: for (Iterator i = getServerList().iterator(); i.hasNext();) {
668: ServerProxy proxy = (ServerProxy) i.next();
669: proxy.checkit(readall);
670: }
671: for (Iterator i = getClusterDaemonList().iterator(); i
672: .hasNext();) {
673: ClusterDaemonProxy proxy = (ClusterDaemonProxy) i.next();
674: proxy.checkit();
675: }
676: }
677:
678: /**
679: * Monitoring thread that checks managed servers periodically
680: */
681: class StateMonitor extends Thread {
682:
683: /**
684: * My DomainMonitor
685: */
686: private DomainMonitor domainMonitor;
687:
688: /**
689: * Logger object to log events
690: */
691: private Logger logger = Log
692: .getLogger("org.objectweb.jonas.domain.management");
693:
694: /**
695: * Default sampling period of 60 seconds
696: */
697: private long samplingPeriod = 60000L;
698:
699: /**
700: * To stop the thread
701: */
702: private boolean stopped = false;
703:
704: /**
705: * Constructor
706: * @param domainMonitor reference on the DomainMonitor instance
707: * @param log the logger object
708: */
709: public StateMonitor(DomainMonitor domainMonitor) {
710: super ("DomainStateMonitor");
711: setDaemon(true);
712: this .domainMonitor = domainMonitor;
713: }
714:
715: /**
716: * Set the sampling period. Allows reconfiguration.
717: * @param sec sampling period in sec.
718: */
719: public void setSamplingPeriod(int sec) {
720: samplingPeriod = sec * 1000L;
721: }
722:
723: /**
724: * @return Sampling period in seconds
725: * @return
726: */
727: public int getSamplingPeriod() {
728: return new Long(samplingPeriod / 1000L).intValue();
729: }
730:
731: /**
732: * Stop this thread.
733: */
734: public void stopit() {
735: stopped = true;
736: }
737:
738: /**
739: * Start the state monitor thread
740: */
741: public void run() {
742: while (!stopped) {
743: try {
744: sleep(samplingPeriod);
745: domainMonitor.checkServerStates(true);
746: } catch (JMException me) {
747: logger.log(BasicLevel.WARN,
748: "Exception while checking server states",
749: me);
750: } catch (InterruptedException e) {
751: logger.log(BasicLevel.ERROR, "Interrupted", e);
752: break;
753: }
754: }
755: }
756: }
757:
758: }
|