KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > monitor > services > ScriptingListener


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.monitor.services;
23
24 import java.util.LinkedList JavaDoc;
25 import java.util.List JavaDoc;
26
27 import javax.management.MBeanServer JavaDoc;
28 import javax.management.Notification JavaDoc;
29 import javax.management.ObjectName JavaDoc;
30
31 import org.apache.bsf.BSFException;
32 import org.apache.bsf.BSFManager;
33 import org.jboss.logging.Logger;
34 import org.jboss.monitor.alarm.AlarmManager;
35 import org.jboss.system.ListenerServiceMBeanSupport;
36
37 import EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
38
39 /**
40  * A simple listener that can subscribe for any combination
41  * of notifications, and asynchronously process them using
42  * a script written using any of the languages supported by
43  * the apache Bean Scripting Framework (BSF).
44  *
45  * The following variables are setup for the script to use:
46  *
47  * "log" - service Logger
48  * "server" - the MBeanServer
49  * "manager" - alarm manager helper
50  *
51  * "notification" - the Notification to be processed
52  * "handback" - the Object sent with the notification
53  *
54  * By setting up a Timer using the TimerService to periodicaly
55  * emit notifications, we can use those notifications as triggers
56  * for performing any sort of polling operation.
57  *
58  * One of the intented uses of this service is to use the "manager"
59  * (see org.jboss.monitor.alarm.AlarmManager) in the script,
60  * help maintain a list of active system alarms in the
61  * ActiveAlarmTable service.
62  *
63  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
64  * @version $Revision: 37459 $
65  */

66 public class ScriptingListener extends ListenerServiceMBeanSupport
67     implements ScriptingListenerMBean
68 {
69    // Private Data --------------------------------------------------
70

71    /** The Script */
72    private String JavaDoc script;
73    
74    /** The language the script is written into */
75    private String JavaDoc language;
76
77    /** Dynamic subscriptions flag */
78    private boolean dynamicSubscriptions;
79
80    /** Set to deliver notification directly */
81    private ObjectName JavaDoc targetListener;
82    
83    /** The number of notifications received/enqueued */
84    private SynchronizedLong notificationsReceived;
85    
86    /** The number of notifications processed/dequeued by the script */
87    private SynchronizedLong notificationsProcessed;
88    
89    /** The total time (msecs) spent executing the script */
90    private SynchronizedLong totalProcessingTime;
91    
92    /** Bean Scripting Framework entry point */
93    private BSFManager manager;
94    
95    /** Enqueued notifications */
96    private List JavaDoc queue;
97    
98    /** Signals stop processing */
99    private boolean stopRequested;
100
101    /** The thread running the script */
102    private Thread JavaDoc processorThread;
103    
104    /** The alarm manager helper */
105    private AlarmManager alm = new AlarmManager(this);
106    
107    // Constructors --------------------------------------------------
108

109    /**
110     * CTOR
111     */

112    public ScriptingListener()
113    {
114       queue = new LinkedList JavaDoc();
115       
116       notificationsReceived = new SynchronizedLong(0);
117       notificationsProcessed = new SynchronizedLong(0);
118       totalProcessingTime = new SynchronizedLong(0);
119    }
120    
121    // ScriptNotificationListenerMBean Implementation ----------------
122

123    /**
124     * @jmx:managed-attribute
125     */

126    public void setScript(String JavaDoc script)
127    {
128       this.script = script;
129    }
130
131    /**
132     * @jmx:managed-attribute
133     */

134    public String JavaDoc getScript()
135    {
136       return script;
137    }
138    
139    /**
140     * @jmx:managed-attribute
141     */

142    public void setScriptLanguage(String JavaDoc language)
143    {
144       this.language = language;
145    }
146
147    /**
148     * @jmx:managed-attribute
149     */

150    public String JavaDoc getScriptLanguage()
151    {
152       return language;
153    }
154    
155    /**
156     * @jmx:managed-attribute
157     */

158    public void setDynamicSubscriptions(boolean dynamicSubscriptions)
159    {
160       this.dynamicSubscriptions = dynamicSubscriptions;
161    }
162
163    /**
164     * @jmx:managed-attribute
165     */

166    public boolean getDynamicSubscriptions()
167    {
168       return this.dynamicSubscriptions;
169    }
170    
171    /**
172     * @jmx:managed-attribute
173     */

174    public long getNotificationsReceived()
175    {
176       return notificationsReceived.get();
177    }
178
179    /**
180     * @jmx:managed-attribute
181     */

182    public long getNotificationsProcessed()
183    {
184       return notificationsProcessed.get();
185    }
186    
187    /**
188     * @jmx:managed-attribute
189     */

190    public long getTotalProcessingTime()
191    {
192       return totalProcessingTime.get();
193    }
194    
195    /**
196     * @jmx:managed-attribute
197     */

198    public long getAverageProcessingTime()
199    {
200       long processed = notificationsProcessed.get();
201       
202       return (processed == 0) ? 0 : totalProcessingTime.get() / processed;
203    }
204    
205    // Lifecycle control (ServiceMBeanSupport) -----------------------
206

207    /**
208     * Start
209     */

210    public void startService() throws Exception JavaDoc
211    {
212       log.debug("Initializing BSFManager for language '" + language + "'");
213       
214       // This is needed until BSF adds it
215
BSFManager.registerScriptingEngine(
216             "groovy",
217             "org.codehaus.groovy.bsf.GroovyEngine",
218             new String JavaDoc[] { "groovy", "gy" }
219            );
220       
221       // I suppose we need one BSFManager per processing thread
222
manager = new BSFManager();
223      
224       manager.setClassLoader(Thread.currentThread().getContextClassLoader());
225       manager.loadScriptingEngine(language);
226       manager.declareBean("log", log, Logger.class);
227       manager.declareBean("server", server, MBeanServer JavaDoc.class);
228       manager.declareBean("manager", alm, AlarmManager.class);
229       
230       // test with a dummy notification first, to see if the script is valid
231
Notification JavaDoc testNotification = new Notification JavaDoc("jboss.script.test", serviceName, 0);
232       manager.declareBean("notification", testNotification, Notification JavaDoc.class);
233       manager.declareBean("handback", "", Object JavaDoc.class);
234       
235       manager.exec(language, "in-memory-script", 0, 0, script);
236       
237       // Start the ScriptProcessor in its own thread
238
processorThread = new Thread JavaDoc(new ScriptProcessor(), "ScriptProcessor[" + serviceName + "]");
239       processorThread.start();
240       
241       // subscribe for notifications
242
super.subscribe(dynamicSubscriptions);
243    }
244    
245    /**
246     * Stop
247     */

248    public void stopService() throws Exception JavaDoc
249    {
250       // unsubscribe for notifications
251
super.unsubscribe();
252       
253       log.debug("Stopping " + processorThread.getName());
254       
255       // tell the ScriptProcessor to stop
256
stopRequested = true;
257       
258       // notify the processing thread in case it is waiting on the queue
259
synchronized (queue)
260       {
261          queue.notify();
262       }
263      
264       try
265       {
266          // wait for the processor to finish, but not for too long
267
processorThread.join(5000);
268       }
269       catch (InterruptedException JavaDoc e)
270       {
271          // set interrupted status
272
Thread.currentThread().interrupt();
273       }
274       
275       // cleanup
276
queue.clear();
277       manager.terminate();
278    }
279    
280    // ListenerServiceMBeanSupport overrides -------------------------
281

282    /**
283     * Overriden to add handling!
284     */

285    public void handleNotification2(Notification JavaDoc notification, Object JavaDoc handback)
286    {
287       // count the received notifications
288
notificationsReceived.increment();
289       
290       // append the received notification to the end of the list,
291
// for processing from a different thread
292
synchronized (queue)
293       {
294          queue.add(new QueueEntry(notification, handback));
295          
296          // hint to the processing thread to kick-in
297
queue.notify();
298       }
299    }
300    
301    // Inner ---------------------------------------------------------
302

303    /**
304     * Simple data holder
305     */

306    private static class QueueEntry
307    {
308       public Notification JavaDoc notification;
309       public Object JavaDoc handback;
310       
311       public QueueEntry(Notification JavaDoc notification, Object JavaDoc handback)
312       {
313          this.notification = notification;
314          this.handback = handback;
315       }
316    }
317    
318    /**
319     * Inner class to encapsulate script execution logic
320     */

321    private class ScriptProcessor implements Runnable JavaDoc
322    {
323       public void run()
324       {
325          String JavaDoc name = Thread.currentThread().getName();
326          log.debug("Started thread: " + name);
327          
328          while (!stopRequested)
329          {
330             QueueEntry entry;
331             
332             synchronized (queue)
333             {
334                while (queue.isEmpty() && !stopRequested)
335                {
336                   try
337                   {
338                      queue.wait();
339                   }
340                   catch (InterruptedException JavaDoc e)
341                   {
342                      // ignore
343
}
344                }
345                
346                if (stopRequested)
347                {
348                   // done
349
break;
350                }
351                else
352                {
353                   // extract the first entry for processing
354
entry = (QueueEntry)queue.remove(0);
355                }
356             }
357             
358             // use this for measurement
359
long start = System.currentTimeMillis();
360             
361             // we have a notification to process
362
try
363             {
364                manager.declareBean("notification", entry.notification, Notification JavaDoc.class);
365                manager.declareBean("handback", entry.handback == null ? "" : entry.handback, Object JavaDoc.class);
366                
367                manager.exec(language, "in-memory-script", 0, 0, script);
368             }
369             catch (BSFException e)
370             {
371                log.warn("Caught exception", e);
372             }
373             
374             // measure time spent processing the script
375
long stop = System.currentTimeMillis();
376             totalProcessingTime.add(stop - start);
377             notificationsProcessed.increment();
378          }
379          log.debug("Stopped thread: " + name);
380       }
381    }
382    
383 }
384
Popular Tags