001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Nicolas Modrzyk
020: * Contributor(s): ______________________.
021: */package org.continuent.sequoia.common.jmx.notifications;
022:
023: import java.io.IOException;
024: import java.io.StringReader;
025: import java.io.StringWriter;
026: import java.util.ArrayList;
027: import java.util.Enumeration;
028: import java.util.Hashtable;
029: import java.util.Iterator;
030:
031: import org.dom4j.Document;
032: import org.dom4j.DocumentHelper;
033: import org.dom4j.Element;
034: import org.dom4j.io.OutputFormat;
035: import org.dom4j.io.SAXReader;
036: import org.dom4j.io.XMLWriter;
037:
038: /**
039: * This class defines a JmxNotification class. This class is used by the
040: * <code>RmiConnector</code> on the controller to send a JMXNotification. This
041: * is done by the following code:
042: *
043: * <pre>
044: * JmxNotification sequoiaNotification = new JmxNotification(priority,
045: * "" + sequence, type, description, ""
046: * + time, controllerName, mbean
047: * .getClass().getName(), "mbeanName",
048: * hostName, "" + port, data);
049: * </pre>
050: *
051: * This create an instance of this JmxNotification class, specific to Sequoia.
052: * We then create a new instance of the Notification object as specified in the
053: * javax.management package
054: *
055: * <pre>
056: * Notification notification = new Notification(type, mbean, sequence, myDate
057: * .getTime(), description);
058: * </pre>
059: *
060: * This class accepts a userData object. We wanted to set this user object to a
061: * specific Sequoia class but this forces generic JMX client to have this class
062: * in their classpath. We just serialize the JmxNotification into an XML string
063: * and feed it in the notification.
064: *
065: * <pre>
066: * notification.setUserData(sequoiaNotification.toString());
067: * </pre>
068: *
069: * This can be retrieved on any jmx client, and on Sequoia specific clients, the
070: * xml is transformed into an instance of this class again for easier
071: * notification handling.
072: *
073: * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
074: */
075: public class JmxNotification {
076: /**
077: * All the tags and attributes used to parse the notification
078: */
079: private static final String ELT_jmxevent = "jmxevent";
080: private static final String ELT_info = "info";
081: private static final String ELT_source = "source";
082: private static final String ELT_data = "data";
083: private static final String ELT_priority = "priority";
084: private static final String ELT_sequence = "sequence";
085: private static final String ELT_type = "type";
086: private static final String ELT_description = "description";
087: private static final String ELT_time = "time";
088: private static final String ELT_controller = "controller";
089: private static final String ELT_mbean = "mbean";
090: private static final String ELT_class = "class";
091: private static final String ELT_server = "server";
092: private static final String ELT_value = "value";
093:
094: private static final String ATT_ip = "ip";
095: private static final String ATT_port = "port";
096: private static final String ATT_name = "name";
097:
098: String priority;
099: String sequence;
100: String type;
101: String description;
102: String controllerName;
103: String mbeanClass;
104: String mbeanName;
105: String mbeanServerIP;
106: String mbeanServerPort;
107: String time;
108: Hashtable dataList;
109:
110: /**
111: * Create a new JmxNotification object
112: *
113: * @param priority notification priority
114: * @param sequence sequence number
115: * @param type notification type
116: * @param description notification description
117: * @param time time the notification was issued
118: * @param controllerName name of the controller issuing the notification
119: * @param mbeanClass class of the mbean issuing the notification
120: * @param mbeanName name of the mbean issuing the notification
121: * @param mbeanServerIP IP address of the mbean
122: * @param mbeanServerPort Port of the mbean
123: * @param dataList Additional data
124: */
125: public JmxNotification(String priority, String sequence,
126: String type, String description, String time,
127: String controllerName, String mbeanClass, String mbeanName,
128: String mbeanServerIP, String mbeanServerPort,
129: Hashtable dataList) {
130: this .priority = priority;
131: this .sequence = sequence;
132: this .type = type;
133: this .description = description;
134: this .controllerName = controllerName;
135: this .mbeanClass = mbeanClass;
136: this .mbeanName = mbeanName;
137: this .mbeanServerIP = mbeanServerIP;
138: this .mbeanServerPort = mbeanServerPort;
139: this .time = time;
140: this .dataList = dataList;
141: }
142:
143: /**
144: * Parse the given xml to create a notification
145: *
146: * @param xml the xml to use to create a <code>JmxNotification</code>
147: * instance
148: * @return a <code>JmxNotification</code> instance which xml version is that
149: * of the given xml arg
150: * @throws Exception if cannot create an instance (the xml is invalid)
151: */
152: public static JmxNotification createNotificationFromXmlString(
153: String xml) throws Exception {
154: StringReader sreader = new StringReader(xml);
155: SAXReader reader = new SAXReader();
156: Document document = reader.read(sreader);
157: return createNotificationFromXml(document);
158: }
159:
160: /**
161: * @return Returns the dataList.
162: */
163: public Hashtable getDataList() {
164: return dataList;
165: }
166:
167: /**
168: * Returns the first value of an entry in the data list of values
169: *
170: * @param key value of a data parameter in the list
171: * @return <code>String</code> value of the corresponding key
172: */
173: public String getDataValue(String key) {
174: if (!dataList.containsKey(key))
175: return null;
176: else
177: return (String) ((ArrayList) dataList.get(key)).get(0);
178: }
179:
180: /**
181: * @return Returns the controllerName.
182: */
183: public String getControllerName() {
184: return controllerName;
185: }
186:
187: /**
188: * Return the controller jmx name
189: *
190: * @return <code>IP:Port</code>
191: */
192: public String getControllerJmxName() {
193: return getMbeanServerIP() + ":" + getMbeanServerPort();
194: }
195:
196: /**
197: * @param controllerName The controllerName to set.
198: */
199: public void setControllerName(String controllerName) {
200: this .controllerName = controllerName;
201: }
202:
203: /**
204: * @return Returns the description.
205: */
206: public String getDescription() {
207: return description;
208: }
209:
210: /**
211: * @param description The description to set.
212: */
213: public void setDescription(String description) {
214: this .description = description;
215: }
216:
217: /**
218: * @return Returns the mbeanClass.
219: */
220: public String getMbeanClass() {
221: return mbeanClass;
222: }
223:
224: /**
225: * @param mbeanClass The mbeanClass to set.
226: */
227: public void setMbeanClass(String mbeanClass) {
228: this .mbeanClass = mbeanClass;
229: }
230:
231: /**
232: * @return Returns the mbeanName.
233: */
234: public String getMbeanName() {
235: return mbeanName;
236: }
237:
238: /**
239: * @param mbeanName The mbeanName to set.
240: */
241: public void setMbeanName(String mbeanName) {
242: this .mbeanName = mbeanName;
243: }
244:
245: /**
246: * @return Returns the mbeanServerIP.
247: */
248: public String getMbeanServerIP() {
249: return mbeanServerIP;
250: }
251:
252: /**
253: * @param mbeanServerIP The mbeanServerIP to set.
254: */
255: public void setMbeanServerIP(String mbeanServerIP) {
256: this .mbeanServerIP = mbeanServerIP;
257: }
258:
259: /**
260: * @return Returns the mbeanServerPort.
261: */
262: public String getMbeanServerPort() {
263: return mbeanServerPort;
264: }
265:
266: /**
267: * @param mbeanServerPort The mbeanServerPort to set.
268: */
269: public void setMbeanServerPort(String mbeanServerPort) {
270: this .mbeanServerPort = mbeanServerPort;
271: }
272:
273: /**
274: * @return Returns the priority.
275: */
276: public String getPriority() {
277: return priority;
278: }
279:
280: /**
281: * @param priority The priority to set.
282: */
283: public void setPriority(String priority) {
284: this .priority = priority;
285: }
286:
287: /**
288: * @return Returns the sequence.
289: */
290: public String getSequence() {
291: return sequence;
292: }
293:
294: /**
295: * @param sequence The sequence to set.
296: */
297: public void setSequence(String sequence) {
298: this .sequence = sequence;
299: }
300:
301: /**
302: * @return Returns the type.
303: */
304: public String getType() {
305: return type;
306: }
307:
308: /**
309: * @param type The type to set.
310: */
311: public void setType(String type) {
312: this .type = type;
313: }
314:
315: /**
316: * Used as a factory to create an instance of this class from a xml document
317: *
318: * @param document a dom4j document
319: * @return an instance of this class with the corresponding parameters
320: */
321: public static JmxNotification createNotificationFromXml(
322: Document document) {
323: String priority = document.selectSingleNode(
324: "//" + ELT_jmxevent + "/" + ELT_info + "/"
325: + ELT_priority).getText();
326: String sequence = document.selectSingleNode(
327: "//" + ELT_jmxevent + "/" + ELT_info + "/"
328: + ELT_sequence).getText();
329: String type = document.selectSingleNode(
330: "//" + ELT_jmxevent + "/" + ELT_info + "/" + ELT_type)
331: .getText();
332: String description = document.selectSingleNode(
333: "//" + ELT_jmxevent + "/" + ELT_info + "/"
334: + ELT_description).getText();
335: String time = document.selectSingleNode(
336: "//" + ELT_jmxevent + "/" + ELT_info + "/" + ELT_time)
337: .getText();
338:
339: String controllerName = document.selectSingleNode(
340: "//" + ELT_jmxevent + "/" + ELT_source + "/"
341: + ELT_controller).getText();
342: String mbeanclass = document.selectSingleNode(
343: "//" + ELT_jmxevent + "/" + ELT_source + "/"
344: + ELT_mbean + "/" + ELT_class).getText();
345: String mbeanname = document.selectSingleNode(
346: "//" + ELT_jmxevent + "/" + ELT_source + "/"
347: + ELT_mbean).valueOf("@" + ATT_name);
348: String serverip = document.selectSingleNode(
349: "//" + ELT_jmxevent + "/" + ELT_source + "/"
350: + ELT_mbean + "/" + ELT_server).valueOf(
351: "@" + ATT_ip);
352: String serverport = document.selectSingleNode(
353: "//" + ELT_jmxevent + "/" + ELT_source + "/"
354: + ELT_mbean + "/" + ELT_server).valueOf(
355: "@" + ATT_port);
356:
357: Element root = document.getRootElement();
358:
359: Hashtable dataList = new Hashtable();
360: for (Iterator i = root.elementIterator(ELT_data); i.hasNext();) {
361: Element data = (Element) i.next();
362: ArrayList list = new ArrayList();
363: for (Iterator j = data.elementIterator(ELT_value); j
364: .hasNext();) {
365: Element value = (Element) j.next();
366: list.add(value.getTextTrim());
367: }
368: dataList.put(data.valueOf("@" + ATT_name), list);
369: }
370: JmxNotification notif = new JmxNotification(priority, sequence,
371: type, description, time, controllerName, mbeanclass,
372: mbeanname, serverip, serverport, dataList);
373: return notif;
374: }
375:
376: /**
377: * Convert the object to the corresponding xml document instance
378: *
379: * @return <code>Document</code> object with the proper values
380: */
381: public Document toXmlDocument() {
382: Document document = DocumentHelper.createDocument();
383: Element root = document.addElement(ELT_jmxevent);
384:
385: // Describe info
386: Element info = root.addElement(ELT_info);
387: info.addElement(ELT_priority).addText(priority);
388: info.addElement(ELT_sequence).addText(sequence);
389: info.addElement(ELT_type).addText(type);
390: info.addElement(ELT_description).addText(description);
391: info.addElement(ELT_time).addText(time);
392:
393: // Describe source
394: Element source = root.addElement(ELT_source);
395: source.addElement(ELT_controller).addText(controllerName);
396:
397: // Describe mbean
398: Element mbean = source.addElement(ELT_mbean).addAttribute(
399: ATT_name, mbeanName);
400: mbean.addElement(ELT_class).addText(mbeanClass);
401: mbean.addElement(ELT_server)
402: .addAttribute(ATT_ip, mbeanServerIP).addAttribute(
403: ATT_port, mbeanServerPort);
404:
405: // Describe data
406: Enumeration keys = dataList.keys();
407: while (keys.hasMoreElements()) {
408: String key = (String) keys.nextElement();
409: Element data = root.addElement(ELT_data).addAttribute(
410: ATT_name, key);
411:
412: Object entry = dataList.get(key);
413: if (entry instanceof ArrayList) {
414: ArrayList list = (ArrayList) entry;
415: for (int i = 0; i < list.size(); i++)
416: data.addElement(ELT_value).addText(
417: (String) list.get(i));
418: } else if (entry instanceof String[]) {
419: String[] list = (String[]) entry;
420: for (int i = 0; i < list.length; i++)
421: data.addElement(ELT_value).addText(list[i]);
422: } else if (entry instanceof String) {
423: data.addElement(ELT_value).addText((String) entry);
424: }
425: }
426: return document;
427: }
428:
429: /**
430: * @return <code>String</code> version in xml formatted text
431: */
432: public String toString() {
433: StringWriter swriter = new StringWriter();
434: OutputFormat format = OutputFormat.createCompactFormat();
435: XMLWriter writer = new XMLWriter(swriter, format);
436: try {
437: writer.write(toXmlDocument());
438: } catch (IOException e) {
439: // ignore
440: }
441: return swriter.getBuffer().toString();
442: }
443:
444: /**
445: * @return Returns the time.
446: */
447: public String getTime() {
448: return time;
449: }
450:
451: /**
452: * @param time The time to set.
453: */
454: public void setTime(String time) {
455: this .time = time;
456: }
457:
458: /**
459: * @param dataList The dataList to set.
460: */
461: public void setDataList(Hashtable dataList) {
462: this.dataList = dataList;
463: }
464:
465: }
|