View Javadoc

1   package net.sf.snmpadaptor4j.api.opennms;
2   
3   import java.math.BigInteger;
4   import java.net.InetAddress;
5   import java.net.UnknownHostException;
6   import net.sf.snmpadaptor4j.api.SnmpException;
7   import net.sf.snmpadaptor4j.object.SnmpDataType;
8   import net.sf.snmpadaptor4j.object.SnmpOid;
9   import org.apache.log4j.Logger;
10  import org.opennms.protocols.snmp.SnmpCounter32;
11  import org.opennms.protocols.snmp.SnmpCounter64;
12  import org.opennms.protocols.snmp.SnmpGauge32;
13  import org.opennms.protocols.snmp.SnmpIPAddress;
14  import org.opennms.protocols.snmp.SnmpInt32;
15  import org.opennms.protocols.snmp.SnmpNull;
16  import org.opennms.protocols.snmp.SnmpObjectId;
17  import org.opennms.protocols.snmp.SnmpOctetString;
18  import org.opennms.protocols.snmp.SnmpOpaque;
19  import org.opennms.protocols.snmp.SnmpPduPacket;
20  import org.opennms.protocols.snmp.SnmpSyntax;
21  import org.opennms.protocols.snmp.SnmpTimeTicks;
22  import org.opennms.protocols.snmp.SnmpUInt32;
23  
24  /**
25   * Support class for <b>joesnmp</b> API.
26   * @author <a href="http://fr.linkedin.com/in/jpminetti/">Jean-Philippe MINETTI</a>
27   */
28  public abstract class OpennmsSupport {
29  
30  	/**
31  	 * Logger.
32  	 */
33  	protected final Logger logger = Logger.getLogger(getClass());
34  
35  	/**
36  	 * Hidden constructor.
37  	 */
38  	protected OpennmsSupport () {
39  		super();
40  	}
41  
42  	/**
43  	 * Creates and returns a new {@link SnmpSyntax}.
44  	 * @param snmpDataType SNMP data type of value.
45  	 * @param value Value.
46  	 * @return New {@link SnmpSyntax}.
47  	 * @throws Exception Exception if an error has occurred.
48  	 */
49  	protected static final SnmpSyntax newSnmpValue (final SnmpDataType snmpDataType, final Object value) throws Exception {
50  		SnmpSyntax snmpValue;
51  		if (snmpDataType == SnmpDataType.integer32) {
52  			snmpValue = new SnmpInt32(toInteger32(value));
53  		}
54  		else if (snmpDataType == SnmpDataType.unsigned32) {
55  			snmpValue = new SnmpUInt32(toUnsigned32(value));
56  		}
57  		else if (snmpDataType == SnmpDataType.gauge32) {
58  			snmpValue = new SnmpGauge32(toUnsigned32(value));
59  		}
60  		else if (snmpDataType == SnmpDataType.counter32) {
61  			snmpValue = new SnmpCounter32(toUnsigned32(value));
62  		}
63  		else if (snmpDataType == SnmpDataType.counter64) {
64  			snmpValue = new SnmpCounter64(toUnsigned64(value));
65  		}
66  		else if (snmpDataType == SnmpDataType.timeTicks) {
67  			snmpValue = new SnmpTimeTicks(toTimeTicks(value));
68  		}
69  		else if (snmpDataType == SnmpDataType.octetString) {
70  			snmpValue = new SnmpOctetString(toOctetString(value));
71  		}
72  		else if (snmpDataType == SnmpDataType.ipAddress) {
73  			snmpValue = new SnmpIPAddress(toIpAddress(value));
74  		}
75  		else if (snmpDataType == SnmpDataType.objectIdentifier) {
76  			snmpValue = new SnmpObjectId(toObjectIdentifier(value));
77  		}
78  		else if (snmpDataType == SnmpDataType.opaque) {
79  			snmpValue = new SnmpOpaque(toOctetString(value));
80  		}
81  		else {
82  			throw new SnmpException(snmpDataType + " unhandled", SnmpPduPacket.ErrWrongType);
83  		}
84  		return snmpValue;
85  	}
86  
87  	/**
88  	 * Creates and returns a new JMX object from a {@link SnmpSyntax}.
89  	 * @param jmxDataType JMX data type of value.
90  	 * @param snmpDataType SNMP data type of value.
91  	 * @param newValue New value encapsulated to an object {@link SnmpSyntax}.
92  	 * @throws Exception Exception if an error has occurred.
93  	 */
94  	protected static Object newJmxValue (final Class<?> jmxDataType, final SnmpDataType snmpDataType, final SnmpSyntax newValue) throws Exception {
95  		Object value;
96  		if (newValue instanceof SnmpNull) {
97  			value = null;
98  		}
99  		else if (snmpDataType == SnmpDataType.integer32) {
100 			if (!(newValue instanceof SnmpInt32)) {
101 				throw new SnmpException("New value is not an integer32", SnmpPduPacket.ErrBadValue);
102 			}
103 			value = fromInteger32(jmxDataType, ((SnmpInt32) newValue).getValue());
104 		}
105 		else if (snmpDataType == SnmpDataType.unsigned32) {
106 			if (!(newValue instanceof SnmpUInt32) || (newValue instanceof SnmpCounter32) || (newValue instanceof SnmpGauge32) || (newValue instanceof SnmpTimeTicks)) {
107 				throw new SnmpException("New value is not an unsigned32", SnmpPduPacket.ErrBadValue);
108 			}
109 			value = fromUnsigned32("unsigned32", jmxDataType, ((SnmpUInt32) newValue).getValue());
110 		}
111 		else if (snmpDataType == SnmpDataType.gauge32) {
112 			if (!(newValue instanceof SnmpGauge32)) {
113 				throw new SnmpException("New value is not a gauge32", SnmpPduPacket.ErrBadValue);
114 			}
115 			value = fromUnsigned32("gauge32", jmxDataType, ((SnmpGauge32) newValue).getValue());
116 		}
117 		else if (snmpDataType == SnmpDataType.counter32) {
118 			throw new SnmpException("counter32 are not writable", SnmpPduPacket.ErrNotWritable);
119 		}
120 		else if (snmpDataType == SnmpDataType.counter64) {
121 			throw new SnmpException("counter64 are not writable", SnmpPduPacket.ErrNotWritable);
122 		}
123 		else if (snmpDataType == SnmpDataType.timeTicks) {
124 			if (!(newValue instanceof SnmpTimeTicks)) {
125 				throw new SnmpException("New value is not a timeTicks", SnmpPduPacket.ErrBadValue);
126 			}
127 			value = fromTimeTicks(jmxDataType, ((SnmpTimeTicks) newValue).getValue());
128 		}
129 		else if (snmpDataType == SnmpDataType.octetString) {
130 			if (!(newValue instanceof SnmpOctetString) || (newValue instanceof SnmpIPAddress) || (newValue instanceof SnmpOpaque)) {
131 				throw new SnmpException("New value is not an octetString", SnmpPduPacket.ErrBadValue);
132 			}
133 			value = fromOctetString("octetString", jmxDataType, ((SnmpOctetString) newValue).getString());
134 		}
135 		else if (snmpDataType == SnmpDataType.ipAddress) {
136 			if (!(newValue instanceof SnmpIPAddress)) {
137 				throw new SnmpException("New value is not an ipAddress", SnmpPduPacket.ErrBadValue);
138 			}
139 			value = fromIpAddress(jmxDataType, ((SnmpIPAddress) newValue).convertToIpAddress());
140 		}
141 		else if (snmpDataType == SnmpDataType.objectIdentifier) {
142 			if (!(newValue instanceof SnmpObjectId)) {
143 				throw new SnmpException("New value is not an objectIdentifier", SnmpPduPacket.ErrBadValue);
144 			}
145 			value = fromObjectIdentifier(jmxDataType, ((SnmpObjectId) newValue).getIdentifiers());
146 		}
147 		else if (snmpDataType == SnmpDataType.opaque) {
148 			if (!(newValue instanceof SnmpOpaque)) {
149 				throw new SnmpException("New value is not an opaque", SnmpPduPacket.ErrBadValue);
150 			}
151 			value = fromOctetString("opaque", jmxDataType, ((SnmpOpaque) newValue).getString());
152 		}
153 		else {
154 			throw new SnmpException(snmpDataType + " unhandled", SnmpPduPacket.ErrWrongType);
155 		}
156 		return value;
157 	}
158 
159 	/**
160 	 * Converts a value to signed 32-bit integer.
161 	 * @param value Value to convert.
162 	 * @return Value as signed 32-bit integer.
163 	 */
164 	private static Integer toInteger32 (final Object value) {
165 		Integer result;
166 		if (value instanceof Integer) {
167 			result = (Integer) value;
168 		}
169 		else if (value instanceof Byte) {
170 			result = new Integer(((Byte) value).intValue());
171 		}
172 		else if (value instanceof Short) {
173 			result = new Integer(((Short) value).intValue());
174 		}
175 		else if (value instanceof Boolean) {
176 			result = new Integer(((Boolean) value).booleanValue() ? 1 : 2);
177 		}
178 		else if (value == null) {
179 			result = new Integer(0);
180 		}
181 		else {
182 			throw new SnmpException(value.getClass() + " is inconsistent with integer32", SnmpPduPacket.ErrWrongType);
183 		}
184 		return result;
185 	}
186 
187 	/**
188 	 * Converts a SNMP signed 32-bit integer to an object.
189 	 * @param type Object type to put in JMX attribute.
190 	 * @param value Value as signed 32-bit integer.
191 	 * @return Object to put in JMX attribute.
192 	 */
193 	private static Object fromInteger32 (final Class<?> type, final int value) {
194 		Object result;
195 		if (Integer.class.equals(type) || int.class.equals(type)) {
196 			result = new Integer(value);
197 		}
198 		else if (Byte.class.equals(type) || byte.class.equals(type)) {
199 			if ((value < Byte.MIN_VALUE) || (value > Byte.MAX_VALUE)) {
200 				throw new SnmpException("the value must be between " + Byte.MIN_VALUE + " and " + Byte.MAX_VALUE, SnmpPduPacket.ErrBadValue);
201 			}
202 			result = new Byte((byte) value);
203 		}
204 		else if (Short.class.equals(type) || short.class.equals(type)) {
205 			if ((value < Short.MIN_VALUE) || (value > Short.MAX_VALUE)) {
206 				throw new SnmpException("the value must be between " + Short.MIN_VALUE + " and " + Short.MAX_VALUE, SnmpPduPacket.ErrBadValue);
207 			}
208 			result = new Short((short) value);
209 		}
210 		else if (Boolean.class.equals(type) || boolean.class.equals(type)) {
211 			if (value == 1) {
212 				result = Boolean.TRUE;
213 			}
214 			else if (value == 2) {
215 				result = Boolean.FALSE;
216 			}
217 			else {
218 				throw new SnmpException("the value must be between true(1) and false(2)", SnmpPduPacket.ErrBadValue);
219 			}
220 		}
221 		else {
222 			throw new SnmpException(type + " is inconsistent with integer32", SnmpPduPacket.ErrWrongType);
223 		}
224 		return result;
225 	}
226 
227 	/**
228 	 * Converts a value to non-negative 32-bit integer.
229 	 * @param value Value to convert.
230 	 * @return Value as non-negative 32-bit integer.
231 	 */
232 	private static Long toUnsigned32 (final Object value) {
233 		Long result;
234 		if (value instanceof Long) {
235 			result = (Long) value;
236 		}
237 		else if (value instanceof Integer) {
238 			result = new Long(((Integer) value).longValue());
239 		}
240 		else if (value instanceof Byte) {
241 			result = new Long(((Byte) value).longValue());
242 		}
243 		else if (value instanceof Short) {
244 			result = new Long(((Short) value).longValue());
245 		}
246 		else if (value == null) {
247 			result = new Long(0L);
248 		}
249 		else {
250 			throw new SnmpException(value.getClass() + " is inconsistent with unsigned32", SnmpPduPacket.ErrWrongType);
251 		}
252 		final long maxValue = 2 * (long) Integer.MAX_VALUE + 1;
253 		if ((result.longValue() < 0) || (result.longValue() > maxValue)) {
254 			throw new SnmpException("the value must be between 0 and " + maxValue, SnmpPduPacket.ErrWrongType);
255 		}
256 		return result;
257 	}
258 
259 	/**
260 	 * Converts a SNMP non-negative 32-bit integer to an object.
261 	 * @param snmpDataTypeName Name of SNMP data type used in the error message.
262 	 * @param type Object type to put in JMX attribute.
263 	 * @param value Value as non-negative 32-bit integer.
264 	 * @return Object to put in JMX attribute.
265 	 */
266 	private static Object fromUnsigned32 (final String snmpDataTypeName, final Class<?> type, final long value) {
267 		Object result;
268 		if (Long.class.equals(type) || long.class.equals(type)) {
269 			result = new Long(value);
270 		}
271 		else if (Integer.class.equals(type) || int.class.equals(type)) {
272 			if (value > Integer.MAX_VALUE) {
273 				throw new SnmpException("the value must be between 0 and " + Integer.MAX_VALUE, SnmpPduPacket.ErrBadValue);
274 			}
275 			result = new Integer((int) value);
276 		}
277 		else if (Byte.class.equals(type) || byte.class.equals(type)) {
278 			if (value > Byte.MAX_VALUE) {
279 				throw new SnmpException("the value must be between 0 and " + Byte.MAX_VALUE, SnmpPduPacket.ErrBadValue);
280 			}
281 			result = new Byte((byte) value);
282 		}
283 		else if (Short.class.equals(type) || short.class.equals(type)) {
284 			if (value > Short.MAX_VALUE) {
285 				throw new SnmpException("the value must be between 0 and " + Short.MAX_VALUE, SnmpPduPacket.ErrBadValue);
286 			}
287 			result = new Short((short) value);
288 		}
289 		else {
290 			throw new SnmpException(type + " is inconsistent with " + snmpDataTypeName, SnmpPduPacket.ErrWrongType);
291 		}
292 		return result;
293 	}
294 
295 	/**
296 	 * Converts a value to non-negative 64-bit integer.
297 	 * @param value Value to convert.
298 	 * @return Value as non-negative 64-bit integer.
299 	 */
300 	private static BigInteger toUnsigned64 (final Object value) {
301 		BigInteger result;
302 		if (value instanceof BigInteger) {
303 			result = (BigInteger) value;
304 		}
305 		else if (value instanceof Long) {
306 			result = BigInteger.valueOf(((Long) value).longValue());
307 		}
308 		else if (value == null) {
309 			result = BigInteger.valueOf(0L);
310 		}
311 		else {
312 			throw new SnmpException(value.getClass() + " is inconsistent with unsigned64", SnmpPduPacket.ErrWrongType);
313 		}
314 		final BigInteger minValue = BigInteger.valueOf(0);
315 		final BigInteger maxValue = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(1));
316 		if ((result.compareTo(minValue) < 0) || (result.compareTo(maxValue) > 0)) {
317 			throw new SnmpException("the value must be between " + minValue + " and " + maxValue, SnmpPduPacket.ErrWrongType);
318 		}
319 		return result;
320 	}
321 
322 	/**
323 	 * Converts a value to non-negative 32-bit integer in hundredths of a second.
324 	 * @param value Value to convert in milliseconds.
325 	 * @return Value as non-negative 32-bit integer in hundredths of a second.
326 	 */
327 	private static Long toTimeTicks (final Object value) {
328 		Long result;
329 		if (value instanceof Long) {
330 			result = new Long(((Long) value).longValue() / 10);
331 		}
332 		else if (value == null) {
333 			result = new Long(0L);
334 		}
335 		else {
336 			throw new SnmpException(value.getClass() + " is inconsistent with timeTicks", SnmpPduPacket.ErrWrongType);
337 		}
338 		final long maxValue = 2 * (long) Integer.MAX_VALUE + 1;
339 		if ((result.longValue() < 0) || (result.longValue() > maxValue)) {
340 			throw new SnmpException("the value must be between 0 and " + maxValue, SnmpPduPacket.ErrWrongType);
341 		}
342 		return result;
343 	}
344 
345 	/**
346 	 * Converts a SNMP non-negative 32-bit integer in hundredths of a second to an object.
347 	 * @param type Object type to put in JMX attribute.
348 	 * @param value Value as non-negative 32-bit integer in hundredths of a second.
349 	 * @return Object to put in JMX attribute in milliseconds.
350 	 */
351 	private static Object fromTimeTicks (final Class<?> type, final long value) {
352 		Object result;
353 		if (Long.class.equals(type) || long.class.equals(type)) {
354 			result = new Long(10 * value);
355 		}
356 		else {
357 			throw new SnmpException(type + " is inconsistent with timeTicks", SnmpPduPacket.ErrWrongType);
358 		}
359 		return result;
360 	}
361 
362 	/**
363 	 * Converts a value to array of ASCII code.
364 	 * @param value Value to convert.
365 	 * @return Value as array of ASCII code.
366 	 */
367 	private static byte[] toOctetString (final Object value) {
368 		byte[] result;
369 		if (value instanceof String) {
370 			result = ((String) value).getBytes();
371 		}
372 		else if (value instanceof byte[]) {
373 			result = (byte[]) value;
374 		}
375 		else if (value == null) {
376 			result = "".getBytes();
377 		}
378 		else {
379 			result = value.toString().getBytes();
380 		}
381 		return result;
382 	}
383 
384 	/**
385 	 * Converts a SNMP array of ASCII code to an object.
386 	 * @param snmpDataTypeName Name of SNMP data type used in the error message.
387 	 * @param type Object type to put in JMX attribute.
388 	 * @param value Value as ASCII code.
389 	 * @return Object to put in JMX attribute.
390 	 */
391 	private static Object fromOctetString (final String snmpDataTypeName, final Class<?> type, final byte[] value) {
392 		Object result;
393 		if (String.class.equals(type)) {
394 			result = new String(value);
395 		}
396 		else if (byte[].class.equals(type)) {
397 			result = value;
398 		}
399 		else {
400 			throw new SnmpException(type + " is inconsistent with " + snmpDataTypeName, SnmpPduPacket.ErrWrongType);
401 		}
402 		return result;
403 	}
404 
405 	/**
406 	 * Converts a value to internet address.
407 	 * @param value Value to convert.
408 	 * @return Value as internet address.
409 	 * @throws Exception Exception if an error has occurred.
410 	 */
411 	private static InetAddress toIpAddress (final Object value) throws Exception {
412 		InetAddress result;
413 		if (value instanceof InetAddress) {
414 			result = (InetAddress) value;
415 		}
416 		else if (value instanceof String) {
417 			try {
418 				result = InetAddress.getByName((String) value);
419 			}
420 			catch (final UnknownHostException e) {
421 				throw new SnmpException("IP address is malformed", SnmpPduPacket.ErrWrongValue);
422 			}
423 		}
424 		else if (value == null) {
425 			result = InetAddress.getByAddress(new byte[] { 0, 0, 0, 0 });
426 		}
427 		else {
428 			throw new SnmpException(value.getClass() + " is inconsistent with ipAddress", SnmpPduPacket.ErrWrongType);
429 		}
430 		return result;
431 	}
432 
433 	/**
434 	 * Converts a SNMP internet address to an object.
435 	 * @param type Object type to put in JMX attribute.
436 	 * @param value Value as internet address.
437 	 * @return Object to put in JMX attribute.
438 	 */
439 	private static Object fromIpAddress (final Class<?> type, final InetAddress value) {
440 		Object result;
441 		if (InetAddress.class.equals(type)) {
442 			result = value;
443 		}
444 		else if (String.class.equals(type)) {
445 			result = value.getHostAddress();
446 		}
447 		else {
448 			throw new SnmpException(type + " is inconsistent with ipAddress", SnmpPduPacket.ErrWrongType);
449 		}
450 		return result;
451 	}
452 
453 	/**
454 	 * Converts a value to OID of SNMP <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB).
455 	 * @param value Value to convert.
456 	 * @return Value as OID of SNMP <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB).
457 	 */
458 	private static int[] toObjectIdentifier (final Object value) {
459 		int[] result;
460 		if (value instanceof SnmpOid) {
461 			result = ((SnmpOid) value).getOid();
462 		}
463 		else if (value instanceof String) {
464 			result = SnmpOid.newInstance((String) value).getOid();
465 		}
466 		else if (value == null) {
467 			result = new int[] { 1 };
468 		}
469 		else {
470 			throw new SnmpException(value.getClass() + " is inconsistent with objectIdentifier", SnmpPduPacket.ErrWrongType);
471 		}
472 		return result;
473 	}
474 
475 	/**
476 	 * Converts an OID of SNMP <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB) to an object.
477 	 * @param type Object type to put in JMX attribute.
478 	 * @param value Value as OID of SNMP <b>M</b>anagement <b>I</b>nformation <b>B</b>ase (MIB).
479 	 * @return Object to put in JMX attribute.
480 	 */
481 	private static Object fromObjectIdentifier (final Class<?> type, final int[] value) {
482 		Object result;
483 		if (SnmpOid.class.equals(type)) {
484 			result = SnmpOid.newInstance(value);
485 		}
486 		else if (String.class.equals(type)) {
487 			result = SnmpOid.newInstance(value).toString();
488 		}
489 		else {
490 			throw new SnmpException(type + " is inconsistent with objectIdentifier", SnmpPduPacket.ErrWrongType);
491 		}
492 		return result;
493 	}
494 
495 }