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:BaseCluster.java 8660 2006-06-20 08:15:28Z danesa $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.management.cluster;
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.Map;
031:
032: import javax.management.JMException;
033: import javax.management.MBeanServer;
034: import javax.management.ObjectName;
035:
036: import org.objectweb.jonas.common.Log;
037: import org.objectweb.jonas.jmx.JmxService;
038: import org.objectweb.jonas.jmx.JonasObjectName;
039: import org.objectweb.jonas.management.j2eemanagement.J2EEDomain;
040: import org.objectweb.jonas.management.monitoring.ClusterDaemonProxy;
041: import org.objectweb.jonas.management.monitoring.DeployAction;
042: import org.objectweb.jonas.management.monitoring.DomainMonitor;
043: import org.objectweb.jonas.management.monitoring.ServerProxy;
044: import org.objectweb.jonas.server.J2EEServer;
045: import org.objectweb.jonas.service.ServiceManager;
046:
047: import org.objectweb.util.monolog.api.BasicLevel;
048: import org.objectweb.util.monolog.api.Logger;
049:
050: /**
051: * Implements basics for cluster management.
052: * To be extended by the different cluster types.
053: * It implements cluster state transition diagram based on the members's state.
054: * A member is represented by a ClusterMember class instance.
055: * @see ClusterMember
056: * @author Adriana Danes
057: */
058: public abstract class BaseCluster implements BaseClusterMBean {
059:
060: /**
061: * The name of this Cluster.
062: * This String is included in the MBean OBJECT_NAME.
063: */
064: protected String name = null;
065:
066: /**
067: * MBean OBJECT_NAME
068: * <domain>:type=<type>,name=<name>
069: * type may be one among: JkCluster, TomcatCluster, etc...
070: */
071: protected ObjectName objectName = null;
072:
073: /**
074: * The list of ClusterMember objects that compose this Cluster
075: * Key = name of the Member.
076: */
077: protected Map members = new HashMap();
078:
079: /**
080: * ClusterFactory that created this Cluster
081: */
082: protected ClusterFactory cf;
083:
084: /**
085: * The cluster state
086: */
087: protected int state = STATE_INIT;
088:
089: /**
090: * This is the initial state, all members are in INITIAL state
091: */
092: public static final int STATE_INIT = 0;
093:
094: /**
095: * All the members are in RUNNING state
096: */
097: public static final int STATE_UP = 1;
098:
099: /**
100: * All the members are in STOPPED state
101: */
102: public static final int STATE_DOWN = 2;
103:
104: /**
105: * All the members are in FAILED state
106: */
107: public static final int STATE_FAILED = 3;
108:
109: /**
110: * At least one members is in FAILED state
111: */
112: public static final int STATE_PARTIALLY_FAILED = 4;
113:
114: /**
115: * At least one members is in RUNNING state, there is no failed member
116: */
117: public static final int STATE_PARTIALLY_UP = 5;
118:
119: /**
120: * At least one members is in STOPPED state, there is no failed member,
121: * there is no running memeber
122: */
123: public static final int STATE_PARTIALLY_DOWN = 6;
124:
125: /**
126: * No member in FAILED state, no member in RUNNING state, no memeber in STOPPED state
127: * The members' state may be UNREACHABLE or UNKNOWN
128: */
129: public static final int STATE_UNKNOWN = 7;
130:
131: /**
132: * domain management logger
133: */
134: protected static Logger logger = Log
135: .getLogger(Log.JONAS_DOMAIN_MANAGEMENT_PREFIX);
136:
137: /**
138: * ref to the Jmx Service
139: */
140: protected JmxService jmx = (JmxService) ServiceManager
141: .getInstance().getJmxService();
142:
143: /**
144: * ref to the domainMonitor
145: */
146: protected DomainMonitor dm;
147:
148: /**
149: * Constructor
150: * @param cf Cluster Factory
151: */
152: public BaseCluster(ClusterFactory cf) {
153: logger.log(BasicLevel.DEBUG, "");
154: this .cf = cf;
155: dm = cf.getDomainMonitor();
156: }
157:
158: /**
159: * Create a new ClusterMember. Depends on the underlaying class.
160: * @param svname
161: * @param proxy
162: */
163: public abstract ClusterMember createClusterMember(String svname,
164: ServerProxy proxy);
165:
166: /**
167: * Set the MBean name, that may be unknown when constructor is called.
168: * @param name its name.
169: * @return the MBean ObjectName
170: * @throws JMException could not create MBean instance
171: */
172: public ObjectName setName(String name) throws JMException {
173: this .name = name;
174: objectName = JonasObjectName.cluster(name, getType());
175: return objectName;
176: }
177:
178: /**
179: * @return The MBean OBJECT_NAME
180: */
181: public String getObjectName() {
182: return objectName.toString();
183: }
184:
185: /**
186: * @return the type of this Cluster (string form)
187: */
188: public abstract String getType();
189:
190: /**
191: * Add a Member to the Cluster
192: * @param m Member to add
193: * @return true if added, false if already there.
194: */
195: public synchronized boolean addMember(ClusterMember m) {
196: String mbr = m.getName();
197: logger.log(BasicLevel.DEBUG, mbr);
198: /*
199: if (members.containsKey(mbr)) {
200: return false;
201: }*/
202: members.put(mbr, m);
203: return true;
204: }
205:
206: /**
207: * Get a server by its name.
208: * @param name fo the server
209: * @return the Server or null if not found.
210: */
211: public synchronized J2EEServer getServer(String name) {
212: for (Iterator it = members.values().iterator(); it.hasNext();) {
213: ClusterMember member = (ClusterMember) it.next();
214: try {
215: if (member.getServerName().equals(name)) {
216: return member.getJ2EEServer();
217: }
218: } catch (JMException e) {
219: logger.log(BasicLevel.WARN, "Cannot get server name: "
220: + e);
221: return null;
222: }
223: }
224: return null;
225: }
226:
227: /**
228: * Get a server by its name.
229: * @param name fo the server
230: * @return the ServerProxy or null if not found.
231: */
232: public synchronized ServerProxy getServerProxy(String name) {
233: for (Iterator it = members.values().iterator(); it.hasNext();) {
234: ClusterMember member = (ClusterMember) it.next();
235: try {
236: if (member.getServerName().equals(name)) {
237: return member.getProxy();
238: }
239: } catch (JMException e) {
240: logger.log(BasicLevel.WARN, "Cannot get server name: "
241: + e);
242: return null;
243: }
244: }
245: return null;
246: }
247:
248: /**
249: * @return The list of ServerProxy
250: */
251: public synchronized Collection getServerProxyList() {
252: Collection ret = new ArrayList();
253: for (Iterator i = members.values().iterator(); i.hasNext();) {
254: ClusterMember m = (ClusterMember) i.next();
255: ret.add(m.getProxy());
256: }
257: return ret;
258: }
259:
260: // --------------------------------------------------------------------------
261: // BaseClusterMBean Implementation
262: // --------------------------------------------------------------------------
263:
264: /**
265: * Get the Cluster State
266: * @return A String representing the cluster current state
267: */
268: public String getState() {
269: updateState();
270: switch (state) {
271: case STATE_INIT:
272: return "INIT";
273: case STATE_UP:
274: return "UP";
275: case STATE_DOWN:
276: return "DOWN";
277: case STATE_FAILED:
278: return "FAILED";
279: case STATE_PARTIALLY_UP:
280: return "PARTIALLY_UP";
281: case STATE_PARTIALLY_DOWN:
282: return "PARTIALLY_DOWN";
283: case STATE_PARTIALLY_FAILED:
284: return "PARTIALLY_FAILED";
285: }
286: return "UNKNOWN";
287: }
288:
289: /**
290: * @return the cluster name
291: */
292: public String getName() {
293: return name;
294: }
295:
296: /**
297: * @return the member number
298: */
299: public int getNbMembers() {
300: return members.size();
301: }
302:
303: /**
304: * @return the Member MBean OBJECT_NAMES
305: */
306: public synchronized String[] getMembers() {
307: logger.log(BasicLevel.DEBUG, "");
308: Collection col = members.values();
309: String[] result = new String[col.size()];
310: int i = 0;
311: for (Iterator it = col.iterator(); it.hasNext();) {
312: ClusterMember m = (ClusterMember) it.next();
313: result[i++] = m.getObjectName().toString();
314: }
315: return result;
316: }
317:
318: /**
319: * MBean operation
320: * Add a server in the cluster (jonasAdmin) - this is only called
321: * for LogicalCluster
322: * @param svname logical name of the server
323: * @param array of urls for connection
324: * @param cdn clusterDaemon used to manage te server
325: */
326: public void addServer(String svname, String[] urls, String cdn)
327: throws JMException {
328:
329: // Possible ClusterDaemon attached to the server
330: ClusterDaemonProxy cdp = null;
331: if (cdn != null) {
332: cdp = dm.findClusterDaemonProxy(cdn);
333: if (cdp == null) {
334: logger.log(BasicLevel.WARN, "Unknown ClusterDaemon :"
335: + cdn);
336: }
337: }
338:
339: // Create the proxy and add it to the list
340: ServerProxy proxy = dm.findServerProxy(svname);
341: if (proxy == null) {
342: ArrayList urlcol = new ArrayList();
343: for (int i = 0; i < urls.length; i++) {
344: urlcol.add(urls[i]);
345: }
346: proxy = new ServerProxy(dm, svname, urlcol, cdp);
347: if (logger.isLoggable(BasicLevel.DEBUG)) {
348: logger.log(BasicLevel.DEBUG, "Adding server : "
349: + svname);
350: }
351: // give a name and register mbean
352: ObjectName on = JonasObjectName.serverProxy(svname);
353: proxy.setObjectName(on.toString());
354: }
355:
356: // Create the ClusterMember object
357: ClusterMember member = createClusterMember(svname, proxy);
358:
359: // Add this member if not already there
360: boolean added = addMember(member);
361: if (!added) {
362: throw new RuntimeException("Server already in cluster: "
363: + svname);
364: }
365: // Build the ObjectName and register MBean for the ClusterMember
366: ObjectName on = JonasObjectName.clusterMember(svname,
367: getType(), name);
368: member.setObjectName(on);
369: MBeanServer mbeanServer = jmx.getJmxServer();
370: if (mbeanServer.isRegistered(on)) {
371: mbeanServer.unregisterMBean(on);
372: }
373: mbeanServer.registerMBean(member, on);
374: }
375:
376: /**
377: * MBean operation
378: * Remove a server from the cluster (jonasAdmin)
379: * @param svname logical name of the server
380: * @return the member corresponding to the server to be removed
381: */
382: public synchronized void removeServer(String svname) {
383: ClusterMember member = (ClusterMember) members.remove(svname);
384: }
385:
386: /**
387: * MBean operation
388: * Start all cluster nodes.
389: */
390: public synchronized void startit() throws JMException {
391: for (Iterator i = members.values().iterator(); i.hasNext();) {
392: ClusterMember m = (ClusterMember) i.next();
393: DeployThread th = new DeployThread(m.getProxy(), null,
394: DeployAction.START, false);
395: th.start();
396: }
397: }
398:
399: /**
400: * MBean operation
401: * Stop all cluster nodes.
402: */
403: public synchronized void stopit() throws JMException {
404: for (Iterator i = members.values().iterator(); i.hasNext();) {
405: ClusterMember m = (ClusterMember) i.next();
406: DeployThread th = new DeployThread(m.getProxy(), null,
407: DeployAction.STOP, false);
408: th.start();
409: }
410: }
411:
412: /**
413: * MBean operation
414: * Deploy a module on all nodes.
415: * @param file file to upload. One among .war,.jar,.ear,.rar
416: */
417: public synchronized void deployModule(String file) {
418: for (Iterator i = members.values().iterator(); i.hasNext();) {
419: ClusterMember m = (ClusterMember) i.next();
420: DeployThread th = new DeployThread(m.getProxy(), file,
421: DeployAction.DEPLOY, false);
422: th.start();
423: }
424: }
425:
426: /**
427: * MBean operation
428: * Undeploy a module on all nodes.
429: * @param file file to upload. One among .war,.jar,.ear,.rar
430: */
431: public synchronized void undeployModule(String file) {
432: for (Iterator i = members.values().iterator(); i.hasNext();) {
433: ClusterMember m = (ClusterMember) i.next();
434: DeployThread th = new DeployThread(m.getProxy(), file,
435: DeployAction.UNDEPLOY, false);
436: th.start();
437: }
438: }
439:
440: /**
441: * MBean operation
442: * Upload a file on all nodes.
443: * @param file file to upload. One among .war,.jar,.ear,.rar
444: * @param repl true if the uploaded file can replace a file with the same name in the jars directory
445: */
446: public void uploadFile(String file, boolean repl) {
447: for (Iterator i = members.values().iterator(); i.hasNext();) {
448: ClusterMember m = (ClusterMember) i.next();
449: DeployThread th = new DeployThread(m.getProxy(), file,
450: DeployAction.UPLOAD, repl);
451: th.start();
452: }
453: }
454:
455: /**
456: * MBean operation
457: * Upload adn deploy a module on all nodes.
458: * @param file file to upload. One among .war,.jar,.ear,.rar
459: * @param repl true if the uploaded file can replace a file with the same name in the jars directory
460: */
461: public synchronized void uploadDeployModule(String file,
462: boolean repl) {
463: for (Iterator i = members.values().iterator(); i.hasNext();) {
464: ClusterMember m = (ClusterMember) i.next();
465: DeployThread th = new DeployThread(m.getProxy(), file,
466: DeployAction.UPLOADDEPLOY, repl);
467: th.start();
468: }
469: }
470:
471: public class DeployThread extends Thread {
472:
473: private ServerProxy proxy;
474: private String filename;
475: private int action;
476: private boolean replace;
477:
478: public DeployThread(ServerProxy proxy, String filename,
479: int action, boolean replace) {
480: this .proxy = proxy;
481: this .filename = filename;
482: this .action = action;
483: this .replace = replace;
484: }
485:
486: public void run() {
487: switch (action) {
488: case DeployAction.START:
489: proxy.startit();
490: break;
491: case DeployAction.STOP:
492: proxy.stopit();
493: break;
494: case DeployAction.DEPLOY:
495: proxy.deployModule(filename);
496: break;
497: case DeployAction.UNDEPLOY:
498: proxy.undeployModule(filename);
499: break;
500: case DeployAction.UPLOADDEPLOY:
501: proxy.uploadDeployModule(filename, replace);
502: break;
503: case DeployAction.UPLOAD:
504: proxy.uploadFile(filename, replace);
505: break;
506: }
507: }
508: }
509:
510: // --------------------------------------------------------------------------
511: // private methods
512: // --------------------------------------------------------------------------
513:
514: /**
515: * State diagram implementation.
516: */
517: private synchronized void updateState() {
518: int nbFailed = 0;
519: int nbRunning = 0;
520: int nbStopped = 0;
521: int nbInitial = 0;
522: int nbMembers = 0;
523: for (Iterator it = members.values().iterator(); it.hasNext();) {
524: ClusterMember member = (ClusterMember) it.next();
525: int memberState = member.getServerState();
526: switch (memberState) {
527: case ServerProxy.UNKNOWN:
528: case ServerProxy.INITIAL:
529: nbInitial++;
530: break;
531: case ServerProxy.RUNNING:
532: nbRunning++;
533: break;
534: case ServerProxy.FAILED:
535: nbFailed++;
536: break;
537: case ServerProxy.STOPPED:
538: nbStopped++;
539: break;
540: }
541: nbMembers++;
542: }
543: if (nbInitial == nbMembers) {
544: state = STATE_INIT;
545: } else if (nbFailed == nbMembers) {
546: state = STATE_FAILED;
547: } else if (nbRunning == nbMembers) {
548: state = STATE_UP;
549: } else if (nbStopped == nbMembers) {
550: state = STATE_DOWN;
551: } else if (nbFailed > 0) {
552: state = STATE_PARTIALLY_FAILED;
553: } else if (nbRunning > 0) {
554: state = STATE_PARTIALLY_UP;
555: } else if (nbStopped > 0) {
556: state = STATE_PARTIALLY_DOWN;
557: } else {
558: state = STATE_UNKNOWN;
559: }
560: }
561:
562: }
|