KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > jmx > adaptor > snmp > agent > TrapFactorySupport


1 /*
2  * Copyright (c) 2003, Intracom S.A. - www.intracom.com
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * This package and its source code is available at www.jboss.org
19 **/

20 package org.jboss.jmx.adaptor.snmp.agent;
21
22 import java.io.InputStream JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.regex.Matcher JavaDoc;
27 import java.util.regex.Pattern JavaDoc;
28 import java.util.regex.PatternSyntaxException JavaDoc;
29
30 import javax.management.Notification JavaDoc;
31
32 import org.jboss.jmx.adaptor.snmp.config.notification.Mapping;
33 import org.jboss.jmx.adaptor.snmp.config.notification.VarBind;
34 import org.jboss.jmx.adaptor.snmp.config.notification.VarBindList;
35 import org.jboss.logging.Logger;
36 import org.jboss.xb.binding.GenericObjectModelFactory;
37 import org.jboss.xb.binding.ObjectModelFactory;
38 import org.jboss.xb.binding.Unmarshaller;
39 import org.jboss.xb.binding.UnmarshallerFactory;
40 import org.jboss.xb.binding.UnmarshallingContext;
41 import org.opennms.protocols.snmp.SnmpPduPacket;
42 import org.opennms.protocols.snmp.SnmpPduRequest;
43 import org.opennms.protocols.snmp.SnmpPduTrap;
44 import org.xml.sax.Attributes JavaDoc;
45
46 /**
47  * <tt>TrapFactorySupport</tt> takes care of translation of Notifications
48  * into SNMP V1 and V2 traps
49  *
50  * Data Structure Guide
51  *
52  * It looks complicated but it ain't. The mappings are read into a structure
53  * that follows the outline defined in the Notification.xsd. Have a look
54  * there and in the example notificationMap.xml and you should get the picture.
55  * As an optimization, 2 things are done:
56  *
57  * 1. The "NotificationType" fields of all the mappings are
58  * read, interpreted and compiled as regular expressions. All the
59  * instances are placed in an array and made accessible in their compiled
60  * form
61  * 2. The "wrapperClass" attribute is interpreted as a class name that
62  * implements interface NotificationWrapper. An instance of each class is
63  * created and similarly placed in an array
64  *
65  * This results in 2 collections one of regular expressions and one of
66  * NotificationWrapper instances. The two collections have exactly the same
67  * size as the collection of mappings. Obviously each read mapping has a "1-1"
68  * correspondence with exactly 1 compiled regular expression and exactly 1
69  * NotificationWrapper instance. The key for the correspondence is the index:
70  * regular expression i corresponds to mapping i that coresponds to
71  * NotificationWrapper instance i. The loading of the 2 collections is
72  * performed in method startService.
73  * Checking for which mapping to apply (implemented in method findMapping) on a
74  * notification is simple: traverse the cached regular expressions and attempt
75  * to match the notification type against them. The FIRST match short circuits
76  * the search and the coresponding mapping index is returned.
77  *
78  * @version $Revision: 44604 $
79  *
80  * @author <a HREF="mailto:spol@intracom.gr">Spyros Pollatos</a>
81  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
82 **/

83 public class TrapFactorySupport
84    implements TrapFactory
85 {
86    /** The logger object */
87    private static final Logger log = Logger.getLogger(TrapFactorySupport.class);
88
89    /** Reference to SNMP variable binding factory */
90    private SnmpVarBindFactory snmpVBFactory = null;
91    
92    /** File that contains notification mappings */
93    private String JavaDoc notificationMapResName = null;
94    
95    /** Uptime clock */
96    private Clock clock = null;
97    
98    /** Trap counter */
99    private Counter trapCount = null;
100    
101    /** Contains the read in mappings */
102    private ArrayList JavaDoc notificationMapList = null;
103     
104    /** Contains the compiled regular expression type specifications */
105    private ArrayList JavaDoc mappingRegExpCache = null;
106    
107    /** Contains instances of the notification wrappers */
108    private ArrayList JavaDoc notificationWrapperCache = null;
109    
110    /**
111     * Create TrapFactorySupport
112    **/

113    public TrapFactorySupport()
114    {
115       this.snmpVBFactory = new SnmpVarBindFactory();
116    }
117
118    /**
119     * Sets the name of the file containing the notification/trap mappings,
120     * the uptime clock and the trap counter
121    **/

122    public void set(String JavaDoc notificationMapResName, Clock clock, Counter count)
123    {
124       this.notificationMapResName = notificationMapResName;
125       this.clock = clock;
126       this.trapCount = count;
127    }
128    
129    /**
130     * Populates the regular expression and wrapper instance collections. Note
131     * that a failure (e.g. to compile a regular expression or to instantiate a
132     * wrapper) generates an error message. Furthermore, the offending
133     * expression or class are skipped and the corresponding collection entry
134     * is null. It is the user's responsibility to track the reported errors in
135     * the logs and act accordingly (i.e. correct them and restart). If not the
136     * corresponding mappings are effectively void and will NOT have effect.
137    **/

138    public void start()
139       throws Exception JavaDoc
140    {
141       log.debug("Reading resource: '" + notificationMapResName + "'");
142       
143       ObjectModelFactory omf = new NotificationBinding();
144       InputStream JavaDoc is = null;
145       try
146       {
147          // locate notifications.xml
148
is = this.getClass().getResourceAsStream(notificationMapResName);
149          
150          // create unmarshaller
151
Unmarshaller unmarshaller = UnmarshallerFactory.newInstance().newUnmarshaller();
152
153          // let JBossXB do it's magic using the MappingObjectModelFactory
154
this.notificationMapList = (ArrayList JavaDoc)unmarshaller.unmarshal(is, omf, null);
155       }
156       catch (Exception JavaDoc e)
157       {
158          log.error("Accessing resource '" + notificationMapResName + "'");
159          throw e;
160       }
161       finally
162       {
163          if (is != null)
164          {
165             // close the XML stream
166
is.close();
167          }
168       }
169       log.debug("Found " + notificationMapList.size() + " notification mappings");
170       
171       // Initialise the cache with the compiled regular expressions denoting
172
// notification type specifications
173
this.mappingRegExpCache =
174          new ArrayList JavaDoc(notificationMapList.size());
175         
176       // Initialise the cache with the instantiated notification wrappers
177
this.notificationWrapperCache =
178          new ArrayList JavaDoc(notificationMapList.size());
179         
180       for (Iterator JavaDoc i = notificationMapList.iterator(); i.hasNext(); )
181       {
182          Mapping mapping = (Mapping)i.next();
183          
184          // Compile and add the regular expression
185
String JavaDoc notificationType = mapping.getNotificationType();
186          
187          try
188          {
189             Pattern JavaDoc re = Pattern.compile(notificationType);
190             this.mappingRegExpCache.add(re);
191          }
192          catch (PatternSyntaxException JavaDoc e)
193          {
194             // Fill the slot to keep index count correct
195
this.mappingRegExpCache.add(null);
196                 
197             log.warn("Error compiling notification mapping for type: " + notificationType, e);
198          }
199             
200          // Instantiate and add the wrapper
201
// Read wrapper class name
202
String JavaDoc wrapperClassName = mapping.getVarBindList().getWrapperClass();
203                 
204          log.debug("notification wrapper class: " + wrapperClassName);
205          
206          try
207          {
208             NotificationWrapper wrapper =
209                (NotificationWrapper)Class.forName(wrapperClassName, true, this.getClass().getClassLoader()).newInstance();
210                 
211             // Initialise it
212
wrapper.set(this.clock, this.trapCount);
213             
214             // Add the wrapper to the cache
215
this.notificationWrapperCache.add(wrapper);
216          }
217          catch (Exception JavaDoc e)
218          {
219             // Fill the slot to keep index count correct
220
this.notificationWrapperCache.add(null);
221                 
222             log.warn("Error compiling notification mapping for type: " + notificationType, e);
223          }
224       }
225       log.debug("Trap factory going active");
226    }
227     
228    /**
229     * Locate mapping applicable for the incoming notification. Key is the
230     * notification's type
231     *
232     * @param n the notification to be examined
233     * @return the index of the mapping
234     * @throws IndexOutOfBoundsException if no mapping found
235    **/

236    private int findMappingIndex(Notification JavaDoc n)
237       throws IndexOutOfBoundsException JavaDoc
238    {
239       // Sequentially check the notification type against the compiled
240
// regular expressions. On first match return the coresponding mapping
241
// index
242
for (int i = 0; i < notificationMapList.size(); i++)
243       {
244          Pattern JavaDoc p = (Pattern JavaDoc) this.mappingRegExpCache.get(i);
245             
246          if (p != null)
247          {
248             Matcher JavaDoc m = p.matcher(n.getType());
249             
250             if (m.matches())
251             {
252                if (log.isTraceEnabled())
253                   log.trace("Match for '" + n.getType() + "' on mapping " + i);
254                return i;
255             }
256          }
257       }
258       // Signal "no mapping found"
259
throw new IndexOutOfBoundsException JavaDoc();
260    }
261     
262    /**
263     * Traslates a Notification to an SNMP V1 trap.
264    **/

265    public SnmpPduTrap generateV1Trap(Notification JavaDoc n)
266       throws MappingFailedException
267    {
268       if (log.isTraceEnabled())
269          log.trace("generateV1Trap");
270         
271       // Locate mapping for incomming event
272
int index = -1;
273         
274       try
275       {
276          index = findMappingIndex(n);
277       }
278       catch (IndexOutOfBoundsException JavaDoc e)
279       {
280          throw new MappingFailedException("No mapping found for notification type: '" +
281                     n.getType() + "'");
282       }
283         
284       Mapping m = (Mapping)this.notificationMapList.get(index);
285         
286       // Create trap
287
SnmpPduTrap trapPdu = new SnmpPduTrap();
288         
289       trapPdu.setTimeStamp(this.clock.uptime());
290         
291       // Organise the 'variable' payload
292
trapPdu.setGeneric(m.getGeneric());
293       trapPdu.setSpecific(m.getSpecific());
294       trapPdu.setEnterprise(m.getEnterprise());
295         
296       // Append the specified varbinds. Get varbinds from mapping and for
297
// each one of the former use the wrapper to get the corresponding
298
// values
299

300       // Get the coresponding wrapper to get access to notification payload
301
NotificationWrapper wrapper =
302          (NotificationWrapper)this.notificationWrapperCache.get(index);
303         
304       if(wrapper != null)
305       {
306          // Prime the wrapper with the notification contents
307
wrapper.prime(n);
308             
309          // Iterate through mapping specified varbinds and organise values
310
// for each
311
List JavaDoc vbList = m.getVarBindList().getVarBindList();
312          
313          for (int i = 0; i < vbList.size(); i++)
314          {
315             VarBind vb = (VarBind)vbList.get(i);
316                 
317             // Append the var bind. Interrogate read vb for OID and
318
// variable tag. The later is used as the key passed to the
319
// wrapper in order for it to locate the required value. That
320
// value and the aforementioned OID are used to generate the
321
// variable binding
322
trapPdu.addVarBind(
323                this.snmpVBFactory.make(vb.getOid(), wrapper.get(vb.getTag())));
324          }
325       }
326       else
327       {
328          throw new MappingFailedException(
329             "Varbind mapping failure: null wrapper defined for " +
330             " notification type '" + m.getNotificationType() + "'" );
331       }
332       return trapPdu;
333    }
334     
335    /**
336     * Traslates a Notification to an SNMP V2 trap.
337     *
338     * TODO: how do you get timestamp, generic, and specific stuff in the trap
339    **/

340    public SnmpPduPacket generateV2Trap(Notification JavaDoc n)
341       throws MappingFailedException
342    {
343       if (log.isTraceEnabled())
344          log.trace("generateV2Trap");
345         
346       // Locate mapping for incomming event
347
int index = -1;
348         
349       try
350       {
351          index = findMappingIndex(n);
352       }
353       catch (IndexOutOfBoundsException JavaDoc e)
354       {
355          throw new MappingFailedException(
356             "No mapping found for notification type: '" + n.getType() + "'");
357       }
358         
359       Mapping m = (Mapping)this.notificationMapList.get(index);
360       
361       // Create trap
362
SnmpPduRequest trapPdu = new SnmpPduRequest(SnmpPduPacket.V2TRAP);
363         
364       // Append the specified varbinds. Get varbinds from mapping and for
365
// each one of the former use the wrapper to get data from the
366
// notification
367

368       // Get the coresponding wrapper
369
NotificationWrapper wrapper =
370          (NotificationWrapper)this.notificationWrapperCache.get(index);
371         
372       if (wrapper != null)
373       {
374          // Prime the wrapper with the notification contents
375
wrapper.prime(n);
376             
377          List JavaDoc vbList = m.getVarBindList().getVarBindList();
378          
379          for (int i = 0; i < vbList.size(); i++)
380          {
381             VarBind vb = (VarBind)vbList.get(i);
382                 
383             // Append the var bind. Interrogate read vb for OID and
384
// variable tag. The later is used as the key passed to the
385
// wrapper in order for it to locate the required value. That
386
// value and the aforementioned OID are used to generate the
387
// variable binding
388
trapPdu.addVarBind(
389                this.snmpVBFactory.make(vb.getOid(), wrapper.get(vb.getTag())));
390          }
391       }
392       else
393       {
394          log.warn("Varbind mapping failure: null wrapper defined for " +
395                   " notification type '" + m.getNotificationType() + "'" );
396       }
397       return trapPdu;
398    }
399    
400    /**
401     * Utility class used by JBossXB to help parse notifications.xml
402     */

403    private static class NotificationBinding implements GenericObjectModelFactory
404    {
405       // GenericObjectModelFactory implementation ----------------------
406

407       public Object JavaDoc completeRoot(Object JavaDoc root, UnmarshallingContext ctx,
408             String JavaDoc uri, String JavaDoc name)
409       {
410          return root;
411       }
412
413       public Object JavaDoc newRoot(Object JavaDoc root, UnmarshallingContext navigator, String JavaDoc namespaceURI,
414                             String JavaDoc localName, Attributes JavaDoc attrs)
415       {
416          ArrayList JavaDoc notifList;
417          
418          if (root == null)
419          {
420             root = notifList = new ArrayList JavaDoc();
421          }
422          else
423          {
424             notifList = (ArrayList JavaDoc) root;
425          }
426          return root;
427       }
428       
429       public Object JavaDoc newChild(Object JavaDoc parent, UnmarshallingContext navigator, String JavaDoc namespaceURI,
430                              String JavaDoc localName, Attributes JavaDoc attrs)
431       {
432          Object JavaDoc child = null;
433
434          if ("mapping".equals(localName))
435          {
436             Mapping m = new Mapping();
437             child = m;
438          }
439          else if ("var-bind-list".equals(localName))
440          {
441             VarBindList vblist = new VarBindList();
442             child = vblist;
443             if (attrs.getLength() > 0)
444             {
445                for (int i = 0; i < attrs.getLength(); i++)
446                {
447                   if ("wrapper-class".equals(attrs.getLocalName(i)))
448                   {
449                      vblist.setWrapperClass(attrs.getValue(i));
450                   }
451                }
452             }
453             // check that wrapper-class is set
454
if (vblist.getWrapperClass() == null)
455             {
456                throw new RuntimeException JavaDoc("'wrapper-class' must be set at 'var-bind-list' element");
457             }
458          }
459          else if ("var-bind".equals(localName))
460          {
461             VarBind vb = new VarBind();
462             child = vb;
463          }
464          return child;
465       }
466
467       public void addChild(Object JavaDoc parent, Object JavaDoc child, UnmarshallingContext navigator,
468                            String JavaDoc namespaceURI, String JavaDoc localName)
469       {
470          if (parent instanceof ArrayList JavaDoc)
471          {
472             ArrayList JavaDoc notifList = (ArrayList JavaDoc)parent;
473             
474             if (child instanceof Mapping)
475             {
476                notifList.add(child);
477             }
478          }
479          else if (parent instanceof Mapping)
480          {
481             Mapping m = (Mapping)parent;
482             
483             if (child instanceof VarBindList)
484             {
485                m.setVarBindList((VarBindList)child);
486             }
487          }
488          else if (parent instanceof VarBindList)
489          {
490             VarBindList vblist = (VarBindList)parent;
491             
492             if (child instanceof VarBind)
493             {
494                vblist.addVarBind((VarBind)child);
495             }
496          }
497       }
498       
499       public void setValue(Object JavaDoc o, UnmarshallingContext navigator, String JavaDoc namespaceURI,
500                            String JavaDoc localName, String JavaDoc value)
501       {
502          if (o instanceof Mapping)
503          {
504             Mapping m = (Mapping)o;
505             
506             if ("notification-type".equals(localName))
507             {
508                m.setNotificationType(value);
509             }
510             else if ("generic".equals(localName))
511             {
512                m.setGeneric(Integer.parseInt(value));
513             }
514             else if ("specific".equals(localName))
515             {
516                m.setSpecific(Integer.parseInt(value));
517             }
518             else if ("enterprise".equals(localName))
519             {
520                m.setEnterprise(value);
521             }
522          }
523          else if (o instanceof VarBind)
524          {
525             VarBind vb = (VarBind)o;
526             
527             if ("tag".equals(localName))
528             {
529                vb.setTag(value);
530             }
531             else if ("oid".equals(localName))
532             {
533                vb.setOid(value);
534             }
535          }
536       }
537
538       public Object JavaDoc completedRoot(Object JavaDoc root, UnmarshallingContext navigator, String JavaDoc namespaceURI, String JavaDoc localName)
539       {
540          return root;
541       }
542    }
543    
544 } // class TrapFactorySupport
545
Popular Tags