KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > snmp > agent > SnmpMibTable


1 /*
2  * @(#)file SnmpMibTable.java
3  * @(#)author Sun Microsystems, Inc.
4  * @(#)version 4.57
5  * @(#)date 08/02/09
6  *
7  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
8  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
9  *
10  */

11
12
13 package com.sun.jmx.snmp.agent;
14
15
16
17 // java imports
18
//
19
import java.io.Serializable JavaDoc;
20 import java.util.Date JavaDoc;
21 import java.util.Vector JavaDoc;
22 import java.util.Enumeration JavaDoc;
23
24 // jmx imports
25
//
26
import javax.management.Notification JavaDoc;
27 import javax.management.ObjectName JavaDoc;
28 import javax.management.NotificationFilter JavaDoc;
29 import javax.management.NotificationListener JavaDoc;
30 import javax.management.NotificationBroadcaster JavaDoc;
31 import javax.management.MBeanNotificationInfo JavaDoc;
32 import javax.management.ListenerNotFoundException JavaDoc;
33 import com.sun.jmx.snmp.SnmpOid;
34 import com.sun.jmx.snmp.SnmpValue;
35 import com.sun.jmx.snmp.SnmpInt;
36 import com.sun.jmx.snmp.SnmpVarBind;
37 import com.sun.jmx.snmp.SnmpStatusException;
38
39 import com.sun.jmx.snmp.EnumRowStatus;
40 import com.sun.jmx.trace.Trace;
41  
42 /**
43  * This class is the base class for SNMP table metadata.
44  * <p>
45  * Its responsibility is to manage a sorted array of OID indexes
46  * according to the SNMP indexing scheme over the "real" table.
47  * Each object of this class can be bound to an
48  * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} to which it will
49  * forward remote entry creation requests, and invoke callbacks
50  * when an entry has been successfully added to / removed from
51  * the OID index array.
52  * </p>
53  *
54  * <p>
55  * For each table defined in the MIB, mibgen will generate a specific
56  * class called Table<i>TableName</i> that will implement the
57  * SnmpTableEntryFactory interface, and a corresponding
58  * <i>TableName</i>Meta class that will extend this class. <br>
59  * The Table<i>TableName</i> class corresponds to the MBean view of the
60  * table while the <i>TableName</i>Meta class corresponds to the
61  * MIB metadata view of the same table.
62  * </p>
63  *
64  * <p>
65  * Objects of this class are instantiated by the generated
66  * whole MIB class extending {@link com.sun.jmx.snmp.agent.SnmpMib}
67  * You should never need to instantiate this class directly.
68  * </p>
69  *
70  * <p><b>This API is a Sun Microsystems internal API and is subject
71  * to change without notice.</b></p>
72  * @see com.sun.jmx.snmp.agent.SnmpMib
73  * @see com.sun.jmx.snmp.agent.SnmpMibEntry
74  * @see com.sun.jmx.snmp.agent.SnmpTableEntryFactory
75  * @see com.sun.jmx.snmp.agent.SnmpTableSupport
76  *
77  * @version 4.57 01/22/04
78  * @author Sun Microsystems, Inc
79  */

80
81 public abstract class SnmpMibTable extends SnmpMibNode
82     implements NotificationBroadcaster JavaDoc, Serializable JavaDoc {
83   
84     /**
85      * Create a new <CODE>SnmpMibTable</CODE> metadata node.
86      *
87      * <p>
88      * @param mib The SNMP MIB to which the metadata will be linked.
89      */

90     public SnmpMibTable(SnmpMib mib) {
91         this.theMib= mib;
92     setCreationEnabled(false);
93     }
94     
95     // -------------------------------------------------------------------
96
// PUBLIC METHODS
97
// -------------------------------------------------------------------
98

99     /**
100      * This method is invoked when the creation of a new entry is requested
101      * by a remote SNMP manager.
102      * <br>By default, remote entry creation is disabled - and this method
103      * will not be called. You can dynamically switch the entry creation
104      * policy by calling <code>setCreationEnabled(true)</code> and <code>
105      * setCreationEnabled(false)</code> on this object.
106      * <p><b><i>
107      * This method is called internally by the SNMP runtime and you
108      * should never need to call it directly. </b></i>However you might want
109      * to extend it in order to implement your own specific application
110      * behaviour, should the default behaviour not be at your convenience.
111      * </p>
112      * <p>
113      * @param req The SNMP subrequest requesting this creation
114      * @param rowOid The OID indexing the conceptual row (entry) for which
115      * the creation was requested.
116      * @param depth The position of the columnar object arc in the OIDs
117      * from the varbind list.
118      *
119      * @exception SnmpStatusException if the entry cannot be created.
120      */

121     public abstract void createNewEntry(SnmpMibSubRequest req, SnmpOid rowOid,
122                     int depth)
123     throws SnmpStatusException;
124
125     /**
126      * Tell whether the specific version of this metadata generated
127      * by <code>mibgen</code> requires entries to be registered with
128      * the MBeanServer. In this case an ObjectName will have to be
129      * passed to addEntry() in order for the table to behave correctly
130      * (case of the generic metadata).
131      * <p>
132      * If that version of the metadata does not require entry to be
133      * registered, then passing an ObjectName becomes optional (null
134      * can be passed instead).
135      *
136      * @return <code>true</code> if registration is required by this
137      * version of the metadata.
138      */

139     public abstract boolean isRegistrationRequired();
140
141     /**
142      * Tell whether a new entry should be created when a SET operation
143      * is received for an entry that does not exist yet.
144      *
145      * @return true if a new entry must be created, false otherwise.<br>
146      * [default: returns <CODE>false</CODE>]
147      **/

148     public boolean isCreationEnabled() {
149     return creationEnabled;
150     }
151
152     /**
153      * This method lets you dynamically switch the creation policy.
154      *
155      * <p>
156      * @param remoteCreationFlag Tells whether remote entry creation must
157      * be enabled or disabled.
158      * <ul><li>
159      * <CODE>setCreationEnabled(true)</CODE> will enable remote entry
160      * creation via SET operations.</li>
161      * <li>
162      * <CODE>setCreationEnabled(false)</CODE> will disable remote entry
163      * creation via SET operations.</li>
164      * <p> By default remote entry creation via SET operation is disabled.
165      * </p>
166      * </ul>
167      **/

168     public void setCreationEnabled(boolean remoteCreationFlag) {
169     creationEnabled = remoteCreationFlag;
170     }
171
172     /**
173      * Return <code>true</code> if the conceptual row contains a columnar
174      * object used to control creation/deletion of rows in this table.
175      * <p>
176      * This columnar object can be either a variable with RowStatus
177      * syntax as defined by RFC 2579, or a plain variable whose
178      * semantics is table specific.
179      * <p>
180      * By default, this function returns <code>false</code>, and it is
181      * assumed that the table has no such control variable.<br>
182      * When <code>mibgen</code> is used over SMIv2 MIBs, it will generate
183      * an <code>hasRowStatus()</code> method returning <code>true</code>
184      * for each table containing an object with RowStatus syntax.
185      * <p>
186      * When this method returns <code>false</code> the default mechanism
187      * for remote entry creation is used.
188      * Otherwise, creation/deletion is performed as specified
189      * by the control variable (see getRowAction() for more details).
190      * <p>
191      * This method is called internally when a SET request involving
192      * this table is processed.
193      * <p>
194      * If you need to implement a control variable which do not use
195      * the RowStatus convention as defined by RFC 2579, you should
196      * subclass the generated table metadata class in order to redefine
197      * this method and make it returns <code>true</code>.<br>
198      * You will then have to redefine the isRowStatus(), mapRowStatus(),
199      * isRowReady(), and setRowStatus() methods to suit your specific
200      * implementation.
201      * <p>
202      * @return <li><code>true</code> if this table contains a control
203      * variable (eg: a variable with RFC 2579 RowStatus syntax),
204      * </li>
205      * <li><code>false</code> if this table does not contain
206      * any control variable.</li>
207      *
208      **/

209     public boolean hasRowStatus() {
210     return false;
211     }
212
213     // ---------------------------------------------------------------------
214
//
215
// Implements the method defined in SnmpMibNode.
216
//
217
// ---------------------------------------------------------------------
218
/**
219      * Generic handling of the <CODE>get</CODE> operation.
220      * <p> The default implementation of this method is to
221      * <ul>
222      * <li> check whether the entry exists, and if not register an
223      * exception for each varbind in the list.
224      * <li> call the generated
225      * <CODE>get(req,oid,depth+1)</CODE> method. </li>
226      * </ul>
227      * <p>
228      * <pre>
229      * public void get(SnmpMibSubRequest req, int depth)
230      * throws SnmpStatusException {
231      * boolean isnew = req.isNewEntry();
232      *
233      * // if the entry does not exists, then registers an error for
234      * // each varbind involved (nb: this should not happen, since
235      * // the error should already have been detected earlier)
236      * //
237      * if (isnew) {
238      * SnmpVarBind var = null;
239      * for (Enumeration e= req.getElements(); e.hasMoreElements();) {
240      * var = (SnmpVarBind) e.nextElement();
241      * req.registerGetException(var,noSuchNameException);
242      * }
243      * }
244      *
245      * final SnmpOid oid = req.getEntryOid();
246      * get(req,oid,depth+1);
247      * }
248      * </pre>
249      * <p> You should not need to override this method in any cases, because
250      * it will eventually call
251      * <CODE>get(SnmpMibSubRequest req, int depth)</CODE> on the generated
252      * derivative of <CODE>SnmpMibEntry</CODE>. If you need to implement
253      * specific policies for minimizing the accesses made to some remote
254      * underlying resources, or if you need to implement some consistency
255      * checks between the different values provided in the varbind list,
256      * you should then rather override
257      * <CODE>get(SnmpMibSubRequest req, int depth)</CODE> on the generated
258      * derivative of <CODE>SnmpMibEntry</CODE>.
259      * <p>
260      *
261      */

262     public void get(SnmpMibSubRequest req, int depth)
263     throws SnmpStatusException {
264
265     final boolean isnew = req.isNewEntry();
266     final SnmpMibSubRequest r = req;
267
268     // if the entry does not exists, then registers an error for
269
// each varbind involved (nb: should not happen, the error
270
// should have been registered earlier)
271
if (isnew) {
272         SnmpVarBind var = null;
273         for (Enumeration JavaDoc e= r.getElements(); e.hasMoreElements();) {
274         var = (SnmpVarBind) e.nextElement();
275         r.registerGetException(var,noSuchInstanceException);
276         }
277     }
278
279     final SnmpOid oid = r.getEntryOid();
280
281     // SnmpIndex index = buildSnmpIndex(oid.longValue(false), 0);
282
// get(req,index,depth+1);
283
//
284
get(req,oid,depth+1);
285     }
286
287     // ---------------------------------------------------------------------
288
//
289
// Implements the method defined in SnmpMibNode.
290
//
291
// ---------------------------------------------------------------------
292
/**
293      * Generic handling of the <CODE>check</CODE> operation.
294      * <p> The default implementation of this method is to
295      * <ul>
296      * <li> check whether a new entry must be created, and if remote
297      * creation of entries is enabled, create it. </li>
298      * <li> call the generated
299      * <CODE>check(req,oid,depth+1)</CODE> method. </li>
300      * </ul>
301      * <p>
302      * <pre>
303      * public void check(SnmpMibSubRequest req, int depth)
304      * throws SnmpStatusException {
305      * final SnmpOid oid = req.getEntryOid();
306      * final int action = getRowAction(req,oid,depth+1);
307      *
308      * beginRowAction(req,oid,depth+1,action);
309      * check(req,oid,depth+1);
310      * }
311      * </pre>
312      * <p> You should not need to override this method in any cases, because
313      * it will eventually call
314      * <CODE>check(SnmpMibSubRequest req, int depth)</CODE> on the generated
315      * derivative of <CODE>SnmpMibEntry</CODE>. If you need to implement
316      * specific policies for minimizing the accesses made to some remote
317      * underlying resources, or if you need to implement some consistency
318      * checks between the different values provided in the varbind list,
319      * you should then rather override
320      * <CODE>check(SnmpMibSubRequest req, int depth)</CODE> on the generated
321      * derivative of <CODE>SnmpMibEntry</CODE>.
322      * <p>
323      *
324      */

325     public void check(SnmpMibSubRequest req, int depth)
326     throws SnmpStatusException {
327     final SnmpOid oid = req.getEntryOid();
328     final int action = getRowAction(req,oid,depth+1);
329
330     final boolean dbg = isDebugOn();
331
332     if (dbg) debug("check","Calling beginRowAction");
333
334     beginRowAction(req,oid,depth+1,action);
335
336     if (dbg) debug("check","Calling check for " + req.getSize() +
337                " varbinds.");
338
339     check(req,oid,depth+1);
340
341     if (dbg) debug("check","check finished");
342     }
343
344     // ---------------------------------------------------------------------
345
//
346
// Implements the method defined in SnmpMibNode.
347
//
348
// ---------------------------------------------------------------------
349
/**
350      * Generic handling of the <CODE>set</CODE> operation.
351      * <p> The default implementation of this method is to
352      * call the generated
353      * <CODE>set(req,oid,depth+1)</CODE> method.
354      * <p>
355      * <pre>
356      * public void set(SnmpMibSubRequest req, int depth)
357      * throws SnmpStatusException {
358      * final SnmpOid oid = req.getEntryOid();
359      * final int action = getRowAction(req,oid,depth+1);
360      *
361      * set(req,oid,depth+1);
362      * endRowAction(req,oid,depth+1,action);
363      * }
364      * </pre>
365      * <p> You should not need to override this method in any cases, because
366      * it will eventually call
367      * <CODE>set(SnmpMibSubRequest req, int depth)</CODE> on the generated
368      * derivative of <CODE>SnmpMibEntry</CODE>. If you need to implement
369      * specific policies for minimizing the accesses made to some remote
370      * underlying resources, or if you need to implement some consistency
371      * checks between the different values provided in the varbind list,
372      * you should then rather override
373      * <CODE>set(SnmpMibSubRequest req, int depth)</CODE> on the generated
374      * derivative of <CODE>SnmpMibEntry</CODE>.
375      * <p>
376      *
377      */

378     public void set(SnmpMibSubRequest req, int depth)
379     throws SnmpStatusException {
380
381     final boolean dbg = isDebugOn();
382     if (dbg) debug("set","Entering set.");
383
384     final SnmpOid oid = req.getEntryOid();
385     final int action = getRowAction(req,oid,depth+1);
386
387     if (dbg) debug("set","Calling set for " + req.getSize() +
388                "varbinds.");
389
390     set(req,oid,depth+1);
391
392     if (dbg) debug("set","Calling endRowAction");
393
394     endRowAction(req,oid,depth+1,action);
395
396     if (dbg) debug("set","RowAction finished");
397     }
398
399         
400     /**
401      * Add a new entry in this <CODE>SnmpMibTable</CODE>.
402      * Also triggers the addEntryCB() callback of the
403      * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
404      * if this node is bound to a factory.
405      *
406      * This method assumes that the given entry will not be registered.
407      * If the entry is going to be registered, or if ObjectName's are
408      * required, then
409      * {@link com.sun.jmx.snmp.agent.SnmpMibTable#addEntry(SnmpOid,
410      * ObjectName, Object)} should be prefered.
411      * <br> This function is mainly provided for backward compatibility.
412      *
413      * <p>
414      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
415      * row to be added.
416      * @param entry The entry to add.
417      *
418      * @exception SnmpStatusException The entry couldn't be added
419      * at the position identified by the given
420      * <code>rowOid</code>, or this version of the metadata
421      * requires ObjectName's.
422      */

423      // public void addEntry(SnmpIndex index, Object entry)
424
public void addEntry(SnmpOid rowOid, Object JavaDoc entry)
425     throws SnmpStatusException {
426       
427      addEntry(rowOid, null, entry);
428     }
429   
430     /**
431      * Add a new entry in this <CODE>SnmpMibTable</CODE>.
432      * Also triggers the addEntryCB() callback of the
433      * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
434      * if this node is bound to a factory.
435      *
436      * <p>
437      * @param oid The <CODE>SnmpOid</CODE> identifying the table
438      * row to be added.
439      *
440      * @param name The ObjectName with which this entry is registered.
441      * This parameter can be omitted if isRegistrationRequired()
442      * return false.
443      *
444      * @param entry The entry to add.
445      *
446      * @exception SnmpStatusException The entry couldn't be added
447      * at the position identified by the given
448      * <code>rowOid</code>, or if this version of the metadata
449      * requires ObjectName's, and the given name is null.
450      */

451     // protected synchronized void addEntry(SnmpIndex index, ObjectName name,
452
// Object entry)
453
public synchronized void addEntry(SnmpOid oid, ObjectName JavaDoc name,
454                       Object JavaDoc entry)
455     throws SnmpStatusException {
456         
457     if (isRegistrationRequired() == true && name == null)
458         throw new SnmpStatusException(SnmpStatusException.badValue);
459
460         if (size == 0) {
461         // indexes.addElement(index);
462
// XX oids.addElement(oid);
463
insertOid(0,oid);
464         if (entries != null)
465         entries.addElement(entry);
466         if (entrynames != null)
467         entrynames.addElement(name);
468             size++;
469         
470         // triggers callbacks on the entry factory
471
//
472
if (factory != null) {
473         try {
474             factory.addEntryCb(0,oid,name,entry,this);
475         } catch (SnmpStatusException x) {
476             removeOid(0);
477             if (entries != null)
478             entries.removeElementAt(0);
479             if (entrynames != null)
480             entrynames.removeElementAt(0);
481             throw x;
482         }
483         }
484
485         // sends the notifications
486
//
487
sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
488                  (new Date JavaDoc()).getTime(), entry, name);
489             return;
490         }
491     
492         // Get the insertion position ...
493
//
494
int pos= 0;
495         // bug jaw.00356.B : use oid rather than index to get the
496
// insertion point.
497
//
498
pos= getInsertionPoint(oid,true);
499         if (pos == size) {
500             // Add a new element in the vectors ...
501
//
502
// indexes.addElement(index);
503
// XX oids.addElement(oid);
504
insertOid(tablecount,oid);
505         if (entries != null)
506         entries.addElement(entry);
507         if (entrynames != null)
508         entrynames.addElement(name);
509             size++;
510         } else {
511             // Insert new element ...
512
//
513
try {
514         // indexes.insertElementAt(index, pos);
515
// XX oids.insertElementAt(oid, pos);
516
insertOid(pos,oid);
517         if (entries != null)
518             entries.insertElementAt(entry, pos);
519         if (entrynames != null)
520             entrynames.insertElementAt(name,pos);
521                 size++;
522             } catch(ArrayIndexOutOfBoundsException JavaDoc e) {
523             }
524         }
525
526     // triggers callbacks on the entry factory
527
//
528
if (factory != null) {
529         try {
530         factory.addEntryCb(pos,oid,name,entry,this);
531         } catch (SnmpStatusException x) {
532         removeOid(pos);
533         if (entries != null)
534             entries.removeElementAt(pos);
535         if (entrynames != null)
536             entrynames.removeElementAt(pos);
537         throw x;
538         }
539     }
540
541     // sends the notifications
542
//
543
sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
544              (new Date JavaDoc()).getTime(), entry, name);
545     }
546   
547     /**
548      * Remove the specified entry from the table.
549      * Also triggers the removeEntryCB() callback of the
550      * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
551      * if this node is bound to a factory.
552      *
553      * <p>
554      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
555      * row to remove.
556      *
557      * @param entry The entry to be removed. This parameter is not used
558      * internally, it is simply passed along to the
559      * removeEntryCB() callback.
560      *
561      * @exception SnmpStatusException if the specified entry couldn't
562      * be removed (if the given <code>rowOid</code> is not
563      * valid for instance).
564      */

565     public synchronized void removeEntry(SnmpOid rowOid, Object JavaDoc entry)
566     throws SnmpStatusException {
567         int pos = findObject(rowOid);
568         if (pos == -1)
569             return;
570     removeEntry(pos,entry);
571     }
572     
573     /**
574      * Remove the specified entry from the table.
575      * Also triggers the removeEntryCB() callback of the
576      * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
577      * if this node is bound to a factory.
578      *
579      * <p>
580      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
581      * row to remove.
582      *
583      * @exception SnmpStatusException if the specified entry couldn't
584      * be removed (if the given <code>rowOid</code> is not
585      * valid for instance).
586      */

587     public void removeEntry(SnmpOid rowOid)
588     throws SnmpStatusException {
589         int pos = findObject(rowOid);
590         if (pos == -1)
591             return;
592     removeEntry(pos,null);
593     }
594     
595     /**
596      * Remove the specified entry from the table.
597      * Also triggers the removeEntryCB() callback of the
598      * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
599      * if this node is bound to a factory.
600      *
601      * <p>
602      * @param pos The position of the entry in the table.
603      *
604      * @param entry The entry to be removed. This parameter is not used
605      * internally, it is simply passed along to the
606      * removeEntryCB() callback.
607      *
608      * @exception SnmpStatusException if the specified entry couldn't
609      * be removed.
610      */

611     public synchronized void removeEntry(int pos, Object JavaDoc entry)
612     throws SnmpStatusException {
613         if (pos == -1)
614             return;
615     if (pos >= size) return;
616
617     Object JavaDoc obj = entry;
618     if (entries != null && entries.size() > pos) {
619         obj = entries.elementAt(pos);
620         entries.removeElementAt(pos);
621     }
622
623     ObjectName JavaDoc name = null;
624     if (entrynames != null && entrynames.size() > pos) {
625         name = (ObjectName JavaDoc) entrynames.elementAt(pos);
626         entrynames.removeElementAt(pos);
627     }
628
629     final SnmpOid rowOid = tableoids[pos];
630     removeOid(pos);
631         size --;
632
633     if (obj == null) obj = entry;
634
635     if (factory != null)
636         factory.removeEntryCb(pos,rowOid,name,obj,this);
637
638         sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_REMOVED,
639              (new Date JavaDoc()).getTime(), obj, name);
640     }
641     
642     /**
643      * Get the entry corresponding to the specified rowOid.
644      *
645      * <p>
646      * @param rowOid The <CODE>SnmpOid</CODE> identifying the
647      * row to be retrieved.
648      *
649      * @return The entry.
650      *
651      * @exception SnmpStatusException There is no entry with the specified
652      * <code>rowOid</code> in the table.
653      */

654     public synchronized Object JavaDoc getEntry(SnmpOid rowOid)
655     throws SnmpStatusException {
656         int pos= findObject(rowOid);
657         if (pos == -1)
658             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
659         return entries.elementAt(pos);
660     }
661       
662     /**
663      * Get the ObjectName of the entry corresponding to the
664      * specified rowOid.
665      * The result of this method is only meaningful if
666      * isRegistrationRequired() yields true.
667      *
668      * <p>
669      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
670      * row whose ObjectName we want to retrieve.
671      *
672      * @return The object name of the entry.
673      *
674      * @exception SnmpStatusException There is no entry with the specified
675      * <code>rowOid</code> in the table.
676      */

677     public synchronized ObjectName JavaDoc getEntryName(SnmpOid rowOid)
678     throws SnmpStatusException {
679         int pos = findObject(rowOid);
680     if (entrynames == null) return null;
681         if (pos == -1 || pos >= entrynames.size())
682             throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
683         return (ObjectName JavaDoc) entrynames.elementAt(pos);
684     }
685       
686     /**
687      * Return the entries stored in this table <CODE>SnmpMibTable</CODE>.
688      * <p>
689      * If the subclass generated by mibgen uses the generic way to access
690      * the entries (i.e. if it goes through the MBeanServer) then some of
691      * the entries may be <code>null</code>. It all depends whether a non
692      * <code>null</code> entry was passed to addEntry().<br>
693      * Otherwise, if it uses the standard way (access the entry directly
694      * through their standard MBean interface) this array will contain all
695      * the entries.
696      * <p>
697      * @return The entries array.
698      */

699     public Object JavaDoc[] getBasicEntries() {
700         Object JavaDoc[] array= new Object JavaDoc[size];
701         entries.copyInto(array);
702         return array;
703     }
704   
705     /**
706      * Get the size of the table.
707      *
708      * @return The number of entries currently registered in this table.
709      */

710     public int getSize() {
711         return size;
712     }
713     
714     // EVENT STUFF
715
//------------
716

717     /**
718      * Enable to add an SNMP entry listener to this
719      * <CODE>SnmpMibTable</CODE>.
720      *
721      * <p>
722      * @param listener The listener object which will handle the
723      * notifications emitted by the registered MBean.
724      *
725      * @param filter The filter object. If filter is null, no filtering
726      * will be performed before handling notifications.
727      *
728      * @param handback The context to be sent to the listener when a
729      * notification is emitted.
730      *
731      * @exception IllegalArgumentException Listener parameter is null.
732      */

733     public synchronized void
734     addNotificationListener(NotificationListener JavaDoc listener,
735                 NotificationFilter JavaDoc filter, Object JavaDoc handback) {
736
737         // Check listener
738
//
739
if (listener == null) {
740             throw new java.lang.IllegalArgumentException JavaDoc
741         ("Listener can't be null") ;
742         }
743
744         // looking for listener in handbackTable
745
//
746
java.util.Vector JavaDoc handbackList =
747         (java.util.Vector JavaDoc) handbackTable.get(listener) ;
748         java.util.Vector JavaDoc filterList =
749         (java.util.Vector JavaDoc) filterTable.get(listener) ;
750         if ( handbackList == null ) {
751             handbackList = new java.util.Vector JavaDoc() ;
752             filterList = new java.util.Vector JavaDoc() ;
753             handbackTable.put(listener, handbackList) ;
754             filterTable.put(listener, filterList) ;
755         }
756
757         // Add the handback and the filter
758
//
759
handbackList.addElement(handback) ;
760         filterList.addElement(filter) ;
761     }
762     
763     /**
764      * Enable to remove an SNMP entry listener from this
765      * <CODE>SnmpMibTable</CODE>.
766      *
767      * @param listener The listener object which will handle the
768      * notifications emitted by the registered MBean.
769      * This method will remove all the information related to this
770      * listener.
771      *
772      * @exception ListenerNotFoundException The listener is not registered
773      * in the MBean.
774      */

775     public synchronized void
776     removeNotificationListener(NotificationListener JavaDoc listener)
777     throws ListenerNotFoundException JavaDoc {
778
779         // looking for listener in handbackTable
780
//
781
java.util.Vector JavaDoc handbackList =
782         (java.util.Vector JavaDoc) handbackTable.get(listener) ;
783         java.util.Vector JavaDoc filterList =
784         (java.util.Vector JavaDoc) filterTable.get(listener) ;
785         if ( handbackList == null ) {
786             throw new ListenerNotFoundException JavaDoc("listener");
787         }
788
789         // If handback is null, remove the listener entry
790
//
791
handbackTable.remove(listener) ;
792         filterTable.remove(listener) ;
793     }
794     
795     /**
796      * Return a <CODE>NotificationInfo</CODE> object containing the
797      * notification class and the notification type sent by the
798      * <CODE>SnmpMibTable</CODE>.
799      */

800     public MBeanNotificationInfo JavaDoc[] getNotificationInfo() {
801         
802         String JavaDoc[] types = {SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
803                           SnmpTableEntryNotification.SNMP_ENTRY_REMOVED};
804         
805         MBeanNotificationInfo JavaDoc[] notifsInfo = {
806         new MBeanNotificationInfo JavaDoc
807         (types, "com.sun.jmx.snmp.agent.SnmpTableEntryNotification",
808          "Notifications sent by the SnmpMibTable")
809     };
810     
811         return notifsInfo;
812     }
813     
814
815     /**
816      * Register the factory through which table entries should
817      * be created when remote entry creation is enabled.
818      *
819      * <p>
820      * @param factory The
821      * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} through
822      * which entries will be created when a remote SNMP manager
823      * request the creation of a new entry via an SNMP SET request.
824      */

825     public void registerEntryFactory(SnmpTableEntryFactory factory) {
826     this.factory = factory;
827     }
828
829     // ----------------------------------------------------------------------
830
// PROTECTED METHODS - RowStatus
831
// ----------------------------------------------------------------------
832

833     /**
834      * Return true if the columnar object identified by <code>var</code>
835      * is used to control the addition/deletion of rows in this table.
836      *
837      * <p>
838      * By default, this method assumes that there is no control variable
839      * and always return <code>false</code>
840      * <p>
841      * If this table was defined using SMIv2, and if it contains a
842      * control variable with RowStatus syntax, <code>mibgen</code>
843      * will generate a non default implementation for this method
844      * that will identify the RowStatus control variable.
845      * <p>
846      * You will have to redefine this method if you need to implement
847      * control variables that do not conform to RFC 2579 RowStatus
848      * TEXTUAL-CONVENTION.
849      * <p>
850      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
851      * row involved in the operation.
852      *
853      * @param var The OID arc identifying the involved columnar object.
854      *
855      * @param userData A contextual object containing user-data.
856      * This object is allocated through the <code>
857      * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
858      * for each incoming SNMP request.
859      *
860      **/

861     protected boolean isRowStatus(SnmpOid rowOid, long var,
862                     Object JavaDoc userData) {
863     return false;
864     }
865
866
867     /**
868      * Return the RowStatus code value specified in this request.
869      * <p>
870      * The RowStatus code value should be one of the values defined
871      * by {@link com.sun.jmx.snmp.EnumRowStatus}. These codes correspond
872      * to RowStatus codes as defined in RFC 2579, plus the <i>unspecified</i>
873      * value which is SNMP Runtime specific.
874      * <p>
875      *
876      * @param req The sub-request that must be handled by this node.
877      *
878      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
879      * row involved in the operation.
880      *
881      * @param depth The depth reached in the OID tree.
882      *
883      * @return The RowStatus code specified in this request, if any:
884      * <ul>
885      * <li>If the specified row does not exist and this table do
886      * not use any variable to control creation/deletion of
887      * rows, then default creation mechanism is assumed and
888      * <i>createAndGo</i> is returned</li>
889      * <li>Otherwise, if the row exists and this table do not use any
890      * variable to control creation/deletion of rows,
891      * <i>unspecified</i> is returned.</li>
892      * <li>Otherwise, if the request does not contain the control variable,
893      * <i>unspecified</i> is returned.</li>
894      * <li>Otherwise, mapRowStatus() is called to extract the RowStatus
895      * code from the SnmpVarBind that contains the control variable.</li>
896      * </ul>
897      *
898      * @exception SnmpStatusException if the value of the control variable
899      * could not be mapped to a RowStatus code.
900      *
901      * @see com.sun.jmx.snmp.EnumRowStatus
902      **/

903     protected int getRowAction(SnmpMibSubRequest req, SnmpOid rowOid,
904                    int depth)
905     throws SnmpStatusException {
906     final boolean isnew = req.isNewEntry();
907     final SnmpVarBind vb = req.getRowStatusVarBind();
908     if (vb == null) {
909         if (isnew && ! hasRowStatus())
910         return EnumRowStatus.createAndGo;
911         else return EnumRowStatus.unspecified;
912     }
913
914     try {
915         return mapRowStatus(rowOid, vb, req.getUserData());
916     } catch( SnmpStatusException x) {
917         checkRowStatusFail(req, x.getStatus());
918     }
919     return EnumRowStatus.unspecified;
920     }
921
922     /**
923      * Map the value of the <code>vbstatus</code> varbind to the
924      * corresponding RowStatus code defined in
925      * {@link com.sun.jmx.snmp.EnumRowStatus}.
926      * These codes correspond to RowStatus codes as defined in RFC 2579,
927      * plus the <i>unspecified</i> value which is SNMP Runtime specific.
928      * <p>
929      * By default, this method assumes that the control variable is
930      * an Integer, and it simply returns its value without further
931      * analysis.
932      * <p>
933      * If this table was defined using SMIv2, and if it contains a
934      * control variable with RowStatus syntax, <code>mibgen</code>
935      * will generate a non default implementation for this method.
936      * <p>
937      * You will have to redefine this method if you need to implement
938      * control variables that do not conform to RFC 2579 RowStatus
939      * TEXTUAL-CONVENTION.
940      *
941      * <p>
942      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
943      * row involved in the operation.
944      *
945      * @param vbstatus The SnmpVarBind containing the value of the control
946      * variable, as identified by the isRowStatus() method.
947      *
948      * @param userData A contextual object containing user-data.
949      * This object is allocated through the <code>
950      * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
951      * for each incoming SNMP request.
952      *
953      * @return The RowStatus code mapped from the value contained
954      * in <code>vbstatus</code>.
955      *
956      * @exception SnmpStatusException if the value of the control variable
957      * could not be mapped to a RowStatus code.
958      *
959      * @see com.sun.jmx.snmp.EnumRowStatus
960      **/

961     protected int mapRowStatus(SnmpOid rowOid, SnmpVarBind vbstatus,
962                    Object JavaDoc userData)
963     throws SnmpStatusException {
964     final SnmpValue rsvalue = vbstatus.value;
965     
966     if (rsvalue instanceof SnmpInt)
967         return ((SnmpInt)rsvalue).intValue();
968     else
969         throw new SnmpStatusException(
970                SnmpStatusException.snmpRspInconsistentValue);
971     }
972
973     /**
974      * Set the control variable to the specified <code>newStatus</code>
975      * value.
976      *
977      * <p>
978      * This method maps the given <code>newStatus</code> to the appropriate
979      * value for the control variable, then sets the control variable in
980      * the entry identified by <code>rowOid</code>. It returns the new
981      * value of the control variable.
982      * <p>
983      * By default, it is assumed that there is no control variable so this
984      * method does nothing and simply returns <code>null</code>.
985      * <p>
986      * If this table was defined using SMIv2, and if it contains a
987      * control variable with RowStatus syntax, <code>mibgen</code>
988      * will generate a non default implementation for this method.
989      * <p>
990      * You will have to redefine this method if you need to implement
991      * control variables that do not conform to RFC 2579 RowStatus
992      * TEXTUAL-CONVENTION.
993      *
994      * <p>
995      * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
996      * row involved in the operation.
997      *
998      * @param newStatus The new status for the row: one of the
999      * RowStatus code defined in
1000     * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
1001     * correspond to RowStatus codes as defined in RFC 2579,
1002     * plus the <i>unspecified</i> value which is SNMP Runtime specific.
1003     *
1004     * @param userData A contextual object containing user-data.
1005     * This object is allocated through the <code>
1006     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1007     * for each incoming SNMP request.
1008     *
1009     * @return The new value of the control variable (usually
1010     * <code>new SnmpInt(newStatus)</code>) or <code>null</code>
1011     * if the table do not have any control variable.
1012     *
1013     * @exception SnmpStatusException If the given <code>newStatus</code>
1014     * could not be set on the specified entry, or if the
1015     * given <code>newStatus</code> is not valid.
1016     *
1017     * @see com.sun.jmx.snmp.EnumRowStatus
1018     **/

1019    protected SnmpValue setRowStatus(SnmpOid rowOid, int newStatus,
1020                     Object JavaDoc userData)
1021    throws SnmpStatusException {
1022    return null;
1023    }
1024
1025    /**
1026     * Tell whether the specified row is ready and can be put in the
1027     * <i>notInService</i> state.
1028     * <p>
1029     * This method is called only once, after all the varbind have been
1030     * set on a new entry for which <i>createAndWait</i> was specified.
1031     * <p>
1032     * If the entry is not yet ready, this method should return false.
1033     * It will then be the responsibility of the entry to switch its
1034     * own state to <i>notInService</i> when it becomes ready.
1035     * No further call to <code>isRowReady()</code> will be made.
1036     * <p>
1037     * By default, this method always return true. <br>
1038     * <code>mibgen</code> will not generate any specific implementation
1039     * for this method - meaning that by default, a row created using
1040     * <i>createAndWait</i> will always be placed in <i>notInService</i>
1041     * state at the end of the request.
1042     * <p>
1043     * If this table was defined using SMIv2, and if it contains a
1044     * control variable with RowStatus syntax, <code>mibgen</code>
1045     * will generate an implementation for this method that will
1046     * delegate the work to the metadata class modelling the conceptual
1047     * row, so that you can override the default behaviour by subclassing
1048     * that metadata class.
1049     * <p>
1050     * You will have to redefine this method if this default mechanism
1051     * does not suit your needs.
1052     *
1053     * <p>
1054     * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
1055     * row involved in the operation.
1056     *
1057     * @param userData A contextual object containing user-data.
1058     * This object is allocated through the <code>
1059     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1060     * for each incoming SNMP request.
1061     *
1062     * @return <code>true</code> if the row can be placed in
1063     * <i>notInService</i> state.
1064     *
1065     * @exception SnmpStatusException An error occured while trying
1066     * to retrieve the row status, and the operation should
1067     * be aborted.
1068     *
1069     * @see com.sun.jmx.snmp.EnumRowStatus
1070     **/

1071    protected boolean isRowReady(SnmpOid rowOid, Object JavaDoc userData)
1072    throws SnmpStatusException {
1073    return true;
1074    }
1075
1076    /**
1077     * Check whether the control variable of the given row can be
1078     * switched to the new specified <code>newStatus</code>.
1079     * <p>
1080     * This method is called during the <i>check</i> phase of a SET
1081     * request when the control variable specifies <i>active</i> or
1082     * <i>notInService</i>.
1083     * <p>
1084     * By default it is assumed that nothing prevents putting the
1085     * row in the requested state, and this method does nothing.
1086     * It is simply provided as a hook so that specific checks can
1087     * be implemented.
1088     * <p>
1089     * Note that if the actual row deletion fails afterward, the
1090     * atomicity of the request is no longer guaranteed.
1091     *
1092     * <p>
1093     * @param req The sub-request that must be handled by this node.
1094     *
1095     * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
1096     * row involved in the operation.
1097     *
1098     * @param depth The depth reached in the OID tree.
1099     *
1100     * @param newStatus The new status for the row: one of the
1101     * RowStatus code defined in
1102     * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
1103     * correspond to RowStatus codes as defined in RFC 2579,
1104     * plus the <i>unspecified</i> value which is SNMP Runtime specific.
1105     *
1106     * @exception SnmpStatusException if switching to this new state
1107     * would fail.
1108     *
1109     **/

1110    protected void checkRowStatusChange(SnmpMibSubRequest req,
1111                    SnmpOid rowOid, int depth,
1112                    int newStatus)
1113    throws SnmpStatusException {
1114
1115    }
1116
1117    /**
1118     * Check whether the specified row can be removed from the table.
1119     * <p>
1120     * This method is called during the <i>check</i> phase of a SET
1121     * request when the control variable specifies <i>destroy</i>
1122     * <p>
1123     * By default it is assumed that nothing prevents row deletion
1124     * and this method does nothing. It is simply provided as a hook
1125     * so that specific checks can be implemented.
1126     * <p>
1127     * Note that if the actual row deletion fails afterward, the
1128     * atomicity of the request is no longer guaranteed.
1129     *
1130     * <p>
1131     * @param req The sub-request that must be handled by this node.
1132     *
1133     * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
1134     * row involved in the operation.
1135     *
1136     * @param depth The depth reached in the OID tree.
1137     *
1138     * @exception SnmpStatusException if the row deletion must be
1139     * rejected.
1140     **/

1141    protected void checkRemoveTableRow(SnmpMibSubRequest req, SnmpOid rowOid,
1142                       int depth)
1143    throws SnmpStatusException {
1144
1145    }
1146
1147    /**
1148     * Remove a table row upon a remote manager request.
1149     *
1150     * This method is called internally when <code>getRowAction()</code>
1151     * yields <i>destroy</i> - i.e.: it is only called when a remote
1152     * manager requests the removal of a table row.<br>
1153     * You should never need to call this function directly.
1154     * <p>
1155     * By default, this method simply calls <code>removeEntry(rowOid)
1156     * </code>.
1157     * <p>
1158     * You can redefine this method if you need to implement some
1159     * specific behaviour when a remote row deletion is invoked.
1160     * <p>
1161     * Note that specific checks should not be implemented in this
1162     * method, but rather in <code>checkRemoveTableRow()</code>.
1163     * If <code>checkRemoveTableRow()</code> succeeds and this method
1164     * fails afterward, the atomicity of the original SET request can no
1165     * longer be guaranteed.
1166     * <p>
1167     *
1168     * @param req The sub-request that must be handled by this node.
1169     *
1170     * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
1171     * row involved in the operation.
1172     *
1173     * @param depth The depth reached in the OID tree.
1174     *
1175     * @exception SnmpStatusException if the actual row deletion fails.
1176     * This should not happen since it would break the
1177     * atomicity of the SET request. Specific checks should
1178     * be implemented in <code>checkRemoveTableRow()</code>
1179     * if needed. If the entry does not exists, no exception
1180     * is generated and the method simply returns.
1181     *
1182     **/

1183    protected void removeTableRow(SnmpMibSubRequest req, SnmpOid rowOid,
1184                  int depth)
1185    throws SnmpStatusException {
1186    
1187    removeEntry(rowOid);
1188    }
1189    
1190    /**
1191     * This method takes care of initial RowStatus handling during the
1192     * check() phase of a SET request.
1193     *
1194     * In particular it will:
1195     * <ul><li>check that the given <code>rowAction</code> returned by
1196     * <code>getRowAction()</code> is valid.</li>
1197     * <li>Then depending on the <code>rowAction</code> specified it will:
1198     * <ul><li>either call <code>createNewEntry()</code> (<code>
1199     * rowAction = <i>createAndGo</i> or <i>createAndWait</i>
1200     * </code>),</li>
1201     * <li>or call <code>checkRemoveTableRow()</code> (<code>
1202     * rowAction = <i>destroy</i></code>),</li>
1203     * <li>or call <code>checkRowStatusChange()</code> (<code>
1204     * rowAction = <i>active</i> or <i>notInService</i></code>),</li>
1205     * <li>or generate a SnmpStatusException if the passed <code>
1206     * rowAction</code> is not correct.</li>
1207     * </ul></li></ul>
1208     * <p>
1209     * In principle, you should not need to redefine this method.
1210     * <p>
1211     * <code>beginRowAction()</code> is called during the check phase
1212     * of a SET request, before actual checking on the varbind list
1213     * is performed.
1214     *
1215     * <p>
1216     * @param req The sub-request that must be handled by this node.
1217     *
1218     * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
1219     * row involved in the operation.
1220     *
1221     * @param depth The depth reached in the OID tree.
1222     *
1223     * @param rowAction The requested action as returned by <code>
1224     * getRowAction()</code>: one of the RowStatus codes defined in
1225     * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
1226     * correspond to RowStatus codes as defined in RFC 2579,
1227     * plus the <i>unspecified</i> value which is SNMP Runtime specific.
1228     *
1229     * @exception SnmpStatusException if the specified <code>rowAction</code>
1230     * is not valid or cannot be executed.
1231     * This should not happen since it would break the
1232     * atomicity of the SET request. Specific checks should
1233     * be implemented in <code>beginRowAction()</code> if needed.
1234     *
1235     * @see com.sun.jmx.snmp.EnumRowStatus
1236     **/

1237    protected synchronized void beginRowAction(SnmpMibSubRequest req,
1238                  SnmpOid rowOid, int depth, int rowAction)
1239    throws SnmpStatusException {
1240    final boolean isnew = req.isNewEntry();
1241    final SnmpOid oid = rowOid;
1242    final int action = rowAction;
1243    
1244    switch (action) {
1245    case EnumRowStatus.unspecified:
1246        if (isnew) {
1247        if (isDebugOn())
1248            debug("beginRowAction","Failed to create row[" + rowOid +
1249              "] : RowStatus = unspecified");
1250        checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess);
1251        }
1252        break;
1253    case EnumRowStatus.createAndGo:
1254    case EnumRowStatus.createAndWait:
1255            if (isnew) {
1256        if (isCreationEnabled()) {
1257            if (isDebugOn())
1258            debug("beginRowAction","Creating row[" + rowOid +
1259                  "] : RowStatus = createAndGo | createAndWait");
1260            createNewEntry(req,oid,depth);
1261        } else {
1262            if (isDebugOn())
1263            debug("beginRowAction","Can't create row[" + rowOid +
1264                  "] : RowStatus = createAndGo | createAndWait" +
1265                  " but creation is disabled");
1266            checkRowStatusFail(req,
1267                       SnmpStatusException.snmpRspNoAccess);
1268        }
1269        } else {
1270        if (isDebugOn())
1271            debug("beginRowAction","Can't create row[" + rowOid +
1272              "] : RowStatus = createAndGo | createAndWait" +
1273              " but row already exists");
1274        checkRowStatusFail(req,
1275                       SnmpStatusException.snmpRspInconsistentValue);
1276        }
1277        break;
1278    case EnumRowStatus.destroy:
1279        if (isnew) {
1280        if (isDebugOn())
1281            debug("beginRowAction","Warning: can't destroy row[" +
1282              rowOid + "] : RowStatus = destroy" +
1283              " but row does not exist");
1284        } else if (!isCreationEnabled()) {
1285        if (isDebugOn())
1286            debug("beginRowAction","Can't destroy row[" + rowOid +
1287              "] : RowStatus = destroy " +
1288              " but creation is disabled");
1289        checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess);
1290        }
1291        checkRemoveTableRow(req,rowOid,depth);
1292        break;
1293    case EnumRowStatus.active:
1294    case EnumRowStatus.notInService:
1295        if (isnew) {
1296        if (isDebugOn())
1297            debug("beginRowAction","Can't switch state of row[" +
1298              rowOid +
1299              "] : specified RowStatus = active | notInService" +
1300              " but row does not exist");
1301        checkRowStatusFail(req,
1302                SnmpStatusException.snmpRspInconsistentValue);
1303        }
1304        checkRowStatusChange(req,rowOid,depth,action);
1305        break;
1306    case EnumRowStatus.notReady:
1307    default:
1308        if (isDebugOn())
1309        debug("beginRowAction","Invalid RowStatus value for row[" +
1310              rowOid + "] : specified RowStatus = " + action);
1311        checkRowStatusFail(req,
1312            SnmpStatusException.snmpRspInconsistentValue);
1313    }
1314    }
1315
1316    /**
1317     * This method takes care of final RowStatus handling during the
1318     * set() phase of a SET request.
1319     *
1320     * In particular it will:
1321     * <ul><li>either call <code>setRowStatus(<i>active</i>)</code>
1322     * (<code> rowAction = <i>createAndGo</i> or <i>active</i>
1323     * </code>),</li>
1324     * <li>or call <code>setRowStatus(<i>notInService</i> or <i>
1325     * notReady</i>)</code> depending on the result of <code>
1326     * isRowReady()</i> (<code>rowAction = <i>createAndWait</i>
1327     * </code>),</li>
1328     * <li>or call <code>setRowStatus(<i>notInService</i>)</code>
1329     * (<code> rowAction = <i>notInService</i></code>),
1330     * <li>or call <code>removeTableRow()</code> (<code>
1331     * rowAction = <i>destroy</i></code>),</li>
1332     * <li>or generate a SnmpStatusException if the passed <code>
1333     * rowAction</code> is not correct. This should be avoided
1334     * since it would break SET request atomicity</li>
1335     * </ul>
1336     * <p>
1337     * In principle, you should not need to redefine this method.
1338     * <p>
1339     * <code>endRowAction()</code> is called during the set() phase
1340     * of a SET request, after the actual set() on the varbind list
1341     * has been performed. The varbind containing the control variable
1342     * is updated with the value returned by setRowStatus() (if it is
1343     * not <code>null</code>).
1344     *
1345     * <p>
1346     * @param req The sub-request that must be handled by this node.
1347     *
1348     * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
1349     * row involved in the operation.
1350     *
1351     * @param depth The depth reached in the OID tree.
1352     *
1353     * @param rowAction The requested action as returned by <code>
1354     * getRowAction()</code>: one of the RowStatus codes defined in
1355     * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
1356     * correspond to RowStatus codes as defined in RFC 2579,
1357     * plus the <i>unspecified</i> value which is SNMP Runtime specific.
1358     *
1359     * @exception SnmpStatusException if the specified <code>rowAction</code>
1360     * is not valid.
1361     *
1362     * @see com.sun.jmx.snmp.EnumRowStatus
1363     **/

1364    protected void endRowAction(SnmpMibSubRequest req, SnmpOid rowOid,
1365                   int depth, int rowAction)
1366    throws SnmpStatusException {
1367    final boolean isnew = req.isNewEntry();
1368    final SnmpOid oid = rowOid;
1369    final int action = rowAction;
1370    final Object JavaDoc data = req.getUserData();
1371    SnmpValue value = null;
1372
1373    switch (action) {
1374    case EnumRowStatus.unspecified:
1375        break;
1376    case EnumRowStatus.createAndGo:
1377        if (isDebugOn())
1378        debug("endRowAction","Setting RowStatus to `active'" +
1379              " for row[" + rowOid + "] : requested RowStatus = "
1380              + "createAndGo");
1381        value = setRowStatus(oid,EnumRowStatus.active,data);
1382        break;
1383    case EnumRowStatus.createAndWait:
1384        if (isRowReady(oid,data)) {
1385        if (isDebugOn())
1386            debug("endRowAction",
1387              "Setting RowStatus to `notInService'" +
1388              " for row[" + rowOid + "] : requested RowStatus = "
1389              + "createAndWait");
1390        value = setRowStatus(oid,EnumRowStatus.notInService,data);
1391        } else {
1392        if (isDebugOn())
1393            debug("endRowAction",
1394              "Setting RowStatus to `notReady'" +
1395              " for row[" + rowOid + "] : requested RowStatus = "
1396              + "createAndWait");
1397        value = setRowStatus(oid,EnumRowStatus.notReady,data);
1398        }
1399        break;
1400    case EnumRowStatus.destroy:
1401        if (isnew) {
1402        if (isDebugOn())
1403            debug("endRowAction",
1404              "Warning: " + " requested RowStatus = destroy," +
1405              "but row[" + rowOid + "] does not exist.");
1406        } else {
1407        if (isDebugOn())
1408            debug("endRowAction",
1409              "destroying row[" + rowOid +
1410              "] : requested RowStatus = destroy");
1411        }
1412        removeTableRow(req,oid,depth);
1413        break;
1414    case EnumRowStatus.active:
1415         if (isDebugOn())
1416        debug("endRowAction",
1417              "Setting RowStatus to `active'" +
1418              " for row[" + rowOid + "] : requested RowStatus = "
1419              + "active");
1420        value = setRowStatus(oid,EnumRowStatus.active,data);
1421        break;
1422    case EnumRowStatus.notInService:
1423         if (isDebugOn())
1424        debug("endRowAction",
1425              "Setting RowStatus to `notInService'" +
1426              " for row[" + rowOid + "] : requested RowStatus = "
1427              + "notInService");
1428        value = setRowStatus(oid,EnumRowStatus.notInService,data);
1429        break;
1430    case EnumRowStatus.notReady:
1431    default:
1432        if (isDebugOn())
1433        debug("endRowAction","Invalid RowStatus value for row[" +
1434              rowOid + "] : specified RowStatus = " + action);
1435        setRowStatusFail(req,
1436              SnmpStatusException.snmpRspInconsistentValue);
1437    }
1438    if (value != null) {
1439        final SnmpVarBind vb = req.getRowStatusVarBind();
1440        if (vb != null) vb.value = value;
1441    }
1442    }
1443
1444    // -------------------------------------------------------------------
1445
// PROTECTED METHODS - get next
1446
// -------------------------------------------------------------------
1447

1448    /**
1449     * Return the next OID arc corresponding to a readable columnar
1450     * object in the underlying entry OBJECT-TYPE, possibly skipping over
1451     * those objects that must not or cannot be returned.
1452     * Calls {@link
1453     * #getNextVarEntryId(com.sun.jmx.snmp.SnmpOid,long,java.lang.Object)},
1454     * until
1455     * {@link #skipEntryVariable(com.sun.jmx.snmp.SnmpOid,long,
1456     * java.lang.Object,int)} returns false.
1457     *
1458     *
1459     * @param rowOid The OID index of the row involved in the operation.
1460     *
1461     * @param var Id of the variable we start from, looking for the next.
1462     *
1463     * @param userData A contextual object containing user-data.
1464     * This object is allocated through the <code>
1465     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1466     * for each incoming SNMP request.
1467     *
1468     * @param pduVersion Protocol version of the original request PDU.
1469     *
1470     * @return The next columnar object id which can be returned using
1471     * the given PDU's protocol version.
1472     *
1473     * @exception SnmpStatusException If no id is found after the given id.
1474     *
1475     **/

1476    protected long getNextVarEntryId(SnmpOid rowOid,
1477                     long var,
1478                     Object JavaDoc userData,
1479                     int pduVersion)
1480    throws SnmpStatusException {
1481    
1482    long varid=var;
1483    do {
1484        varid = getNextVarEntryId(rowOid,varid,userData);
1485    } while (skipEntryVariable(rowOid,varid,userData,pduVersion));
1486
1487    return varid;
1488    }
1489
1490    /**
1491     * Hook for subclasses.
1492     * The default implementation of this method is to always return
1493     * false. Subclasses should redefine this method so that it returns
1494     * true when:
1495     * <ul><li>the variable is a leaf that is not instantiated,</li>
1496     * <li>or the variable is a leaf whose type cannot be returned by that
1497     * version of the protocol (e.g. an Counter64 with SNMPv1).</li>
1498     * </ul>
1499     *
1500     * @param rowOid The OID index of the row involved in the operation.
1501     *
1502     * @param var Id of the variable we start from, looking for the next.
1503     *
1504     * @param userData A contextual object containing user-data.
1505     * This object is allocated through the <code>
1506     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1507     * for each incoming SNMP request.
1508     *
1509     * @param pduVersion Protocol version of the original request PDU.
1510     *
1511     * @return true if the variable must be skipped by the get-next
1512     * algorithm.
1513     */

1514    protected boolean skipEntryVariable(SnmpOid rowOid,
1515                    long var,
1516                    Object JavaDoc userData,
1517                    int pduVersion) {
1518    return false;
1519    }
1520
1521    /**
1522     * Get the <CODE>SnmpOid</CODE> index of the row that follows
1523     * the given <CODE>oid</CODE> in the table. The given <CODE>
1524     * oid</CODE> does not need to be a valid row OID index.
1525     *
1526     * <p>
1527     * @param oid The OID from which the search will begin.
1528     *
1529     * @param userData A contextual object containing user-data.
1530     * This object is allocated through the <code>
1531     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1532     * for each incoming SNMP request.
1533     *
1534     * @return The next <CODE>SnmpOid</CODE> index.
1535     *
1536     * @exception SnmpStatusException There is no index following the
1537     * specified <CODE>oid</CODE> in the table.
1538     */

1539    protected SnmpOid getNextOid(SnmpOid oid, Object JavaDoc userData)
1540    throws SnmpStatusException {
1541    
1542        if (size == 0)
1543            throw noSuchInstanceException;
1544        
1545        final SnmpOid resOid = oid;
1546            
1547        // Just a simple check to speed up retrieval of last element ...
1548
//
1549
// XX SnmpOid last= (SnmpOid) oids.lastElement();
1550
SnmpOid last= tableoids[tablecount-1];
1551        if (last.equals(resOid)) {
1552            // Last element of the table ...
1553
//
1554
throw noSuchInstanceException;
1555        }
1556        
1557        // First find the oid. This will allow to speed up retrieval process
1558
// during smart discovery of table (using the getNext) as the
1559
// management station will use the valid index returned during a
1560
// previous getNext ...
1561
//
1562

1563    // Returns the position following the position at which resOid
1564
// is found, or the position at which resOid should be inserted.
1565
//
1566
final int newPos = getInsertionPoint(resOid,false);
1567
1568    // If the position returned is not out of bound, we will find
1569
// the next element in the array.
1570
//
1571
if (newPos > -1 && newPos < size) {
1572            try {
1573        // XX last = (SnmpOid) oids.elementAt(newPos);
1574
last = tableoids[newPos];
1575            } catch(ArrayIndexOutOfBoundsException JavaDoc e) {
1576                throw noSuchInstanceException;
1577            }
1578    } else {
1579        // We are dealing with the last element of the table ..
1580
//
1581
throw noSuchInstanceException;
1582    }
1583
1584            
1585        return last;
1586    }
1587
1588    /**
1589     * Return the first entry OID registered in the table.
1590     *
1591     * <p>
1592     * @param userData A contextual object containing user-data.
1593     * This object is allocated through the <code>
1594     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1595     * for each incoming SNMP request.
1596     *
1597     * @return The <CODE>SnmpOid</CODE> of the first entry in the table.
1598     *
1599     * @exception SnmpStatusException If the table is empty.
1600     */

1601    protected SnmpOid getNextOid(Object JavaDoc userData)
1602    throws SnmpStatusException {
1603        if (size == 0)
1604            throw noSuchInstanceException;
1605    // XX return (SnmpOid) oids.firstElement();
1606
return tableoids[0];
1607    }
1608    
1609    // -------------------------------------------------------------------
1610
// Abstract Protected Methods
1611
// -------------------------------------------------------------------
1612

1613    /**
1614     * This method is used internally and is implemented by the
1615     * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
1616     *
1617     * <p> Return the next OID arc corresponding to a readable columnar
1618     * object in the underlying entry OBJECT-TYPE.</p>
1619     *
1620     * <p>
1621     * @param rowOid The OID index of the row involved in the operation.
1622     *
1623     * @param var Id of the variable we start from, looking for the next.
1624     *
1625     * @param userData A contextual object containing user-data.
1626     * This object is allocated through the <code>
1627     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1628     * for each incoming SNMP request.
1629     *
1630     * @return The next columnar object id.
1631     *
1632     * @exception SnmpStatusException If no id is found after the given id.
1633     *
1634     **/

1635    abstract protected long getNextVarEntryId(SnmpOid rowOid, long var,
1636                          Object JavaDoc userData)
1637    throws SnmpStatusException;
1638
1639    /**
1640     * This method is used internally and is implemented by the
1641     * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
1642     *
1643     * <p>
1644     * @param rowOid The OID index of the row involved in the operation.
1645     *
1646     * @param var The var we want to validate.
1647     *
1648     * @param userData A contextual object containing user-data.
1649     * This object is allocated through the <code>
1650     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1651     * for each incoming SNMP request.
1652     *
1653     * @exception SnmpStatusException If this id is not valid.
1654     *
1655     */

1656    abstract protected void validateVarEntryId(SnmpOid rowOid, long var,
1657                           Object JavaDoc userData)
1658    throws SnmpStatusException;
1659
1660    /**
1661     *
1662     * This method is used internally and is implemented by the
1663     * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
1664     *
1665     * <p>
1666     * @param rowOid The OID index of the row involved in the operation.
1667     *
1668     * @param var The OID arc.
1669     *
1670     * @param userData A contextual object containing user-data.
1671     * This object is allocated through the <code>
1672     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1673     * for each incoming SNMP request.
1674     *
1675     * @exception SnmpStatusException If this id is not valid.
1676     *
1677     */

1678    abstract protected boolean isReadableEntryId(SnmpOid rowOid, long var,
1679                         Object JavaDoc userData)
1680    throws SnmpStatusException;
1681
1682    /**
1683     * This method is used internally and is implemented by the
1684     * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
1685     */

1686    abstract protected void get(SnmpMibSubRequest req,
1687                SnmpOid rowOid, int depth)
1688    throws SnmpStatusException;
1689    
1690    /**
1691     * This method is used internally and is implemented by the
1692     * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
1693     */

1694    abstract protected void check(SnmpMibSubRequest req,
1695                  SnmpOid rowOid, int depth)
1696    throws SnmpStatusException;
1697    
1698    /**
1699     * This method is used internally and is implemented by the
1700     * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
1701     */

1702    abstract protected void set(SnmpMibSubRequest req,
1703                SnmpOid rowOid, int depth)
1704    throws SnmpStatusException;
1705    
1706    // ----------------------------------------------------------------------
1707
// PACKAGE METHODS
1708
// ----------------------------------------------------------------------
1709

1710    /**
1711     * Get the <CODE>SnmpOid</CODE> index of the row that follows the
1712     * index extracted from the specified OID array.
1713     * Builds the SnmpOid corresponding to the row OID and calls
1714     * <code>getNextOid(oid,userData)</code>;
1715     *
1716     * <p>
1717     * @param oid The OID array.
1718     *
1719     * @param pos The position in the OID array at which the index starts.
1720     *
1721     * @param userData A contextual object containing user-data.
1722     * This object is allocated through the <code>
1723     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
1724     * for each incoming SNMP request.
1725     *
1726     * @return The next <CODE>SnmpOid</CODE>.
1727     *
1728     * @exception SnmpStatusException There is no index following the
1729     * specified one in the table.
1730     */

1731    SnmpOid getNextOid(long[] oid, int pos, Object JavaDoc userData)
1732    throws SnmpStatusException {
1733        
1734        // Construct the sub-oid starting at pos.
1735
// This sub-oid correspond to the oid part just after the entry
1736
// variable oid.
1737
//
1738
final SnmpOid resOid = new SnmpEntryOid(oid,pos);
1739            
1740    return getNextOid(resOid,userData);
1741    }
1742
1743    // ---------------------------------------------------------------------
1744
//
1745
// Register an exception when checking the RowStatus variable
1746
//
1747
// ---------------------------------------------------------------------
1748

1749    final static void checkRowStatusFail(SnmpMibSubRequest req,
1750                     int errorStatus)
1751    throws SnmpStatusException {
1752    final SnmpVarBind statusvb = req.getRowStatusVarBind();
1753    final SnmpStatusException x = new SnmpStatusException(errorStatus);
1754    req.registerCheckException(statusvb,x);
1755    }
1756
1757    // ---------------------------------------------------------------------
1758
//
1759
// Register an exception when checking the RowStatus variable
1760
//
1761
// ---------------------------------------------------------------------
1762

1763    final static void setRowStatusFail(SnmpMibSubRequest req,
1764                       int errorStatus)
1765    throws SnmpStatusException {
1766    final SnmpVarBind statusvb = req.getRowStatusVarBind();
1767    final SnmpStatusException x = new SnmpStatusException(errorStatus);
1768    req.registerSetException(statusvb,x);
1769    }
1770
1771    // ---------------------------------------------------------------------
1772
//
1773
// Implements the method defined in SnmpMibNode.
1774
//
1775
// ---------------------------------------------------------------------
1776
final synchronized void findHandlingNode(SnmpVarBind varbind,
1777                         long[] oid, int depth,
1778                         SnmpRequestTree handlers)
1779    throws SnmpStatusException {
1780
1781    final int length = oid.length;
1782
1783    if (handlers == null)
1784        throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
1785
1786    if (depth >= length)
1787        throw new SnmpStatusException(SnmpStatusException.noAccess);
1788
1789    if (oid[depth] != nodeId)
1790        throw new SnmpStatusException(SnmpStatusException.noAccess);
1791
1792    if (depth+2 >= length)
1793        throw new SnmpStatusException(SnmpStatusException.noAccess);
1794
1795    // Checks that the oid is valid
1796
// validateOid(oid,depth);
1797

1798    // Gets the part of the OID that identifies the entry
1799
final SnmpOid entryoid = new SnmpEntryOid(oid, depth+2);
1800
1801    // Finds the entry: false means that the entry does not exists
1802
final Object JavaDoc data = handlers.getUserData();
1803    final boolean hasEntry = contains(entryoid, data);
1804
1805    // Fails if the entry is not found and the table does not
1806
// not support creation.
1807
// We know that the entry does not exists if (isentry == false).
1808
if (!hasEntry) {
1809        if (!handlers.isCreationAllowed())
1810        // we're not doing a set
1811
throw noSuchInstanceException;
1812        else if (!isCreationEnabled())
1813        // we're doing a set but creation is disabled.
1814
throw new
1815            SnmpStatusException(SnmpStatusException.snmpRspNoAccess);
1816    }
1817
1818    final long var = oid[depth+1];
1819
1820    // Validate the entry id
1821
if (hasEntry) {
1822        // The entry already exists - validate the id
1823
validateVarEntryId(entryoid,var,data);
1824    }
1825
1826    // Registers this node for the identified entry.
1827
//
1828
if (handlers.isSetRequest() && isRowStatus(entryoid,var,data))
1829
1830        // We only try to identify the RowStatus for SET operations
1831
//
1832
handlers.add(this,depth,entryoid,varbind,(!hasEntry),varbind);
1833
1834    else
1835        handlers.add(this,depth,entryoid,varbind,(!hasEntry));
1836    }
1837
1838
1839    // ---------------------------------------------------------------------
1840
//
1841
// Implements the method defined in SnmpMibNode. The algorithm is very
1842
// largely inspired from the original getNext() method.
1843
//
1844
// ---------------------------------------------------------------------
1845
final synchronized long[] findNextHandlingNode(SnmpVarBind varbind,
1846                      long[] oid, int pos, int depth,
1847                      SnmpRequestTree handlers,
1848                      AcmChecker checker)
1849    throws SnmpStatusException {
1850        int length = oid.length;
1851        
1852        if (handlers == null)
1853        // This should be considered as a genErr, but we do not want to
1854
// abort the whole request, so we're going to throw
1855
// a noSuchObject...
1856
//
1857
throw noSuchObjectException;
1858        
1859        final Object JavaDoc data = handlers.getUserData();
1860        final int pduVersion = handlers.getRequestPduVersion();
1861        
1862        long var= -1;
1863        
1864        // If the querried oid contains less arcs than the OID of the
1865
// xxxEntry object, we must return the first leaf under the
1866
// first columnar object: the best way to do that is to reset
1867
// the queried oid:
1868
// oid[0] = nodeId (arc of the xxxEntry object)
1869
// pos = 0 (points to the arc of the xxxEntry object)
1870
// then we just have to proceed...
1871
//
1872
if (pos >= length) {
1873        // this will have the side effect to set
1874
// oid[pos] = nodeId
1875
// and
1876
// (pos+1) = length
1877
// so we won't fall into the "else if" cases below -
1878
// so using "else if" rather than "if ..." is guaranteed
1879
// to be safe.
1880
//
1881
oid = new long[1];
1882        oid[0] = nodeId;
1883        pos = 0;
1884        length = 1;
1885        } else if (oid[pos] > nodeId) {
1886        // oid[pos] is expected to be the id of the xxxEntry ...
1887
// The id requested is greater than the id of the xxxEntry,
1888
// so we won't find the next element in this table... (any
1889
// element in this table will have a smaller OID)
1890
//
1891
throw noSuchObjectException;
1892        } else if (oid[pos] < nodeId) {
1893        // we must return the first leaf under the first columnar
1894
// object, so we are back to our first case where pos was
1895
// out of bounds... => reset the oid to contain only the
1896
// arc of the xxxEntry object.
1897
//
1898
oid = new long[1];
1899        oid[0] = nodeId;
1900        pos = 0;
1901        length = 0;
1902        } else if ((pos + 1) < length) {
1903        // The arc at the position "pos+1" is the id of the columnar
1904
// object (ie: the id of the variable in the table entry)
1905
//
1906
var = oid[pos+1];
1907        }
1908        
1909        // Now that we've got everything right we can begin.
1910
SnmpOid entryoid = null ;
1911        
1912        if (pos == (length - 1)) {
1913        // pos points to the last arc in the oid, and this arc is
1914
// guaranteed to be the xxxEntry id (we have handled all
1915
// the other possibilities before)
1916
//
1917
// We must therefore return the first leaf below the first
1918
// columnar object in the table.
1919
//
1920
// Get the first index. If an exception is raised,
1921
// then it means that the table is empty. We thus do not
1922
// have to catch the exception - we let it propagate to
1923
// the caller.
1924
//
1925
entryoid = getNextOid(data);
1926        var = getNextVarEntryId(entryoid,var,data,pduVersion);
1927        } else if ( pos == (length-2)) {
1928        // In that case we have (pos+1) = (length-1), so pos
1929
// points to the arc of the querried variable (columnar object).
1930
// Since the requested oid stops there, it means we have
1931
// to return the first leaf under this columnar object.
1932
//
1933
// So we first get the first index:
1934
// Note: if this raises an exception, this means that the table
1935
// is empty, so we can let the exception propagate to the caller.
1936
//
1937
entryoid = getNextOid(data);
1938
1939        // XXX revisit: not exactly perfect:
1940
// a specific row could be empty.. But we don't know
1941
// how to make the difference! => tradeoff holes
1942
// in tables can't be properly supported (all rows
1943
// must have the same holes)
1944
//
1945
if (skipEntryVariable(entryoid,var,data,pduVersion)) {
1946            var = getNextVarEntryId(entryoid,var,data,pduVersion);
1947        }
1948        } else {
1949        
1950        // So now there remain one last case, namely: some part of the
1951
// index is provided by the oid...
1952
// We build a possibly incomplete and invalid index from
1953
// the OID.
1954
// The piece of index provided should begin at pos+2
1955
// oid[pos] = id of the xxxEntry object,
1956
// oid[pos+1] = id of the columnar object,
1957
// oid[pos+2] ... oid[length-1] = piece of index.
1958
//
1959

1960        // We get the next index following the provided index.
1961
// If this raises an exception, then it means that we have
1962
// reached the last index in the table, and we must then
1963
// try with the next columnar object.
1964
//
1965
// Bug fix 4269251
1966
// The SnmpIndex is defined to contain a valid oid:
1967
// this is not an SNMP requirement for the getNext request.
1968
// So we no more use the SnmpIndex but directly the SnmpOid.
1969
//
1970
try {
1971            entryoid = getNextOid(oid, pos + 2, data);
1972
1973            // If the variable must ne skipped, fall through...
1974
//
1975
// XXX revisit: not exactly perfect:
1976
// a specific row could be empty.. But we don't know
1977
// how to make the difference! => tradeoff holes
1978
// in tables can't be properly supported (all rows
1979
// must have the same holes)
1980
//
1981
if (skipEntryVariable(entryoid,var,data,pduVersion))
1982            throw noSuchObjectException;
1983        } catch(SnmpStatusException se) {
1984            entryoid = getNextOid(data);
1985            var = getNextVarEntryId(entryoid,var,data,pduVersion);
1986        }
1987        }
1988
1989        return findNextAccessibleOid(entryoid,
1990                     varbind,
1991                     oid,
1992                     depth,
1993                     handlers,
1994                     checker,
1995                     data,
1996                     var);
1997    }
1998    
1999    private long[] findNextAccessibleOid(SnmpOid entryoid,
2000                     SnmpVarBind varbind,long[] oid,
2001                     int depth, SnmpRequestTree handlers,
2002                     AcmChecker checker, Object JavaDoc data,
2003                     long var)
2004    throws SnmpStatusException {
2005    final int pduVersion = handlers.getRequestPduVersion();
2006
2007    // Loop on each var (column)
2008
while(true) {
2009        // This should not happen. If it happens, (bug, or customized
2010
// methods returning garbage instead of raising an exception),
2011
// it probably means that there is nothing to return anyway.
2012
// So we throw the exception.
2013
// => will skip to next node in the MIB tree.
2014
//
2015
if (entryoid == null || var == -1 ) throw noSuchObjectException;
2016
2017        
2018        // So here we know both the row (entryoid) and the column (var)
2019
//
2020

2021        try {
2022        // Raising an exception here will make the catch() clause
2023
// switch to the next variable. If `var' is not readable
2024
// for this specific entry, it is not readable for any
2025
// other entry => skip to next column.
2026
//
2027
if (!isReadableEntryId(entryoid,var,data))
2028            throw noSuchObjectException;
2029
2030        // Prepare the result and the ACM checker.
2031
//
2032
final long[] etable = entryoid.longValue(false);
2033        final int elength = etable.length;
2034        final long[] result = new long[depth + 2 + elength];
2035        result[0] = -1 ; // Bug detector!
2036

2037        // Copy the entryOid at the end of `result'
2038
//
2039
java.lang.System.arraycopy(etable, 0, result,
2040                       depth+2, elength);
2041        
2042        // Set the node Id and var Id in result.
2043
//
2044
result[depth] = nodeId;
2045        result[depth+1] = var;
2046
2047        // Append nodeId.varId.<rowOid> to ACM checker.
2048
//
2049
checker.add(depth,result,depth,elength+2);
2050
2051        // No we're going to ACM check our OID.
2052
try {
2053            checker.checkCurrentOid();
2054            
2055            // No exception thrown by checker => this is all OK!
2056
// we have it: register the handler and return the
2057
// result.
2058
//
2059
handlers.add(this,depth,entryoid,varbind,false);
2060            return result;
2061        } catch(SnmpStatusException e) {
2062            // Skip to the next entry. If an exception is
2063
// thrown, will be catch by enclosing catch
2064
// and a skip is done to the next var.
2065
//
2066
entryoid = getNextOid(entryoid, data);
2067        } finally {
2068            // Clean the checker.
2069
//
2070
checker.remove(depth,elength+2);
2071        }
2072        } catch(SnmpStatusException e) {
2073        // Catching an exception here means we have to skip to the
2074
// next column.
2075
//
2076
// Back to the first row.
2077
entryoid = getNextOid(data);
2078        
2079        // Find out the next column.
2080
//
2081
var = getNextVarEntryId(entryoid,var,data,pduVersion);
2082
2083        }
2084
2085        // This should not happen. If it happens, (bug, or customized
2086
// methods returning garbage instead of raising an exception),
2087
// it probably means that there is nothing to return anyway.
2088
// No need to continue, we throw an exception.
2089
// => will skip to next node in the MIB tree.
2090
//
2091
if (entryoid == null || var == -1 )
2092        throw noSuchObjectException;
2093    }
2094    }
2095
2096
2097    /**
2098     * Validate the specified OID.
2099     *
2100     * <p>
2101     * @param oid The OID array.
2102     *
2103     * @param pos The position in the array.
2104     *
2105     * @exception SnmpStatusException If the validation fails.
2106     */

2107    final void validateOid(long[] oid, int pos) throws SnmpStatusException {
2108        final int length= oid.length;
2109
2110    // Control the length of the oid
2111
//
2112
if (pos +2 >= length)
2113            throw noSuchInstanceException;
2114
2115    // Check that the entry identifier is specified
2116
//
2117
if (oid[pos] != nodeId)
2118            throw noSuchObjectException;
2119
2120    }
2121    
2122    // ----------------------------------------------------------------------
2123
// PRIVATE METHODS
2124
// ----------------------------------------------------------------------
2125

2126    /**
2127     * Enable this <CODE>SnmpMibTable</CODE> to send a notification.
2128     *
2129     * <p>
2130     * @param notification The notification to send.
2131     */

2132    private synchronized void sendNotification(Notification JavaDoc notification) {
2133
2134        // loop on listener
2135
//
2136
for(java.util.Enumeration JavaDoc k = handbackTable.keys();
2137        k.hasMoreElements(); ) {
2138            
2139            NotificationListener JavaDoc listener =
2140        (NotificationListener JavaDoc) k.nextElement();
2141
2142            // Get the associated handback list and the associated filter list
2143
//
2144
java.util.Vector JavaDoc handbackList =
2145        (java.util.Vector JavaDoc) handbackTable.get(listener) ;
2146            java.util.Vector JavaDoc filterList =
2147        (java.util.Vector JavaDoc) filterTable.get(listener) ;
2148
2149            // loop on handback
2150
//
2151
java.util.Enumeration JavaDoc f = filterList.elements();
2152            for(java.util.Enumeration JavaDoc h = handbackList.elements();
2153        h.hasMoreElements(); ) {
2154                
2155                Object JavaDoc handback = h.nextElement();
2156                NotificationFilter JavaDoc filter =
2157            (NotificationFilter JavaDoc)f.nextElement();
2158
2159                if ((filter == null) ||
2160                    ((filter != null) &&
2161             (filter.isNotificationEnabled(notification)))) {
2162            
2163                    listener.handleNotification(notification,handback) ;
2164                }
2165            }
2166        }
2167    }
2168    
2169    /**
2170     * This method is used by the SnmpMibTable to create and send a table
2171     * entry notification to all the listeners registered for this kind of
2172     * notification.
2173     *
2174     * <p>
2175     * @param type The notification type.
2176     *
2177     * @param timeStamp The notification emission date.
2178     *
2179     * @param entry The entry object.
2180     */

2181    private void sendNotification(String JavaDoc type, long timeStamp,
2182                  Object JavaDoc entry, ObjectName JavaDoc name) {
2183        
2184        synchronized(this) {
2185            sequenceNumber = sequenceNumber + 1;
2186        }
2187
2188        SnmpTableEntryNotification notif =
2189        new SnmpTableEntryNotification(type, this, sequenceNumber,
2190                       timeStamp, entry, name);
2191            
2192        this.sendNotification(notif) ;
2193    }
2194    
2195    /**
2196     * Return true if the entry identified by the given OID index
2197     * is contained in this table.
2198     * <p>
2199     * <b>Do not call this method directly</b>.
2200     * <p>
2201     * This method is provided has a hook for subclasses.
2202     * It is called when a get/set request is received in order to
2203     * determine whether the specified entry is contained in the table.
2204     * You may want to override this method if you need to perform e.g.
2205     * lazy evaluation of tables (you need to update the table when a
2206     * request is received) or if your table is virtual.
2207     * <p>
2208     * Note that this method is called by the Runtime from within a
2209     * synchronized block.
2210     *
2211     * @param oid The index part of the OID we're looking for.
2212     * @param userData A contextual object containing user-data.
2213     * This object is allocated through the <code>
2214     * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
2215     * for each incoming SNMP request.
2216     *
2217     * @return <code>true</code> if the entry is found, <code>false</code>
2218     * otherwise.
2219     *
2220     * @since 1.5
2221     **/

2222    protected boolean contains(SnmpOid oid, Object JavaDoc userData) {
2223    return (findObject(oid) > -1);
2224    }
2225
2226    /**
2227     * Look for the given oid in the OID table (tableoids) and returns
2228     * its position.
2229     *
2230     * <p>
2231     * @param oid The OID we're looking for.
2232     *
2233     * @return The position of the OID in the table. -1 if the given
2234     * OID was not found.
2235     *
2236     **/

2237    private final int findObject(SnmpOid oid) {
2238        int low= 0;
2239        int max= size - 1;
2240        SnmpOid pos;
2241        int comp;
2242        int curr= low + (max-low)/2;
2243        //System.out.println("Try to retrieve: " + oid.toString());
2244
while (low <= max) {
2245
2246            // XX pos = (SnmpOid) oids.elementAt(curr);
2247
pos = tableoids[curr];
2248      
2249            //System.out.println("Compare with" + pos.toString());
2250
// never know ...we might find something ...
2251
//
2252
comp = oid.compareTo(pos);
2253            if (comp == 0)
2254                return curr;
2255      
2256            if (oid.equals(pos) == true) {
2257                return curr;
2258            }
2259            if (comp > 0) {
2260                low = curr + 1;
2261            } else {
2262                max = curr - 1;
2263            }
2264            curr = low + (max-low)/2;
2265        }
2266        return -1;
2267    }
2268    
2269    /**
2270     * Search the position at which the given oid should be inserted
2271     * in the OID table (tableoids).
2272     *
2273     * <p>
2274     * @param oid The OID we would like to insert.
2275     *
2276     * @return The position at which the OID should be inserted in
2277     * the table.
2278     *
2279     * @exception SnmpStatusException if the OID is already present in the
2280     * table.
2281     *
2282     **/

2283    private final int getInsertionPoint(SnmpOid oid)
2284    throws SnmpStatusException {
2285    return getInsertionPoint(oid, true);
2286    }
2287    
2288    /**
2289     * Search the position at which the given oid should be inserted
2290     * in the OID table (tableoids).
2291     *
2292     * <p>
2293     * @param oid The OID we would like to insert.
2294     *
2295     * @param fail Tells whether a SnmpStatusException must be generated
2296     * if the given OID is already present in the table.
2297     *
2298     * @return The position at which the OID should be inserted in
2299     * the table. When the OID is found, it returns the next
2300     * position. Note that it is not valid to insert twice the
2301     * same OID. This feature is only an optimization to improve
2302     * the getNextOid() behaviour.
2303     *
2304     * @exception SnmpStatusException if the OID is already present in the
2305     * table and <code>fail</code> is <code>true</code>.
2306     *
2307     **/

2308    private final int getInsertionPoint(SnmpOid oid, boolean fail)
2309    throws SnmpStatusException {
2310
2311    final int failStatus = SnmpStatusException.snmpRspNotWritable;
2312        int low= 0;
2313        int max= size - 1;
2314        SnmpOid pos;
2315        int comp;
2316        int curr= low + (max-low)/2;
2317        while (low <= max) {
2318      
2319            // XX pos= (SnmpOid) oids.elementAt(curr);
2320
pos= tableoids[curr];
2321      
2322            // never know ...we might find something ...
2323
//
2324
comp= oid.compareTo(pos);
2325
2326            if (comp == 0) {
2327        if (fail)
2328            throw new SnmpStatusException(failStatus,curr);
2329        else
2330            return curr+1;
2331        }
2332
2333            if (comp>0) {
2334                low= curr +1;
2335            } else {
2336                max= curr -1;
2337            }
2338            curr= low + (max-low)/2;
2339        }
2340        return curr;
2341    }
2342    
2343    /**
2344     * Remove the OID located at the given position.
2345     *
2346     * <p>
2347     * @param pos The position at which the OID to be removed is located.
2348     *
2349     **/

2350    private final void removeOid(int pos) {
2351    if (pos >= tablecount) return;
2352    if (pos < 0) return;
2353    final int l1 = --tablecount-pos;
2354    tableoids[pos] = null;
2355    if (l1 > 0)
2356        java.lang.System.arraycopy(tableoids,pos+1,tableoids,pos,l1);
2357    tableoids[tablecount] = null;
2358    }
2359
2360    /**
2361     * Insert an OID at the given position.
2362     *
2363     * <p>
2364     * @param oid The OID to be inserted in the table
2365     * @param pos The position at which the OID to be added is located.
2366     *
2367     **/

2368    private final void insertOid(int pos, SnmpOid oid) {
2369    if (pos >= tablesize || tablecount == tablesize) {
2370        // Vector must be enlarged
2371

2372        // Save old vector
2373
final SnmpOid[] olde = tableoids;
2374
2375        // Allocate larger vectors
2376
tablesize += Delta;
2377        tableoids = new SnmpOid[tablesize];
2378
2379        // Check pos validity
2380
if (pos > tablecount) pos = tablecount;
2381        if (pos < 0) pos = 0;
2382
2383        final int l1 = pos;
2384        final int l2 = tablecount - pos;
2385
2386        // Copy original vector up to `pos'
2387
if (l1 > 0)
2388            java.lang.System.arraycopy(olde,0,tableoids,0,l1);
2389
2390        // Copy original vector from `pos' to end, leaving
2391
// an empty room at `pos' in the new vector.
2392
if (l2 > 0)
2393            java.lang.System.arraycopy(olde,l1,tableoids,
2394                           l1+1,l2);
2395
2396        } else if (pos < tablecount) {
2397        // Vector is large enough to accomodate one additional
2398
// entry.
2399
//
2400
// Shift vector, making an empty room at `pos'
2401

2402        java.lang.System.arraycopy(tableoids,pos,tableoids,
2403                       pos+1,tablecount-pos);
2404        }
2405
2406        // Fill the gap at `pos'
2407
tableoids[pos] = oid;
2408        tablecount++;
2409    }
2410
2411
2412    // Returns true if debug is on
2413
private final static boolean isDebugOn() {
2414        return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
2415    }
2416
2417    // Prints a debug message
2418
private final void debug(String JavaDoc func, String JavaDoc info) {
2419        Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP,
2420           getClass().getName(), func, info);
2421    }
2422
2423    // ----------------------------------------------------------------------
2424
// PROTECTED VARIABLES
2425
// ----------------------------------------------------------------------
2426

2427    /**
2428     * The id of the contained entry object.
2429     * @serial
2430     */

2431    protected int nodeId=1;
2432  
2433    /**
2434     * The MIB to which the metadata is linked.
2435     * @serial
2436     */

2437    protected SnmpMib theMib;
2438    
2439    /**
2440     * <CODE>true</CODE> if remote creation of entries via SET operations
2441     * is enabled.
2442     * [default value is <CODE>false</CODE>]
2443     * @serial
2444     */

2445    protected boolean creationEnabled = false;
2446
2447    /**
2448     * The entry factory
2449     */

2450    protected SnmpTableEntryFactory factory = null;
2451    
2452    // ----------------------------------------------------------------------
2453
// PRIVATE VARIABLES
2454
// ----------------------------------------------------------------------
2455

2456    /**
2457     * The number of elements in the table.
2458     * @serial
2459     */

2460    private int size=0;
2461  
2462    /**
2463     * The list of indexes.
2464     * @serial
2465     */

2466    // private Vector indexes= new Vector();
2467

2468    /**
2469     * The list of OIDs.
2470     * @serial
2471     */

2472    // private Vector oids= new Vector();
2473
private final static int Delta = 16;
2474    private int tablecount = 0;
2475    private int tablesize = Delta;
2476    private SnmpOid tableoids[] = new SnmpOid[tablesize];
2477
2478    /**
2479     * The list of entries.
2480     * @serial
2481     */

2482    private final Vector JavaDoc entries= new Vector JavaDoc();
2483  
2484    /**
2485     * The list of object names.
2486     * @serial
2487     */

2488    private final Vector JavaDoc entrynames= new Vector JavaDoc();
2489  
2490    /**
2491     * Callback handlers
2492     */

2493    // final Vector callbacks = new Vector();
2494

2495    /**
2496     * Listener hastable containing the hand-back objects.
2497     */

2498    private java.util.Hashtable JavaDoc handbackTable = new java.util.Hashtable JavaDoc();
2499    
2500    /**
2501     * Listener hastable containing the filter objects.
2502     */

2503    private java.util.Hashtable JavaDoc filterTable = new java.util.Hashtable JavaDoc();
2504
2505    // PACKAGE VARIABLES
2506
//------------------
2507
/**
2508     * SNMP table sequence number.
2509     * The default value is set to 0.
2510     */

2511    transient long sequenceNumber = 0;
2512}
2513
Popular Tags