KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > snmp > daemon > SnmpInformRequest


1 /*
2  * @(#)file SnmpInformRequest.java
3  * @(#)author Sun Microsystems, Inc.
4  * @(#)version 1.17
5  * @(#)date 08/02/09
6  *
7  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
8  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
9  *
10  */

11
12 package com.sun.jmx.snmp.daemon ;
13
14
15 // JAVA imports
16
//
17
import java.io.Serializable JavaDoc;
18 import java.net.InetAddress JavaDoc;
19 import java.util.Vector JavaDoc;
20 import java.util.Date JavaDoc;
21
22 // JMX imports
23
//
24
import com.sun.jmx.snmp.SnmpMessage;
25 import com.sun.jmx.snmp.SnmpVarBind;
26 import com.sun.jmx.snmp.SnmpPduFactory;
27 import com.sun.jmx.snmp.SnmpPduPacket;
28 import com.sun.jmx.snmp.SnmpPduRequest;
29 import com.sun.jmx.snmp.SnmpPduBulk;
30 import com.sun.jmx.snmp.SnmpDefinitions;
31 import com.sun.jmx.snmp.SnmpStatusException;
32 import com.sun.jmx.snmp.SnmpTooBigException;
33 import com.sun.jmx.snmp.SnmpVarBindList;
34 import com.sun.jmx.snmp.SnmpPdu;
35 import com.sun.jmx.snmp.SnmpPduRequestType;
36
37 // SNMP Runtime imports
38
//
39
import com.sun.jmx.trace.Trace;
40
41
42 /**
43  * This class is used by the {@link com.sun.jmx.snmp.daemon.SnmpAdaptorServer SNMP adaptor server} to send inform requests
44  * to an SNMP manager and receive inform responses.
45  * <P>
46  * This class provides basic functions that enable you to fire inform requests,
47  * handle retries, timeouts, and process responses from the manager.
48  * <BR>
49  * The SNMP adaptor server specifies the destination of the inform request and controls
50  * the size of a single inform request/response to fit into its <CODE>bufferSize</CODE>.
51  * It specifies the maximum number of tries and the timeout to be used for the inform requests.
52  * It also provides resources such as the authentication mechanism (using its PDU factory),
53  * controlling all inform requests created by it, and finally the inform response to the user.
54  * <P>
55  * Each inform request, when ready to be sent, is assigned a unique identifier which helps
56  * in identifying the inform request with matching inform responses to the protocol engine
57  * lying transparently underneath. The engine does the job of retrying the inform requests
58  * when the timer expires and calls the SNMP adaptor server when a timeout occurs after exhausting
59  * the maximum number of tries.
60  * <P>
61  * The inform request object provides the method, {@link #waitForCompletion waitForCompletion(long time)},
62  * which enables a user to operate in a synchronous mode with an inform request.
63  * This is done by blocking the user thread for the desired time interval.
64  * The user thread gets notified whenever a request reaches completion, independently of the status of the response.
65  * <P>
66  * If an {@link com.sun.jmx.snmp.daemon.SnmpInformHandler inform callback} is provided when sending the inform request,
67  * the user operates in an asynchronous mode with the inform request. The user thread is not blocked
68  * and the specific inform callback implementation provided by the user is invoked when the inform response is received.
69  *
70  * <P>
71  * <B>Note:</B>
72  * <BR>From RFC 1905, the SNMP inform request is defined as a request generated and transmitted
73  * by an SNMPv2 entity acting in a manager role to another SNMPv2 entity also acting in a manager role.
74  * The mechanisms to implement this behaviour are defined in the SNMP manager API.
75  * <BR>
76  * Nevertheless, this feature has derived and in some documentations, the inform request appears
77  * like an SNMPv2 trap that gets responded.
78  * <BR>The <CODE>SnmpInformRequest</CODE> class is used to fullfill this latter case.
79  * <p><b>This API is a Sun Microsystems internal API and is subject
80  * to change without notice.</b></p>
81  */

82
83 public class SnmpInformRequest implements SnmpDefinitions {
84     
85     // VARIABLES
86
//----------
87

88     /**
89      * This object maintains a global counter for the inform request ID.
90      */

91     private static SnmpRequestCounter requestCounter = new SnmpRequestCounter();
92     
93     /**
94      * This contains a list of <CODE>SnmpVarBind</CODE> objects for making the SNMP inform requests.
95      */

96     private SnmpVarBindList varBindList = null;
97     
98     /**
99      * The error status associated with the inform response packet.
100      */

101     int errorStatus = 0;
102     
103     /**
104      * The index in <CODE>SnmpVarBindList</CODE> that caused the exception.
105      */

106     int errorIndex = 0;
107     
108     //private SnmpVarBind internalVarBind[] = null;
109
SnmpVarBind internalVarBind[] = null;
110
111     //private String reason = null;
112
String JavaDoc reason = null;
113         
114     /**
115      * The SNMP adaptor associated with this inform request.
116      */

117     private transient SnmpAdaptorServer adaptor;
118         
119     /**
120      * The session object associated with this inform request.
121      */

122     private transient SnmpSession informSession;
123         
124     /**
125      * The user implementation of the callback interface for this request.
126      */

127     private SnmpInformHandler callback = null;
128         
129     /**
130      * The inform request PDU.
131      */

132     //private SnmpPduPacket requestPdu;
133
SnmpPdu requestPdu;
134
135     /**
136      * The inform response PDU.
137      */

138     //private SnmpPduRequest responsePdu;
139
SnmpPduRequestType responsePdu;
140     
141     /**
142      * Base status of an inform request.
143      */

144     final static private int stBase = 1;
145     
146     /**
147      * Status of an inform request: in progress.
148      */

149     final static public int stInProgress = stBase;
150   
151     /**
152      * Status of an inform request: waiting to be sent.
153      */

154     final static public int stWaitingToSend = (stBase << 1) | stInProgress;
155   
156     /**
157      * Status of an inform request: waiting for reply.
158      */

159     final static public int stWaitingForReply = (stBase << 2) | stInProgress;
160   
161     /**
162      * Status of an inform request: reply received.
163      */

164     final static public int stReceivedReply = (stBase << 3) | stInProgress;
165   
166     /**
167      * Status of an inform request: request aborted.
168      */

169     final static public int stAborted = (stBase << 4);
170   
171     /**
172      * Status of an inform request: timeout.
173      */

174     final static public int stTimeout = (stBase << 5);
175   
176     /**
177      * Status of an inform request: internal error occured.
178      */

179     final static public int stInternalError = (stBase << 6);
180   
181     /**
182      * Status of an inform request: result available for the request.
183      */

184     final static public int stResultsAvailable = (stBase << 7);
185   
186     /**
187      * Status of an inform request: request never used.
188      */

189     final static public int stNeverUsed = (stBase << 8);
190         
191     /**
192      * Number of tries performed for the current polling operation.
193      */

194     private int numTries = 0;
195
196     /**
197      * Timeout.
198      * The default amount of time is 3000 millisec.
199      */

200     private int timeout = 3 * 1000; // 3 seconds.
201

202     /**
203      */

204     private int reqState = stNeverUsed;
205
206     // Polling control parameters.
207
private long prevPollTime = 0; // value of 0 means poll never happened.
208
private long nextPollTime = 0;
209     private long waitTimeForResponse;
210     private Date JavaDoc debugDate = new Date JavaDoc();
211
212     /**
213      * The request ID for an active inform request.
214      */

215     private int requestId = 0;
216     
217     private int port = 0;
218
219     private InetAddress JavaDoc address = null;
220     private String JavaDoc communityString = null;
221     
222     String JavaDoc dbgTag = "SnmpInformRequest";
223     
224     // CONSTRUCTORS
225
//-------------
226

227     /**
228      * For SNMP Runtime internal use only.
229      * Constructor for creating new inform request. This object can be created only by an SNMP adaptor object.
230      * @param session <CODE>SnmpSession</CODE> object for this inform request.
231      * @param adp <CODE>SnmpAdaptorServer</CODE> object for this inform request.
232      * @param addr The <CODE>InetAddress</CODE> destination for this inform request.
233      * @param cs The community string to be used for the inform request.
234      * @param requestCB Callback interface for the inform request.
235      * @exception SnmpStatusException SNMP adaptor is not ONLINE or session is dead.
236      */

237     SnmpInformRequest(SnmpSession session,
238               SnmpAdaptorServer adp,
239               InetAddress JavaDoc addr,
240               String JavaDoc cs,
241               int p,
242               SnmpInformHandler requestCB)
243         throws SnmpStatusException {
244         
245         informSession = session;
246         adaptor = adp;
247         address = addr;
248         communityString = cs;
249     port = p;
250         callback = requestCB;
251         informSession.addInformRequest(this); // add to adaptor queue.
252
setTimeout(adaptor.getTimeout()) ;
253     }
254
255     // PUBLIC METHODS
256
//---------------
257

258     /**
259      * Gets the request id (invoke identifier) of the current inform request.
260      * @return The request id.
261      */

262     final public synchronized int getRequestId () {
263         return requestId;
264     }
265
266     /**
267      * Gets the destination address of the current inform request.
268      * @return The destination address.
269      */

270     synchronized InetAddress JavaDoc getAddress() {
271         return address;
272     }
273
274     /**
275      * Gets the current status of the inform request.
276      * @return The current status of the inform request.
277      */

278     final public synchronized int getRequestStatus() {
279         return reqState ;
280     }
281     
282     /**
283      * Indicates whether or not the inform request was aborted.
284      * @return <CODE>true</CODE> if the inform request was aborted, <CODE>false</CODE> otherwise.
285      */

286     final public synchronized boolean isAborted() {
287         return ((reqState & stAborted) == stAborted);
288     }
289
290     /**
291      * Indicates whether or not the inform request is in progress.
292      * @return <CODE>true</CODE> if the inform request is in progress, <CODE>false</CODE> otherwise.
293      */

294     final public synchronized boolean inProgress() {
295         return ((reqState & stInProgress) == stInProgress);
296     }
297
298     /**
299      * Indicates whether or not the inform request result is available.
300      * @return <CODE>true</CODE> if the inform request result is available, <CODE>false</CODE> otherwise.
301      */

302     final public synchronized boolean isResultAvailable() {
303         return (reqState == stResultsAvailable);
304     }
305     
306     /**
307      * Gets the status associated with the <CODE>SnmpVarBindList</CODE>.
308      * @return The error status.
309      */

310     final public synchronized int getErrorStatus() {
311         return errorStatus;
312     }
313
314     /**
315      * Gets the index.
316      * <P>NOTE: this value is equal to the <CODE>errorIndex</CODE> field minus 1.
317      * @return The error index.
318      */

319     final public synchronized int getErrorIndex() {
320         return errorIndex;
321     }
322
323     /**
324      * Gets the maximum number of tries before declaring that the manager is not responding.
325      * @return The maximum number of times an inform request should be tried.
326      */

327     final public int getMaxTries() {
328         return adaptor.getMaxTries();
329     }
330     
331     /**
332      * Gets the number of tries performed for the current inform request.
333      * @return The number of tries performed.
334      */

335     final public synchronized int getNumTries() {
336         return numTries ;
337     }
338     
339     /**
340      * For SNMP Runtime internal use only.
341      */

342     final synchronized void setTimeout(int value) {
343         timeout = value ;
344     }
345     
346     /**
347      * Gets absolute time in milliseconds (based on epoch time) when the next
348      * polling activity will begin.
349      * @return The absolute time when polling will begin.
350      */

351     final public synchronized long getAbsNextPollTime () {
352         return nextPollTime ;
353     }
354     
355     /**
356      * Gets absolute time in milliseconds (based on epoch time) before which an inform
357      * response is expected from a manager.
358      * @return The absolute time within which an inform response is expected.
359      */

360     final public synchronized long getAbsMaxTimeToWait() {
361         if (prevPollTime == 0) {
362             return System.currentTimeMillis() ; // should never happen.
363
} else {
364             return waitTimeForResponse ;
365         }
366     }
367     
368     /**
369      * Gets the <CODE>SnmpVarBindList</CODE> of the inform response.
370      * It returns a null value if the inform request is in progress.
371      * This ensures accidental manipulation does not occur when a request is in progress.
372      * In case of an error, <CODE>SnmpVarBindList</CODE> is the copy
373      * of the original <CODE>SnmpVarBindList</CODE> at the time of making the inform request.
374      * @return The list of <CODE>SnmpVarBind</CODE> objects returned by the manager or the null value if the request
375      * is in progress.
376      */

377     public final synchronized SnmpVarBindList getResponseVarBindList() {
378         if (inProgress())
379             return null;
380         return varBindList;
381     }
382             
383     /**
384      * Used in synchronous mode only.
385      * Provides a hook that enables a synchronous operation on a previously sent inform request.
386      * Only one inform request can be in synchronous mode on a given thread.
387      * The blocked thread is notified when the inform request state reaches completion.
388      * If the inform request is not active, the method returns immediately.
389      * The user must get the error status of the inform request to determine the
390      * exact status of the request.
391      *
392      * @param time The amount of time to wait. Zero means block until complete.
393      * @return <CODE>true</CODE> if the inform request has completed, <CODE>false</CODE> if it is still active.
394      */

395     final public boolean waitForCompletion(long time) {
396         
397         if (! inProgress()) // check if request is in progress.
398
return true;
399
400         if (informSession.thisSessionContext()) {
401             // We can manipulate callback safely as we are in session thread.
402
//
403
SnmpInformHandler savedCallback = callback;
404             callback = null;
405             informSession.waitForResponse(this, time);
406             callback = savedCallback;
407         } else {
408             // This is being done from a different thread. So notifyClient will do the notification.
409
//
410
synchronized (this) {
411                 SnmpInformHandler savedCallback = callback ;
412                 try {
413                     callback = null ;
414                     this.wait(time) ;
415                 } catch (InterruptedException JavaDoc e) {
416                 }
417                 callback = savedCallback ;
418             }
419         }
420         
421         return (! inProgress()); // true if request completed.
422
}
423
424     /**
425      * Cancels the active inform request and removes itself from the polling list.
426      */

427     final public void cancelRequest() {
428         errorStatus = snmpReqAborted;
429         stopRequest();
430         deleteRequest();
431         notifyClient();
432     }
433
434     /**
435      * Notifies the registered client about the completion of an operation.
436      */

437     final public synchronized void notifyClient() {
438         this.notifyAll();
439     }
440
441     /**
442      * Finalizer of the <CODE>SnmpInformRequest</CODE> objects.
443      * This method is called by the garbage collector on an object
444      * when garbage collection determines that there are no more references to the object.
445      * <P>Sets all the references to this SNMP inform request object to <CODE>null</CODE>.
446      */

447     public void finalize() {
448         callback = null;
449         varBindList = null;
450         internalVarBind = null;
451         adaptor = null;
452         informSession = null;
453         requestPdu = null;
454     responsePdu = null;
455     }
456
457     /**
458      * Returns the <CODE>String</CODE> representation of an error code.
459      * @param errcode The error code as an integer.
460      * @return The error code as a <CODE>String</CODE>.
461      */

462     public static String JavaDoc snmpErrorToString(int errcode) {
463         switch (errcode) {
464         case snmpRspNoError :
465             return "noError" ;
466         case snmpRspTooBig :
467             return "tooBig" ;
468         case snmpRspNoSuchName :
469             return "noSuchName" ;
470         case snmpRspBadValue :
471             return "badValue" ;
472         case snmpRspReadOnly :
473             return "readOnly" ;
474         case snmpRspGenErr :
475             return "genErr" ;
476         case snmpRspNoAccess :
477             return "noAccess" ;
478         case snmpRspWrongType :
479             return "wrongType" ;
480         case snmpRspWrongLength :
481             return "wrongLength" ;
482         case snmpRspWrongEncoding :
483             return "wrongEncoding" ;
484         case snmpRspWrongValue :
485             return "wrongValue" ;
486         case snmpRspNoCreation :
487             return "noCreation" ;
488         case snmpRspInconsistentValue :
489             return "inconsistentValue" ;
490         case snmpRspResourceUnavailable :
491             return "resourceUnavailable" ;
492         case snmpRspCommitFailed :
493             return "commitFailed" ;
494         case snmpRspUndoFailed :
495             return "undoFailed" ;
496         case snmpRspAuthorizationError :
497             return "authorizationError" ;
498         case snmpRspNotWritable :
499             return "notWritable" ;
500         case snmpRspInconsistentName :
501             return "inconsistentName" ;
502         case snmpReqTimeout :
503             return "reqTimeout" ;
504         case snmpReqAborted :
505             return "reqAborted" ;
506         case snmpRspDecodingError :
507             return "rspDecodingError" ;
508         case snmpReqEncodingError :
509             return "reqEncodingError" ;
510         case snmpReqPacketOverflow :
511             return "reqPacketOverflow" ;
512         case snmpRspEndOfTable :
513             return "rspEndOfTable" ;
514         case snmpReqRefireAfterVbFix :
515             return "reqRefireAfterVbFix" ;
516         case snmpReqHandleTooBig :
517             return "reqHandleTooBig" ;
518         case snmpReqTooBigImpossible :
519             return "reqTooBigImpossible" ;
520         case snmpReqInternalError :
521             return "reqInternalError" ;
522         case snmpReqSocketIOError :
523             return "reqSocketIOError" ;
524         case snmpReqUnknownError :
525             return "reqUnknownError" ;
526         case snmpWrongSnmpVersion :
527             return "wrongSnmpVersion" ;
528     case snmpUnknownPrincipal:
529         return "snmpUnknownPrincipal";
530     case snmpAuthNotSupported:
531         return "snmpAuthNotSupported";
532     case snmpPrivNotSupported:
533         return "snmpPrivNotSupported";
534     case snmpBadSecurityLevel:
535         return "snmpBadSecurityLevel";
536     case snmpUsmBadEngineId:
537         return "snmpUsmBadEngineId";
538     case snmpUsmInvalidTimeliness:
539         return "snmpUsmInvalidTimeliness";
540         }
541         return "Unknown Error = " + errcode;
542     }
543     
544     // PRIVATE AND PACKAGE METHODS
545
//----------------------------
546

547     /**
548      * For SNMP Runtime internal use only.
549      * Starts an inform request in asynchronous mode. The callback interface
550      * is used to notify the user upon request completion.
551      * @param vblst The list of <CODE>SnmpVarBind</CODE> to be used.
552      * @exception SnmpStatusException This inform request is already in progress.
553      */

554     synchronized void start(SnmpVarBindList vblst) throws SnmpStatusException {
555         if (inProgress())
556             throw new SnmpStatusException("Inform request already in progress.");
557         setVarBindList(vblst);
558         initializeAndFire();
559     }
560
561     private synchronized void initializeAndFire() {
562         requestPdu = null;
563     responsePdu = null;
564         reason = null;
565         startRequest(System.currentTimeMillis());
566         setErrorStatusAndIndex(0, 0);
567     }
568     
569     /**
570      * This method submits the inform request for polling and marks the request
571      * active. It does nothing if the request is already active.
572      * The poll will be scheduled to happen immediately.
573      * @param starttime The start time for polling.
574      */

575     private synchronized void startRequest(long starttime) {
576         nextPollTime = starttime;
577         prevPollTime = 0;
578         schedulePoll();
579     }
580     
581     /**
582      * This method creates a new request ID. The ID is submitted to the poll server for scheduling.
583      */

584     private void schedulePoll() {
585         numTries = 0;
586         initNewRequest();
587         setRequestStatus(stWaitingToSend);
588         informSession.getSnmpQManager().addRequest(this);
589     }
590     
591     /**
592      * This method determines whether the inform request is to be retried. This is used if the
593      * peer did not respond to a previous request. If the request exceeds
594      * the maxTries limit, a timeout is signaled.
595      */

596     void action() {
597         if (inProgress() == false)
598             return;
599         while (true) {
600             try {
601                 if (numTries == 0) {
602                     invokeOnReady();
603                 } else if (numTries < getMaxTries()) {
604                     invokeOnRetry();
605                 } else {
606                     invokeOnTimeout();
607                 }
608                 return ;
609             } catch (OutOfMemoryError JavaDoc omerr) {
610                 // Consider it as a try !
611
//
612
numTries++;
613                 if (isDebugOn()) {
614                     debug("action", "Inform request hit out of memory situation...");
615                 }
616                 Thread.currentThread().yield();
617             }
618         }
619     }
620     
621     final private void invokeOnReady() {
622         if (requestPdu == null) {
623             requestPdu = constructPduPacket();
624         }
625         if (requestPdu != null) {
626             if (sendPdu() == false)
627                 queueResponse();
628         }
629     }
630
631     final private void invokeOnRetry() {
632         invokeOnReady();
633     }
634     
635     final private void invokeOnTimeout() {
636         errorStatus = snmpReqTimeout;
637         queueResponse();
638     }
639     
640     final private void queueResponse() {
641         informSession.addResponse(this);
642     }
643     
644     /**
645      * Constructs an inform request PDU.
646      */

647     synchronized SnmpPdu constructPduPacket() {
648         SnmpPduPacket reqpdu = null;
649         Exception JavaDoc excep = null;
650         try {
651             reqpdu = new SnmpPduRequest();
652             reqpdu.port = port;
653             reqpdu.type = pduInformRequestPdu;
654             reqpdu.version = snmpVersionTwo;
655             reqpdu.community = communityString.getBytes("8859_1");
656             reqpdu.requestId = getRequestId();
657             reqpdu.varBindList = internalVarBind;
658
659             if (isTraceOn()) {
660                 trace("constructPduPacket", "Packet built");
661             }
662
663         } catch (Exception JavaDoc e) {
664             excep = e;
665             errorStatus = snmpReqUnknownError;
666             reason = e.getMessage();
667         }
668         if (excep != null) {
669             if (isDebugOn()) {
670                 debug("constructPduPacket", excep);
671             }
672             reqpdu = null;
673             queueResponse();
674         }
675         return reqpdu;
676     }
677     
678     boolean sendPdu() {
679         try {
680             responsePdu = null;
681       
682             SnmpPduFactory pduFactory = adaptor.getPduFactory();
683             SnmpMessage msg = (SnmpMessage)pduFactory.encodeSnmpPdu((SnmpPduPacket)requestPdu, adaptor.getBufferSize().intValue());
684
685             if (msg == null) {
686                 if (isDebugOn()) {
687                     debug("sendPdu", "pdu factory returned a null value");
688                 }
689                 throw new SnmpStatusException(snmpReqUnknownError);
690                 // This exception will caught hereafter and reported as an snmpReqUnknownError
691
// FIXME: may be it's not the best behaviour ?
692
}
693
694             int maxPktSize = adaptor.getBufferSize().intValue();
695             byte[] encoding = new byte[maxPktSize];
696             int encodingLength = msg.encodeMessage(encoding);
697       
698             if (isTraceOn()) {
699                 trace("sendPdu", "Dump : \n" + msg.printMessage());
700             }
701
702             sendPduPacket(encoding, encodingLength);
703             return true;
704         } catch (SnmpTooBigException ar) {
705     
706             if (isDebugOn()) {
707                 debug("sendPdu", ar);
708             }
709       
710             setErrorStatusAndIndex(snmpReqPacketOverflow, ar.getVarBindCount());
711             requestPdu = null;
712             reason = ar.getMessage();
713             if (isDebugOn()) {
714                 debug("sendPdu", "Packet Overflow while building inform request");
715             }
716         } catch (java.io.IOException JavaDoc ioe) {
717             setErrorStatusAndIndex(snmpReqSocketIOError, 0);
718             reason = ioe.getMessage();
719         } catch (Exception JavaDoc e) {
720             if (isDebugOn()) {
721                 debug("sendPdu", e);
722             }
723             setErrorStatusAndIndex(snmpReqUnknownError, 0);
724             reason = e.getMessage();
725         }
726         return false;
727     }
728
729     /**
730      * Sends the prepared PDU packet to the manager and updates the data structure
731      * to expect a response. It acquires a lock on the socket to prevent a case
732      * where a response arrives before this thread could insert the
733      * request into the wait queue.
734      * @exception IOException Signals that an I/O exception of some sort has occurred.
735      */

736     final void sendPduPacket(byte[] buffer, int length) throws java.io.IOException JavaDoc {
737     
738         if (isTraceOn()) {
739             trace("sendPduPacket", "Send to peer. Peer/Port : " + address.getHostName() + "/" + port +
740                   ". Length = " + length + "\nDump : \n" + SnmpMessage.dumpHexBuffer(buffer,0, length));
741         }
742         SnmpSocket theSocket = informSession.getSocket();
743         synchronized (theSocket) {
744             theSocket.sendPacket(buffer, length, address, port);
745             setRequestSentTime(System.currentTimeMillis());
746         }
747     }
748
749     /**
750      * For SNMP Runtime internal use only.
751      */

752     final void processResponse() {
753     
754         if (isTraceOn()) {
755             trace("processResponse", "errstatus = " + errorStatus);
756         }
757
758         if (inProgress() == false) { // check if this request is still alive.
759
responsePdu = null;
760             return; // the request may have cancelled.
761
}
762
763         if (errorStatus >= snmpReqInternalError) {
764             handleInternalError("Internal Error...");
765             return;
766         }
767
768         try {
769             parsePduPacket(responsePdu);
770             //responsePdu = null;
771

772             // At this point the errorIndex is rationalized to start with 0.
773
switch (errorStatus) {
774             case snmpRspNoError :
775                 handleSuccess();
776                 return;
777             case snmpReqTimeout :
778                 handleTimeout();
779                 return;
780             case snmpReqInternalError :
781                 handleInternalError("Unknown internal error. deal with it later!");
782                 return;
783             case snmpReqHandleTooBig :
784                 setErrorStatusAndIndex(snmpRspTooBig, 0);
785                 handleError("Cannot handle too-big situation...");
786                 return;
787             case snmpReqRefireAfterVbFix :
788                 // Refire request after fixing varbindlist.
789
initializeAndFire();
790                 return;
791             default :
792                 handleError("Error status set in packet...!!");
793                 return;
794             }
795         } catch (Exception JavaDoc e) {
796             if (isDebugOn()) {
797                 debug("processResponse", e);
798             }
799             reason = e.getMessage();
800         }
801         handleInternalError(reason);
802     }
803     
804     /**
805      * Parses the inform response packet. If the agent responds with error set,
806      * it does not parse any further.
807      */

808     synchronized void parsePduPacket(SnmpPduRequestType rpdu) {
809         
810         if (rpdu == null)
811             return;
812     
813         errorStatus = rpdu.getErrorStatus();
814         errorIndex = rpdu.getErrorIndex();
815     
816         if (errorStatus == snmpRspNoError) {
817             updateInternalVarBindWithResult(((SnmpPdu)rpdu).varBindList);
818             return;
819         }
820     
821         if (errorStatus != snmpRspNoError)
822             --errorIndex; // rationalize for index to start with 0.
823

824         if (isTraceOn()) {
825             trace("parsePduPacket", "received inform response. ErrorStatus/ErrorIndex = " + errorStatus + "/" + errorIndex);
826         }
827     }
828     
829     /**
830      * Calls the user implementation of the <CODE>SnmpInformHandler</CODE> interface.
831      */

832     private void handleSuccess() {
833         
834         setRequestStatus(stResultsAvailable);
835
836         if (isTraceOn()) {
837             trace("handleSuccess", "Invoking user defined callback...");
838         }
839
840         deleteRequest(); // delete only non-poll request.
841
notifyClient();
842         
843         requestPdu = null;
844     //responsePdu = null;
845
internalVarBind = null;
846
847         try { // catch all user exception which may happen in callback.
848
if (callback != null)
849                 callback.processSnmpPollData(this, errorStatus, errorIndex, getVarBindList());
850         } catch (Exception JavaDoc e) {
851             if (isDebugOn()) {
852                 debug("handleSuccess", "Exception generated by user callback");
853                 debug("handleSuccess", e);
854             }
855         } catch (OutOfMemoryError JavaDoc ome) {
856             if (isDebugOn()) {
857                 debug("handleSuccess", "OutOfMemory Error generated by user callback");
858                 debug("handleSuccess", ome);
859             }
860             Thread.currentThread().yield();
861         }
862         return;
863     }
864
865     /**
866      * Calls the user implementation of the <CODE>SnmpInformHandler</CODE> interface.
867      */

868     private void handleTimeout() {
869         
870         setRequestStatus(stTimeout);
871         
872         if (isDebugOn()) {
873             debug("handleTimeout", "Snmp error/index = " + snmpErrorToString(errorStatus) + "/" +
874                   errorIndex + ". Invoking timeout user defined callback...");
875         }
876         deleteRequest();
877         notifyClient();
878
879         requestPdu = null;
880     responsePdu = null;
881         internalVarBind = null;
882
883         try {
884             if (callback != null)
885                 callback.processSnmpPollTimeout(this);
886         } catch (Exception JavaDoc e) { // catch any exception a user might not handle.
887
if (isDebugOn()) {
888                 debug("handleTimeout", "Exception generated by user callback");
889                 debug("handleTimeout", e);
890             }
891         } catch (OutOfMemoryError JavaDoc ome) {
892             if (isDebugOn()) {
893                 debug("handleTimeout", "OutOfMemory Error generated by user callback");
894                 debug("handleTimeout", ome);
895             }
896             Thread.currentThread().yield();
897         }
898         return;
899     }
900   
901     /**
902      * Calls the user implementation of the <CODE>SnmpInformHandler</CODE> interface.
903      */

904     private void handleError(String JavaDoc msg) {
905         
906         setRequestStatus(stResultsAvailable);
907
908         if (isDebugOn()) {
909             debug("handleError", "Snmp error/index = " + snmpErrorToString(errorStatus) + "/" +
910                   errorIndex + ". Invoking error user defined callback...\n" + getVarBindList());
911         }
912         deleteRequest();
913         notifyClient();
914         
915         requestPdu = null;
916     responsePdu = null;
917         internalVarBind = null;
918         
919         try {
920             if (callback != null)
921                 callback.processSnmpPollData(this, getErrorStatus(), getErrorIndex(), getVarBindList());
922         } catch (Exception JavaDoc e) { // catch any exception a user might not handle.
923
if (isDebugOn()) {
924                 debug("handleError", "Exception generated by user callback");
925                 debug("handleError", e);
926             }
927         } catch (OutOfMemoryError JavaDoc ome) {
928             if (isDebugOn()) {
929                 debug("handleError", "OutOfMemory Error generated by user callback");
930                 debug("handleError", ome);
931             }
932             Thread.currentThread().yield();
933         }
934     }
935
936     /**
937      * Calls the user implementation of the <CODE>SnmpInformHandler</CODE> interface.
938      */

939     private void handleInternalError(String JavaDoc msg) {
940         
941         setRequestStatus(stInternalError);
942         if (reason == null)
943             reason = msg;
944
945         if (isDebugOn()) {
946             debug("handleInternalError", "Snmp error/index = " + snmpErrorToString(errorStatus) + "/" +
947                   errorIndex + ". Invoking internal error user defined callback...\n" + getVarBindList());
948         }
949
950         deleteRequest();
951         notifyClient();
952
953         requestPdu = null;
954     responsePdu = null;
955         internalVarBind = null;
956         
957         try {
958             if (callback != null)
959                 callback.processSnmpInternalError(this, reason);
960         } catch (Exception JavaDoc e) { // catch any exception a user might not handle.
961
if (isDebugOn()) {
962                 debug("handleInternalError", "Exception generated by user callback");
963                 debug("handleInternalError", e);
964             }
965         } catch (OutOfMemoryError JavaDoc ome) {
966             if (isDebugOn()) {
967                 debug("handleInternalError", "OutOfMemory Error generated by user callback");
968                 debug("handleInternalError", ome);
969             }
970             Thread.currentThread().yield();
971         }
972     }
973
974     void updateInternalVarBindWithResult(SnmpVarBind[] list) {
975      
976         if ((list == null) || (list.length == 0))
977             return;
978     
979         int idx = 0;
980         
981         for(int i = 0; i < internalVarBind.length && idx < list.length; i++) {
982             SnmpVarBind avar = internalVarBind[i];
983             if (avar == null)
984                 continue;
985                 
986             SnmpVarBind res = list[idx];
987             avar.setSnmpValue(res.getSnmpValue());
988             idx++;
989         }
990     }
991     
992     /**
993      * For SNMP Runtime internal use only.
994      */

995     final void invokeOnResponse(Object JavaDoc resp) {
996         if (resp != null) {
997             if (resp instanceof SnmpPduRequestType)
998                 responsePdu = (SnmpPduRequestType) resp;
999             else
1000                return;
1001        }
1002        setRequestStatus(stReceivedReply);
1003        queueResponse();
1004    }
1005    
1006    /**
1007     * This method cancels an active inform request and removes it from the polling list.
1008     */

1009    private void stopRequest() {
1010        
1011        // Remove the clause synchronized of the stopRequest method.
1012
// Synchronization is isolated as possible to avoid thread lock.
1013
// Note: the method removeRequest from SendQ is synchronized.
1014
// fix bug jaw.00392.B
1015
//
1016
synchronized(this) {
1017            setRequestStatus(stAborted);
1018        }
1019        informSession.getSnmpQManager().removeRequest(this);
1020        synchronized(this) {
1021            requestId = 0;
1022        }
1023    }
1024    
1025    final synchronized void deleteRequest() {
1026        informSession.removeInformRequest(this);
1027    }
1028    
1029    /**
1030     * For SNMP Runtime internal use only.
1031     * Gets the active <CODE>SnmpVarBindList</CODE>. The contents of it
1032     * are not guaranteed to be consistent when the inform request is active.
1033     * @return The list of <CODE>SnmpVarBind</CODE> objects.
1034     */

1035    final synchronized SnmpVarBindList getVarBindList() {
1036        return varBindList;
1037    }
1038
1039    /**
1040     * For SNMP Runtime internal use only.
1041     * You should specify the <CODE>SnmpVarBindList</CODE> at SnmpInformRequest creation time.
1042     * You cannot modify it during the life-time of the object.
1043     */

1044    final synchronized void setVarBindList(SnmpVarBindList newvblst) {
1045        varBindList = newvblst;
1046        if (internalVarBind == null || internalVarBind.length != varBindList.size()) {
1047            internalVarBind = new SnmpVarBind[varBindList.size()];
1048        }
1049        varBindList.copyInto(internalVarBind);
1050    }
1051
1052    /**
1053     * For SNMP Runtime internal use only.
1054     */

1055    final synchronized void setErrorStatusAndIndex(int stat, int idx) {
1056        errorStatus = stat;
1057        errorIndex = idx;
1058    }
1059    
1060    /**
1061     * For SNMP Runtime internal use only.
1062     */

1063    final synchronized void setPrevPollTime(long prev) {
1064        prevPollTime = prev;
1065    }
1066
1067    /**
1068     * For SNMP Runtime internal use only.
1069     */

1070    final void setRequestSentTime(long sendtime) {
1071        numTries++;
1072        setPrevPollTime(sendtime);
1073        waitTimeForResponse = prevPollTime + timeout*numTries;
1074        setRequestStatus(stWaitingForReply);
1075    
1076        if (isTraceOn()) {
1077            trace("setRequestSentTime", "Inform request Successfully sent");
1078        }
1079    
1080        informSession.getSnmpQManager().addWaiting(this);
1081    }
1082
1083    /**
1084     * Initializes the request id from the request counter.
1085     */

1086    final synchronized void initNewRequest() {
1087        requestId = requestCounter.getNewId();
1088    }
1089
1090    /**
1091     * For SNMP Runtime internal use only.
1092     */

1093    long timeRemainingForAction(long currtime) {
1094        switch (reqState) {
1095        case stWaitingToSend :
1096            return nextPollTime - currtime;
1097        case stWaitingForReply :
1098            return waitTimeForResponse - currtime;
1099        default :
1100            return -1;
1101        }
1102    }
1103
1104    /**
1105     * Returns the string state corresponding to the specified integer state.
1106     * @param state The integer state.
1107     * @return The string state.
1108     */

1109    final static String JavaDoc statusDescription(int state) {
1110        switch (state) {
1111        case stWaitingToSend :
1112            return "Waiting to send.";
1113        case stWaitingForReply :
1114            return "Waiting for reply.";
1115        case stReceivedReply :
1116            return "Response arrived.";
1117        case stAborted :
1118            return "Aborted by user.";
1119        case stTimeout :
1120            return "Timeout Occured.";
1121        case stInternalError :
1122            return "Internal error.";
1123        case stResultsAvailable :
1124            return "Results available";
1125        case stNeverUsed :
1126            return "Inform request in createAndWait state";
1127        }
1128        return "Unknown inform request state.";
1129    }
1130
1131    /**
1132     * Sets the request status to the specified value.
1133     * @param reqst The new status request.
1134     */

1135    final synchronized void setRequestStatus(int reqst) {
1136        reqState = reqst;
1137    }
1138
1139    /**
1140     * Gives a status report of the request.
1141     * @return The status report of the request.
1142     */

1143    public synchronized String JavaDoc toString() {
1144        StringBuffer JavaDoc s = new StringBuffer JavaDoc(300) ;
1145        s.append(tostring()) ;
1146        s.append("\nPeer/Port : " + address.getHostName() + "/" + port) ;
1147
1148        return s.toString() ;
1149    }
1150    
1151    private synchronized String JavaDoc tostring() {
1152        StringBuffer JavaDoc s = new StringBuffer JavaDoc("InformRequestId = " + requestId);
1153        s.append(" " + "Status = " + statusDescription(reqState));
1154        s.append(" Timeout/MaxTries/NumTries = " + timeout*numTries + "/" +
1155                 + getMaxTries() + "/" + numTries);
1156
1157        if (prevPollTime > 0) {
1158            debugDate.setTime(prevPollTime);
1159            s.append("\nPrevPolled = " + debugDate.toString());
1160        } else
1161            s.append("\nNeverPolled");
1162        s.append(" / RemainingTime(millis) = " +
1163                 timeRemainingForAction(System.currentTimeMillis()));
1164
1165        return s.toString();
1166    }
1167
1168    // TRACES & DEBUG
1169
//---------------
1170

1171    boolean isTraceOn() {
1172        return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP);
1173    }
1174
1175    void trace(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
1176        Trace.send(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
1177    }
1178
1179    void trace(String JavaDoc func, String JavaDoc info) {
1180        trace(dbgTag, func, info);
1181    }
1182    
1183    boolean isDebugOn() {
1184        return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
1185    }
1186
1187    void debug(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
1188        Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
1189    }
1190
1191    void debug(String JavaDoc clz, String JavaDoc func, Throwable JavaDoc exception) {
1192        Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, exception);
1193    }
1194    
1195    void debug(String JavaDoc func, String JavaDoc info) {
1196        debug(dbgTag, func, info);
1197    }
1198    
1199    void debug(String JavaDoc func, Throwable JavaDoc exception) {
1200        debug(dbgTag, func, exception);
1201    }
1202    
1203}
1204
Popular Tags