001: /*_############################################################################
002: _##
003: _## SNMP4J-Agent - MOTableIndex.java
004: _##
005: _## Copyright (C) 2005-2007 Frank Fock (SNMP4J.org)
006: _##
007: _## Licensed under the Apache License, Version 2.0 (the "License");
008: _## you may not use this file except in compliance with the License.
009: _## You may obtain a copy of the License at
010: _##
011: _## http://www.apache.org/licenses/LICENSE-2.0
012: _##
013: _## Unless required by applicable law or agreed to in writing, software
014: _## distributed under the License is distributed on an "AS IS" BASIS,
015: _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: _## See the License for the specific language governing permissions and
017: _## limitations under the License.
018: _##
019: _##########################################################################*/
020:
021: package org.snmp4j.agent.mo;
022:
023: import org.snmp4j.smi.*;
024:
025: /**
026: * The <code>MOTableIndex</code> class represents a index definition of a
027: * conceptual table. An index always has to implement also the
028: * {@link MOTableIndexValidator} interface for validation of index values
029: * for newly created rows.
030: *
031: * @author Frank Fock
032: * @version 1.0
033: */
034: public class MOTableIndex implements MOTableIndexValidator {
035:
036: public static final int MAX_INDEX_OID_LENGTH = 127;
037:
038: private MOTableSubIndex[] subindexes;
039: private boolean impliedLength = false;
040: private MOTableIndexValidator validator;
041:
042: /**
043: * Creates a index definition from an array of sub-index definitions.
044: * @param subIndexes
045: * an array of sub-index definitions with at least one element.
046: */
047: public MOTableIndex(MOTableSubIndex[] subIndexes) {
048: if ((subIndexes == null) || (subIndexes.length < 1)) {
049: throw new IllegalArgumentException(
050: "Index definition must have at least one sub-index");
051: }
052: this .subindexes = subIndexes;
053: }
054:
055: /**
056: * Creates a index definition from an array of sub-index definitions where
057: * the last sub-index may have an implied length.
058: * @param subIndexes
059: * an array of sub-index definitions with at least one element.
060: * @param impliedLength
061: * if <code>true</code> the last sub-index has an implied length if at has
062: * a variable length at all.
063: */
064: public MOTableIndex(MOTableSubIndex[] subIndexes,
065: boolean impliedLength) {
066: this (subIndexes);
067: this .impliedLength = impliedLength;
068: }
069:
070: /**
071: * Creates a index definition from an array of sub-index definitions where
072: * the last sub-index may have an implied length.
073: * @param subIndexes
074: * an array of sub-index definitions with at least one element.
075: * @param impliedLength
076: * if <code>true</code> the last sub-index has an implied length if at has
077: * a variable length at all.
078: * @param validator
079: * an index validator that is called whenever a new index value needs to
080: * validated.
081: */
082: public MOTableIndex(MOTableSubIndex[] subIndexes,
083: boolean impliedLength, MOTableIndexValidator validator) {
084: this (subIndexes, impliedLength);
085: this .validator = validator;
086: }
087:
088: /**
089: * Gets the sub-index definition at the specified index.
090: * @param index
091: * a valid sub-index index (zero-based).
092: * @return
093: * the <code>MOTableSubIndex</code>.
094: */
095: public MOTableSubIndex getIndex(int index) {
096: return this .subindexes[index];
097: }
098:
099: public boolean isImpliedLength() {
100: return impliedLength;
101: }
102:
103: /**
104: * Gets the index validator (if present).
105: * @return
106: * the <code>MOTableIndexValidator</code> associated with this index or
107: * <code>null</code>.
108: */
109: public MOTableIndexValidator getValidator() {
110: return validator;
111: }
112:
113: /**
114: * Sets the index validator associated with this index definition.
115: * @param validator
116: * a <code>MOTableIndexValidator</code> instance.
117: */
118: public void setValidator(MOTableIndexValidator validator) {
119: this .validator = validator;
120: }
121:
122: /**
123: * Gets the number of sub-index definitions in this index definition.
124: * @return
125: * the sub-index count.
126: */
127: public int size() {
128: return subindexes.length;
129: }
130:
131: private static boolean checkIndexBytes(OID index, long start,
132: long end) {
133: if ((start < 0) || (start > MOTableIndex.MAX_INDEX_OID_LENGTH)
134: || (end < 0)
135: || (end > MOTableIndex.MAX_INDEX_OID_LENGTH)) {
136: return false;
137: }
138: for (int i = (int) start; ((i < index.size()) && (i < end)); i++) {
139: if (index.getUnsigned(i) > 255) {
140: return false;
141: }
142: }
143: return true;
144: }
145:
146: private static boolean isStringSyntax(int smiSyntax) {
147: switch (smiSyntax) {
148: case SMIConstants.SYNTAX_OCTET_STRING:
149: case SMIConstants.SYNTAX_IPADDRESS:
150: case SMIConstants.SYNTAX_OPAQUE: {
151: return true;
152: }
153: }
154: return false;
155: }
156:
157: /**
158: * Checks whether an index OID is a valid index for this index definition
159: * or not.
160: * @param index
161: * an OID (possibly zero length).
162: * @return
163: * <code>true</code> if the index is valid or <code>false</code> otherwise.
164: */
165: public boolean isValidIndex(OID index) {
166: if (index.size() > MOTableIndex.MAX_INDEX_OID_LENGTH) {
167: return false;
168: }
169: int l = 0;
170: int i;
171: for (i = 0; ((i < size()) && (l < index.size())); i++) {
172: MOTableSubIndex subIndex = getIndex(i);
173: if ((i + 1 == size()) && (isImpliedLength())) {
174: int type = subIndex.getSmiSyntax();
175: switch (type) {
176: case SMIConstants.SYNTAX_OCTET_STRING:
177: case SMIConstants.SYNTAX_IPADDRESS:
178: if (!checkIndexBytes(index, l, index.size())) {
179: return false;
180: }
181: break;
182: }
183: return true;
184: } else if ((subIndex.getMinLength() != subIndex
185: .getMaxLength())) {
186: if (index.size() < index.get(l) + 1) {
187: return false;
188: }
189: if ((index.get(l) < subIndex.getMinLength())
190: || (index.get(l) > subIndex.getMaxLength())) {
191: return false;
192: }
193: if (isStringSyntax(subIndex.getSmiSyntax())) {
194: if (!checkIndexBytes(index, l, l
195: + index.getUnsigned(l) + 1)) {
196: return false;
197: }
198: }
199: l += index.getUnsigned(l) + 1;
200: } else {
201: if (isStringSyntax(subIndex.getSmiSyntax())) {
202: if (!checkIndexBytes(index, l, l
203: + subIndex.getMaxLength())) {
204: return false;
205: }
206: }
207: // min == max
208: l += subIndex.getMaxLength();
209: }
210: }
211: return (((index.size() == l) && (i >= size())) && ((validator == null) || (validator
212: .isValidIndex(index))));
213: }
214:
215: private static Variable getIndexVariable(
216: MOTableSubIndex subIndexDef, OID subIndex,
217: boolean impliedLength) {
218: switch (subIndexDef.getSmiSyntax()) {
219: case SMIConstants.SYNTAX_OCTET_STRING: {
220: if ((impliedLength)
221: || (subIndexDef.getMinLength() == subIndexDef
222: .getMaxLength())) {
223: OctetString s = new OctetString(subIndex.toByteArray());
224: return s;
225: }
226: OID suffix = new OID(subIndex.getValue(), 1, subIndex
227: .size() - 1);
228: return new OctetString(suffix.toByteArray());
229: }
230: case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: {
231: if ((impliedLength)
232: || (subIndexDef.getMinLength() == subIndexDef
233: .getMaxLength())) {
234: return subIndex;
235: }
236: OID suffix = new OID(subIndex.getValue(), 1, subIndex
237: .size() - 1);
238: return suffix;
239: }
240: case SMIConstants.SYNTAX_UNSIGNED_INTEGER32: {
241: return new Gauge32(subIndex.get(subIndex.size() - 1));
242: }
243: case SMIConstants.SYNTAX_TIMETICKS: {
244: return new TimeTicks(subIndex.get(subIndex.size() - 1));
245: }
246: case SMIConstants.SYNTAX_INTEGER: {
247: return new Integer32(subIndex.get(subIndex.size() - 1));
248: }
249: case SMIConstants.SYNTAX_IPADDRESS: {
250: return new IpAddress(subIndex.toString());
251: }
252: /*
253: case SMIConstants.SYN_NETADDRESS: {
254: String id = subIndex.toString();
255: return new IpAddress(id.substring(id.indexOf(".") + 1));
256: }
257: */
258: }
259: return null;
260: }
261:
262: /**
263: * Split a table index into an array of object IDs each representing the
264: * value of its corresponding index object. For example if a table's index
265: * would be defined as INDEX { ifIndex, ipAddress } and the index given
266: * would be "1.127.0.0.1" the resulting array would be { "1", "127.0.0.1" }
267: *
268: * @param index
269: * an OID denoting a table's index value.
270: * @return
271: * an array of OID instances with the same size as returned by
272: * {@link #size}. If the given index is not a valid object ID
273: * <code>null</code> is returned.
274: */
275: public OID[] getIndexOIDs(OID index) {
276: OID[] r = new OID[size()];
277: int[] ind = index.getValue();
278: int pos = 0;
279: for (int i = 0; i < subindexes.length; i++) {
280: if ((i + 1 == size()) && (isImpliedLength())) {
281: r[i] = new OID(ind, pos, index.size() - pos);
282: break;
283: } else if ((subindexes[i].getMinLength() != subindexes[i]
284: .getMaxLength())) {
285: r[i] = new OID(ind, pos, index.get(pos) + 1);
286: } else {
287: r[i] = new OID(index.getValue(), pos, subindexes[i]
288: .getMaxLength());
289: }
290: pos += r[i].size();
291: }
292: return r;
293: }
294:
295: /**
296: * Gets the index values contained in an index OID.
297: * @param index
298: * the index OID.
299: * @return
300: * an array of values representing the index.
301: * @see #getIndexOID
302: */
303: public Variable[] getIndexValues(OID index) {
304: OID[] oids = getIndexOIDs(index);
305: Variable[] values = new Variable[oids.length];
306: for (int i = 0; i < oids.length; i++) {
307: boolean implied = ((isImpliedLength()) && (i + 1 == size()));
308: values[i] = getIndexVariable(subindexes[i], oids[i],
309: implied);
310: }
311: return values;
312: }
313:
314: /**
315: * Gets the index OID from an array of index values.
316: * @param indexValues
317: * an array of Variable instances that has to match the number and type
318: * of sub-indexes in this index.
319: * @return
320: * the corresponding index OID.
321: * @see #getIndexValues
322: */
323: public OID getIndexOID(Variable[] indexValues) {
324: if (indexValues.length != size()) {
325: throw new IllegalArgumentException(
326: "Index value length != size()");
327: }
328: OID index = new OID();
329: for (int i = 0; i < indexValues.length; i++) {
330: if (indexValues[i].getSyntax() == this .subindexes[i]
331: .getSmiSyntax()) {
332: index.append(indexValues[i]
333: .toSubIndex((i + 1 == indexValues.length)
334: && impliedLength));
335: } else {
336: throw new IllegalArgumentException(
337: "Syntax of index value #"
338: + i
339: + " = "
340: + indexValues[i].getSyntaxString()
341: + " does not match index definition "
342: + AbstractVariable
343: .getSyntaxString(this.subindexes[i]
344: .getSmiSyntax()));
345: }
346: }
347: return index;
348: }
349: }
|