
org.snmp4j.util.TreeUtils Maven / Gradle / Ivy
/*_############################################################################
_##
_## SNMP4J - TreeUtils.java
_##
_## Copyright (C) 2003-2018 Frank Fock and Jochen Katz (SNMP4J.org)
_##
_## Licensed under the Apache License, Version 2.0 (the "License");
_## you may not use this file except in compliance with the License.
_## You may obtain a copy of the License at
_##
_## http://www.apache.org/licenses/LICENSE-2.0
_##
_## Unless required by applicable law or agreed to in writing, software
_## distributed under the License is distributed on an "AS IS" BASIS,
_## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
_## See the License for the specific language governing permissions and
_## limitations under the License.
_##
_##########################################################################*/
package org.snmp4j.util;
import java.io.*;
import java.util.*;
import org.snmp4j.*;
import org.snmp4j.event.*;
import org.snmp4j.log.*;
import org.snmp4j.mp.*;
import org.snmp4j.smi.*;
public class TreeUtils extends AbstractSnmpUtility {
private static final LogAdapter logger =
LogFactory.getLogger(TreeUtils.class);
private int maxRepetitions = 10;
private boolean ignoreLexicographicOrder;
/**
* Creates a TreeUtils
instance. The created instance is thread safe as long as the supplied
* Session
and
* PDUFactory
are thread safe.
*
* @param snmpSession
* a SNMP Session
instance.
* @param pduFactory
* a PDUFactory
instance that creates the PDU that are used by this instance to retrieve MIB
* tree data using GETBULK/GETNEXT operations.
*/
public TreeUtils(Session snmpSession, PDUFactory pduFactory) {
super(snmpSession, pduFactory);
}
/**
* Gets a subtree with GETNEXT (SNMPv1) or GETBULK (SNMP2c, SNMPv3) operations from the specified target
* synchronously.
*
* @param target
* a Target
that specifies the target command responder including its network transport
* address.
* @param rootOID
* the OID that specifies the root of the sub-tree to retrieve (not included).
*
* @return a possibly empty List of TreeEvent
instances where each instance carries zero or more values
* (or an error condition) in depth-first-order.
*/
public List getSubtree(Target> target, OID rootOID) {
List l = new LinkedList<>();
TreeListener listener = new InternalTreeListener(l);
synchronized (listener) {
OID[] rootOIDs = new OID[]{rootOID};
walk(target, rootOIDs, null, listener);
try {
listener.wait();
} catch (InterruptedException ex) {
logger.warn("Tree retrieval interrupted: " + ex.getMessage());
}
}
return l;
}
/**
* Walks a subtree with GETNEXT (SNMPv1) or GETBULK (SNMP2c, SNMPv3) operations from the specified target
* asynchronously.
*
* @param target
* a Target
that specifies the target command responder including its network transport
* address.
* @param rootOIDs
* the OIDs which specify the subtrees to walk. Each OID defines a sub-tree that is walked. The walk ends if
* (a) an SNMP error occurs, (b) all returned variable bindings for an iteration contain an exception value
* (i.e., {@link Null#endOfMibView}) or for each rootOIDs element, the returned VariableBinding's OID has
* not the same prefix, (c) a VariableBinding out of lexicographic order is returned.
*
* @return a possibly empty List of TreeEvent
instances where each instance carries zero or
* rootOIDs.length
values.
* @since 2.1
*/
public List walk(Target> target, OID[] rootOIDs) {
List l = new LinkedList<>();
TreeListener listener = new InternalTreeListener(l);
synchronized (listener) {
walk(target, rootOIDs, null, listener);
try {
listener.wait();
} catch (InterruptedException ex) {
logger.warn("Tree retrieval interrupted: " + ex.getMessage());
}
}
return l;
}
/**
* Gets a subtree with GETNEXT (SNMPv1) or GETBULK (SNMP2c, SNMPv3) operations from the specified target
* asynchronously.
*
* @param target
* a Target
that specifies the target command responder including its network transport
* address.
* @param rootOID
* the OID that specifies the root of the sub-tree to retrieve (not included).
* @param userObject
* an optional user object that will be transparently handed over to the supplied
* TreeListener
.
* @param listener
* the TreeListener
that processes the {@link TreeEvent}s generated by this method. Each event
* object may carry zero or more object instances from the sub-tree in depth-first-order.
*/
public void getSubtree(Target> target, OID rootOID, Object userObject, TreeListener listener) {
walk(target, new OID[]{rootOID}, userObject, listener);
}
/**
* Walks a subtree with GETNEXT (SNMPv1) or GETBULK (SNMP2c, SNMPv3) operations from the specified target
* asynchronously.
*
* @param target
* a Target
that specifies the target command responder including its network transport
* address.
* @param rootOIDs
* the OIDs which specify the subtrees to walk. Each OID defines a sub-tree that is walked. The walk ends if
* (a) an SNMP error occurs, (b) all returned variable bindings for an iteration contain an exception value
* (i.e., {@link Null#endOfMibView}) or for each rootOIDs element, the returned VariableBinding's OID has
* not the same prefix, (c) a VariableBinding out of lexicographic order is returned.
* @param userObject
* an optional user object that will be transparently handed over to the supplied
* TreeListener
.
* @param listener
* the TreeListener
that processes the {@link TreeEvent}s generated by this method. Each event
* object may carry zero or more object instances from the sub-tree in depth-first-order if rootOIDs has a
* single element. If it has more than one element, then each {@link TreeEvent} contains the variable
* bindings of each iteration.
*
* @since 2.1
*/
public void walk(Target> target, OID[] rootOIDs, Object userObject, TreeListener listener) {
PDU request = pduFactory.createPDU(target);
for (OID oid : rootOIDs) {
request.add(new VariableBinding(oid));
}
if (target.getVersion() == SnmpConstants.version1) {
request.setType(PDU.GETNEXT);
} else if (request.getType() != PDU.GETNEXT) {
request.setType(PDU.GETBULK);
request.setMaxRepetitions(maxRepetitions);
}
TreeRequest treeRequest =
new TreeRequest(listener, rootOIDs, target, userObject, request);
treeRequest.send();
}
/**
* Sets the maximum number of the variable bindings per TreeEvent
returned by this instance.
*
* @param maxRepetitions
* the maximum repetitions used for GETBULK requests. For SNMPv1 this values has no effect (it is then
* implicitly one).
*/
public void setMaxRepetitions(int maxRepetitions) {
this.maxRepetitions = maxRepetitions;
}
/**
* Set the ignore lexicographic order errors flage value.
*
* @param ignoreLexicographicOrder
* true
to ignore lexicographic order errors,
* false
otherwise (default).
*
* @since 1.10.1
*/
public void setIgnoreLexicographicOrder(boolean ignoreLexicographicOrder) {
this.ignoreLexicographicOrder = ignoreLexicographicOrder;
}
/**
* Gets the maximum number of the variable bindings per TreeEvent
returned by this instance.
*
* @return the maximum repetitions used for GETBULK requests. For SNMPv1 this values has no effect (it is then
* implicitly one).
*/
public int getMaxRepetitions() {
return maxRepetitions;
}
/**
* Return the ignore lexicographic order errors flage value.
*
* @return true
if lexicographic order errors are ignored,
* false
otherwise (default).
* @since 1.10.1
*/
public boolean isIgnoreLexicographicOrder() {
return ignoreLexicographicOrder;
}
class TreeRequest implements ResponseListener {
private TreeListener listener;
private Object userObject;
private PDU request;
private OID[] rootOIDs;
private Target> target;
public TreeRequest(TreeListener listener, OID[] rootOIDs, Target> target, Object userObject, PDU request) {
this.listener = listener;
this.userObject = userObject;
this.request = request;
this.rootOIDs = rootOIDs;
this.target = target;
}
public void send() {
try {
session.send(request, target, null, this);
} catch (IOException iox) {
listener.finished(new TreeEvent(this, userObject, iox));
}
}
public void onResponse(ResponseEvent event) {
session.cancel(event.getRequest(), this);
PDU respPDU = event.getResponse();
if (respPDU == null) {
listener.finished(new TreeEvent(this, userObject,
RetrievalEvent.STATUS_TIMEOUT));
} else if (respPDU.getErrorStatus() != 0) {
if (target.getVersion() == SnmpConstants.version1 && respPDU.getErrorStatus() == PDU.noSuchName) {
listener.finished(new TreeEvent(this, userObject, new VariableBinding[0]));
}
listener.finished(new TreeEvent(this, userObject,
respPDU.getErrorStatus()));
} else if (respPDU.getType() == PDU.REPORT) {
listener.finished(new TreeEvent(this, userObject, respPDU));
} else {
List l = new ArrayList(respPDU.size());
List lastOIDs = null;
if (!ignoreLexicographicOrder) {
lastOIDs = new ArrayList(request.size());
for (int i = 0; i < request.size(); i++) {
lastOIDs.add(request.get(i).getOid());
}
}
boolean finished = false;
for (int i = 0; ((!finished) || (i % rootOIDs.length > 0)) && (i < respPDU.size()); i++) {
int r = i % rootOIDs.length;
VariableBinding vb = respPDU.get(i);
if ((vb.getOid() == null) ||
(vb.getOid().size() < rootOIDs[r].size()) ||
(rootOIDs[r].leftMostCompare(rootOIDs[r].size(), vb.getOid()) != 0)) {
finished = true;
} else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
finished = true;
} else if (!ignoreLexicographicOrder && (lastOIDs != null) &&
(vb.getOid().compareTo(lastOIDs.get(r)) <= 0)) {
listener.finished(new TreeEvent(this, userObject,
RetrievalEvent.STATUS_WRONG_ORDER));
finished = true;
break;
} else {
finished = false;
if (lastOIDs != null) {
lastOIDs.set(r, vb.getOid());
}
l.add(vb);
}
if ((rootOIDs.length > 1) && (i + 1) % rootOIDs.length == 0) {
// next "row"
VariableBinding[] vbs = l.toArray(new VariableBinding[l.size()]);
listener.next(new TreeEvent(this, userObject, vbs));
l.clear();
}
}
if (respPDU.size() == 0) {
finished = true;
}
VariableBinding[] vbs = l.toArray(new VariableBinding[l.size()]);
if (finished) {
listener.finished(new TreeEvent(this, userObject, vbs));
} else {
if (listener.next(new TreeEvent(this, userObject, vbs))) {
int lastRowIndex = ((respPDU.size() / rootOIDs.length) - 1) * rootOIDs.length;
request.clear();
for (int i = Math.max(0, lastRowIndex); i < lastRowIndex + rootOIDs.length; i++) {
VariableBinding next = (VariableBinding) respPDU.get(i).clone();
next.setVariable(new Null());
request.add(next);
}
if (request.size() > 0) {
send();
} else {
listener.finished(new TreeEvent(this, userObject, new VariableBinding[0]));
}
} else {
listener.finished(new TreeEvent(this, userObject, vbs));
}
}
}
}
}
class InternalTreeListener implements TreeListener {
private List collectedEvents;
private volatile boolean finished = false;
public InternalTreeListener(List eventList) {
collectedEvents = eventList;
}
public synchronized boolean next(TreeEvent event) {
collectedEvents.add(event);
return true;
}
public synchronized void finished(TreeEvent event) {
collectedEvents.add(event);
finished = true;
notify();
}
public List getCollectedEvents() {
return collectedEvents;
}
public boolean isFinished() {
return finished;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy