001: /*_############################################################################
002: _##
003: _## SNMP4J-AgentX - AgentXSharedMOTableSupport.java
004: _##
005: _## Copyright (C) 2005-2007 Frank Fock (SNMP4J.org)
006: _##
007: _## This program is free software; you can redistribute it and/or modify
008: _## it under the terms of the GNU General Public License version 2 as
009: _## published by the Free Software Foundation.
010: _##
011: _## This program is distributed in the hope that it will be useful,
012: _## but WITHOUT ANY WARRANTY; without even the implied warranty of
013: _## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: _## GNU General Public License for more details.
015: _##
016: _## You should have received a copy of the GNU General Public License
017: _## along with this program; if not, write to the Free Software
018: _## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
019: _## MA 02110-1301 USA
020: _##
021: _##########################################################################*/
022:
023: package org.snmp4j.agent.agentx.subagent;
024:
025: import java.io.IOException;
026:
027: import org.snmp4j.agent.agentx.*;
028: import org.snmp4j.agent.mo.*;
029: import org.snmp4j.log.LogAdapter;
030: import org.snmp4j.log.LogFactory;
031: import org.snmp4j.smi.*;
032: import org.snmp4j.agent.agentx.subagent.index.AnyNewIndexOID;
033: import org.snmp4j.agent.agentx.subagent.index.NewIndexOID;
034:
035: /**
036: * The <code>AgentXSharedMOTableSupport</code> provides helper functions for
037: * shared table implementations to register rows and indexes at a master agent.
038: *
039: * @author Frank Fock
040: * @version 1.0
041: */
042: public class AgentXSharedMOTableSupport implements MOTableRowListener {
043:
044: private static final LogAdapter LOGGER = LogFactory
045: .getLogger(AgentXSharedMOTableSupport.class);
046:
047: public static final int INDEX_MODE_ALLOCATE = AgentXProtocol.FLAG_ALLOCATE_INDEX;
048: public static final int INDEX_MODE_ANY_INDEX = AgentXProtocol.FLAG_ANY_INDEX;
049: public static final int INDEX_MODE_NEW_INDEX = AgentXProtocol.FLAG_NEW_INDEX;
050:
051: private AgentX agentX;
052: private AgentXSession session;
053: private OctetString context;
054: private byte priority = AgentXProtocol.DEFAULT_PRIORITY;
055: private byte indexMode = INDEX_MODE_ALLOCATE;
056:
057: /**
058: * Creates a shared table support object for a AgentX connection, session,
059: * and context.
060: *
061: * @param agentX
062: * an AgentX connection.
063: * @param session
064: * an AgentXSession session (does not need to be open at creation time).
065: * @param context
066: * a context ("" by default).
067: */
068: public AgentXSharedMOTableSupport(AgentX agentX,
069: AgentXSession session, OctetString context) {
070: this .agentX = agentX;
071: this .session = session;
072: this .context = context;
073: }
074:
075: /**
076: * Creates a shared table support object for a AgentX connection, session,
077: * and context.
078: *
079: * @param agentX
080: * an AgentX connection.
081: * @param session
082: * an AgentXSession session (does not need to be open at creation time).
083: * @param context
084: * a context ("" by default).
085: * @param priority
086: * the registration priority used for this shared table support.
087: * @param indexAllocationMode
088: * the index allocation mode to be used as default for this shared table.
089: */
090: public AgentXSharedMOTableSupport(AgentX agentX,
091: AgentXSession session, OctetString context, byte priority,
092: byte indexAllocationMode) {
093: this (agentX, session, context);
094: this .priority = priority;
095: this .indexMode = indexAllocationMode;
096: }
097:
098: /**
099: * Process shared table row events. If index mode is
100: * {@link #INDEX_MODE_ALLOCATE} this method will do nothing if the associated
101: * AgentX session is closed. For other index modes, the event's veto status
102: * will be set to the AgentX error {@link AgentXProtocol#AGENTX_NOT_OPEN}.
103: * <p>
104: * If the index OID of a created row has zero length then, depending on the
105: * current index mode, a new or any new index is allocated at the master
106: * agent.
107: *
108: * @param event
109: * a <code>MOTableRowEvent</code> indicating a row change in an AgentX
110: * shared table.
111: */
112: public void rowChanged(MOTableRowEvent event) {
113: if ((indexMode == INDEX_MODE_ALLOCATE)
114: && getSession().isClosed()) {
115: // ignore closed session for allocation mode
116: if (LOGGER.isInfoEnabled()) {
117: LOGGER
118: .info("Row event "
119: + event
120: + " ignored, because session to master agent is closed: "
121: + getSession());
122: }
123: return;
124: }
125: switch (event.getType()) {
126: case MOTableRowEvent.CREATE: {
127: OID index2Allocate = event.getRow().getIndex();
128: int status = allocateIndex(context, event.getTable()
129: .getIndexDef(),
130: (event.getRow().getIndex().size() == 0) ? indexMode
131: : 0, index2Allocate);
132: if (status != AgentXProtocol.AGENTX_SUCCESS) {
133: event.setVetoStatus(status);
134: }
135: break;
136: }
137: case MOTableRowEvent.ADD: {
138: int status = registerRow(event.getTable(), event.getRow());
139: if (status != AgentXProtocol.AGENTX_SUCCESS) {
140: event.setVetoStatus(status);
141: }
142: break;
143: }
144: case MOTableRowEvent.DELETE: {
145: int status = unregisterRow(event.getTable(), event.getRow());
146: if (status != AgentXProtocol.AGENTX_SUCCESS) {
147: event.setVetoStatus(status);
148: } else {
149: OID index2Deallocate = event.getRow().getIndex();
150: status = deallocateIndex(context, event.getTable()
151: .getIndexDef(), index2Deallocate);
152: }
153: break;
154: }
155: default: {
156: if (LOGGER.isDebugEnabled()) {
157: LOGGER.debug("Ignored AgentX shared table event "
158: + event);
159: }
160: }
161: }
162: }
163:
164: /**
165: * Allocate a new or any index at the master agent and return its value in
166: * <code>allocateIndex</code>.
167: *
168: * @param context
169: * the context for which to allocate the index. Specify an empty
170: * <code>OctetString</code> for the default context.
171: * @param indexDef
172: * the index definition with OID values for sub-index definitions.
173: * @param indexAllocationMode
174: * one of {@link AgentXProtocol#FLAG_ANY_INDEX},
175: * {@link AgentXProtocol#FLAG_NEW_INDEX}, or 0 (if index value is supplied
176: * by <code>allocateIndex</code>).
177: * @param allocatedIndex
178: * the index value to allocate or if <code>indexAllocationMode</code> is
179: * not zero then an (arbitrary non-null OID) which returns the allocated
180: * new index value. If <code>allocateIndex</code> is an instance of
181: * {@link AnyNewIndexOID} or {@link NewIndexOID} the index value of the
182: * row will be replaced by a globally unique index value allocated by the
183: * master agent. The caller is responsible for changing the rows index
184: * in the table model of the shared table.
185: * @return
186: * {@link AgentXProtocol#AGENTX_SUCCESS} if the index could be allocated
187: * or an AgentX protocol error code if allocation failed and
188: * <code>allocateIndex</code> is not altered.
189: */
190: public int allocateIndex(OctetString context,
191: MOTableIndex indexDef, byte indexAllocationMode,
192: OID allocatedIndex) {
193: VariableBinding[] vbs = new VariableBinding[indexDef.size()];
194: Variable[] indexValues;
195: if (allocatedIndex instanceof AnyNewIndexOID) {
196: indexAllocationMode = INDEX_MODE_ANY_INDEX;
197: } else if (allocatedIndex instanceof NewIndexOID) {
198: indexAllocationMode = INDEX_MODE_NEW_INDEX;
199: }
200: if (indexAllocationMode == 0) {
201: indexValues = indexDef.getIndexValues(allocatedIndex);
202: } else {
203: indexValues = new Variable[indexDef.size()];
204: for (int i = 0; i < indexDef.size(); i++) {
205: MOTableSubIndex subIndex = indexDef.getIndex(i);
206: indexValues[i] = AbstractVariable
207: .createFromSyntax(subIndex.getSmiSyntax());
208: }
209: }
210: for (int i = 0; i < indexDef.size(); i++) {
211: MOTableSubIndex subIndex = indexDef.getIndex(i);
212: OID oid = subIndex.getOid();
213: if (oid == null) {
214: throw new IllegalArgumentException("Sub-index " + i
215: + " has no OID");
216: }
217: vbs[i] = new VariableBinding();
218: vbs[i].setOid(oid);
219: vbs[i].setVariable(indexValues[i]);
220: }
221: AgentXIndexAllocatePDU pdu = new AgentXIndexAllocatePDU(
222: context, vbs);
223: if (indexAllocationMode != 0) {
224: pdu.addFlag(indexAllocationMode);
225: }
226: pdu.setSessionAttributes(session);
227: try {
228: AgentXResponseEvent response = agentX.send(pdu, session
229: .createAgentXTarget(), session.getPeer()
230: .getTransport());
231: if (response.getResponse() != null) {
232: AgentXResponsePDU resp = response.getResponse();
233: if (resp.getErrorStatus() == AgentXProtocol.AGENTX_SUCCESS) {
234: OID index = indexDef.getIndexOID(getVariables(resp
235: .getVariableBindings()));
236: allocatedIndex.setValue(index.getValue());
237: if (LOGGER.isDebugEnabled()) {
238: LOGGER.debug("Allocated index "
239: + allocatedIndex + " for context "
240: + context + " and index definition "
241: + indexDef);
242: }
243: } else {
244: if (LOGGER.isDebugEnabled()) {
245: LOGGER
246: .debug("Index allocation failed for context "
247: + context
248: + " and index definition "
249: + indexDef
250: + " with value "
251: + allocatedIndex);
252: }
253: }
254: return resp.getErrorStatus();
255: } else {
256: return AgentXProtocol.AGENTX_TIMEOUT;
257: }
258: } catch (IOException ex) {
259: LOGGER.error("Failed to allocate index " + indexDef
260: + " at " + session, ex);
261: }
262: return AgentXProtocol.AGENTX_DISCONNECT;
263: }
264:
265: /**
266: * Deallocate an index at the master agent.
267: *
268: * @param context
269: * the context for which to allocate the index. Specify an empty
270: * <code>OctetString</code> for the default context.
271: * @param indexDef
272: * the index definition with OID values for sub-index definitions.
273: * @param allocatedIndex
274: * the index value of the previously allocated index.
275: * @return
276: * {@link AgentXProtocol#AGENTX_SUCCESS} if the index could be deallocated
277: * or an AgentX protocol error code if deallocation failed.
278: */
279: public int deallocateIndex(OctetString context,
280: MOTableIndex indexDef, OID allocatedIndex) {
281: VariableBinding[] vbs = new VariableBinding[indexDef.size()];
282: Variable[] indexValues = indexDef
283: .getIndexValues(allocatedIndex);
284: for (int i = 0; i < indexDef.size(); i++) {
285: vbs[i] = new VariableBinding();
286: MOTableSubIndex subIndex = indexDef.getIndex(i);
287: OID oid = subIndex.getOid();
288: if (oid == null) {
289: throw new IllegalArgumentException("Sub-index " + i
290: + " has no OID");
291: }
292: vbs[i].setOid(oid);
293: vbs[i].setVariable(indexValues[i]);
294: }
295: AgentXIndexDeallocatePDU pdu = new AgentXIndexDeallocatePDU(
296: context, vbs);
297: pdu.setSessionAttributes(session);
298: try {
299: AgentXResponseEvent response = agentX.send(pdu, session
300: .createAgentXTarget(), session.getPeer()
301: .getTransport());
302: if (response.getResponse() != null) {
303: AgentXResponsePDU resp = response.getResponse();
304: return resp.getErrorStatus();
305: } else {
306: return AgentXProtocol.AGENTX_TIMEOUT;
307: }
308: } catch (IOException ex) {
309: LOGGER.error("Failed to deallocate index " + indexDef
310: + " at " + session, ex);
311: }
312: return AgentXProtocol.AGENTX_DISCONNECT;
313: }
314:
315: public int registerRow(MOTable table, MOTableRow row2Register) {
316: OID subtree = new OID(table.getOID());
317: subtree.append(table.getColumn(0).getColumnID());
318: subtree.append(row2Register.getIndex());
319: AgentXRegisterPDU pdu = new AgentXRegisterPDU(context, subtree,
320: priority, (byte) (table.getOID().size() + 1), table
321: .getColumn(table.getColumnCount() - 1)
322: .getColumnID());
323: if (table.getColumnCount() == 1) {
324: pdu.addFlag(AgentXProtocol.FLAG_INSTANCE_REGISTRATION);
325: }
326: pdu.setSessionAttributes(session);
327: try {
328: AgentXResponseEvent resp = agentX.send(pdu, session
329: .createAgentXTarget(), session.getPeer()
330: .getTransport());
331: if (resp.getResponse() == null) {
332: return AgentXProtocol.AGENTX_TIMEOUT;
333: } else if (resp.getResponse().getErrorStatus() != AgentXProtocol.AGENTX_SUCCESS) {
334: return resp.getResponse().getErrorStatus();
335: }
336: } catch (IOException ex) {
337: LOGGER.error(
338: "Failed to send AgentXRegister pdu " + pdu + " to "
339: + session + " because: " + ex.getMessage(),
340: ex);
341: return AgentXProtocol.AGENTX_DISCONNECT;
342: }
343: return AgentXProtocol.AGENTX_SUCCESS;
344: }
345:
346: public int unregisterRow(MOTable table, MOTableRow row2Unregister) {
347: OID subtree = new OID(table.getOID());
348: subtree.append(table.getColumn(0).getColumnID());
349: subtree.append(row2Unregister.getIndex());
350: AgentXUnregisterPDU pdu = new AgentXUnregisterPDU(context,
351: subtree, priority, (byte) (table.getOID().size() + 1),
352: table.getColumn(table.getColumnCount() - 1)
353: .getColumnID());
354: pdu.setSessionAttributes(session);
355: try {
356: AgentXResponseEvent resp = agentX.send(pdu, session
357: .createAgentXTarget(), session.getPeer()
358: .getTransport());
359: if (resp.getResponse() == null) {
360: return AgentXProtocol.AGENTX_TIMEOUT;
361: } else if (resp.getResponse().getErrorStatus() != AgentXProtocol.AGENTX_SUCCESS) {
362: return resp.getResponse().getErrorStatus();
363: }
364: } catch (IOException ex) {
365: LOGGER.error(
366: "Failed to send AgentXRegister pdu " + pdu + " to "
367: + session + " because: " + ex.getMessage(),
368: ex);
369: return AgentXProtocol.AGENTX_DISCONNECT;
370: }
371: return AgentXProtocol.AGENTX_SUCCESS;
372: }
373:
374: private static Variable[] getVariables(VariableBinding[] vbs) {
375: Variable[] variables = new Variable[vbs.length];
376: for (int i = 0; i < vbs.length; i++) {
377: variables[i] = vbs[i].getVariable();
378: }
379: return variables;
380: }
381:
382: public void setPriority(byte priority) {
383: this .priority = priority;
384: }
385:
386: /**
387: * Sets the AgentX session to be used for this shared table support.
388: * @param session
389: * an <code>AgentXSession</code> instance.
390: */
391: public void setSession(AgentXSession session) {
392: this .session = session;
393: }
394:
395: /**
396: * Sets the index mode to be used by this shared table support object.
397: * {@link #INDEX_MODE_ALLOCATE} simply allocates index values at the master
398: * agent, whereas {@link #INDEX_MODE_ANY_INDEX} fetches any currently
399: * unique index value from the master agent for a new row and
400: * {@link #INDEX_MODE_NEW_INDEX} fetches a new index (never used before by
401: * the master).
402: * @param indexMode
403: * an index mode to be used for shared tables supported by this object.
404: */
405: public void setIndexMode(byte indexMode) {
406: this .indexMode = indexMode;
407: }
408:
409: public void setContext(OctetString context) {
410: this .context = context;
411: }
412:
413: public byte getPriority() {
414: return priority;
415: }
416:
417: /**
418: * Gets the AgentX session used by this shared table support object.
419: * @return
420: * an <code>AgentXSession</code> instance or <code>null</code> if there
421: * is no connection/session established with the master agent.
422: */
423: public AgentXSession getSession() {
424: return session;
425: }
426:
427: public byte getIndexMode() {
428: return indexMode;
429: }
430:
431: public OctetString getContext() {
432: return context;
433: }
434:
435: public AgentX getAgentX() {
436: return agentX;
437: }
438:
439: }
|