blob: 8b78b26cb00f62b6e565720fed4a91ef5059aa7c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2003 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
26package com.sun.jmx.snmp.agent;
27
28
29// java imports
30//
31import java.util.Vector;
32import java.util.Enumeration;
33import java.util.Iterator;
34
35// jmx imports
36//
37import javax.management.AttributeList;
38import javax.management.Attribute;
39import javax.management.MBeanException;
40import javax.management.MBeanServer;
41import javax.management.ObjectName;
42import javax.management.ReflectionException;
43import javax.management.InstanceNotFoundException;
44import javax.management.InvalidAttributeValueException;
45import javax.management.InstanceAlreadyExistsException;
46import javax.management.MBeanRegistrationException;
47import javax.management.NotCompliantMBeanException;
48import javax.management.RuntimeOperationsException;
49import com.sun.jmx.snmp.SnmpOid;
50import com.sun.jmx.snmp.SnmpValue;
51import com.sun.jmx.snmp.SnmpVarBind;
52import com.sun.jmx.snmp.SnmpStatusException;
53
54
55/**
56 * <p>
57 * This class is a utility class that transforms SNMP GET / SET requests
58 * into standard JMX getAttributes() setAttributes() requests.
59 * </p>
60 *
61 * <p>
62 * The transformation relies on the metadata information provided by the
63 * {@link com.sun.jmx.snmp.agent.SnmpGenericMetaServer} object which is
64 * passed as the first parameter to every method. This SnmpGenericMetaServer
65 * object is usually a Metadata object generated by <code>mibgen</code>.
66 * </p>
67 *
68 * <p><b><i>
69 * This class is used internally by mibgen generated metadata objects and
70 * you should never need to use it directly.
71 * </b></i></p>
72 * <p><b>This API is a Sun Microsystems internal API and is subject
73 * to change without notice.</b></p>
74 **/
75
76public class SnmpGenericObjectServer {
77
78 // ----------------------------------------------------------------------
79 //
80 // Protected variables
81 //
82 // ----------------------------------------------------------------------
83
84 /**
85 * The MBean server through which the MBeans will be accessed.
86 **/
87 protected final MBeanServer server;
88
89 // ----------------------------------------------------------------------
90 //
91 // Constructors
92 //
93 // ----------------------------------------------------------------------
94
95 /**
96 * Builds a new SnmpGenericObjectServer. Usually there will be a single
97 * object of this type per MIB.
98 *
99 * @param server The MBeanServer in which the MBean accessed by this
100 * MIB are registered.
101 **/
102 public SnmpGenericObjectServer(MBeanServer server) {
103 this.server = server;
104 }
105
106 /**
107 * Execute an SNMP GET request.
108 *
109 * <p>
110 * This method first builds the list of attributes that need to be
111 * retrieved from the MBean and then calls getAttributes() on the
112 * MBean server. Then it updates the SnmpMibSubRequest with the values
113 * retrieved from the MBean.
114 * </p>
115 *
116 * <p>
117 * The SNMP metadata information is obtained through the given
118 * <code>meta</code> object, which usually is an instance of a
119 * <code>mibgen</code> generated class.
120 * </p>
121 *
122 * <p><b><i>
123 * This method is called internally by <code>mibgen</code> generated
124 * objects and you should never need to call it directly.
125 * </i></b></p>
126 *
127 * @param meta The metadata object impacted by the subrequest
128 * @param name The ObjectName of the MBean impacted by this subrequest
129 * @param req The SNMP subrequest to execute on the MBean
130 * @param depth The depth of the SNMP object in the OID tree.
131 *
132 * @exception SnmpStatusException whenever an SNMP exception must be
133 * raised. Raising an exception will abort the request.<br>
134 * Exceptions should never be raised directly, but only by means of
135 * <code>
136 * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
137 * </code>
138 **/
139 public void get(SnmpGenericMetaServer meta, ObjectName name,
140 SnmpMibSubRequest req, int depth)
141 throws SnmpStatusException {
142
143 // java.lang.System.out.println(">>>>>>>>> GET " + name);
144
145 final int size = req.getSize();
146 final Object data = req.getUserData();
147 final String[] nameList = new String[size];
148 final SnmpVarBind[] varList = new SnmpVarBind[size];
149 final long[] idList = new long[size];
150 int i = 0;
151
152 for (Enumeration e=req.getElements(); e.hasMoreElements();) {
153 final SnmpVarBind var= (SnmpVarBind) e.nextElement();
154 try {
155 final long id = var.oid.getOidArc(depth);
156 nameList[i] = meta.getAttributeName(id);
157 varList[i] = var;
158 idList[i] = id;
159
160 // Check the access rights according to the MIB.
161 // The MBean might be less restrictive (have a getter
162 // while the MIB defines the variable as AFN)
163 //
164 meta.checkGetAccess(id,data);
165
166 //java.lang.System.out.println(nameList[i] + " added.");
167 i++;
168 } catch(SnmpStatusException x) {
169 //java.lang.System.out.println("exception for " + nameList[i]);
170 //x.printStackTrace();
171 req.registerGetException(var,x);
172 }
173 }
174
175 AttributeList result = null;
176 int errorCode = SnmpStatusException.noSuchInstance;
177
178 try {
179 result = server.getAttributes(name,nameList);
180 } catch (InstanceNotFoundException f) {
181 //java.lang.System.out.println(name + ": instance not found.");
182 //f.printStackTrace();
183 result = new AttributeList();
184 } catch (ReflectionException r) {
185 //java.lang.System.out.println(name + ": reflexion error.");
186 //r.printStackTrace();
187 result = new AttributeList();
188 } catch (Exception x) {
189 result = new AttributeList();
190 }
191
192
193 final Iterator it = result.iterator();
194
195 for (int j=0; j < i; j++) {
196 if (!it.hasNext()) {
197 //java.lang.System.out.println(name + "variable[" + j +
198 // "] absent");
199 final SnmpStatusException x =
200 new SnmpStatusException(errorCode);
201 req.registerGetException(varList[j],x);
202 continue;
203 }
204
205 final Attribute att = (Attribute) it.next();
206
207 while ((j < i) && (! nameList[j].equals(att.getName()))) {
208 //java.lang.System.out.println(name + "variable[" +j +
209 // "] not found");
210 final SnmpStatusException x =
211 new SnmpStatusException(errorCode);
212 req.registerGetException(varList[j],x);
213 j++;
214 }
215
216 if ( j == i) break;
217
218 try {
219 varList[j].value =
220 meta.buildSnmpValue(idList[j],att.getValue());
221 } catch (SnmpStatusException x) {
222 req.registerGetException(varList[j],x);
223 }
224 //java.lang.System.out.println(att.getName() + " retrieved.");
225 }
226 //java.lang.System.out.println(">>>>>>>>> END GET");
227 }
228
229 /**
230 * Get the value of an SNMP variable.
231 *
232 * <p><b><i>
233 * You should never need to use this method directly.
234 * </i></b></p>
235 *
236 * @param meta The impacted metadata object
237 * @param name The ObjectName of the impacted MBean
238 * @param id The OID arc identifying the variable we're trying to set.
239 * @param data User contextual data allocated through the
240 * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
241 *
242 * @return The value of the variable.
243 *
244 * @exception SnmpStatusException whenever an SNMP exception must be
245 * raised. Raising an exception will abort the request. <br>
246 * Exceptions should never be raised directly, but only by means of
247 * <code>
248 * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
249 * </code>
250 **/
251 public SnmpValue get(SnmpGenericMetaServer meta, ObjectName name,
252 long id, Object data)
253 throws SnmpStatusException {
254 final String attname = meta.getAttributeName(id);
255 Object result = null;
256
257 try {
258 result = server.getAttribute(name,attname);
259 } catch (MBeanException m) {
260 Exception t = m.getTargetException();
261 if (t instanceof SnmpStatusException)
262 throw (SnmpStatusException) t;
263 throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
264 } catch (Exception e) {
265 throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
266 }
267
268 return meta.buildSnmpValue(id,result);
269 }
270
271 /**
272 * Execute an SNMP SET request.
273 *
274 * <p>
275 * This method first builds the list of attributes that need to be
276 * set on the MBean and then calls setAttributes() on the
277 * MBean server. Then it updates the SnmpMibSubRequest with the new
278 * values retrieved from the MBean.
279 * </p>
280 *
281 * <p>
282 * The SNMP metadata information is obtained through the given
283 * <code>meta</code> object, which usually is an instance of a
284 * <code>mibgen</code> generated class.
285 * </p>
286 *
287 * <p><b><i>
288 * This method is called internally by <code>mibgen</code> generated
289 * objects and you should never need to call it directly.
290 * </i></b></p>
291 *
292 * @param meta The metadata object impacted by the subrequest
293 * @param name The ObjectName of the MBean impacted by this subrequest
294 * @param req The SNMP subrequest to execute on the MBean
295 * @param depth The depth of the SNMP object in the OID tree.
296 *
297 * @exception SnmpStatusException whenever an SNMP exception must be
298 * raised. Raising an exception will abort the request. <br>
299 * Exceptions should never be raised directly, but only by means of
300 * <code>
301 * req.registerGetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
302 * </code>
303 **/
304 public void set(SnmpGenericMetaServer meta, ObjectName name,
305 SnmpMibSubRequest req, int depth)
306 throws SnmpStatusException {
307
308 final int size = req.getSize();
309 final AttributeList attList = new AttributeList(size);
310 final String[] nameList = new String[size];
311 final SnmpVarBind[] varList = new SnmpVarBind[size];
312 final long[] idList = new long[size];
313 int i = 0;
314
315 for (Enumeration e=req.getElements(); e.hasMoreElements();) {
316 final SnmpVarBind var= (SnmpVarBind) e.nextElement();
317 try {
318 final long id = var.oid.getOidArc(depth);
319 final String attname = meta.getAttributeName(id);
320 final Object attvalue=
321 meta.buildAttributeValue(id,var.value);
322 final Attribute att = new Attribute(attname,attvalue);
323 attList.add(att);
324 nameList[i] = attname;
325 varList[i] = var;
326 idList[i] = id;
327 i++;
328 } catch(SnmpStatusException x) {
329 req.registerSetException(var,x);
330 }
331 }
332
333 AttributeList result = null;
334 int errorCode = SnmpStatusException.noAccess;
335
336 try {
337 result = server.setAttributes(name,attList);
338 } catch (InstanceNotFoundException f) {
339 result = new AttributeList();
340 errorCode = SnmpStatusException.snmpRspInconsistentName;
341 } catch (ReflectionException r) {
342 errorCode = SnmpStatusException.snmpRspInconsistentName;
343 result = new AttributeList();
344 } catch (Exception x) {
345 result = new AttributeList();
346 }
347
348 final Iterator it = result.iterator();
349
350 for (int j=0; j < i; j++) {
351 if (!it.hasNext()) {
352 final SnmpStatusException x =
353 new SnmpStatusException(errorCode);
354 req.registerSetException(varList[j],x);
355 continue;
356 }
357
358 final Attribute att = (Attribute) it.next();
359
360 while ((j < i) && (! nameList[j].equals(att.getName()))) {
361 final SnmpStatusException x =
362 new SnmpStatusException(SnmpStatusException.noAccess);
363 req.registerSetException(varList[j],x);
364 j++;
365 }
366
367 if ( j == i) break;
368
369 try {
370 varList[j].value =
371 meta.buildSnmpValue(idList[j],att.getValue());
372 } catch (SnmpStatusException x) {
373 req.registerSetException(varList[j],x);
374 }
375
376 }
377 }
378
379 /**
380 * Set the value of an SNMP variable.
381 *
382 * <p><b><i>
383 * You should never need to use this method directly.
384 * </i></b></p>
385 *
386 * @param meta The impacted metadata object
387 * @param name The ObjectName of the impacted MBean
388 * @param x The new requested SnmpValue
389 * @param id The OID arc identifying the variable we're trying to set.
390 * @param data User contextual data allocated through the
391 * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
392 *
393 * @return The new value of the variable after the operation.
394 *
395 * @exception SnmpStatusException whenever an SNMP exception must be
396 * raised. Raising an exception will abort the request. <br>
397 * Exceptions should never be raised directly, but only by means of
398 * <code>
399 * req.registerSetException(<i>VariableId</i>,<i>SnmpStatusException</i>)
400 * </code>
401 **/
402 public SnmpValue set(SnmpGenericMetaServer meta, ObjectName name,
403 SnmpValue x, long id, Object data)
404 throws SnmpStatusException {
405 final String attname = meta.getAttributeName(id);
406 final Object attvalue=
407 meta.buildAttributeValue(id,x);
408 final Attribute att = new Attribute(attname,attvalue);
409
410 Object result = null;
411
412 try {
413 server.setAttribute(name,att);
414 result = server.getAttribute(name,attname);
415 } catch(InvalidAttributeValueException iv) {
416 throw new
417 SnmpStatusException(SnmpStatusException.snmpRspWrongValue);
418 } catch (InstanceNotFoundException f) {
419 throw new
420 SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
421 } catch (ReflectionException r) {
422 throw new
423 SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
424 } catch (MBeanException m) {
425 Exception t = m.getTargetException();
426 if (t instanceof SnmpStatusException)
427 throw (SnmpStatusException) t;
428 throw new
429 SnmpStatusException(SnmpStatusException.noAccess);
430 } catch (Exception e) {
431 throw new
432 SnmpStatusException(SnmpStatusException.noAccess);
433 }
434
435 return meta.buildSnmpValue(id,result);
436 }
437
438 /**
439 * Checks whether an SNMP SET request can be successfully performed.
440 *
441 * <p>
442 * For each variable in the subrequest, this method calls
443 * checkSetAccess() on the meta object, and then tries to invoke the
444 * check<i>AttributeName</i>() method on the MBean. If this method
445 * is not defined then it is assumed that the SET won't fail.
446 * </p>
447 *
448 * <p><b><i>
449 * This method is called internally by <code>mibgen</code> generated
450 * objects and you should never need to call it directly.
451 * </i></b></p>
452 *
453 * @param meta The metadata object impacted by the subrequest
454 * @param name The ObjectName of the MBean impacted by this subrequest
455 * @param req The SNMP subrequest to execute on the MBean
456 * @param depth The depth of the SNMP object in the OID tree.
457 *
458 * @exception SnmpStatusException if the requested SET operation must
459 * be rejected. Raising an exception will abort the request. <br>
460 * Exceptions should never be raised directly, but only by means of
461 * <code>
462 * req.registerCheckException(<i>VariableId</i>,<i>SnmpStatusException</i>)
463 * </code>
464 *
465 **/
466 public void check(SnmpGenericMetaServer meta, ObjectName name,
467 SnmpMibSubRequest req, int depth)
468 throws SnmpStatusException {
469
470 final Object data = req.getUserData();
471
472 for (Enumeration e=req.getElements(); e.hasMoreElements();) {
473 final SnmpVarBind var= (SnmpVarBind) e.nextElement();
474 try {
475 final long id = var.oid.getOidArc(depth);
476 // call meta.check() here, and meta.check will call check()
477 check(meta,name,var.value,id,data);
478 } catch(SnmpStatusException x) {
479 req.registerCheckException(var,x);
480 }
481 }
482 }
483
484 /**
485 * Checks whether a SET operation can be performed on a given SNMP
486 * variable.
487 *
488 * @param meta The impacted metadata object
489 * @param name The ObjectName of the impacted MBean
490 * @param x The new requested SnmpValue
491 * @param id The OID arc identifying the variable we're trying to set.
492 * @param data User contextual data allocated through the
493 * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}
494 *
495 * <p>
496 * This method calls checkSetAccess() on the meta object, and then
497 * tries to invoke the check<i>AttributeName</i>() method on the MBean.
498 * If this method is not defined then it is assumed that the SET
499 * won't fail.
500 * </p>
501 *
502 * <p><b><i>
503 * This method is called internally by <code>mibgen</code> generated
504 * objects and you should never need to call it directly.
505 * </i></b></p>
506 *
507 * @exception SnmpStatusException if the requested SET operation must
508 * be rejected. Raising an exception will abort the request. <br>
509 * Exceptions should never be raised directly, but only by means of
510 * <code>
511 * req.registerCheckException(<i>VariableId</i>,<i>SnmpStatusException</i>)
512 * </code>
513 *
514 **/
515 // XXX xxx ZZZ zzz Maybe we should go through the MBeanInfo here?
516 public void check(SnmpGenericMetaServer meta, ObjectName name,
517 SnmpValue x, long id, Object data)
518 throws SnmpStatusException {
519
520 meta.checkSetAccess(x,id,data);
521 try {
522 final String attname = meta.getAttributeName(id);
523 final Object attvalue= meta.buildAttributeValue(id,x);
524 final Object[] params = new Object[1];
525 final String[] signature = new String[1];
526
527 params[0] = attvalue;
528 signature[0] = attvalue.getClass().getName();
529 server.invoke(name,"check"+attname,params,signature);
530
531 } catch( SnmpStatusException e) {
532 throw e;
533 }
534 catch (InstanceNotFoundException i) {
535 throw new
536 SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
537 } catch (ReflectionException r) {
538 // checkXXXX() not defined => do nothing
539 } catch (MBeanException m) {
540 Exception t = m.getTargetException();
541 if (t instanceof SnmpStatusException)
542 throw (SnmpStatusException) t;
543 throw new SnmpStatusException(SnmpStatusException.noAccess);
544 } catch (Exception e) {
545 throw new
546 SnmpStatusException(SnmpStatusException.noAccess);
547 }
548 }
549
550 public void registerTableEntry(SnmpMibTable meta, SnmpOid rowOid,
551 ObjectName objname, Object entry)
552 throws SnmpStatusException {
553 if (objname == null)
554 throw new
555 SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
556 try {
557 if (entry != null && !server.isRegistered(objname))
558 server.registerMBean(entry, objname);
559 } catch (InstanceAlreadyExistsException e) {
560 throw new
561 SnmpStatusException(SnmpStatusException.snmpRspInconsistentName);
562 } catch (MBeanRegistrationException e) {
563 throw new SnmpStatusException(SnmpStatusException.snmpRspNoAccess);
564 } catch (NotCompliantMBeanException e) {
565 throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
566 } catch (RuntimeOperationsException e) {
567 throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
568 } catch(Exception e) {
569 throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
570 }
571 }
572
573}