001: /*_############################################################################
002: _##
003: _## SNMP4J-AgentX - AgentXRequest.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.util.*;
026:
027: import org.snmp4j.*;
028: import org.snmp4j.mp.*;
029: import org.snmp4j.smi.*;
030: import org.snmp4j.agent.DefaultMOContextScope;
031: import org.snmp4j.agent.MOScope;
032: import org.snmp4j.agent.ManagedObject;
033: import org.snmp4j.log.LogAdapter;
034: import org.snmp4j.log.LogFactory;
035: import org.snmp4j.agent.request.AbstractRequest;
036: import org.snmp4j.agent.request.SubRequest;
037: import org.snmp4j.agent.request.SubRequestIterator;
038: import org.snmp4j.agent.request.RequestStatusListener;
039: import org.snmp4j.agent.request.RequestStatus;
040: import org.snmp4j.agent.request.RequestStatusEvent;
041: import org.snmp4j.agent.agentx.AgentXResponsePDU;
042: import org.snmp4j.agent.agentx.AgentXGetBulkPDU;
043: import org.snmp4j.agent.agentx.AgentXRequestPDU;
044: import org.snmp4j.agent.agentx.AgentXVariableBindingPDU;
045: import org.snmp4j.agent.agentx.AgentXPDU;
046: import org.snmp4j.agent.agentx.AgentXContextPDU;
047: import org.snmp4j.agent.agentx.AgentXCommandEvent;
048: import org.snmp4j.agent.MOQuery;
049: import org.snmp4j.agent.request.SubRequestIteratorSupport;
050: import org.snmp4j.agent.request.Request;
051:
052: /**
053: * The <code>AgentXRequest</code> class represents AgentX sub-agent requests.
054: * AgentX sub-agent requests are similar to SNMP requests but especially for
055: * SET request processing and query scopes differences apply.
056: *
057: * @author Frank Fock
058: * @version 1.0
059: */
060: public class AgentXRequest extends AbstractRequest {
061:
062: private static final LogAdapter logger = LogFactory
063: .getLogger(AgentXRequest.class);
064:
065: public static final OctetString DEFAULT_CONTEXT = new OctetString();
066:
067: private AgentXCommandEvent requestEvent;
068: private AgentXResponsePDU response;
069:
070: private static int nextTransactionID = 0;
071:
072: public AgentXRequest(AgentXCommandEvent request) {
073: this .requestEvent = request;
074: correctRequestValues();
075: this .transactionID = nextTransactionID();
076: }
077:
078: public static int nextTransactionID() {
079: return nextTransactionID++;
080: }
081:
082: public int size() {
083: if (requestEvent.getCommand() instanceof AgentXRequestPDU) {
084: return ((AgentXRequestPDU) requestEvent.getCommand())
085: .size();
086: } else if (requestEvent.getCommand() instanceof AgentXVariableBindingPDU) {
087: return ((AgentXVariableBindingPDU) requestEvent
088: .getCommand()).size();
089: }
090: return 0;
091: }
092:
093: public boolean isBulkRequest() {
094: return requestEvent.getCommand().getType() == AgentXPDU.AGENTX_GETBULK_PDU;
095: }
096:
097: private void correctRequestValues() {
098: AgentXPDU request = requestEvent.getCommand();
099: if (request instanceof AgentXGetBulkPDU) {
100: repeaterStartIndex = getNonRepeaters();
101: repeaterRowSize = Math.max(size() - repeaterStartIndex, 0);
102: } else {
103: repeaterStartIndex = 0;
104: repeaterRowSize = size();
105: }
106: }
107:
108: protected void setupSubRequests() {
109: int capacity = size();
110: int totalRepetitions = 0;
111: if (requestEvent.getCommand() instanceof AgentXGetBulkPDU) {
112: totalRepetitions = repeaterRowSize * getMaxRepetitions();
113: }
114: subrequests = new ArrayList(capacity + totalRepetitions);
115: if (response == null) {
116: response = createResponse();
117: }
118: if (requestEvent.getCommand() instanceof AgentXRequestPDU) {
119: AgentXRequestPDU rangeRequest = (AgentXRequestPDU) requestEvent
120: .getCommand();
121: MOScope[] ranges = rangeRequest.getRanges();
122: for (int i = 0; i < ranges.length; i++) {
123: AgentXSubRequest subReq = new AgentXSubRequest(
124: new DefaultMOContextScope(getContext(),
125: ranges[i]), i);
126: addSubRequest(subReq);
127: }
128: } else if (requestEvent.getCommand() instanceof AgentXVariableBindingPDU) {
129: AgentXVariableBindingPDU vbRequest = (AgentXVariableBindingPDU) requestEvent
130: .getCommand();
131: VariableBinding[] vbs = vbRequest.getVariableBindings();
132: for (int i = 0; i < vbs.length; i++) {
133: AgentXSubRequest subReq = new AgentXSubRequest(vbs[i],
134: i);
135: addSubRequest(subReq);
136: }
137: }
138: if (logger.isDebugEnabled()) {
139: logger.debug("AgentXSubRequests initialized: "
140: + subrequests);
141: }
142: }
143:
144: public int getMaxRepetitions() {
145: if (requestEvent.getCommand() instanceof AgentXGetBulkPDU) {
146: return ((AgentXGetBulkPDU) requestEvent.getCommand())
147: .getMaxRepetitions() & 0xFFFF;
148: }
149: return 0;
150: }
151:
152: public int getNonRepeaters() {
153: if (requestEvent.getCommand() instanceof AgentXGetBulkPDU) {
154: return ((AgentXGetBulkPDU) requestEvent.getCommand())
155: .getNonRepeaters() & 0xFFFF;
156: }
157: return 0;
158: }
159:
160: private void addSubRequest(SubRequest subReq) {
161: subrequests.add(subReq);
162: response.add(subReq.getVariableBinding());
163: }
164:
165: protected int getMaxPhase() {
166: return (is2PC()) ? PHASE_2PC_CLEANUP : PHASE_1PC;
167: }
168:
169: public Object getSource() {
170: return requestEvent;
171: }
172:
173: public void setRequestEvent(AgentXCommandEvent requestEvent) {
174: this .requestEvent = requestEvent;
175: }
176:
177: protected void assignErrorStatus2Response() {
178: int errStatus = getErrorStatus();
179: response.setErrorStatus((short) errStatus);
180: response.setErrorIndex((short) getErrorIndex());
181: }
182:
183: private AgentXResponsePDU createResponse() {
184: AgentXResponsePDU resp = new AgentXResponsePDU(0, (short) 0,
185: (short) 0);
186: resp.setTransactionID(transactionID);
187: return resp;
188: }
189:
190: public AgentXResponsePDU getResponsePDU() {
191: return (AgentXResponsePDU) getResponse();
192: }
193:
194: public Object getResponse() {
195: if (response == null) {
196: response = createResponse();
197: assignErrorStatus2Response();
198: } else {
199: assignErrorStatus2Response();
200: }
201: if (is2PC()) {
202: response.clear();
203: if ((requestEvent.getCommand().getType() == AgentXPDU.AGENTX_CLEANUPSET_PDU)
204: || (requestEvent.getCommand().getType() == AgentXPDU.AGENTX_UNDOSET_PDU)) {
205: return null;
206: }
207: }
208: return response;
209: }
210:
211: public Iterator iterator() {
212: initSubRequests();
213: return new AgentXSubRequestIterator();
214: }
215:
216: protected boolean is2PC() {
217: return ((requestEvent.getCommand().getType() >= AgentXPDU.AGENTX_TESTSET_PDU) && (requestEvent
218: .getCommand().getType() <= AgentXPDU.AGENTX_CLEANUPSET_PDU));
219: }
220:
221: public OctetString getContext() {
222: if (requestEvent.getCommand() instanceof AgentXContextPDU) {
223: return ((AgentXContextPDU) requestEvent.getCommand())
224: .getContext();
225: }
226: return DEFAULT_CONTEXT;
227: }
228:
229: public OctetString getViewName() {
230: throw new UnsupportedOperationException();
231: }
232:
233: public void setViewName(OctetString viewName) {
234: throw new UnsupportedOperationException();
235: }
236:
237: public int getSecurityLevel() {
238: throw new UnsupportedOperationException();
239: }
240:
241: public int getSecurityModel() {
242: throw new UnsupportedOperationException();
243: }
244:
245: public OctetString getSecurityName() {
246: throw new UnsupportedOperationException();
247: }
248:
249: public int getViewType() {
250: throw new UnsupportedOperationException();
251: }
252:
253: protected synchronized void addRepeaterSubRequest() {
254: int predecessorIndex = subrequests.size() - repeaterRowSize;
255: AgentXSubRequest sreq = new AgentXSubRequest(
256: (AgentXSubRequest) subrequests.get(predecessorIndex),
257: subrequests.size());
258: addSubRequest(sreq);
259: }
260:
261: /**
262: * Returns the last repetition row that is complete (regarding the number
263: * of elements in the row).
264: * @return
265: * a sub list of the sub-requests list that contains the row's elements.
266: * If no such row exists <code>null</code> is returned.
267: */
268: private List lastRow() {
269: if (repeaterRowSize == 0) {
270: return null;
271: }
272: int rows = (subrequests.size() - repeaterStartIndex)
273: / repeaterRowSize;
274: int startIndex = repeaterStartIndex
275: + (repeaterRowSize * (rows - 1));
276: int endIndex = repeaterStartIndex + (repeaterRowSize * rows);
277: return subrequests.subList(startIndex, endIndex);
278: }
279:
280: public int getMessageProcessingModel() {
281: throw new UnsupportedOperationException();
282: }
283:
284: public String toString() {
285: return getClass().getName() + "[subrequests=" + subrequests
286: + ",phase=" + phase + ",requestEvent=" + requestEvent
287: + "]";
288: }
289:
290: public boolean isPhaseComplete() {
291: if (errorStatus == SnmpConstants.SNMP_ERROR_SUCCESS) {
292: initSubRequests();
293: for (Iterator it = subrequests.iterator(); it.hasNext();) {
294: SubRequest subreq = (SubRequest) it.next();
295: RequestStatus status = subreq.getStatus();
296: if (status.getErrorStatus() != SnmpConstants.SNMP_ERROR_SUCCESS) {
297: return true;
298: } else if (!status.isPhaseComplete()) {
299: return false;
300: }
301: }
302: }
303: return true;
304: }
305:
306: /**
307: * The AgentXSubRequestIterator iterates over the subrequests in a AgentX
308: * request. In case of bulk operations, it also may physically append
309: * new sub-request instances while iterating, until the bulk operations
310: * limits are reached.
311: *
312: * @author Frank Fock
313: * @version 1.0
314: */
315: public class AgentXSubRequestIterator implements SubRequestIterator {
316:
317: private int cursor = 0;
318: private int increment = 1;
319:
320: protected AgentXSubRequestIterator() {
321: }
322:
323: protected AgentXSubRequestIterator(int offset, int increment) {
324: this .cursor = offset;
325: this .increment = increment;
326: }
327:
328: private int getRepeaterCount() {
329: AgentXPDU pdu = requestEvent.getCommand();
330: if (pdu instanceof AgentXGetBulkPDU) {
331: AgentXGetBulkPDU bulkPDU = (AgentXGetBulkPDU) pdu;
332: return Math.max(bulkPDU.size()
333: - bulkPDU.getNonRepeaters(), 0);
334: }
335: return 0;
336: }
337:
338: public boolean hasNext() {
339: AgentXPDU reqPDU = requestEvent.getCommand();
340: if (reqPDU.getType() == AgentXPDU.AGENTX_GETBULK_PDU) {
341: AgentXGetBulkPDU bulkPDU = (AgentXGetBulkPDU) reqPDU;
342: if (cursor < Math.min(bulkPDU.size(), bulkPDU
343: .getNonRepeaters())) {
344: return true;
345: } else {
346: if (cursor < bulkPDU.getNonRepeaters()
347: + bulkPDU.getMaxRepetitions()
348: * getRepeaterCount()) {
349: List lastRow = lastRow();
350: if (lastRow != null) {
351: boolean allEndOfMibView = true;
352: for (Iterator it = lastRow.iterator(); it
353: .hasNext();) {
354: SubRequest sreq = (SubRequest) it
355: .next();
356: if (sreq.getVariableBinding()
357: .getSyntax() != SMIConstants.EXCEPTION_END_OF_MIB_VIEW) {
358: allEndOfMibView = false;
359: break;
360: }
361: }
362: if (allEndOfMibView) {
363: return false;
364: }
365: }
366: return true;
367: }
368: }
369: return false;
370: }
371: return (cursor < size());
372: }
373:
374: public SubRequest nextSubRequest() {
375: if (!hasNext()) {
376: throw new NoSuchElementException();
377: }
378: if ((isBulkRequest()) && (cursor >= subrequests.size())) {
379: while (cursor >= subrequests.size()) {
380: addRepeaterSubRequest();
381: }
382: }
383: SubRequest sreq = (SubRequest) subrequests.get(cursor);
384: cursor += increment;
385: return sreq;
386: }
387:
388: public void remove() {
389: throw new UnsupportedOperationException(
390: "Remove is not supported " + "on sub-requests");
391: }
392:
393: public Object next() {
394: return nextSubRequest();
395: }
396:
397: public boolean equals(Object other) {
398: if (other instanceof AgentXRequest) {
399: return ((AgentXRequest) other).getTransactionID() == getTransactionID();
400: }
401: return false;
402: }
403:
404: public int hashCode() {
405: return getTransactionID();
406: }
407: }
408:
409: /**
410: * The <code>AgentXSubRequest</code> implements the <code>SubRequest</code>
411: * interface for AgentX sub-requests.
412: *
413: * @author Frank Fock
414: * @version 1.0
415: */
416: public class AgentXSubRequest implements SubRequest,
417: RequestStatusListener {
418:
419: private RequestStatus status;
420: private VariableBinding vb;
421: private Object undoValue;
422: private MOScope scope;
423: private MOQuery query;
424: private ManagedObject targetMO;
425: private int index;
426:
427: private volatile Object userObject;
428:
429: private AgentXSubRequest(int index) {
430: this .index = index;
431: status = new RequestStatus();
432: status.addRequestStatusListener(this );
433: }
434:
435: protected AgentXSubRequest(MOScope searchRange, int index) {
436: this (index);
437: this .scope = searchRange;
438: this .vb = new VariableBinding(searchRange.getLowerBound());
439: }
440:
441: protected AgentXSubRequest(VariableBinding subrequest, int index) {
442: this (index);
443: this .vb = subrequest;
444: OID oid = this .vb.getOid();
445: this .scope = new DefaultMOContextScope(getContext(), oid,
446: true, oid, true);
447: }
448:
449: protected AgentXSubRequest(AgentXSubRequest predecessor,
450: int index) {
451: this (index);
452: this .vb = new VariableBinding(predecessor
453: .getVariableBinding().getOid());
454: switch (requestEvent.getCommand().getType()) {
455: case AgentXPDU.AGENTX_GETBULK_PDU:
456: case AgentXPDU.AGENTX_GETNEXT_PDU: {
457: this .scope = new DefaultMOContextScope(getContext(),
458: predecessor.getVariableBinding().getOid(),
459: false, predecessor.getScope().getUpperBound(),
460: predecessor.getScope().isUpperIncluded());
461: break;
462: }
463: default: {
464: this .scope = new DefaultMOContextScope(getContext(),
465: predecessor.getScope());
466: }
467: }
468: // Do not copy queries because they need to be updated externally only!
469: // this.query = predecessor.getQuery();
470: }
471:
472: public Request getRequest() {
473: return AgentXRequest.this ;
474: }
475:
476: public RequestStatus getStatus() {
477: return status;
478: }
479:
480: public VariableBinding getVariableBinding() {
481: return vb;
482: }
483:
484: public void setStatus(RequestStatus status) {
485: this .status = status;
486: }
487:
488: public Object getUndoValue() {
489: return undoValue;
490: }
491:
492: public void setUndoValue(Object undoInformation) {
493: this .undoValue = undoInformation;
494: }
495:
496: public void requestStatusChanged(RequestStatusEvent event) {
497: int newStatus = event.getStatus().getErrorStatus();
498: AgentXRequest.this .setErrorStatus(newStatus);
499: if (logger.isDebugEnabled()
500: && (newStatus != SnmpConstants.SNMP_ERROR_SUCCESS)) {
501: new Exception("Error "
502: + event.getStatus().getErrorStatus()
503: + " generated at: " + vb).printStackTrace();
504: }
505: }
506:
507: public MOScope getScope() {
508: return scope;
509: }
510:
511: public void completed() {
512: status.setPhaseComplete(true);
513: }
514:
515: public boolean hasError() {
516: return getStatus().getErrorStatus() != SnmpConstants.SNMP_ERROR_SUCCESS;
517: }
518:
519: public boolean isComplete() {
520: return status.isPhaseComplete();
521: }
522:
523: public void setTargetMO(ManagedObject managedObject) {
524: this .targetMO = managedObject;
525: }
526:
527: public ManagedObject getTargetMO() {
528: return targetMO;
529: }
530:
531: public int getIndex() {
532: return index;
533: }
534:
535: public void setQuery(MOQuery query) {
536: this .query = query;
537: }
538:
539: public MOQuery getQuery() {
540: return query;
541: }
542:
543: public String toString() {
544: return getClass().getName() + "[scope=" + scope + ",vb="
545: + vb + ",status=" + status + ",query=" + query
546: + ",index=" + index + ",targetMO=" + targetMO + "]";
547: }
548:
549: public SubRequestIterator repetitions() {
550: initSubRequests();
551: if (requestEvent.getCommand().getType() == AgentXPDU.AGENTX_GETBULK_PDU) {
552: AgentXGetBulkPDU getBulk = (AgentXGetBulkPDU) requestEvent
553: .getCommand();
554: int repeaters = getBulk.size()
555: - getBulk.getNonRepeaters();
556: return new AgentXSubRequestIterator(getIndex(),
557: repeaters);
558: }
559: return new SubRequestIteratorSupport(Collections.EMPTY_LIST
560: .iterator());
561: }
562:
563: public void updateNextRepetition() {
564: SubRequestIterator repetitions = repetitions();
565: // skip this one
566: repetitions.next();
567: if (repetitions.hasNext()) {
568: if ((getStatus().getErrorStatus() == PDU.noError)
569: && (!this .vb.isException())) {
570: AgentXSubRequest nsreq = (AgentXSubRequest) repetitions
571: .nextSubRequest();
572: nsreq.query = null;
573: nsreq.scope = new DefaultMOContextScope(
574: getContext(), this .getVariableBinding()
575: .getOid(), false, this .getScope()
576: .getUpperBound(), this .getScope()
577: .isUpperIncluded());
578: } else if (this .vb.isException()) {
579: while (repetitions.hasNext()) {
580: AgentXSubRequest nsreq = (AgentXSubRequest) repetitions
581: .nextSubRequest();
582: nsreq.query = null;
583: nsreq.getVariableBinding().setOid(
584: this .vb.getOid());
585: nsreq.getVariableBinding().setVariable(
586: this .vb.getVariable());
587: nsreq.getStatus().setPhaseComplete(true);
588: }
589: }
590: }
591: }
592:
593: public final void setErrorStatus(int errorStatus) {
594: getStatus().setErrorStatus(errorStatus);
595: }
596:
597: public final int getErrorStatus() {
598: return getStatus().getErrorStatus();
599: }
600:
601: public Object getUserObject() {
602: return userObject;
603: }
604:
605: public void setUserObject(Object userObject) {
606: this.userObject = userObject;
607: }
608: }
609: }
|