001: /*_############################################################################
002: _##
003: _## SNMP4J - TreeUtils.java
004: _##
005: _## Copyright (C) 2003-2008 Frank Fock and Jochen Katz (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.util;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import org.snmp4j.*;
027: import org.snmp4j.event.*;
028: import org.snmp4j.log.*;
029: import org.snmp4j.mp.*;
030: import org.snmp4j.smi.*;
031:
032: public class TreeUtils extends AbstractSnmpUtility {
033:
034: private static final LogAdapter logger = LogFactory
035: .getLogger(TreeUtils.class);
036:
037: private int maxRepetitions = 10;
038:
039: /**
040: * Creates a <code>TreeUtils</code> instance. The created instance is thread
041: * safe as long as the supplied <code>Session</code> and
042: * <code>PDUFactory</code> are thread safe.
043: *
044: * @param snmpSession
045: * a SNMP <code>Session</code> instance.
046: * @param pduFactory
047: * a <code>PDUFactory</code> instance that creates the PDU that are used
048: * by this instance to retrieve MIB tree data using GETBULK/GETNEXT
049: * operations.
050: */
051: public TreeUtils(Session snmpSession, PDUFactory pduFactory) {
052: super (snmpSession, pduFactory);
053: }
054:
055: /**
056: * Gets a subtree with GETNEXT (SNMPv1) or GETBULK (SNMP2c, SNMPv3) operations
057: * from the specified target synchronously.
058: *
059: * @param target
060: * a <code>Target</code> that specifies the target command responder
061: * including its network transport address.
062: * @param rootOID
063: * the OID that specifies the root of the sub-tree to retrieve
064: * (not included).
065: * @return
066: * a possibly empty List of <code>TreeEvent</code> instances where each
067: * instance carries zero or more values (or an error condition)
068: * in depth-first-order.
069: */
070: public List getSubtree(Target target, OID rootOID) {
071: List l = new LinkedList();
072: TreeListener listener = new InternalTreeListener(l);
073: synchronized (listener) {
074: walk(target, rootOID, rootOID, null, listener);
075: try {
076: listener.wait();
077: } catch (InterruptedException ex) {
078: logger.warn("Tree retrieval interrupted: "
079: + ex.getMessage());
080: }
081: }
082: return l;
083: }
084:
085: /**
086: * Gets a subtree with GETNEXT (SNMPv1) or GETBULK (SNMP2c, SNMPv3) operations
087: * from the specified target asynchronously.
088: *
089: * @param target
090: * a <code>Target</code> that specifies the target command responder
091: * including its network transport address.
092: * @param rootOID
093: * the OID that specifies the root of the sub-tree to retrieve
094: * (not included).
095: * @param userObject
096: * an optional user object that will be transparently handed over to the
097: * supplied <code>TreeListener</code>.
098: * @param listener
099: * the <code>TreeListener</code> that processes the {@link TreeEvent}s
100: * generated by this method. Each event object may carry zero or more
101: * object instances from the sub-tree in depth-first-order.
102: */
103: public void getSubtree(Target target, OID rootOID,
104: Object userObject, TreeListener listener) {
105: walk(target, rootOID, rootOID, userObject, listener);
106: }
107:
108: private void walk(Target target, OID rootOID, OID startOID,
109: Object userObject, TreeListener listener) {
110: PDU request = pduFactory.createPDU(target);
111: request.add(new VariableBinding(startOID));
112: if (target.getVersion() == SnmpConstants.version1) {
113: request.setType(PDU.GETNEXT);
114: } else {
115: request.setType(PDU.GETBULK);
116: request.setMaxRepetitions(maxRepetitions);
117: }
118: TreeRequest treeRequest = new TreeRequest(listener, rootOID,
119: target, userObject, request);
120: treeRequest.send();
121: }
122:
123: /**
124: * Sets the maximum number of the variable bindings per <code>TreeEvent</code>
125: * returned by this instance.
126: * @param maxRepetitions
127: * the maximum repetitions used for GETBULK requests. For SNMPv1 this
128: * values has no effect (it is then implicitly one).
129: */
130: public void setMaxRepetitions(int maxRepetitions) {
131: this .maxRepetitions = maxRepetitions;
132: }
133:
134: /**
135: * Gets the maximum number of the variable bindings per <code>TreeEvent</code>
136: * returned by this instance.
137: * @return
138: * the maximum repetitions used for GETBULK requests. For SNMPv1 this
139: * values has no effect (it is then implicitly one).
140: */
141: public int getMaxRepetitions() {
142: return maxRepetitions;
143: }
144:
145: class TreeRequest implements ResponseListener {
146:
147: private TreeListener listener;
148: private Object userObject;
149: private PDU request;
150: private OID rootOID;
151: private Target target;
152:
153: public TreeRequest(TreeListener listener, OID rootOID,
154: Target target, Object userObject, PDU request) {
155: this .listener = listener;
156: this .userObject = userObject;
157: this .request = request;
158: this .rootOID = rootOID;
159: this .target = target;
160: }
161:
162: public void send() {
163: try {
164: session.send(request, target, null, this );
165: } catch (IOException iox) {
166: listener.finished(new TreeEvent(this , userObject, iox));
167: }
168: }
169:
170: public void onResponse(ResponseEvent event) {
171: session.cancel(event.getRequest(), this );
172: PDU respPDU = event.getResponse();
173: if (respPDU == null) {
174: listener.finished(new TreeEvent(this , userObject,
175: RetrievalEvent.STATUS_TIMEOUT));
176: } else if (respPDU.getErrorStatus() != 0) {
177: listener.finished(new TreeEvent(this , userObject,
178: respPDU.getErrorStatus()));
179: } else if (respPDU.getType() == PDU.REPORT) {
180: listener.finished(new TreeEvent(this , userObject,
181: respPDU));
182: } else {
183: List l = new ArrayList(respPDU.size());
184: OID lastOID = request.get(0).getOid();
185: boolean finished = false;
186: for (int i = 0; (!finished) && (i < respPDU.size()); i++) {
187: VariableBinding vb = respPDU.get(i);
188: if ((vb.getOid() == null)
189: || (vb.getOid().size() < rootOID.size())
190: || (rootOID.leftMostCompare(rootOID.size(),
191: vb.getOid()) != 0)) {
192: finished = true;
193: } else if (Null.isExceptionSyntax(vb.getVariable()
194: .getSyntax())) {
195: finished = true;
196: } else if (vb.getOid().compareTo(lastOID) <= 0) {
197: listener.finished(new TreeEvent(this ,
198: userObject,
199: RetrievalEvent.STATUS_WRONG_ORDER));
200: finished = true;
201: break;
202: } else {
203: lastOID = vb.getOid();
204: l.add(vb);
205: }
206: }
207: if (respPDU.size() == 0) {
208: finished = true;
209: }
210: VariableBinding[] vbs = (VariableBinding[]) l
211: .toArray(new VariableBinding[l.size()]);
212: if (finished) {
213: listener.finished(new TreeEvent(this , userObject,
214: vbs));
215: } else {
216: if (listener.next(new TreeEvent(this , userObject,
217: vbs))) {
218: VariableBinding next = (VariableBinding) respPDU
219: .get(respPDU.size() - 1).clone();
220: next.setVariable(new Null());
221: request.set(0, next);
222: request.setRequestID(new Integer32(0));
223: send();
224: return;
225: } else {
226: finished = true;
227: }
228: }
229: }
230: }
231: }
232:
233: class InternalTreeListener implements TreeListener {
234:
235: private List collectedEvents;
236:
237: public InternalTreeListener(List eventList) {
238: collectedEvents = eventList;
239: }
240:
241: public synchronized boolean next(TreeEvent event) {
242: collectedEvents.add(event);
243: return true;
244: }
245:
246: public synchronized void finished(TreeEvent event) {
247: collectedEvents.add(event);
248: notify();
249: }
250:
251: public List getCollectedEvents() {
252: return collectedEvents;
253: }
254: }
255: }
|