KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#)file SnmpSession.java
3  * @(#)author Sun Microsystems, Inc.
4  * @(#)version 1.12
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
13 package com.sun.jmx.snmp.daemon;
14
15
16 // java imports
17
//
18
import java.util.Vector JavaDoc;
19 import java.util.Enumeration JavaDoc;
20 import java.util.Hashtable JavaDoc;
21 import java.util.Stack JavaDoc;
22 import java.net.InetAddress JavaDoc;
23 import java.net.SocketException JavaDoc;
24 import java.io.InterruptedIOException JavaDoc;
25
26 // jmx imports
27
//
28
import com.sun.jmx.snmp.SnmpDefinitions;
29 import com.sun.jmx.snmp.SnmpStatusException;
30 import com.sun.jmx.snmp.SnmpVarBindList;
31 import com.sun.jmx.snmp.SnmpScopedPduRequest;
32 // SNMP runtime imports
33
//
34
import com.sun.jmx.trace.Trace;
35
36 /**
37  * This class is used for sending INFORM REQUESTS from an agent to a manager.
38  *
39  * Creates, controls, and manages one or more inform requests.
40  *
41  * The SnmpSession maintains the list of all active inform requests and inform responses.
42  * Each SnmpSession has a dispatcher that is a thread used to service all the inform requests it creates
43  * and each SnmpSession uses a separate socket for sending/receiving inform requests/responses.
44  *
45  * An SnmpSession object is associated with an SNMP adaptor server.
46  * It is created the first time an inform request is sent by the SNMP adaptor server
47  * and is destroyed (with its associated SnmpSocket) when the SNMP adaptor server is stopped.
48  *
49  */

50
51 class SnmpSession implements SnmpDefinitions, Runnable JavaDoc {
52
53     // PRIVATE VARIABLES
54
//------------------
55

56     /**
57      * The SNMP adaptor associated with this SnmpSession.
58      */

59     protected transient SnmpAdaptorServer adaptor;
60     /**
61      * The SnmpSocket to be used to communicate with the manager
62      * by all inform requests created in this session.
63      */

64     protected transient SnmpSocket informSocket = null;
65     /**
66      * This table maintains the list of inform requests.
67      */

68     private transient Hashtable JavaDoc informRequestList = new Hashtable JavaDoc();
69     /**
70      * This table maintains the list of inform responses.
71      * A FIFO queue is needed here.
72      */

73     private transient Stack JavaDoc informRespq = new Stack JavaDoc();
74     /**
75      * The dispatcher that will service all inform responses to inform requests generated
76      * using this session object. An SnmpSession object creates one or more inform requests.
77      * Thus it services all inform requests, which are created by this session object,
78      * when an inform response arrives for an inform request generated by the session.
79      */

80     private transient Thread JavaDoc myThread = null;
81     /**
82      * Request being synchronized from session thread. This happens when
83      * a user does sync operation from a callback.
84      */

85     private transient SnmpInformRequest syncInformReq ;
86     
87     SnmpQManager snmpQman = null;
88     
89     String JavaDoc dbgTag = "SnmpSession";
90     
91     private boolean isBeingCancelled = false;
92     
93     // PUBLIC CONSTRUCTORS
94
//--------------------
95

96     /**
97      * Constructor for creating a new session.
98      * @param adp The SNMP adaptor associated with this SnmpSession.
99      * @exception SocketException Unable to initialize the SnmpSocket.
100      */

101     public SnmpSession(SnmpAdaptorServer adp) throws SocketException JavaDoc {
102         adaptor = adp;
103     snmpQman = new SnmpQManager();
104     SnmpResponseHandler snmpRespHdlr = new SnmpResponseHandler(adp, snmpQman);
105         initialize(adp, snmpRespHdlr);
106     }
107     /**
108      * Constructor for creating a new session. Allows subclassing.
109      */

110     public SnmpSession() throws SocketException JavaDoc {
111     }
112     // OTHER METHODS
113
//--------------
114
/**
115      * Initializes the SnmpSession.
116      * @param adp The SNMP adaptor associated with this SnmpSession.
117      * @exception SocketException Unable to initialize the SnmpSocket.
118      */

119     protected synchronized void initialize(SnmpAdaptorServer adp,
120                        SnmpResponseHandler snmpRespHdlr)
121     throws SocketException JavaDoc {
122     informSocket = new SnmpSocket(snmpRespHdlr, adp.getAddress(), adp.getBufferSize().intValue());
123
124         myThread = new Thread JavaDoc(this, "SnmpSession");
125         myThread.start();
126     }
127
128     /**
129      * Indicates whether the thread for this session is active and the SNMP adaptor server ONLINE.
130      * @return true if active, false otherwise.
131      */

132     synchronized boolean isSessionActive() {
133         //return ((myThread != null) && (myThread.isAlive()));
134
return ((adaptor.isActive()) && (myThread != null) && (myThread.isAlive()));
135     }
136     
137     /**
138      * Gets the SnmpSocket which will be used by inform requests created in this session.
139      * @return The socket which will be used in this session.
140      */

141     SnmpSocket getSocket() {
142         return informSocket;
143     }
144
145     /**
146      * Gets the SnmpQManager which will be used by inform requests created in this session.
147      * @return The SnmpQManager which will be used in this session.
148      */

149     SnmpQManager getSnmpQManager() {
150         return snmpQman;
151     }
152
153     /**
154      * Indicates whether this session is performing synchronous operation for an inform request.
155      * @return <CODE>true</CODE> if the session is performing synchronous operation, <CODE>false</CODE> otherwise.
156      */

157     private synchronized boolean syncInProgress() {
158         return syncInformReq != null ;
159     }
160     
161     private synchronized void setSyncMode(SnmpInformRequest req) {
162         syncInformReq = req ;
163     }
164
165     private synchronized void resetSyncMode() {
166         if (syncInformReq == null)
167             return ;
168         syncInformReq = null ;
169         if (thisSessionContext())
170             return ;
171         this.notifyAll() ;
172     }
173     
174     /**
175      * Returns <CODE>true</CODE> if the current executing thread is this session's dispatcher.
176      * Typically used to detect whether the user is doing a sync operation from
177      * this dispatcher context. For instance, a user gives a sync command
178      * from within a request callback using its associated session.
179      * @return <CODE>true</CODE> if current thread is this session's dispatcher, <CODE>false</CODE> otherwise.
180      */

181     boolean thisSessionContext() {
182         return (Thread.currentThread() == myThread) ;
183     }
184     
185     /**
186      * Sends an inform request to the specified InetAddress destination using the specified community string.
187      * @param addr The InetAddress destination for this inform request.
188      * @param cs The community string to be used for the inform request.
189      * @param cb The callback that is invoked when a request is complete.
190      * @param vblst A list of SnmpVarBind instances or null.
191      * @exception SnmpStatusException SNMP adaptor is not ONLINE or session
192      * is dead.
193      */

194     SnmpInformRequest makeAsyncRequest(InetAddress JavaDoc addr, String JavaDoc cs,
195                        SnmpInformHandler cb,
196                        SnmpVarBindList vblst, int port)
197         throws SnmpStatusException {
198         
199         if (!isSessionActive()) {
200             throw new SnmpStatusException("SNMP adaptor server not ONLINE");
201         }
202         SnmpInformRequest snmpreq = new SnmpInformRequest(this, adaptor, addr, cs, port, cb);
203         snmpreq.start(vblst);
204         return snmpreq;
205     }
206
207     /**
208      * Performs sync operations on active requests. Any number of inform requests
209      * can be done in sync mode but only one per thread.
210      * The user can do synchronous operation using the request handle only.
211      */

212     void waitForResponse(SnmpInformRequest req, long waitTime) {
213         
214         if (! req.inProgress())
215             return ;
216         setSyncMode(req) ;
217
218         if (isTraceOn()) {
219             trace("waitForResponse", "Session switching to sync mode for inform request " + req.getRequestId());
220         }
221         long maxTime ;
222         if (waitTime <= 0)
223             maxTime = System.currentTimeMillis() + 6000 * 1000 ;
224         else
225             maxTime = System.currentTimeMillis() + waitTime ;
226
227         while (req.inProgress() || syncInProgress()) {
228             waitTime = maxTime - System.currentTimeMillis() ;
229             if (waitTime <= 0)
230                 break ;
231             synchronized (this) {
232                 if (! informRespq.removeElement(req)) {
233                     try {
234                         this.wait(waitTime) ;
235                     } catch(InterruptedException JavaDoc e) {
236                     }
237                     continue ;
238                 }
239             }
240             try {
241                 processResponse(req) ;
242             } catch (Exception JavaDoc e) {
243                 if (isDebugOn()) {
244                     debug("waitForResponse", e);
245                 }
246             }
247         }
248         resetSyncMode() ;
249         return ;
250     }
251     
252     /**
253      * Dispatcher method for this session thread. This is the dispatcher method
254      * which goes in an endless-loop and waits for servicing inform requests
255      * which received a reply from the manager.
256      */

257     public void run() {
258         myThread = Thread.currentThread();
259         myThread.setPriority(Thread.NORM_PRIORITY);
260
261         SnmpInformRequest reqc = null;
262         while (myThread != null) {
263             try {
264                 reqc = nextResponse();
265                 if (reqc != null) {
266                     processResponse(reqc);
267                 }
268             } catch (ThreadDeath JavaDoc d) {
269                 myThread = null;
270                 if (isDebugOn()) {
271                     debug("run", "Session thread unexpectedly shutting down");
272                 }
273                 throw d ;
274             }
275         }
276         if (isTraceOn()) {
277             trace("run", "Session thread shutting down");
278         }
279         myThread = null ;
280     }
281     
282     private void processResponse(SnmpInformRequest reqc) {
283         
284         while (reqc != null && myThread != null) {
285             try {
286                 if (reqc != null) {
287                     if (isTraceOn()) {
288                         trace("processResponse", "Processing response to req = " + reqc.getRequestId());
289                     }
290                     reqc.processResponse() ; // Handles out of memory.
291
reqc = null ; // finished processing.
292
}
293                 
294             } catch (Exception JavaDoc e) {
295                 if (isDebugOn()) {
296                     debug("processResponse", e);
297                 }
298                 reqc = null ;
299             } catch (OutOfMemoryError JavaDoc ome) {
300                 if (isDebugOn()) {
301                     debug("processResponse", "Out of memory error in session thread");
302                     debug("processResponse", ome);
303                 }
304                 Thread.currentThread().yield();
305                 continue ; // re-process the request.
306
}
307         }
308     }
309     
310     // HANDLING INFORM REQUESTS LIST AND INFORM RESPONSES LIST
311
//--------------------------------------------------------
312

313     /**
314      * Adds an inform request.
315      * @param snmpreq The inform request to add.
316      * @exception SnmpStatusException SNMP adaptor is not ONLINE or session is dead.
317      */

318     synchronized void addInformRequest(SnmpInformRequest snmpreq) throws SnmpStatusException {
319         
320         // If the adaptor is not ONLINE, stop adding requests.
321
//
322
if (!isSessionActive()) {
323             throw new SnmpStatusException("SNMP adaptor is not ONLINE or session is dead...") ;
324         }
325         informRequestList.put(snmpreq, snmpreq);
326     }
327     
328     /**
329      * Deletes an inform request.
330      * @param snmpreq The inform request to delete.
331      */

332     synchronized void removeInformRequest(SnmpInformRequest snmpreq) {
333     // deleteRequest can be called from destroySnmpSession.
334
//In such a case remove is done in cancelAllRequest method.
335
if(!isBeingCancelled)
336         informRequestList.remove(snmpreq) ;
337
338         if (syncInformReq != null && syncInformReq == snmpreq) {
339             resetSyncMode() ;
340         }
341     }
342             
343     /**
344      * Cancels all pending inform requests in this session.
345      */

346     private void cancelAllRequests() {
347         final SnmpInformRequest[] list;
348     
349     synchronized(this) {
350         
351         if (informRequestList.isEmpty()) {
352         return ;
353         }
354
355         isBeingCancelled = true;
356         
357         list = new SnmpInformRequest[informRequestList.size()];
358         java.util.Iterator JavaDoc it = informRequestList.values().iterator();
359         int i = 0;
360         while(it.hasNext()) {
361         SnmpInformRequest req = (SnmpInformRequest)it.next();
362         list[i++] = req;
363         it.remove();
364         }
365         informRequestList.clear();
366     }
367     
368     for(int i = 0; i < list.length; i++)
369         list[i].cancelRequest();
370     }
371     
372     /**
373      * Adds the inform request object which received a response to an inform request
374      * generated by the session. This is added to a private store, which
375      * will be eventually picked up by the dispatcher for processing.
376      * @param reqc The inform request that received the response from the manager.
377      */

378     void addResponse(SnmpInformRequest reqc) {
379         
380         SnmpInformRequest snmpreq = (SnmpInformRequest) reqc ;
381         if (isSessionActive()) {
382             synchronized(this) {
383                 informRespq.push(reqc) ;
384                 this.notifyAll() ;
385             }
386         } else {
387             if (isDebugOn()) {
388                 debug("addResponse", "Adaptor not ONLINE or session thread dead. So inform response is dropped..." + reqc.getRequestId());
389             }
390         }
391         return ;
392     }
393
394     private synchronized SnmpInformRequest nextResponse() {
395         
396         if (informRespq.isEmpty()) {
397             try {
398                 if (isTraceOn()) {
399                     trace("nextResponse", "Blocking for response");
400                 }
401                 this.wait();
402             } catch(InterruptedException JavaDoc e) {
403             }
404         }
405         if (informRespq.isEmpty())
406             return null;
407         SnmpInformRequest reqc = (SnmpInformRequest) informRespq.firstElement();
408         informRespq.removeElementAt(0) ;
409         return reqc ;
410     }
411     
412     private synchronized void cancelAllResponses() {
413         if (informRespq != null) {
414             syncInformReq = null ;
415             informRespq.removeAllElements() ;
416             this.notifyAll() ;
417         }
418     }
419     
420     /**
421      * Destroys any pending inform requests and then stops the session.
422      * The session will not be usable after this method returns.
423      */

424     final void destroySession() {
425         
426         cancelAllRequests() ;
427         cancelAllResponses() ;
428         synchronized(this) {
429             informSocket.close() ;
430             informSocket = null ;
431         }
432         snmpQman.stopQThreads() ;
433         snmpQman = null ;
434         killSessionThread() ;
435     }
436     
437     /**
438      * Make sure you are killing the thread when it is active. Instead
439      * prepare for a graceful exit.
440      */

441     private synchronized void killSessionThread() {
442         
443         if ((myThread != null) && (myThread.isAlive())) {
444             if (isTraceOn()) {
445                 trace("killSessionThread", "Destroying session");
446             }
447             if (!thisSessionContext()) {
448                 myThread = null ;
449                 this.notifyAll() ;
450             } else
451                 myThread = null ;
452         }
453     }
454
455     /**
456      * Finalizer of the <CODE>SnmpSession</CODE> objects.
457      * This method is called by the garbage collector on an object
458      * when garbage collection determines that there are no more references to the object.
459      * <P>Removes all the requests for this SNMP session, closes the socket and
460      * sets all the references to the <CODE>SnmpSession</CODE> object to <CODE>null</CODE>.
461      */

462     public void finalize() {
463         
464         if (informRespq != null)
465             informRespq.removeAllElements() ;
466         informRespq = null ;
467         if (informSocket != null)
468             informSocket.close() ;
469         informSocket = null ;
470
471         if (isTraceOn()) {
472             trace("finalize", "Shutting all servers");
473         }
474         snmpQman = null ;
475     }
476     
477     // TRACES & DEBUG
478
//---------------
479

480     boolean isTraceOn() {
481         return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP);
482     }
483
484     void trace(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
485         Trace.send(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
486     }
487
488     void trace(String JavaDoc func, String JavaDoc info) {
489         trace(dbgTag, func, info);
490     }
491     
492     boolean isDebugOn() {
493         return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
494     }
495
496     void debug(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
497         Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
498     }
499
500     void debug(String JavaDoc clz, String JavaDoc func, Throwable JavaDoc exception) {
501         Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, exception);
502     }
503
504     void debug(String JavaDoc func, String JavaDoc info) {
505         debug(dbgTag, func, info);
506     }
507     
508     void debug(String JavaDoc func, Throwable JavaDoc exception) {
509         debug(dbgTag, func, exception);
510     }
511 }
512
Popular Tags