blob: d86389b1a6628ef0c899960f27334c983cea9000 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27package com.sun.jmx.snmp.agent;
28
29
30
31// java imports
32//
33import java.io.Serializable;
34import java.util.Vector;
35import java.util.Enumeration;
36
37// jmx imports
38//
39import com.sun.jmx.snmp.SnmpOid;
40import com.sun.jmx.snmp.SnmpValue;
41import com.sun.jmx.snmp.SnmpVarBind;
42import com.sun.jmx.snmp.SnmpStatusException;
43
44/**
45 * Represents a node in an SNMP MIB which is neither a group nor a variable.
46 * This class defines a list of sub-nodes and the methods that allow to
47 * manipulate the sub-nodes.
48 * <P>
49 * This class is used internally and by the class generated by
50 * <CODE>mibgen</CODE>.
51 * You should not need to use this class directly.
52 *
53 * <p><b>This API is a Sun Microsystems internal API and is subject
54 * to change without notice.</b></p>
55 */
56
57public class SnmpMibOid extends SnmpMibNode implements Serializable {
58 private static final long serialVersionUID = 5012254771107446812L;
59
60 /**
61 * Default constructor.
62 */
63 public SnmpMibOid() {
64 }
65
66 // PUBLIC METHODS
67 //---------------
68
69 /**
70 * Generic handling of the <CODE>get</CODE> operation.
71 *
72 * <p> This method should be overridden in subclasses.
73 * <p>
74 *
75 * @param req The sub-request that must be handled by this node.
76 *
77 * @param depth The depth reached in the OID tree.
78 *
79 * @exception SnmpStatusException The default implementation (if not
80 * overridden) is to generate a SnmpStatusException.
81 */
82 public void get(SnmpMibSubRequest req, int depth)
83 throws SnmpStatusException {
84 for (Enumeration e= req.getElements(); e.hasMoreElements();) {
85 SnmpVarBind var= (SnmpVarBind) e.nextElement();
86 SnmpStatusException x =
87 new SnmpStatusException(SnmpStatusException.noSuchObject);
88 req.registerGetException(var,x);
89 }
90 }
91
92 /**
93 * Generic handling of the <CODE>set</CODE> operation.
94 *
95 * <p> This method should be overridden in subclasses.
96 * <p>
97 *
98 * @param req The sub-request that must be handled by this node.
99 *
100 * @param depth The depth reached in the OID tree.
101 *
102 * @exception SnmpStatusException The default implementation (if not
103 * overridden) is to generate a SnmpStatusException.
104 */
105 public void set(SnmpMibSubRequest req, int depth)
106 throws SnmpStatusException {
107 for (Enumeration e= req.getElements(); e.hasMoreElements();) {
108 SnmpVarBind var= (SnmpVarBind) e.nextElement();
109 SnmpStatusException x =
110 new SnmpStatusException(SnmpStatusException.noAccess);
111 req.registerSetException(var,x);
112 }
113 }
114
115 /**
116 * Generic handling of the <CODE>check</CODE> operation.
117 *
118 * <p> This method should be overridden in subclasses.
119 * <p>
120 *
121 * @param req The sub-request that must be handled by this node.
122 *
123 * @param depth The depth reached in the OID tree.
124 *
125 * @exception SnmpStatusException The default implementation (if not
126 * overriden) is to generate a SnmpStatusException.
127 */
128 public void check(SnmpMibSubRequest req, int depth)
129 throws SnmpStatusException {
130 for (Enumeration e= req.getElements(); e.hasMoreElements();) {
131 SnmpVarBind var= (SnmpVarBind) e.nextElement();
132 SnmpStatusException x =
133 new SnmpStatusException(SnmpStatusException.noAccess);
134 req.registerCheckException(var,x);
135 }
136 }
137
138
139
140 // ---------------------------------------------------------------------
141 //
142 // Implements the method defined in SnmpMibNode.
143 //
144 // ---------------------------------------------------------------------
145 //
146 void findHandlingNode(SnmpVarBind varbind,
147 long[] oid, int depth,
148 SnmpRequestTree handlers)
149 throws SnmpStatusException {
150
151
152 final int length = oid.length;
153 SnmpMibNode node = null;
154
155 if (handlers == null)
156 throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
157
158 if (depth > length) {
159 // Nothing is left... the oid is not valid
160 throw noSuchObjectException;
161
162 } else if (depth == length) {
163 // The oid is not complete...
164 throw noSuchInstanceException;
165
166 } else {
167 // Some children variable or subobject is being querried
168 // getChild() will raise an exception if no child is found.
169 //
170 final SnmpMibNode child= getChild(oid[depth]);
171
172 // XXXX zzzz : what about null children?
173 // (variables for nested groups)
174 // if child==null, then we're dealing with a variable or
175 // a table: we register this node.
176 // This behaviour should be overriden in subclasses,
177 // in particular in group meta classes: the group
178 // meta classes that hold tables should take care
179 // of forwarding this call to all the tables involved.
180 //
181 if (child == null)
182 handlers.add(this,depth,varbind);
183 else
184 child.findHandlingNode(varbind,oid,depth+1,handlers);
185 }
186 }
187
188 // ---------------------------------------------------------------------
189 //
190 // Implements the method defined in SnmpMibNode.
191 //
192 // ---------------------------------------------------------------------
193 //
194 long[] findNextHandlingNode(SnmpVarBind varbind,
195 long[] oid, int pos, int depth,
196 SnmpRequestTree handlers,
197 AcmChecker checker)
198 throws SnmpStatusException {
199
200
201 final int length = oid.length;
202 SnmpMibNode node = null;
203 long[] result = null;
204 if (handlers == null)
205 // This should be considered as a genErr, but we do not want to
206 // abort the whole request, so we're going to throw
207 // a noSuchObject...
208 //
209 throw noSuchObjectException;
210
211 final Object data = handlers.getUserData();
212 final int pduVersion = handlers.getRequestPduVersion();
213
214 if (pos >= length) {
215 long[] newOid= new long[1];
216 newOid[0]= getNextVarId(-1,data,pduVersion);
217 result = findNextHandlingNode(varbind,newOid,0,depth,handlers,
218 checker);
219 return result;
220 }
221
222 // search the element specified in the oid
223 //
224 long[] newOid= new long[1];
225 long index= oid[pos];
226
227 while (true) {
228
229 try {
230 final SnmpMibNode child = getChild(index);
231 // SnmpOid result = null;
232 if (child == null) {
233 // shouldn't happen
234 throw noSuchObjectException;
235 // validateVarId(index);
236 // handlers.add(this,varbind,depth);
237 // result = new SnmpOid(0);
238 } else {
239 checker.add(depth, index);
240 try {
241 result = child.findNextHandlingNode(varbind,oid,pos+1,
242 depth+1,handlers,
243 checker);
244 } finally {
245 checker.remove(depth);
246 }
247 }
248
249 // Build up the leaf OID
250 result[depth] = index;
251 return result;
252
253 } catch(SnmpStatusException e) {
254 // If there is no such element go one level up ...
255 //
256 index= getNextVarId(index,data,pduVersion);
257
258 // There is no need to carry the original oid ...
259 newOid[0]=index;
260 pos= 1;
261 oid=newOid;
262 }
263 }
264 }
265
266
267 /**
268 * Computes the root OID of the MIB.
269 */
270 public void getRootOid(Vector<Integer> result) {
271
272 // If a node has several children, let assume that we are one step to
273 // far in order to get the MIB root.
274 //
275 if (nbChildren != 1)
276 return;
277
278 result.addElement(varList[0]);
279
280 // Now query our child.
281 //
282 children.firstElement().getRootOid(result);
283
284 }
285
286 /**
287 * Registers a specific node in the tree.
288 */
289 public void registerNode(String oidString ,SnmpMibNode node)
290 throws IllegalAccessException {
291 SnmpOid oid= new SnmpOid(oidString);
292 registerNode(oid.longValue(), 0, node);
293 }
294
295 // PROTECTED METHODS
296 //------------------
297
298 /**
299 * Registers a specific node in the tree.
300 */
301 void registerNode(long[] oid, int cursor ,SnmpMibNode node)
302 throws IllegalAccessException {
303
304 if (cursor >= oid.length)
305 throw new IllegalAccessException();
306
307 // Check if the node is already defined
308 //
309 long var= oid[cursor];
310
311 //System.out.println("entering registration for val="
312 // + String.valueOf(var) + " position= " + cursor);
313
314 int pos = retrieveIndex(var);
315 if (pos == nbChildren) {
316 nbChildren++;
317 varList= new int[nbChildren];
318 varList[0]= (int) var;
319 pos =0;
320 if ( (cursor + 1) == oid.length) {
321 // That 's the end of the trip.
322 // Do not forward the registration
323
324 //System.out.println("End of trip for val="
325 // + String.valueOf(var) + " position= " + cursor);
326 children.insertElementAt(node,pos);
327 return;
328 }
329
330 //System.out.println("Create node for val="
331 // + String.valueOf(var) + " position= " + cursor);
332 SnmpMibOid child= new SnmpMibOid();
333 children.insertElementAt(child, pos);
334 child.registerNode(oid, cursor + 1, node);
335 return;
336 }
337 if (pos == -1) {
338 // The node is not yet registered
339 //
340 int[] tmp= new int[nbChildren + 1];
341 tmp[nbChildren]= (int) var;
342 System.arraycopy(varList, 0, tmp, 0, nbChildren);
343 varList= tmp;
344 nbChildren++;
345 SnmpMibNode.sort(varList);
346 int newPos = retrieveIndex(var);
347 varList[newPos]= (int) var;
348 if ( (cursor + 1) == oid.length) {
349 // That 's the end of the trip.
350 // Do not forward the registration
351
352 //System.out.println("End of trip for val="
353 // + String.valueOf(var) + " position= " + cursor);
354 children.insertElementAt(node, newPos);
355 return;
356 }
357 SnmpMibOid child= new SnmpMibOid();
358 // System.out.println("Create node for val=" +
359 // String.valueOf(var) + " position= " + cursor);
360 children.insertElementAt(child, newPos);
361 child.registerNode(oid, cursor + 1, node);
362 return;
363 }
364 else {
365 // The node is already registered
366 //
367 SnmpMibNode child= children.elementAt(pos);
368 if ( (cursor + 1) == oid.length ) {
369 //System.out.println("Node already registered val=" +
370 // String.valueOf(var) + " position= " + cursor);
371 if (child == node) return;
372 if (child != null && node != null) {
373 // Now we're going to patch the tree the following way:
374 // if a subgroup has been registered before its father,
375 // we're going to replace the father OID node with
376 // the actual group-node and export the children from
377 // the temporary OID node to the actual group node.
378 //
379
380 if (node instanceof SnmpMibGroup) {
381 // `node' is a group => replace `child' with `node'
382 // export the child's subtree to `node'.
383 //
384 ((SnmpMibOid)child).exportChildren((SnmpMibOid)node);
385 children.setElementAt(node,pos);
386 return;
387
388 } else if ((node instanceof SnmpMibOid) &&
389 (child instanceof SnmpMibGroup)) {
390 // `node' is a temporary node, and `child' is a
391 // group => keep child and export the node's
392 // subtree to `child'.
393 //
394 ((SnmpMibOid)node).exportChildren((SnmpMibOid)child);
395 return;
396 } else if (node instanceof SnmpMibOid) {
397 // `node' and `child' are both temporary OID nodes
398 // => replace `child' with `node' and export child's
399 // subtree to `node'.
400 //
401 ((SnmpMibOid)child).exportChildren((SnmpMibOid)node);
402 children.setElementAt(node,pos);
403 return;
404 }
405 }
406 children.setElementAt(node,pos);
407 return;
408 } else {
409 if (child == null)
410 throw new IllegalAccessException();
411 ((SnmpMibOid)child).registerNode(oid, cursor + 1, node);
412 }
413 }
414 }
415
416 /**
417 * Export this node's children to a brother node that will replace
418 * this node in the OID tree.
419 * This method is a patch that fixes the problem of registering
420 * a subnode before its father node.
421 *
422 **/
423 void exportChildren(SnmpMibOid brother)
424 throws IllegalAccessException {
425
426 if (brother == null) return;
427 final long[] oid = new long[1];
428 for (int i=0; i<nbChildren; i++) {
429 final SnmpMibNode child = children.elementAt(i);
430 if (child == null) continue;
431 oid[0] = varList[i];
432 brother.registerNode(oid,0,child);
433 }
434 }
435
436 // PRIVATE METHODS
437 //----------------
438
439 SnmpMibNode getChild(long id) throws SnmpStatusException {
440
441 // first we need to retrieve the identifier in the list of children
442 //
443 final int pos= getInsertAt(id);
444 if (pos >= nbChildren)
445 throw noSuchObjectException;
446
447 if (varList[pos] != (int) id)
448 throw noSuchObjectException;
449
450 // Access the node
451 //
452 SnmpMibNode child = null;
453 try {
454 child = children.elementAtNonSync(pos);
455 } catch(ArrayIndexOutOfBoundsException e) {
456 throw noSuchObjectException;
457 }
458 if (child == null)
459 throw noSuchInstanceException;
460 return child;
461 }
462
463 private int retrieveIndex(long val) {
464
465 int low= 0;
466 int cursor= (int) val;
467 if (varList == null || varList.length < 1)
468 return nbChildren;
469
470 int max= varList.length -1 ;
471 int curr= low + (max-low)/2;
472 int elmt= 0;
473 while (low <= max) {
474 elmt= varList[curr];
475 if (cursor == elmt) {
476 // We need to get the next index ...
477 //
478 return curr;
479 }
480 if (elmt < cursor) {
481 low= curr +1;
482 } else {
483 max= curr -1;
484 }
485 curr= low + (max-low)/2;
486 }
487 return -1;
488 }
489
490 private int getInsertAt(long val) {
491
492 int low= 0;
493 final int index= (int) val;
494 if (varList == null)
495 return -1;
496 int max= varList.length -1 ;
497 int elmt=0;
498 //final int[] v = varList;
499
500 //if (index > a[max])
501 //return max +1;
502
503
504 int curr= low + (max-low)/2;
505 while (low <= max) {
506
507 elmt= varList[curr];
508
509 // never know ...we might find something ...
510 //
511 if (index == elmt)
512 return curr;
513
514 if (elmt < index) {
515 low= curr +1;
516 } else {
517 max= curr -1;
518 }
519 curr= low + (max-low)/2;
520 }
521
522 return curr;
523 }
524
525 // PRIVATE VARIABLES
526 //------------------
527
528 /**
529 * Contains the list of sub nodes.
530 */
531 private NonSyncVector<SnmpMibNode> children = new NonSyncVector<SnmpMibNode>(1);
532
533 /**
534 * The number of sub nodes.
535 */
536 private int nbChildren= 0;
537
538
539 // All the methods of the Vector class are synchronized.
540 // Synchronization is a very expensive operation. In our case it is
541 // not always required...
542 //
543 @SuppressWarnings("serial") // We will never serialize this
544 class NonSyncVector<E> extends Vector<E> {
545
546 public NonSyncVector(int size) {
547 super(size);
548 }
549
550 final void addNonSyncElement(E obj) {
551 ensureCapacity(elementCount + 1);
552 elementData[elementCount++] = obj;
553 }
554
555 @SuppressWarnings("unchecked") // cast to E
556 final E elementAtNonSync(int index) {
557 return (E) elementData[index];
558 }
559
560 }
561}