Architecture - Scalars
FriendlySNMP API presents scalars declared in MIBs as
org.friendlysnmp.FScalar
class objects.
How and where scalars are created
The following discussion uses a scalar imageSize declared in
DEMO-SCALAR-RW-MIB
from a demo application as an example.
This scalar is defined in the MIB as follows:
imageSize OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-write
STATUS current
DESCRIPTION "Image size defined by MIB browser. Valid format is NNNxMMM"
::= { demoMIBObjects 3 }
|
Tools discussed in MIB-to-Java generation
convert the MIB file
DEMO-SCALAR-RW-MIB
into Java class DemoScalarRwMibFriend .
This class has the following structure:
public class DemoScalarRwMibFriend extends BaseMib {
private FScalar imageSize;
. . .
public FScalar getImageSize() {
return imageSize;
}
}
|
The scalar imageSize is initialized when object of the class
DemoScalarRwMibFriend added to the SNMP agent.
How to access scalar object
There are two techniques to get access to FScalar objects.
Technique 1. Direct access from the MIB object using getters
generated for each scalar. This technique is used most of the time:
DemoScalarRwMibFriend mib = new DemoScalarRwMibFriend();
. . .
FScalar scalar = mib.getImageSize();
|
Technique 2. Indirect access from the agent object using scalar OID.
This technique is used very rear, usually when a MIB object is hidden,
for example when MIB is internal to the agent and is not visible from the outside:
import org.snmp4j.mp.SnmpConstants;
. . .
FriendlyAgent agent = new FriendlyAgent();
. . .
FScalar scalar = agent.getScalar(SnmpConstants.sysDescr);
|
Scalar internals
The FScalar class is a wrapper which hides SNMP4J
org.snmp4j.agent.mo.MOScalar managed object.
The class provides
persistency layer and mechanism to add / remove
listeners.
Each scalar object is associated with immutable identifier
org.friendlysnmp.FID .
See also FID.
The scalar FID could be accessed but cannot be modified.
Scalar syntax and value
The FScalar class provides transparent scalar values
access with conversion basic Java objects and primitives to / from
SNMP4J specific org.snmp4j.smi.Variable .
The conversion is driven by scalar syntax declared in the MIB and may throw
an exception.
There are two techniques to set scalar value:
// Technique 1.
try {
scalar.setValue(..);
} catch (FException e) {
// handle the problem
}
// Technique 2.
scalar.setValueEx(..); // report the problem
|
The Technique 1 requires exception handling. Exception is usually thrown
when the new value cannot be properly converted into internal presentation.
Propagating the exception in many cases is not possible and code has only
an option to log the exception.
Code becomes polluted with useless try/catch blocks annoying a developer.
The debugged code throws exceptions of this kind in very rare cases.
The Technique 2 does not require exception handling. Exception is propagated
to the SNMP agent. The application has an option to register listener to
handle exceptions of this kind in the SNMP agent. This option is preferable.
It allows central handling of the exception.
For example, a GUI application may show popup window with the problem.
See section Events and Listeners for details.
Scalar value could be retrieved with the
FScalar.getValue()
method which returns generic Object .
Scalar persistency
Scalar persistency makes sense only for scalars declared with read-write
access in a MIB.
The scalar persistent value is saved into an external to the application
persistent storage and the scalar value restored from it after the application startup.
The scalar value becomes persistent only after successful explicit SNMP SET
request from a MIB browser for non-volatile scalars.
See also Persistency.
The scalar is volatile by default
and its value is not stored in the persistent storage.
Explicit call scalar.setVolatile(false)
is required to enable scalar persistency.
This call also loads scalar persistent value from external storage
if scalar persistent value exists.
This call does nothing for read-only scalar.
private DemoScalarRwMibFriend mib = new DemoScalarRwMibFriend();
. . .
FScalar scalar = mib.getImageSize();
scalar.setVolatile(false); // loads persistent value (if exist)
if (scalar.isPersistLoaded()) {
... use persistent value ...
} else {
... use default value ...
}
|
Scalar GET event and listener
The FScalar class supports listening GET events which are triggered
by MIB browser GET requests.
The following methods in the class allow adding and removing GET listeners:
public void addGetListener(FScalarGetListener l)
public void removeGetListener(FScalarGetListener l)
|
GET listener is called when a MIB browser requests a scalar value.
The GET request from the MIB browser is received
by the SNMP agent in the application.
The SNMP agent keeps collection of all scalars as managed objects.
The application is responsible to update the scalar value in the listener's code
thus making the scalar value correctly reflect the application's current
internal value associated with the scalar. This update is required for
scalars which represent dynamic application values. Example of the code from
demo application to update the scalar:
private JTextField tfImageSize = new JTextField();
. . .
private DemoScalarRwMibFriend mib = new DemoScalarRwMibFriend();
. . .
mib.getImageSize().addGetListener(new FScalarGetListener() {
public void get(FScalar scalar) {
scalar.setValueEx(tfImageSize.getText());
}
});
|
See also Events and Listeners.
Scalar VALIDATE + SET event and listener
The FScalar class supports listening SET events which are triggered
by MIB browser SET requests. Each SET event is prepended with VALIDATION event.
Handling VALIDATION event is optional. It allows rejecting invalid SET request.
The following methods in the class allow adding and removing SET
and optional VALIDATE listeners:
public void addValidationListener(FScalarValidationListener l)
public void removeValidationListener(FScalarValidationListener l)
public void addSetListener(FScalarSetListener l)
public void removeSetListener(FScalarSetListener l)
|
VALIDATE listener is called when a MIB browser attempts to SET a new value
to the scalar.
This listener makes no sense for read-only scalar and it is not called
at all for it.
Missing VALIDATE listener for read-write scalar allows MIB browser
to set any new value.
SET listener is called when a MIB browser attempts to SET a new value
and VALIDATION listener is missing or it allows the new value.
The application is responsible for updating its internal copy of the
value associated with the new scalar value and starting to use it.
Example of the listeners code to VALIDATE and SET scalar value:
private JTextField tfImageSize = new JTextField();
. . .
private DemoScalarRwMibFriend mib = new DemoScalarRwMibFriend();
. . .
// Validate new value
mib.getImageSize().addValidationListener(new FScalarValidationListener() {
public ValueValidation validate(FScalar scalar, Object objValue) {
String sValue = objValue.toString();
if (some condition) {
return ValueValidation.WRONG_VALUE;
}
return ValueValidation.SUCCESS;
}
});
// Set new value
mib.getImageSize().addSetListener(new FScalarSetListener() {
public void get(FScalar scalar) {
public void set(FScalar scalar) {
tfImageSize.setText(scalar.getValue().toString());
}
}
});
|
Restore default value
Each read-write scalar over the lifetime has two sources of values:
default value which is initially set in the agent and a value which is set from
a MIB browser and preserved in a persistency storage.
It is very difficult to rollback scalar value
to a default after a new value is set from a MIB browser.
The FriendlySNMP API provides an option to remove scalar value from persistency
storage. The access to the scalars persistency storage is provided in
FRIENDLY-SNMP-MIB .
The agent is notified about this action via SET operation. It is agent's
responsibility to handle this type of events with the following
RESTORE DEFAULTS listeners:
public void addRestoreDefaultListener(FRestoreDefaultListener l)
public void removeRestoreDefaultListener(FRestoreDefaultListener l)
|
Missing RESTORE DEFAULT listeners is not a disaster for the application if
the application is restarted to pick up the new persistency storage state.
Example of the listener code to RESTORE DEFAULT scalar value:
private final static String IMAGE_SIZE = "800x600";
private JTextField tfImageSize = new JTextField();
. . .
private DemoScalarRwMibFriend mib = new DemoScalarRwMibFriend();
. . .
mib.getImageSize().addRestoreDefaultListener(new FRestoreDefaultListener() {
public void restoreDefault(FRestoreDefaultEvent e) throws FException {
FScalar scalar = e.getScalar();
scalar.setValue(IMAGE_SIZE);
tfImageSize.setText(scalar.getValue().toString());
}
});
|
Static and dynamic scalar
Static scalar has a value which never (or very rare) changes during a lifetime
of the application.
Usually these types of values are read-only scalars.
Examples of such scalars are application name,
working directory, startup time, and so on.
The value of a static scalar should be set explicitly
without using GET listeners overhead.
Application may set value of
a static scalar at startup and do not keep a working copy of this scalar value.
MIB browser GET request is satisfied with a scalar value which is already set
in the scalar object.
Dynamic scalar has a value which is changing frequently in the code.
Application with read-only scalar should provide
GET listener to handle MIB browser request to access this scalar.
Application with read-write scalar should provide
at minimum GET and SET listeners to handle MIB browser request to access this scalar.
|