001: /*
002: * Copyright (C) The MX4J Contributors.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the MX4J License version 1.0.
006: * See the terms of the MX4J License in the documentation provided with this software.
007: */
008:
009: package mx4j.tools.jython;
010:
011: import java.io.BufferedReader;
012: import java.io.IOException;
013: import java.io.InputStream;
014: import java.io.InputStreamReader;
015: import java.net.URL;
016: import javax.management.InstanceNotFoundException;
017: import javax.management.ListenerNotFoundException;
018: import javax.management.MBeanRegistration;
019: import javax.management.MBeanServer;
020: import javax.management.Notification;
021: import javax.management.NotificationFilter;
022: import javax.management.NotificationListener;
023: import javax.management.ObjectName;
024:
025: import mx4j.log.Log;
026: import mx4j.log.Logger;
027: import org.python.core.Py;
028: import org.python.core.PyCode;
029: import org.python.core.PySystemState;
030: import org.python.util.PythonInterpreter;
031:
032: /**
033: * This MBean enables you to run scripts written in jython. Scripts can be run
034: * using the managed operation runScript or by listening notifcations from
035: * another MBean. To us it you need to install jython 2.1 or higher from
036: * <a href="http://www.jython.org">here</a>
037: * <p/>
038: * If you want to use a jython library remember to add the jython jar to the
039: * classpath in the right location or modify the python.path address
040: * <p/>
041: * The scripts have always the "server" embedded variable which points
042: * to the current server. It also automatically import some JMX modules as:
043: * <p/>
044: * <ul>
045: * <li>from javax.management import *
046: * <li>from javax.management.loading import *
047: * </ul>
048: *
049: * @version $Revision: 1.9 $
050: */
051: public class JythonRunner implements JythonRunnerMBean,
052: NotificationListener, MBeanRegistration {
053: private MBeanServer server = null;
054:
055: private ObjectName targetMBeanName, objectName;
056:
057: private String notificationName;
058:
059: private boolean useText = true;
060:
061: private boolean useCache = false;
062:
063: private String scriptText;
064:
065: private URL scriptFile;
066:
067: private PyCode cache = null;
068:
069: private static PythonInterpreter interpreter;
070:
071: public void handleNotification(Notification notification,
072: Object handback) {
073: if (notificationName != null
074: && !notification.getType().equals(notificationName))
075: return;
076:
077: Logger logger = getLogger();
078: if (logger.isEnabledFor(Logger.DEBUG))
079: logger.debug("Notification " + notification
080: + " hit, sending message");
081: runScript();
082: }
083:
084: private Logger getLogger() {
085: return Log.getLogger(getClass().getName());
086: }
087:
088: /**
089: * Executes a given script. If useText is true the text passed will be run as a script
090: * otherwise the script will be loaded from the URL an executed
091: */
092: public void runScript() {
093: PythonInterpreter interp = getPythonInterpreter();
094: interp.set("server", server);
095: String script = null;
096: if (useText) {
097: script = scriptText;
098: } else {
099: try {
100: script = loadStream(scriptFile.openStream());
101: } catch (IOException e) {
102: Logger log = getLogger();
103: log.error("Exception during url opening", e);
104: }
105: }
106: interp.exec(script);
107: }
108:
109: public static PythonInterpreter getPythonInterpreter() {
110: if (interpreter == null) {
111: interpreter = new PythonInterpreter();
112: PySystemState sys = Py.getSystemState();
113: sys.add_package("javax.management");
114: sys.add_package("javax.management.loading");
115: sys.add_package("javax.management.modelmbean");
116: sys.add_package("javax.management.monitor");
117: sys.add_package("javax.management.openmbean");
118: sys.add_package("javax.management.remote");
119: sys.add_package("javax.management.remote.rmi");
120: sys.add_package("javax.management.relation");
121: sys.add_package("javax.management.timer");
122: try {
123: String script = loadStream(JythonRunner.class
124: .getClassLoader().getResourceAsStream(
125: "mx4j/tools/jython/jmxUtils.py"));
126: interpreter.exec(script);
127: } catch (IOException e) {
128: e.printStackTrace();
129: }
130: }
131: return interpreter;
132: }
133:
134: protected static String loadStream(InputStream in)
135: throws IOException {
136: BufferedReader reader = new BufferedReader(
137: new InputStreamReader(in));
138: String line = null;
139: StringBuffer buffer = new StringBuffer();
140: while ((line = reader.readLine()) != null) {
141: buffer.append(line);
142: buffer.append("\n");
143: }
144: return buffer.toString();
145: }
146:
147: /**
148: * Gets the specific notification type being listened
149: */
150: public String getNotificationType() {
151: return notificationName;
152: }
153:
154: /**
155: * Sets the notification being listed. If null any notification will trigger
156: * the execution of the script. Otherwise only notifications matching notificationName
157: * will trigger it
158: */
159: public void setNotificationType(String notificationName) {
160: this .notificationName = notificationName;
161: }
162:
163: /**
164: * Sets the object being observed by this MBean. The MBean will register
165: * itself as a listener of targetMBeanName
166: */
167: public void setObservedObject(ObjectName targetMBeanName) {
168: this .targetMBeanName = targetMBeanName;
169: registerListener();
170: }
171:
172: /**
173: * Gets the object being observed by this MBean
174: */
175: public ObjectName getObservedObject() {
176: return targetMBeanName;
177: }
178:
179: /**
180: * Indicates wether to use the script given in the ScripText variable or
181: * the one given in the script File.
182: */
183: public boolean getUseText() {
184: return this .useText;
185: }
186:
187: /**
188: * Sets the content of the script. If you want to use a file, use ScriptFile
189: * instead.
190: */
191: public void setScript(String text) {
192: this .scriptText = text;
193: this .useText = true;
194: }
195:
196: /**
197: * Returns the script as text.
198: */
199: public String getScript() {
200: return this .scriptText;
201: }
202:
203: /**
204: * Returns the URL pointing to the script source
205: */
206: public URL getScriptURL() {
207: return scriptFile;
208: }
209:
210: /**
211: * Sets the script source as URL. If the cache script variable is true
212: * the file will be loaded only once, otherwise everytime the script is
213: * executed
214: */
215: public void setScriptURL(URL file) {
216: this .scriptFile = file;
217: this .useText = false;
218: }
219:
220: /**
221: * Returns whether the script should be kept in the cache. If true, no further
222: * attempts to read the script will be done afterwards. By default is false
223: */
224: public boolean getCacheScript() {
225: return useCache;
226: }
227:
228: /**
229: * Sets whether the script should be kept in the cache. If true, no further
230: * attempts to read the script will be done afterwards. By default is false
231: */
232: public void setCacheScript(boolean useCache) {
233: this .useCache = useCache;
234: }
235:
236: /**
237: * Gathers some basic data
238: */
239: public ObjectName preRegister(MBeanServer server, ObjectName name)
240: throws java.lang.Exception {
241: this .server = server;
242: this .objectName = name;
243: return name;
244: }
245:
246: public void postRegister(Boolean registrationDone) {
247: }
248:
249: public void preDeregister() throws java.lang.Exception {
250: unregisterListener();
251: }
252:
253: public void postDeregister() {
254: }
255:
256: protected void registerListener() {
257: try {
258: if (targetMBeanName != null
259: && server.isInstanceOf(targetMBeanName,
260: "javax.management.NotificationBroadcaster")) {
261: server.addNotificationListener(targetMBeanName, this ,
262: new MessageFilter(), null);
263: }
264: } catch (InstanceNotFoundException e) {
265: Logger log = getLogger();
266: log.error("Exception during notification registration", e);
267: }
268: }
269:
270: protected void unregisterListener() {
271: try {
272: if (targetMBeanName != null
273: && server.isInstanceOf(targetMBeanName,
274: "javax.management.NotificationBroadcaster")) {
275: server
276: .removeNotificationListener(targetMBeanName,
277: this );
278: }
279: } catch (InstanceNotFoundException e) {
280: Logger log = getLogger();
281: log
282: .error(
283: "Exception during notification unregistration",
284: e);
285: } catch (ListenerNotFoundException e) {
286: }
287: }
288:
289: private class MessageFilter implements NotificationFilter {
290: public boolean isNotificationEnabled(Notification notification) {
291: return notificationName == null
292: || (notification.getType() != null && notification
293: .getType().equals(notificationName));
294: }
295: }
296: }
|