001: /*_############################################################################
002: _##
003: _## SNMP4J-Agent - MOScalar.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 java.io.*;
024: import java.util.*;
025:
026: import org.snmp4j.agent.*;
027: import org.snmp4j.agent.io.*;
028: import org.snmp4j.agent.request.*;
029: import org.snmp4j.mp.*;
030: import org.snmp4j.smi.*;
031:
032: /**
033: * The <code>MOScalar</code> class represents scalar SNMP managed objects.
034: *
035: * @author Frank Fock
036: * @version 1.0
037: */
038: public class MOScalar implements ManagedObject, MOScope,
039: SerializableManagedObject {
040:
041: private OID oid;
042: private volatile OID lowerBound;
043: private volatile OID upperBound;
044: private Variable value;
045: private MOAccess access;
046: private boolean isVolatile;
047: private transient Vector moValueValidationListeners;
048: private transient Vector moChangeListeners;
049:
050: /**
051: * Creates a scalar MO instance with OID, maximum access level and initial
052: * value.
053: * @param id
054: * the instance OID of the scalar instance (last sub-identifier should be
055: * zero).
056: * @param access
057: * the maximum access level supported by this instance.
058: * @param value
059: * the initial value of the scalar instance. If the initial value is
060: * <code>null</code> or a Counter syntax, the scalar is created as a
061: * volatile (non-persistent) instance by default.
062: */
063: public MOScalar(OID id, MOAccess access, Variable value) {
064: this .oid = id;
065: this .access = access;
066: this .value = value;
067: this .isVolatile = isVolatileByDefault(value);
068: }
069:
070: private static boolean isVolatileByDefault(Variable value) {
071: if (value == null) {
072: return true;
073: }
074: switch (value.getSyntax()) {
075: case SMIConstants.SYNTAX_COUNTER32:
076: case SMIConstants.SYNTAX_COUNTER64: {
077: return true;
078: }
079: default:
080: return false;
081: }
082: }
083:
084: /**
085: * Returns the scope of OIDs that are covered by this scalar's object
086: * registration. This range is
087: * <code>1.3.6...n</code> <= x < <code>1.3.6...n+1</code> where n is the
088: * last subidentifier of the OID registred by the corresponding OBJECT-TYPE
089: * definition. Prior to version 1.1.2, this method returned a scope equal
090: * to the scope now returned by {@link #getSingleInstanceScope()}.
091: *
092: * @return
093: * a MOScope that covers the OIDs by this scalar object registration.
094: */
095: public MOScope getScope() {
096: return this ;
097: }
098:
099: /**
100: * Returns a scope that covers only the scalar instance itself without any
101: * possible OIDs down in the tree or at the same level.
102: * @return
103: * a scope that covers exactly the OID of this scalar.
104: * @since 1.1.2
105: */
106: public MOScope getSingleInstanceScope() {
107: return new DefaultMOScope(oid, true, oid, true);
108: }
109:
110: public OID find(MOScope range) {
111: if (access.isAccessibleForRead()
112: && range.isCovered(getSingleInstanceScope())) {
113: return oid;
114: }
115: return null;
116: }
117:
118: public void get(SubRequest request) {
119: RequestStatus status = request.getStatus();
120: if (checkRequestScope(request)) {
121: if (access.isAccessibleForRead()) {
122: VariableBinding vb = request.getVariableBinding();
123: vb.setOid(getOid());
124: vb.setVariable((Variable) getValue().clone());
125: request.completed();
126: } else {
127: status
128: .setErrorStatus(SnmpConstants.SNMP_ERROR_NO_ACCESS);
129: }
130: }
131: }
132:
133: private boolean checkRequestScope(SubRequest request) {
134: if (!request.getVariableBinding().getOid().equals(oid)) {
135: VariableBinding vb = request.getVariableBinding();
136: vb.setOid(getOid());
137: vb.setVariable(Null.noSuchInstance);
138: request.completed();
139: return false;
140: }
141: return true;
142: }
143:
144: public boolean next(SubRequest request) {
145: if (access.isAccessibleForRead()
146: && (request.getScope()
147: .isCovered(getSingleInstanceScope()))) {
148: VariableBinding vb = request.getVariableBinding();
149: vb.setOid(getOid());
150: vb.setVariable((Variable) getValue().clone());
151: request.completed();
152: return true;
153: }
154: return false;
155: }
156:
157: /**
158: * Checks whether the new value contained in the supplied sub-request is a
159: * valid value for this object. The checks are performed by firing a
160: * {@link MOValueValidationEvent} the registered listeners.
161: *
162: * @param request
163: * the <code>SubRequest</code> with the new value.
164: * @return
165: * {@link SnmpConstants#SNMP_ERROR_SUCCESS} if the new value is OK,
166: * any other appropriate SNMPv2/v3 error status if not.
167: */
168: public int isValueOK(SubRequest request) {
169: if (moValueValidationListeners != null) {
170: Variable oldValue = value;
171: Variable newValue = request.getVariableBinding()
172: .getVariable();
173: MOValueValidationEvent event = new MOValueValidationEvent(
174: this , oldValue, newValue);
175: fireValidate(event);
176: return event.getValidationStatus();
177: }
178: return SnmpConstants.SNMP_ERROR_SUCCESS;
179: }
180:
181: public void prepare(SubRequest request) {
182: RequestStatus status = request.getStatus();
183: if (oid.equals(request.getVariableBinding().getOid())) {
184: if (access.isAccessibleForWrite()) {
185: VariableBinding vb = request.getVariableBinding();
186: if (vb.getVariable().getSyntax() != getValue()
187: .getSyntax()) {
188: status
189: .setErrorStatus(SnmpConstants.SNMP_ERROR_WRONG_TYPE);
190: return;
191: }
192: if (moChangeListeners != null) {
193: MOChangeEvent event = new MOChangeEvent(this , this ,
194: request.getVariableBinding().getOid(),
195: getValue(), request.getVariableBinding()
196: .getVariable(), true);
197: fireBeforePrepareMOChange(event);
198: if (event.getDenyReason() != SnmpConstants.SNMP_ERROR_SUCCESS) {
199: status.setErrorStatus(event.getDenyReason());
200: status.setPhaseComplete(true);
201: return;
202: }
203: }
204: int valueOK = isValueOK(request);
205: if ((moChangeListeners != null)
206: && (valueOK == SnmpConstants.SNMP_ERROR_SUCCESS)) {
207: MOChangeEvent event = new MOChangeEvent(this , this ,
208: request.getVariableBinding().getOid(),
209: getValue(), request.getVariableBinding()
210: .getVariable(), true);
211: fireAfterPrepareMOChange(event);
212: valueOK = event.getDenyReason();
213: }
214: status.setErrorStatus(valueOK);
215: status.setPhaseComplete(true);
216: } else {
217: status
218: .setErrorStatus(SnmpConstants.SNMP_ERROR_NOT_WRITEABLE);
219: }
220: } else {
221: status.setErrorStatus(SnmpConstants.SNMP_ERROR_NO_CREATION);
222: }
223: }
224:
225: public void commit(SubRequest request) {
226: RequestStatus status = request.getStatus();
227: VariableBinding vb = request.getVariableBinding();
228: if (moChangeListeners != null) {
229: MOChangeEvent event = new MOChangeEvent(this , this , vb
230: .getOid(), getValue(), vb.getVariable(), false);
231: fireBeforeMOChange(event);
232: }
233: request.setUndoValue(getValue());
234: setValue(vb.getVariable());
235: status.setPhaseComplete(true);
236: if (moChangeListeners != null) {
237: MOChangeEvent event = new MOChangeEvent(this , this , request
238: .getVariableBinding().getOid(), (Variable) request
239: .getUndoValue(), vb.getVariable(), false);
240: fireAfterMOChange(event);
241: }
242: }
243:
244: public void undo(SubRequest request) {
245: RequestStatus status = request.getStatus();
246: if ((request.getUndoValue() != null)
247: && (request.getUndoValue() instanceof Variable)) {
248: int errorStatus = setValue((Variable) request
249: .getUndoValue());
250: status.setErrorStatus(errorStatus);
251: status.setPhaseComplete(true);
252: } else {
253: status.setErrorStatus(SnmpConstants.SNMP_ERROR_UNDO_FAILED);
254: }
255: }
256:
257: public void cleanup(SubRequest request) {
258: request.setUndoValue(null);
259: request.getStatus().setPhaseComplete(true);
260: }
261:
262: /**
263: * Gets the instance OID of this scalar managed object.
264: * @return
265: * the instance OID (by reference).
266: */
267: public OID getOid() {
268: return oid;
269: }
270:
271: public OID getLowerBound() {
272: if (lowerBound == null) {
273: lowerBound = new OID(oid.getValue(), 0, oid.size() - 1);
274: }
275: return lowerBound;
276: }
277:
278: public OID getUpperBound() {
279: if (upperBound == null) {
280: upperBound = new OID(getLowerBound().nextPeer());
281: }
282: return upperBound;
283: }
284:
285: public boolean isCovered(MOScope other) {
286: return (other.getLowerBound().startsWith(oid) && (other
287: .getLowerBound().size() > oid.size() || other
288: .isLowerIncluded()))
289: && (other.getUpperBound().startsWith(oid) && ((other
290: .getUpperBound().size() > oid.size()) || other
291: .isUpperIncluded()));
292: }
293:
294: public boolean isLowerIncluded() {
295: return false;
296: }
297:
298: public boolean isUpperIncluded() {
299: return false;
300: }
301:
302: /**
303: * Returns the actual value of this scalar managed object. For a basic
304: * instrumentation, overwrite this method to provide always the actual
305: * value and/or to update the internal <code>value</code> member and
306: * call <code>super.</code>{@link #getValue()}.
307: *
308: * @return
309: * a non <code>null</code> Variable with the same syntax defined for
310: * this scalar object.
311: */
312: public Variable getValue() {
313: return value;
314: }
315:
316: public boolean isVolatile() {
317: return isVolatile;
318: }
319:
320: /**
321: * Sets the value of this scalar managed object without checking it for
322: * the correct syntax.
323: * @param value
324: * a Variable with the with the same syntax defined for
325: * this scalar object (not checked).
326: * @return
327: * a SNMP error code (zero indicating success by default).
328: */
329: public int setValue(Variable value) {
330: this .value = value;
331: return SnmpConstants.SNMP_ERROR_SUCCESS;
332: }
333:
334: /**
335: * Sets the volatile flag for this instance.
336: * @param isVolatile
337: * if <code>true</code> the state of this object will not be persistently
338: * stored, otherwise the agent may save the state of this object
339: * persistently.
340: */
341: public void setVolatile(boolean isVolatile) {
342: this .isVolatile = isVolatile;
343: }
344:
345: public boolean isOverlapping(MOScope other) {
346: return DefaultMOScope.overlaps(this , other);
347: }
348:
349: /**
350: * Adds a value validation listener to check new values.
351: * @param l
352: * a <code>MOValueValidationListener</code> instance.
353: */
354: public synchronized void addMOValueValidationListener(
355: MOValueValidationListener l) {
356: if (moValueValidationListeners == null) {
357: moValueValidationListeners = new Vector(2);
358: }
359: moValueValidationListeners.add(l);
360: }
361:
362: /**
363: * Removes a value validation listener
364: * @param l
365: * a <code>MOValueValidationListener</code> instance.
366: */
367: public synchronized void removeMOValueValidationListener(
368: MOValueValidationListener l) {
369: if (moValueValidationListeners != null) {
370: moValueValidationListeners.remove(l);
371: }
372: }
373:
374: protected void fireValidate(MOValueValidationEvent validationEvent) {
375: if (moValueValidationListeners != null) {
376: Vector listeners = moValueValidationListeners;
377: int count = listeners.size();
378: for (int i = 0; i < count; i++) {
379: ((MOValueValidationListener) listeners.elementAt(i))
380: .validate(validationEvent);
381: }
382: }
383: }
384:
385: public OID getID() {
386: return getOid();
387: }
388:
389: public synchronized void load(MOInput input) throws IOException {
390: Variable v = input.readVariable();
391: setValue(v);
392: }
393:
394: public synchronized void save(MOOutput output) throws IOException {
395: output.writeVariable(value);
396: }
397:
398: public boolean covers(OID oid) {
399: return oid.startsWith(this .oid);
400: }
401:
402: public String toString() {
403: return getClass().getName() + "[oid=" + getOid() + ",access="
404: + access + ",value=" + getValue() + ",volatile="
405: + isVolatile() + toStringDetails() + "]";
406: }
407:
408: protected String toStringDetails() {
409: return "";
410: }
411:
412: /**
413: * Adds a <code>MOChangeListener</code> that needs to be informed about
414: * state changes of this scalar.
415: * @param l
416: * a <code>MOChangeListener</code> instance.
417: * @since 1.1
418: */
419: public synchronized void addMOChangeListener(MOChangeListener l) {
420: if (moChangeListeners == null) {
421: moChangeListeners = new Vector(2);
422: }
423: moChangeListeners.add(l);
424: }
425:
426: /**
427: * Removes a <code>MOChangeListener</code>.
428: * @param l
429: * a <code>MOChangeListener</code> instance.
430: * @since 1.1
431: */
432: public synchronized void removeMOChangeListener(MOChangeListener l) {
433: if (moChangeListeners != null) {
434: moChangeListeners.remove(l);
435: }
436: }
437:
438: protected void fireBeforePrepareMOChange(MOChangeEvent changeEvent) {
439: if (moChangeListeners != null) {
440: Vector listeners = moChangeListeners;
441: int count = listeners.size();
442: for (int i = 0; i < count; i++) {
443: ((MOChangeListener) listeners.get(i))
444: .beforePrepareMOChange(changeEvent);
445: }
446: }
447: }
448:
449: protected void fireAfterPrepareMOChange(MOChangeEvent changeEvent) {
450: if (moChangeListeners != null) {
451: Vector listeners = moChangeListeners;
452: int count = listeners.size();
453: for (int i = 0; i < count; i++) {
454: ((MOChangeListener) listeners.get(i))
455: .afterPrepareMOChange(changeEvent);
456: }
457: }
458: }
459:
460: protected void fireBeforeMOChange(MOChangeEvent changeEvent) {
461: if (moChangeListeners != null) {
462: Vector listeners = moChangeListeners;
463: int count = listeners.size();
464: for (int i = 0; i < count; i++) {
465: ((MOChangeListener) listeners.get(i))
466: .beforeMOChange(changeEvent);
467: }
468: }
469: }
470:
471: protected void fireAfterMOChange(MOChangeEvent changeEvent) {
472: if (moChangeListeners != null) {
473: Vector listeners = moChangeListeners;
474: int count = listeners.size();
475: for (int i = 0; i < count; i++) {
476: ((MOChangeListener) listeners.get(i))
477: .afterMOChange(changeEvent);
478: }
479: }
480: }
481: }
|