PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jre-1.6.0/src/com/sun/jmx/snmp/daemon/SnmpSession.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 511 lines | 289 code | 65 blank | 157 comment | 58 complexity | d9ca0ddbfb29a09d299664898464e462 MD5 | raw file
  1. /*
  2. * %Z%file %M%
  3. * %Z%author Sun Microsystems, Inc.
  4. * %Z%version %I%
  5. * %Z%date %D%
  6. *
  7. * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
  8. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. *
  10. */
  11. package com.sun.jmx.snmp.daemon;
  12. // java imports
  13. //
  14. import java.util.Vector;
  15. import java.util.Enumeration;
  16. import java.util.Hashtable;
  17. import java.util.Stack;
  18. import java.net.InetAddress;
  19. import java.net.SocketException;
  20. import java.io.InterruptedIOException;
  21. // jmx imports
  22. //
  23. import com.sun.jmx.snmp.SnmpDefinitions;
  24. import com.sun.jmx.snmp.SnmpStatusException;
  25. import com.sun.jmx.snmp.SnmpVarBindList;
  26. import com.sun.jmx.snmp.SnmpScopedPduRequest;
  27. // SNMP runtime imports
  28. //
  29. import com.sun.jmx.trace.Trace;
  30. /**
  31. * This class is used for sending INFORM REQUESTS from an agent to a manager.
  32. *
  33. * Creates, controls, and manages one or more inform requests.
  34. *
  35. * The SnmpSession maintains the list of all active inform requests and inform responses.
  36. * Each SnmpSession has a dispatcher that is a thread used to service all the inform requests it creates
  37. * and each SnmpSession uses a separate socket for sending/receiving inform requests/responses.
  38. *
  39. * An SnmpSession object is associated with an SNMP adaptor server.
  40. * It is created the first time an inform request is sent by the SNMP adaptor server
  41. * and is destroyed (with its associated SnmpSocket) when the SNMP adaptor server is stopped.
  42. *
  43. */
  44. class SnmpSession implements SnmpDefinitions, Runnable {
  45. // PRIVATE VARIABLES
  46. //------------------
  47. /**
  48. * The SNMP adaptor associated with this SnmpSession.
  49. */
  50. protected transient SnmpAdaptorServer adaptor;
  51. /**
  52. * The SnmpSocket to be used to communicate with the manager
  53. * by all inform requests created in this session.
  54. */
  55. protected transient SnmpSocket informSocket = null;
  56. /**
  57. * This table maintains the list of inform requests.
  58. */
  59. private transient Hashtable informRequestList = new Hashtable();
  60. /**
  61. * This table maintains the list of inform responses.
  62. * A FIFO queue is needed here.
  63. */
  64. private transient Stack informRespq = new Stack();
  65. /**
  66. * The dispatcher that will service all inform responses to inform requests generated
  67. * using this session object. An SnmpSession object creates one or more inform requests.
  68. * Thus it services all inform requests, which are created by this session object,
  69. * when an inform response arrives for an inform request generated by the session.
  70. */
  71. private transient Thread myThread = null;
  72. /**
  73. * Request being synchronized from session thread. This happens when
  74. * a user does sync operation from a callback.
  75. */
  76. private transient SnmpInformRequest syncInformReq ;
  77. SnmpQManager snmpQman = null;
  78. String dbgTag = "SnmpSession";
  79. private boolean isBeingCancelled = false;
  80. // PUBLIC CONSTRUCTORS
  81. //--------------------
  82. /**
  83. * Constructor for creating a new session.
  84. * @param adp The SNMP adaptor associated with this SnmpSession.
  85. * @exception SocketException Unable to initialize the SnmpSocket.
  86. */
  87. public SnmpSession(SnmpAdaptorServer adp) throws SocketException {
  88. adaptor = adp;
  89. snmpQman = new SnmpQManager();
  90. SnmpResponseHandler snmpRespHdlr = new SnmpResponseHandler(adp, snmpQman);
  91. initialize(adp, snmpRespHdlr);
  92. }
  93. /**
  94. * Constructor for creating a new session. Allows subclassing.
  95. */
  96. public SnmpSession() throws SocketException {
  97. }
  98. // OTHER METHODS
  99. //--------------
  100. /**
  101. * Initializes the SnmpSession.
  102. * @param adp The SNMP adaptor associated with this SnmpSession.
  103. * @exception SocketException Unable to initialize the SnmpSocket.
  104. */
  105. protected synchronized void initialize(SnmpAdaptorServer adp,
  106. SnmpResponseHandler snmpRespHdlr)
  107. throws SocketException {
  108. informSocket = new SnmpSocket(snmpRespHdlr, adp.getAddress(), adp.getBufferSize().intValue());
  109. myThread = new Thread(this, "SnmpSession");
  110. myThread.start();
  111. }
  112. /**
  113. * Indicates whether the thread for this session is active and the SNMP adaptor server ONLINE.
  114. * @return true if active, false otherwise.
  115. */
  116. synchronized boolean isSessionActive() {
  117. //return ((myThread != null) && (myThread.isAlive()));
  118. return ((adaptor.isActive()) && (myThread != null) && (myThread.isAlive()));
  119. }
  120. /**
  121. * Gets the SnmpSocket which will be used by inform requests created in this session.
  122. * @return The socket which will be used in this session.
  123. */
  124. SnmpSocket getSocket() {
  125. return informSocket;
  126. }
  127. /**
  128. * Gets the SnmpQManager which will be used by inform requests created in this session.
  129. * @return The SnmpQManager which will be used in this session.
  130. */
  131. SnmpQManager getSnmpQManager() {
  132. return snmpQman;
  133. }
  134. /**
  135. * Indicates whether this session is performing synchronous operation for an inform request.
  136. * @return <CODE>true</CODE> if the session is performing synchronous operation, <CODE>false</CODE> otherwise.
  137. */
  138. private synchronized boolean syncInProgress() {
  139. return syncInformReq != null ;
  140. }
  141. private synchronized void setSyncMode(SnmpInformRequest req) {
  142. syncInformReq = req ;
  143. }
  144. private synchronized void resetSyncMode() {
  145. if (syncInformReq == null)
  146. return ;
  147. syncInformReq = null ;
  148. if (thisSessionContext())
  149. return ;
  150. this.notifyAll() ;
  151. }
  152. /**
  153. * Returns <CODE>true</CODE> if the current executing thread is this session's dispatcher.
  154. * Typically used to detect whether the user is doing a sync operation from
  155. * this dispatcher context. For instance, a user gives a sync command
  156. * from within a request callback using its associated session.
  157. * @return <CODE>true</CODE> if current thread is this session's dispatcher, <CODE>false</CODE> otherwise.
  158. */
  159. boolean thisSessionContext() {
  160. return (Thread.currentThread() == myThread) ;
  161. }
  162. /**
  163. * Sends an inform request to the specified InetAddress destination using the specified community string.
  164. * @param addr The InetAddress destination for this inform request.
  165. * @param cs The community string to be used for the inform request.
  166. * @param cb The callback that is invoked when a request is complete.
  167. * @param vblst A list of SnmpVarBind instances or null.
  168. * @exception SnmpStatusException SNMP adaptor is not ONLINE or session
  169. * is dead.
  170. */
  171. SnmpInformRequest makeAsyncRequest(InetAddress addr, String cs,
  172. SnmpInformHandler cb,
  173. SnmpVarBindList vblst, int port)
  174. throws SnmpStatusException {
  175. if (!isSessionActive()) {
  176. throw new SnmpStatusException("SNMP adaptor server not ONLINE");
  177. }
  178. SnmpInformRequest snmpreq = new SnmpInformRequest(this, adaptor, addr, cs, port, cb);
  179. snmpreq.start(vblst);
  180. return snmpreq;
  181. }
  182. /**
  183. * Performs sync operations on active requests. Any number of inform requests
  184. * can be done in sync mode but only one per thread.
  185. * The user can do synchronous operation using the request handle only.
  186. */
  187. void waitForResponse(SnmpInformRequest req, long waitTime) {
  188. if (! req.inProgress())
  189. return ;
  190. setSyncMode(req) ;
  191. if (isTraceOn()) {
  192. trace("waitForResponse", "Session switching to sync mode for inform request " + req.getRequestId());
  193. }
  194. long maxTime ;
  195. if (waitTime <= 0)
  196. maxTime = System.currentTimeMillis() + 6000 * 1000 ;
  197. else
  198. maxTime = System.currentTimeMillis() + waitTime ;
  199. while (req.inProgress() || syncInProgress()) {
  200. waitTime = maxTime - System.currentTimeMillis() ;
  201. if (waitTime <= 0)
  202. break ;
  203. synchronized (this) {
  204. if (! informRespq.removeElement(req)) {
  205. try {
  206. this.wait(waitTime) ;
  207. } catch(InterruptedException e) {
  208. }
  209. continue ;
  210. }
  211. }
  212. try {
  213. processResponse(req) ;
  214. } catch (Exception e) {
  215. if (isDebugOn()) {
  216. debug("waitForResponse", e);
  217. }
  218. }
  219. }
  220. resetSyncMode() ;
  221. return ;
  222. }
  223. /**
  224. * Dispatcher method for this session thread. This is the dispatcher method
  225. * which goes in an endless-loop and waits for servicing inform requests
  226. * which received a reply from the manager.
  227. */
  228. public void run() {
  229. myThread = Thread.currentThread();
  230. myThread.setPriority(Thread.NORM_PRIORITY);
  231. SnmpInformRequest reqc = null;
  232. while (myThread != null) {
  233. try {
  234. reqc = nextResponse();
  235. if (reqc != null) {
  236. processResponse(reqc);
  237. }
  238. } catch (ThreadDeath d) {
  239. myThread = null;
  240. if (isDebugOn()) {
  241. debug("run", "Session thread unexpectedly shutting down");
  242. }
  243. throw d ;
  244. }
  245. }
  246. if (isTraceOn()) {
  247. trace("run", "Session thread shutting down");
  248. }
  249. myThread = null ;
  250. }
  251. private void processResponse(SnmpInformRequest reqc) {
  252. while (reqc != null && myThread != null) {
  253. try {
  254. if (reqc != null) {
  255. if (isTraceOn()) {
  256. trace("processResponse", "Processing response to req = " + reqc.getRequestId());
  257. }
  258. reqc.processResponse() ; // Handles out of memory.
  259. reqc = null ; // finished processing.
  260. }
  261. } catch (Exception e) {
  262. if (isDebugOn()) {
  263. debug("processResponse", e);
  264. }
  265. reqc = null ;
  266. } catch (OutOfMemoryError ome) {
  267. if (isDebugOn()) {
  268. debug("processResponse", "Out of memory error in session thread");
  269. debug("processResponse", ome);
  270. }
  271. Thread.currentThread().yield();
  272. continue ; // re-process the request.
  273. }
  274. }
  275. }
  276. // HANDLING INFORM REQUESTS LIST AND INFORM RESPONSES LIST
  277. //--------------------------------------------------------
  278. /**
  279. * Adds an inform request.
  280. * @param snmpreq The inform request to add.
  281. * @exception SnmpStatusException SNMP adaptor is not ONLINE or session is dead.
  282. */
  283. synchronized void addInformRequest(SnmpInformRequest snmpreq) throws SnmpStatusException {
  284. // If the adaptor is not ONLINE, stop adding requests.
  285. //
  286. if (!isSessionActive()) {
  287. throw new SnmpStatusException("SNMP adaptor is not ONLINE or session is dead...") ;
  288. }
  289. informRequestList.put(snmpreq, snmpreq);
  290. }
  291. /**
  292. * Deletes an inform request.
  293. * @param snmpreq The inform request to delete.
  294. */
  295. synchronized void removeInformRequest(SnmpInformRequest snmpreq) {
  296. // deleteRequest can be called from destroySnmpSession.
  297. //In such a case remove is done in cancelAllRequest method.
  298. if(!isBeingCancelled)
  299. informRequestList.remove(snmpreq) ;
  300. if (syncInformReq != null && syncInformReq == snmpreq) {
  301. resetSyncMode() ;
  302. }
  303. }
  304. /**
  305. * Cancels all pending inform requests in this session.
  306. */
  307. private void cancelAllRequests() {
  308. final SnmpInformRequest[] list;
  309. synchronized(this) {
  310. if (informRequestList.isEmpty()) {
  311. return ;
  312. }
  313. isBeingCancelled = true;
  314. list = new SnmpInformRequest[informRequestList.size()];
  315. java.util.Iterator it = informRequestList.values().iterator();
  316. int i = 0;
  317. while(it.hasNext()) {
  318. SnmpInformRequest req = (SnmpInformRequest)it.next();
  319. list[i++] = req;
  320. it.remove();
  321. }
  322. informRequestList.clear();
  323. }
  324. for(int i = 0; i < list.length; i++)
  325. list[i].cancelRequest();
  326. }
  327. /**
  328. * Adds the inform request object which received a response to an inform request
  329. * generated by the session. This is added to a private store, which
  330. * will be eventually picked up by the dispatcher for processing.
  331. * @param reqc The inform request that received the response from the manager.
  332. */
  333. void addResponse(SnmpInformRequest reqc) {
  334. SnmpInformRequest snmpreq = (SnmpInformRequest) reqc ;
  335. if (isSessionActive()) {
  336. synchronized(this) {
  337. informRespq.push(reqc) ;
  338. this.notifyAll() ;
  339. }
  340. } else {
  341. if (isDebugOn()) {
  342. debug("addResponse", "Adaptor not ONLINE or session thread dead. So inform response is dropped..." + reqc.getRequestId());
  343. }
  344. }
  345. return ;
  346. }
  347. private synchronized SnmpInformRequest nextResponse() {
  348. if (informRespq.isEmpty()) {
  349. try {
  350. if (isTraceOn()) {
  351. trace("nextResponse", "Blocking for response");
  352. }
  353. this.wait();
  354. } catch(InterruptedException e) {
  355. }
  356. }
  357. if (informRespq.isEmpty())
  358. return null;
  359. SnmpInformRequest reqc = (SnmpInformRequest) informRespq.firstElement();
  360. informRespq.removeElementAt(0) ;
  361. return reqc ;
  362. }
  363. private synchronized void cancelAllResponses() {
  364. if (informRespq != null) {
  365. syncInformReq = null ;
  366. informRespq.removeAllElements() ;
  367. this.notifyAll() ;
  368. }
  369. }
  370. /**
  371. * Destroys any pending inform requests and then stops the session.
  372. * The session will not be usable after this method returns.
  373. */
  374. final void destroySession() {
  375. cancelAllRequests() ;
  376. cancelAllResponses() ;
  377. synchronized(this) {
  378. informSocket.close() ;
  379. informSocket = null ;
  380. }
  381. snmpQman.stopQThreads() ;
  382. snmpQman = null ;
  383. killSessionThread() ;
  384. }
  385. /**
  386. * Make sure you are killing the thread when it is active. Instead
  387. * prepare for a graceful exit.
  388. */
  389. private synchronized void killSessionThread() {
  390. if ((myThread != null) && (myThread.isAlive())) {
  391. if (isTraceOn()) {
  392. trace("killSessionThread", "Destroying session");
  393. }
  394. if (!thisSessionContext()) {
  395. myThread = null ;
  396. this.notifyAll() ;
  397. } else
  398. myThread = null ;
  399. }
  400. }
  401. /**
  402. * Finalizer of the <CODE>SnmpSession</CODE> objects.
  403. * This method is called by the garbage collector on an object
  404. * when garbage collection determines that there are no more references to the object.
  405. * <P>Removes all the requests for this SNMP session, closes the socket and
  406. * sets all the references to the <CODE>SnmpSession</CODE> object to <CODE>null</CODE>.
  407. */
  408. public void finalize() {
  409. if (informRespq != null)
  410. informRespq.removeAllElements() ;
  411. informRespq = null ;
  412. if (informSocket != null)
  413. informSocket.close() ;
  414. informSocket = null ;
  415. if (isTraceOn()) {
  416. trace("finalize", "Shutting all servers");
  417. }
  418. snmpQman = null ;
  419. }
  420. // TRACES & DEBUG
  421. //---------------
  422. boolean isTraceOn() {
  423. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP);
  424. }
  425. void trace(String clz, String func, String info) {
  426. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
  427. }
  428. void trace(String func, String info) {
  429. trace(dbgTag, func, info);
  430. }
  431. boolean isDebugOn() {
  432. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
  433. }
  434. void debug(String clz, String func, String info) {
  435. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
  436. }
  437. void debug(String clz, String func, Throwable exception) {
  438. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, exception);
  439. }
  440. void debug(String func, String info) {
  441. debug(dbgTag, func, info);
  442. }
  443. void debug(String func, Throwable exception) {
  444. debug(dbgTag, func, exception);
  445. }
  446. }