PageRenderTime 61ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1372 lines | 610 code | 140 blank | 622 comment | 111 complexity | 56646be23f8a35a1cd2390cf4b293e78 MD5 | raw file
  1. /*
  2. * %Z%file %M%
  3. * %Z%author Sun Microsystems, Inc.
  4. * %Z%version %I%
  5. * %Z%lastedit %E%
  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 import
  13. //
  14. import java.io.ObjectInputStream;
  15. import java.io.IOException;
  16. import java.net.InetAddress;
  17. import java.util.Vector;
  18. import java.util.Enumeration;
  19. // jmx import
  20. //
  21. import javax.management.MBeanServer;
  22. import javax.management.MBeanRegistration;
  23. import javax.management.ObjectName;
  24. import javax.management.NotificationListener;
  25. import javax.management.NotificationFilter;
  26. import javax.management.NotificationBroadcaster;
  27. import javax.management.NotificationBroadcasterSupport;
  28. import javax.management.MBeanNotificationInfo;
  29. import javax.management.AttributeChangeNotification;
  30. import javax.management.ListenerNotFoundException;
  31. import javax.management.loading.ClassLoaderRepository;
  32. import javax.management.MBeanServerFactory;
  33. // jmx RI import
  34. //
  35. import com.sun.jmx.trace.Trace;
  36. import java.util.NoSuchElementException;
  37. // JSR 160 import
  38. //
  39. // XXX Revisit:
  40. // used to import com.sun.jmx.snmp.MBeanServerForwarder
  41. // Now using JSR 160 instead. => this is an additional
  42. // dependency to JSR 160.
  43. //
  44. import javax.management.remote.MBeanServerForwarder;
  45. /**
  46. * Defines generic behavior for the server part of a connector or an adaptor.
  47. * Most connectors or adaptors extend <CODE>CommunicatorServer</CODE>
  48. * and inherit this behavior. Connectors or adaptors that do not fit into
  49. * this model do not extend <CODE>CommunicatorServer</CODE>.
  50. * <p>
  51. * A <CODE>CommunicatorServer</CODE> is an active object, it listens for
  52. * client requests and processes them in its own thread. When necessary, a
  53. * <CODE>CommunicatorServer</CODE> creates other threads to process multiple
  54. * requests concurrently.
  55. * <p>
  56. * A <CODE>CommunicatorServer</CODE> object can be stopped by calling the
  57. * <CODE>stop</CODE> method. When it is stopped, the
  58. * <CODE>CommunicatorServer</CODE> no longer listens to client requests and
  59. * no longer holds any thread or communication resources.
  60. * It can be started again by calling the <CODE>start</CODE> method.
  61. * <p>
  62. * A <CODE>CommunicatorServer</CODE> has a <CODE>State</CODE> attribute
  63. * which reflects its activity.
  64. * <p>
  65. * <TABLE>
  66. * <TR><TH>CommunicatorServer</TH> <TH>State</TH></TR>
  67. * <TR><TD><CODE>stopped</CODE></TD> <TD><CODE>OFFLINE</CODE></TD></TR>
  68. * <TR><TD><CODE>starting</CODE></TD> <TD><CODE>STARTING</CODE></TD></TR>
  69. * <TR><TD><CODE>running</CODE></TD> <TD><CODE>ONLINE</CODE></TD></TR>
  70. * <TR><TD><CODE>stopping</CODE></TD> <TD><CODE>STOPPING</CODE></TD></TR>
  71. * </TABLE>
  72. * <p>
  73. * The <CODE>STARTING</CODE> state marks the transition
  74. * from <CODE>OFFLINE</CODE> to <CODE>ONLINE</CODE>.
  75. * <p>
  76. * The <CODE>STOPPING</CODE> state marks the transition from
  77. * <CODE>ONLINE</CODE> to <CODE>OFFLINE</CODE>. This occurs when the
  78. * <CODE>CommunicatorServer</CODE> is finishing or interrupting active
  79. * requests.
  80. * <p>
  81. * When a <CODE>CommunicatorServer</CODE> is unregistered from the MBeanServer,
  82. * it is stopped automatically.
  83. * <p>
  84. * When the value of the <CODE>State</CODE> attribute changes the
  85. * <CODE>CommunicatorServer</CODE> sends a
  86. * <tt>{@link javax.management.AttributeChangeNotification}</tt> to the
  87. * registered listeners, if any.
  88. *
  89. * <p><b>This API is a Sun Microsystems internal API and is subject
  90. * to change without notice.</b></p>
  91. * @version %I% %G%
  92. * @author Sun Microsystems, Inc
  93. */
  94. public abstract class CommunicatorServer
  95. implements Runnable, MBeanRegistration, NotificationBroadcaster,
  96. CommunicatorServerMBean {
  97. //
  98. // States of a CommunicatorServer
  99. //
  100. /**
  101. * Represents an <CODE>ONLINE</CODE> state.
  102. */
  103. public static final int ONLINE = 0 ;
  104. /**
  105. * Represents an <CODE>OFFLINE</CODE> state.
  106. */
  107. public static final int OFFLINE = 1 ;
  108. /**
  109. * Represents a <CODE>STOPPING</CODE> state.
  110. */
  111. public static final int STOPPING = 2 ;
  112. /**
  113. * Represents a <CODE>STARTING</CODE> state.
  114. */
  115. public static final int STARTING = 3 ;
  116. //
  117. // Types of connectors.
  118. //
  119. /**
  120. * Indicates that it is an RMI connector type.
  121. */
  122. //public static final int RMI_TYPE = 1 ;
  123. /**
  124. * Indicates that it is an HTTP connector type.
  125. */
  126. //public static final int HTTP_TYPE = 2 ;
  127. /**
  128. * Indicates that it is an HTML connector type.
  129. */
  130. //public static final int HTML_TYPE = 3 ;
  131. /**
  132. * Indicates that it is an SNMP connector type.
  133. */
  134. public static final int SNMP_TYPE = 4 ;
  135. /**
  136. * Indicates that it is an HTTPS connector type.
  137. */
  138. //public static final int HTTPS_TYPE = 5 ;
  139. //
  140. // Package variables
  141. //
  142. /**
  143. * The state of the connector server.
  144. */
  145. transient volatile int state = OFFLINE ;
  146. /**
  147. * The object name of the connector server.
  148. * @serial
  149. */
  150. ObjectName objectName ;
  151. MBeanServer topMBS;
  152. MBeanServer bottomMBS;
  153. /**
  154. */
  155. transient String dbgTag = null ;
  156. /**
  157. * The maximum number of clients that the CommunicatorServer can
  158. * process concurrently.
  159. * @serial
  160. */
  161. int maxActiveClientCount = 1 ;
  162. /**
  163. */
  164. transient int servedClientCount = 0 ;
  165. /**
  166. * The host name used by this CommunicatorServer.
  167. * @serial
  168. */
  169. String host = null ;
  170. /**
  171. * The port number used by this CommunicatorServer.
  172. * @serial
  173. */
  174. int port = -1 ;
  175. //
  176. // Private fields
  177. //
  178. /* This object controls access to the "state" and "interrupted" variables.
  179. If held at the same time as the lock on "this", the "this" lock must
  180. be taken first. */
  181. private transient Object stateLock = new Object();
  182. private transient Vector<ClientHandler>
  183. clientHandlerVector = new Vector<ClientHandler>() ;
  184. private transient Thread fatherThread = Thread.currentThread() ;
  185. private transient Thread mainThread = null ;
  186. private volatile boolean stopRequested = false ;
  187. private boolean interrupted = false;
  188. private transient Exception startException = null;
  189. // Notifs count, broadcaster and info
  190. private transient long notifCount = 0;
  191. private transient NotificationBroadcasterSupport notifBroadcaster =
  192. new NotificationBroadcasterSupport();
  193. private transient MBeanNotificationInfo[] notifInfos = null;
  194. /**
  195. * Instantiates a <CODE>CommunicatorServer</CODE>.
  196. *
  197. * @param connectorType Indicates the connector type. Possible values are:
  198. * SNMP_TYPE.
  199. *
  200. * @exception <CODE>java.lang.IllegalArgumentException</CODE>
  201. * This connector type is not correct.
  202. */
  203. public CommunicatorServer(int connectorType)
  204. throws IllegalArgumentException {
  205. switch (connectorType) {
  206. case SNMP_TYPE :
  207. infoType = Trace.INFO_ADAPTOR_SNMP ;
  208. break;
  209. default:
  210. throw new IllegalArgumentException("Invalid connector Type") ;
  211. }
  212. dbgTag = makeDebugTag() ;
  213. }
  214. protected Thread createMainThread() {
  215. return new Thread (this, makeThreadName());
  216. }
  217. /**
  218. * Starts this <CODE>CommunicatorServer</CODE>.
  219. * <p>
  220. * Has no effect if this <CODE>CommunicatorServer</CODE> is
  221. * <CODE>ONLINE</CODE> or <CODE>STOPPING</CODE>.
  222. * @param timeout Time in ms to wait for the connector to start.
  223. * If <code>timeout</code> is positive, wait for at most
  224. * the specified time. An infinite timeout can be specified
  225. * by passing a <code>timeout</code> value equals
  226. * <code>Long.MAX_VALUE</code>. In that case the method
  227. * will wait until the connector starts or fails to start.
  228. * If timeout is negative or zero, returns as soon as possible
  229. * without waiting.
  230. * @exception CommunicationException if the connectors fails to start.
  231. * @exception InterruptedException if the thread is interrupted or the
  232. * timeout expires.
  233. */
  234. public void start(long timeout)
  235. throws CommunicationException, InterruptedException {
  236. boolean start;
  237. synchronized (stateLock) {
  238. if (state == STOPPING) {
  239. // Fix for bug 4352451:
  240. // "java.net.BindException: Address in use".
  241. waitState(OFFLINE, 60000);
  242. }
  243. start = (state == OFFLINE);
  244. if (start) {
  245. changeState(STARTING);
  246. stopRequested = false;
  247. interrupted = false;
  248. startException = null;
  249. }
  250. }
  251. if (!start) {
  252. if (isTraceOn())
  253. trace("start","Connector is not OFFLINE") ;
  254. return;
  255. }
  256. if (isTraceOn())
  257. trace("start","--> Start connector ") ;
  258. mainThread = createMainThread();
  259. mainThread.start() ;
  260. if (timeout > 0) waitForStart(timeout);
  261. }
  262. /**
  263. * Starts this <CODE>CommunicatorServer</CODE>.
  264. * <p>
  265. * Has no effect if this <CODE>CommunicatorServer</CODE> is
  266. * <CODE>ONLINE</CODE> or <CODE>STOPPING</CODE>.
  267. */
  268. public void start() {
  269. try {
  270. start(0);
  271. } catch (InterruptedException x) {
  272. // can not happen because of `0'
  273. trace("start","interrupted: " + x);
  274. }
  275. }
  276. /**
  277. * Stops this <CODE>CommunicatorServer</CODE>.
  278. * <p>
  279. * Has no effect if this <CODE>CommunicatorServer</CODE> is
  280. * <CODE>OFFLINE</CODE> or <CODE>STOPPING</CODE>.
  281. */
  282. public void stop() {
  283. synchronized (stateLock) {
  284. if (state == OFFLINE || state == STOPPING) {
  285. if (isTraceOn())
  286. trace("stop","Connector is not ONLINE") ;
  287. return;
  288. }
  289. changeState(STOPPING);
  290. //
  291. // Stop the connector thread
  292. //
  293. if (isTraceOn())
  294. trace("stop","Interrupt main thread") ;
  295. stopRequested = true ;
  296. if (!interrupted) {
  297. interrupted = true;
  298. mainThread.interrupt();
  299. }
  300. }
  301. //
  302. // Call terminate on each active client handler
  303. //
  304. if (isTraceOn()) {
  305. trace("stop","terminateAllClient") ;
  306. }
  307. terminateAllClient() ;
  308. // ----------------------
  309. // changeState
  310. // ----------------------
  311. synchronized (stateLock) {
  312. if (state == STARTING)
  313. changeState(OFFLINE);
  314. }
  315. }
  316. /**
  317. * Tests whether the <CODE>CommunicatorServer</CODE> is active.
  318. *
  319. * @return True if connector is <CODE>ONLINE</CODE>; false otherwise.
  320. */
  321. public boolean isActive() {
  322. synchronized (stateLock) {
  323. return (state == ONLINE);
  324. }
  325. }
  326. /**
  327. * <p>Waits until either the State attribute of this MBean equals the
  328. * specified <VAR>wantedState</VAR> parameter,
  329. * or the specified <VAR>timeOut</VAR> has elapsed.
  330. * The method <CODE>waitState</CODE> returns with a boolean value
  331. * indicating whether the specified <VAR>wantedState</VAR> parameter
  332. * equals the value of this MBean's State attribute at the time the method
  333. * terminates.</p>
  334. *
  335. * <p>Two special cases for the <VAR>timeOut</VAR> parameter value are:</p>
  336. * <UL><LI> if <VAR>timeOut</VAR> is negative then <CODE>waitState</CODE>
  337. * returns immediately (i.e. does not wait at all),</LI>
  338. * <LI> if <VAR>timeOut</VAR> equals zero then <CODE>waitState</CODE>
  339. * waits untill the value of this MBean's State attribute
  340. * is the same as the <VAR>wantedState</VAR> parameter (i.e. will wait
  341. * indefinitely if this condition is never met).</LI></UL>
  342. *
  343. * @param wantedState The value of this MBean's State attribute to wait
  344. * for. <VAR>wantedState</VAR> can be one of:
  345. * <ul>
  346. * <li><CODE>CommunicatorServer.OFFLINE</CODE>,</li>
  347. * <li><CODE>CommunicatorServer.ONLINE</CODE>,</li>
  348. * <li><CODE>CommunicatorServer.STARTING</CODE>,</li>
  349. * <li><CODE>CommunicatorServer.STOPPING</CODE>.</li>
  350. * </ul>
  351. * @param timeOut The maximum time to wait for, in milliseconds,
  352. * if positive.
  353. * Infinite time out if 0, or no waiting at all if negative.
  354. *
  355. * @return true if the value of this MBean's State attribute is the
  356. * same as the <VAR>wantedState</VAR> parameter; false otherwise.
  357. */
  358. public boolean waitState(int wantedState, long timeOut) {
  359. if (isTraceOn())
  360. trace("waitState", wantedState + "(0on,1off,2st) TO=" + timeOut +
  361. " ; current state = " + getStateString());
  362. long endTime = 0;
  363. if (timeOut > 0)
  364. endTime = System.currentTimeMillis() + timeOut;
  365. synchronized (stateLock) {
  366. while (state != wantedState) {
  367. if (timeOut < 0) {
  368. if (isTraceOn())
  369. trace("waitState", "timeOut < 0, return without wait");
  370. return false;
  371. } else {
  372. try {
  373. if (timeOut > 0) {
  374. long toWait = endTime - System.currentTimeMillis();
  375. if (toWait <= 0) {
  376. if (isTraceOn())
  377. trace("waitState", "timed out");
  378. return false;
  379. }
  380. stateLock.wait(toWait);
  381. } else { // timeOut == 0
  382. stateLock.wait();
  383. }
  384. } catch (InterruptedException e) {
  385. if (isTraceOn())
  386. trace("waitState", "wait interrupted");
  387. return (state == wantedState);
  388. }
  389. }
  390. }
  391. if (isTraceOn())
  392. trace("waitState", "returning in desired state");
  393. return true;
  394. }
  395. }
  396. /**
  397. * <p>Waits until the communicator is started or timeout expires.
  398. *
  399. * @param timeout Time in ms to wait for the connector to start.
  400. * If <code>timeout</code> is positive, wait for at most
  401. * the specified time. An infinite timeout can be specified
  402. * by passing a <code>timeout</code> value equals
  403. * <code>Long.MAX_VALUE</code>. In that case the method
  404. * will wait until the connector starts or fails to start.
  405. * If timeout is negative or zero, returns as soon as possible
  406. * without waiting.
  407. *
  408. * @exception CommunicationException if the connectors fails to start.
  409. * @exception InterruptedException if the thread is interrupted or the
  410. * timeout expires.
  411. *
  412. */
  413. private void waitForStart(long timeout)
  414. throws CommunicationException, InterruptedException {
  415. if (isTraceOn())
  416. trace("waitForStart", "Timeout=" + timeout +
  417. " ; current state = " + getStateString());
  418. final long startTime = System.currentTimeMillis();
  419. synchronized (stateLock) {
  420. while (state == STARTING) {
  421. // Time elapsed since startTime...
  422. //
  423. final long elapsed = System.currentTimeMillis() - startTime;
  424. // wait for timeout - elapsed.
  425. // A timeout of Long.MAX_VALUE is equivalent to something
  426. // like 292271023 years - which is pretty close to
  427. // forever as far as we are concerned ;-)
  428. //
  429. final long remainingTime = timeout-elapsed;
  430. // If remainingTime is negative, the timeout has elapsed.
  431. //
  432. if (remainingTime < 0) {
  433. if (isTraceOn())
  434. trace("waitForStart",
  435. "timeout < 0, return without wait");
  436. throw new InterruptedException("Timeout expired");
  437. }
  438. // We're going to wait until someone notifies on the
  439. // the stateLock object, or until the timeout expires,
  440. // or until the thread is interrupted.
  441. //
  442. try {
  443. stateLock.wait(remainingTime);
  444. } catch (InterruptedException e) {
  445. if (isTraceOn())
  446. trace("waitForStart", "wait interrupted");
  447. // If we are now ONLINE, then no need to rethrow the
  448. // exception... we're simply going to exit the while
  449. // loop. Otherwise, throw the InterruptedException.
  450. //
  451. if (state != ONLINE) throw e;
  452. }
  453. }
  454. // We're no longer in STARTING state
  455. //
  456. if (state == ONLINE) {
  457. // OK, we're started, everything went fine, just return
  458. //
  459. if (isTraceOn()) trace("waitForStart", "started");
  460. return;
  461. } else if (startException instanceof CommunicationException) {
  462. // There was some exception during the starting phase.
  463. // Cast and throw...
  464. //
  465. throw (CommunicationException)startException;
  466. } else if (startException instanceof InterruptedException) {
  467. // There was some exception during the starting phase.
  468. // Cast and throw...
  469. //
  470. throw (InterruptedException)startException;
  471. } else if (startException != null) {
  472. // There was some exception during the starting phase.
  473. // Wrap and throw...
  474. //
  475. throw new CommunicationException(startException,
  476. "Failed to start: "+
  477. startException);
  478. } else {
  479. // We're not ONLINE, and there's no exception...
  480. // Something went wrong but we don't know what...
  481. //
  482. throw new CommunicationException("Failed to start: state is "+
  483. getStringForState(state));
  484. }
  485. }
  486. }
  487. /**
  488. * Gets the state of this <CODE>CommunicatorServer</CODE> as an integer.
  489. *
  490. * @return <CODE>ONLINE</CODE>, <CODE>OFFLINE</CODE>,
  491. * <CODE>STARTING</CODE> or <CODE>STOPPING</CODE>.
  492. */
  493. public int getState() {
  494. synchronized (stateLock) {
  495. return state ;
  496. }
  497. }
  498. /**
  499. * Gets the state of this <CODE>CommunicatorServer</CODE> as a string.
  500. *
  501. * @return One of the strings "ONLINE", "OFFLINE", "STARTING" or
  502. * "STOPPING".
  503. */
  504. public String getStateString() {
  505. return getStringForState(state) ;
  506. }
  507. /**
  508. * Gets the host name used by this <CODE>CommunicatorServer</CODE>.
  509. *
  510. * @return The host name used by this <CODE>CommunicatorServer</CODE>.
  511. */
  512. public String getHost() {
  513. try {
  514. host = InetAddress.getLocalHost().getHostName();
  515. } catch (Exception e) {
  516. host = "Unknown host";
  517. }
  518. return host ;
  519. }
  520. /**
  521. * Gets the port number used by this <CODE>CommunicatorServer</CODE>.
  522. *
  523. * @return The port number used by this <CODE>CommunicatorServer</CODE>.
  524. */
  525. public int getPort() {
  526. synchronized (stateLock) {
  527. return port ;
  528. }
  529. }
  530. /**
  531. * Sets the port number used by this <CODE>CommunicatorServer</CODE>.
  532. *
  533. * @param port The port number used by this
  534. * <CODE>CommunicatorServer</CODE>.
  535. *
  536. * @exception java.lang.IllegalStateException This method has been invoked
  537. * while the communicator was ONLINE or STARTING.
  538. */
  539. public void setPort(int port) throws java.lang.IllegalStateException {
  540. synchronized (stateLock) {
  541. if ((state == ONLINE) || (state == STARTING))
  542. throw new IllegalStateException("Stop server before " +
  543. "carrying out this operation");
  544. this.port = port;
  545. dbgTag = makeDebugTag();
  546. }
  547. }
  548. /**
  549. * Gets the protocol being used by this <CODE>CommunicatorServer</CODE>.
  550. * @return The protocol as a string.
  551. */
  552. public abstract String getProtocol() ;
  553. /**
  554. * Gets the number of clients that have been processed by this
  555. * <CODE>CommunicatorServer</CODE> since its creation.
  556. *
  557. * @return The number of clients handled by this
  558. * <CODE>CommunicatorServer</CODE>
  559. * since its creation. This counter is not reset by the
  560. * <CODE>stop</CODE> method.
  561. */
  562. int getServedClientCount() {
  563. return servedClientCount ;
  564. }
  565. /**
  566. * Gets the number of clients currently being processed by this
  567. * <CODE>CommunicatorServer</CODE>.
  568. *
  569. * @return The number of clients currently being processed by this
  570. * <CODE>CommunicatorServer</CODE>.
  571. */
  572. int getActiveClientCount() {
  573. int result = clientHandlerVector.size() ;
  574. return result ;
  575. }
  576. /**
  577. * Gets the maximum number of clients that this
  578. * <CODE>CommunicatorServer</CODE> can process concurrently.
  579. *
  580. * @return The maximum number of clients that this
  581. * <CODE>CommunicatorServer</CODE> can
  582. * process concurrently.
  583. */
  584. int getMaxActiveClientCount() {
  585. return maxActiveClientCount ;
  586. }
  587. /**
  588. * Sets the maximum number of clients this
  589. * <CODE>CommunicatorServer</CODE> can process concurrently.
  590. *
  591. * @param c The number of clients.
  592. *
  593. * @exception java.lang.IllegalStateException This method has been invoked
  594. * while the communicator was ONLINE or STARTING.
  595. */
  596. void setMaxActiveClientCount(int c)
  597. throws java.lang.IllegalStateException {
  598. synchronized (stateLock) {
  599. if ((state == ONLINE) || (state == STARTING)) {
  600. throw new IllegalStateException(
  601. "Stop server before carrying out this operation");
  602. }
  603. maxActiveClientCount = c ;
  604. }
  605. }
  606. /**
  607. * For SNMP Runtime internal use only.
  608. */
  609. void notifyClientHandlerCreated(ClientHandler h) {
  610. clientHandlerVector.addElement(h) ;
  611. }
  612. /**
  613. * For SNMP Runtime internal use only.
  614. */
  615. synchronized void notifyClientHandlerDeleted(ClientHandler h) {
  616. clientHandlerVector.removeElement(h);
  617. notifyAll();
  618. }
  619. /**
  620. * The number of times the communicator server will attempt
  621. * to bind before giving up.
  622. **/
  623. protected int getBindTries() {
  624. return 50;
  625. }
  626. /**
  627. * The delay, in ms, during which the communicator server will sleep before
  628. * attempting to bind again.
  629. **/
  630. protected long getBindSleepTime() {
  631. return 100;
  632. }
  633. /**
  634. * For SNMP Runtime internal use only.
  635. * <p>
  636. * The <CODE>run</CODE> method executed by this connector's main thread.
  637. */
  638. public void run() {
  639. // Fix jaw.00667.B
  640. // It seems that the init of "i" and "success"
  641. // need to be done outside the "try" clause...
  642. // A bug in Java 2 production release ?
  643. //
  644. int i = 0;
  645. boolean success = false;
  646. // ----------------------
  647. // Bind
  648. // ----------------------
  649. try {
  650. // Fix for bug 4352451: "java.net.BindException: Address in use".
  651. //
  652. final int bindRetries = getBindTries();
  653. final long sleepTime = getBindSleepTime();
  654. while (i < bindRetries && !success) {
  655. try {
  656. // Try socket connection.
  657. //
  658. doBind();
  659. success = true;
  660. } catch (CommunicationException ce) {
  661. i++;
  662. try {
  663. Thread.sleep(sleepTime);
  664. } catch (InterruptedException ie) {
  665. throw ie;
  666. }
  667. }
  668. }
  669. // Retry last time to get correct exception.
  670. //
  671. if (!success) {
  672. // Try socket connection.
  673. //
  674. doBind();
  675. }
  676. } catch(Exception x) {
  677. if (isDebugOn()) {
  678. debug("run","Unexpected exception = "+x) ;
  679. }
  680. synchronized(stateLock) {
  681. startException = x;
  682. changeState(OFFLINE);
  683. }
  684. if (isTraceOn()) {
  685. trace("run","State is OFFLINE") ;
  686. }
  687. doError(x);
  688. return;
  689. }
  690. try {
  691. // ----------------------
  692. // State change
  693. // ----------------------
  694. changeState(ONLINE) ;
  695. if (isTraceOn()) {
  696. trace("run","State is ONLINE") ;
  697. }
  698. // ----------------------
  699. // Main loop
  700. // ----------------------
  701. while (!stopRequested) {
  702. servedClientCount++;
  703. doReceive() ;
  704. waitIfTooManyClients() ;
  705. doProcess() ;
  706. }
  707. if (isTraceOn()) {
  708. trace("run","Stop has been requested") ;
  709. }
  710. } catch(InterruptedException x) {
  711. if (isTraceOn()) {
  712. trace("run","Interrupt caught") ;
  713. }
  714. changeState(STOPPING);
  715. } catch(Exception x) {
  716. if (isDebugOn()) {
  717. debug("run","Unexpected exception = "+x) ;
  718. }
  719. changeState(STOPPING);
  720. } finally {
  721. synchronized (stateLock) {
  722. interrupted = true;
  723. Thread.currentThread().interrupted();
  724. }
  725. // ----------------------
  726. // unBind
  727. // ----------------------
  728. try {
  729. doUnbind() ;
  730. waitClientTermination() ;
  731. changeState(OFFLINE);
  732. if (isTraceOn()) {
  733. trace("run","State is OFFLINE") ;
  734. }
  735. } catch(Exception x) {
  736. if (isDebugOn()) {
  737. debug("run","Unexpected exception = "+x) ;
  738. }
  739. changeState(OFFLINE);
  740. }
  741. }
  742. }
  743. /**
  744. */
  745. protected abstract void doError(Exception e) throws CommunicationException;
  746. //
  747. // To be defined by the subclass.
  748. //
  749. // Each method below is called by run() and must be subclassed.
  750. // If the method sends an exception (Communication or Interrupt), this
  751. // will end up the run() method and switch the connector offline.
  752. //
  753. // If it is a CommunicationException, run() will call
  754. // Debug.printException().
  755. //
  756. // All these methods should propagate the InterruptedException to inform
  757. // run() that the connector must be switch OFFLINE.
  758. //
  759. //
  760. //
  761. // doBind() should do all what is needed before calling doReceive().
  762. // If doBind() throws an exception, doUnbind() is not to be called
  763. // and run() ends up.
  764. //
  765. /**
  766. */
  767. protected abstract void doBind()
  768. throws CommunicationException, InterruptedException ;
  769. /**
  770. * <CODE>doReceive()</CODE> should block until a client is available.
  771. * If this method throws an exception, <CODE>doProcess()</CODE> is not
  772. * called but <CODE>doUnbind()</CODE> is called then <CODE>run()</CODE>
  773. * stops.
  774. */
  775. protected abstract void doReceive()
  776. throws CommunicationException, InterruptedException ;
  777. /**
  778. * <CODE>doProcess()</CODE> is called after <CODE>doReceive()</CODE>:
  779. * it should process the requests of the incoming client.
  780. * If it throws an exception, <CODE>doUnbind()</CODE> is called and
  781. * <CODE>run()</CODE> stops.
  782. */
  783. protected abstract void doProcess()
  784. throws CommunicationException, InterruptedException ;
  785. /**
  786. * <CODE>doUnbind()</CODE> is called whenever the connector goes
  787. * <CODE>OFFLINE</CODE>, except if <CODE>doBind()</CODE> has thrown an
  788. * exception.
  789. */
  790. protected abstract void doUnbind()
  791. throws CommunicationException, InterruptedException ;
  792. /**
  793. * Get the <code>MBeanServer</code> object to which incoming requests are
  794. * sent. This is either the MBean server in which this connector is
  795. * registered, or an <code>MBeanServerForwarder</code> leading to that
  796. * server.
  797. */
  798. public synchronized MBeanServer getMBeanServer() {
  799. return topMBS;
  800. }
  801. /**
  802. * Set the <code>MBeanServer</code> object to which incoming
  803. * requests are sent. This must be either the MBean server in
  804. * which this connector is registered, or an
  805. * <code>MBeanServerForwarder</code> leading to that server. An
  806. * <code>MBeanServerForwarder</code> <code>mbsf</code> leads to an
  807. * MBean server <code>mbs</code> if
  808. * <code>mbsf.getMBeanServer()</code> is either <code>mbs</code>
  809. * or an <code>MBeanServerForwarder</code> leading to
  810. * <code>mbs</code>.
  811. *
  812. * @exception IllegalArgumentException if <code>newMBS</code> is neither
  813. * the MBean server in which this connector is registered nor an
  814. * <code>MBeanServerForwarder</code> leading to that server.
  815. *
  816. * @exception IllegalStateException This method has been invoked
  817. * while the communicator was ONLINE or STARTING.
  818. */
  819. public synchronized void setMBeanServer(MBeanServer newMBS)
  820. throws IllegalArgumentException, IllegalStateException {
  821. synchronized (stateLock) {
  822. if (state == ONLINE || state == STARTING)
  823. throw new IllegalStateException("Stop server before " +
  824. "carrying out this operation");
  825. }
  826. final String error =
  827. "MBeanServer argument must be MBean server where this " +
  828. "server is registered, or an MBeanServerForwarder " +
  829. "leading to that server";
  830. Vector seenMBS = new Vector();
  831. for (MBeanServer mbs = newMBS;
  832. mbs != bottomMBS;
  833. mbs = ((MBeanServerForwarder) mbs).getMBeanServer()) {
  834. if (!(mbs instanceof MBeanServerForwarder))
  835. throw new IllegalArgumentException(error);
  836. if (seenMBS.contains(mbs))
  837. throw new IllegalArgumentException("MBeanServerForwarder " +
  838. "loop");
  839. seenMBS.addElement(mbs);
  840. }
  841. topMBS = newMBS;
  842. }
  843. //
  844. // To be called by the subclass if needed
  845. //
  846. /**
  847. * For internal use only.
  848. */
  849. ObjectName getObjectName() {
  850. return objectName ;
  851. }
  852. /**
  853. * For internal use only.
  854. */
  855. void changeState(int newState) {
  856. int oldState;
  857. synchronized (stateLock) {
  858. if (state == newState)
  859. return;
  860. oldState = state;
  861. state = newState;
  862. stateLock.notifyAll();
  863. }
  864. sendStateChangeNotification(oldState, newState);
  865. }
  866. /**
  867. * Returns the string used in debug traces.
  868. */
  869. String makeDebugTag() {
  870. return "CommunicatorServer["+ getProtocol() + ":" + getPort() + "]" ;
  871. }
  872. /**
  873. * Returns the string used to name the connector thread.
  874. */
  875. String makeThreadName() {
  876. String result ;
  877. if (objectName == null)
  878. result = "CommunicatorServer" ;
  879. else
  880. result = objectName.toString() ;
  881. return result ;
  882. }
  883. /**
  884. * This method blocks if there are too many active clients.
  885. * Call to <CODE>wait()</CODE> is terminated when a client handler
  886. * thread calls <CODE>notifyClientHandlerDeleted(this)</CODE> ;
  887. */
  888. private synchronized void waitIfTooManyClients()
  889. throws InterruptedException {
  890. while (getActiveClientCount() >= maxActiveClientCount) {
  891. if (isTraceOn()) {
  892. trace("waitIfTooManyClients",
  893. "Waiting for a client to terminate") ;
  894. }
  895. wait();
  896. }
  897. }
  898. /**
  899. * This method blocks until there is no more active client.
  900. */
  901. private void waitClientTermination() {
  902. int s = clientHandlerVector.size() ;
  903. if (isTraceOn()) {
  904. if (s >= 1) {
  905. trace("waitClientTermination","waiting for " +
  906. s + " clients to terminate") ;
  907. }
  908. }
  909. // The ClientHandler will remove themselves from the
  910. // clientHandlerVector at the end of their run() method, by
  911. // calling notifyClientHandlerDeleted().
  912. // Since the clientHandlerVector is modified by the ClientHandler
  913. // threads we must avoid using Enumeration or Iterator to loop
  914. // over this array. We must also take care of NoSuchElementException
  915. // which could be thrown if the last ClientHandler removes itself
  916. // between the call to clientHandlerVector.isEmpty() and the call
  917. // to clientHandlerVector.firstElement().
  918. // What we *MUST NOT DO* is locking the clientHandlerVector, because
  919. // this would most probably cause a deadlock.
  920. //
  921. while (! clientHandlerVector.isEmpty()) {
  922. try {
  923. clientHandlerVector.firstElement().join();
  924. } catch (NoSuchElementException x) {
  925. trace("waitClientTermination","No element left: " + x);
  926. }
  927. }
  928. if (isTraceOn()) {
  929. if (s >= 1) {
  930. trace("waitClientTermination","Ok, let's go...") ;
  931. }
  932. }
  933. }
  934. /**
  935. * Call <CODE>interrupt()</CODE> on each pending client.
  936. */
  937. private void terminateAllClient() {
  938. final int s = clientHandlerVector.size() ;
  939. if (isTraceOn()) {
  940. if (s >= 1) {
  941. trace("terminateAllClient","Interrupting " + s + " clients") ;
  942. }
  943. }
  944. // The ClientHandler will remove themselves from the
  945. // clientHandlerVector at the end of their run() method, by
  946. // calling notifyClientHandlerDeleted().
  947. // Since the clientHandlerVector is modified by the ClientHandler
  948. // threads we must avoid using Enumeration or Iterator to loop
  949. // over this array.
  950. // We cannot use the same logic here than in waitClientTermination()
  951. // because there is no guarantee that calling interrupt() on the
  952. // ClientHandler will actually terminate the ClientHandler.
  953. // Since we do not want to wait for the actual ClientHandler
  954. // termination, we cannot simply loop over the array until it is
  955. // empty (this might result in calling interrupt() endlessly on
  956. // the same client handler. So what we do is simply take a snapshot
  957. // copy of the vector and loop over the copy.
  958. // What we *MUST NOT DO* is locking the clientHandlerVector, because
  959. // this would most probably cause a deadlock.
  960. //
  961. final ClientHandler[] handlers =
  962. clientHandlerVector.toArray(new ClientHandler[0]);
  963. for (ClientHandler h : handlers) {
  964. try {
  965. h.interrupt() ;
  966. } catch (Exception x) {
  967. if (isTraceOn())
  968. trace("terminateAllClient",
  969. "Failed to interrupt pending request: "+x+
  970. " - skiping");
  971. }
  972. }
  973. }
  974. /**
  975. * Controls the way the CommunicatorServer service is deserialized.
  976. */
  977. private void readObject(ObjectInputStream stream)
  978. throws IOException, ClassNotFoundException {
  979. // Call the default deserialization of the object.
  980. //
  981. stream.defaultReadObject();
  982. // Call the specific initialization for the CommunicatorServer service.
  983. // This is for transient structures to be initialized to specific
  984. // default values.
  985. //
  986. stateLock = new Object();
  987. state = OFFLINE;
  988. stopRequested = false;
  989. servedClientCount = 0;
  990. clientHandlerVector = new Vector<ClientHandler>();
  991. fatherThread = Thread.currentThread();
  992. mainThread = null;
  993. notifCount = 0;
  994. notifInfos = null;
  995. notifBroadcaster = new NotificationBroadcasterSupport();
  996. dbgTag = makeDebugTag();
  997. }
  998. //
  999. // NotificationBroadcaster
  1000. //
  1001. /**
  1002. * Adds a listener for the notifications emitted by this
  1003. * CommunicatorServer.
  1004. * There is only one type of notifications sent by the CommunicatorServer:
  1005. * they are <tt>{@link javax.management.AttributeChangeNotification}</tt>,
  1006. * sent when the <tt>State</tt> attribute of this CommunicatorServer
  1007. * changes.
  1008. *
  1009. * @param listener The listener object which will handle the emitted
  1010. * notifications.
  1011. * @param filter The filter object. If filter is null, no filtering
  1012. * will be performed before handling notifications.
  1013. * @param handback An object which will be sent back unchanged to the
  1014. * listener when a notification is emitted.
  1015. *
  1016. * @exception IllegalArgumentException Listener parameter is null.
  1017. */
  1018. public void addNotificationListener(NotificationListener listener,
  1019. NotificationFilter filter,
  1020. Object handback)
  1021. throws java.lang.IllegalArgumentException {
  1022. if (isDebugOn()) {
  1023. debug("addNotificationListener","Adding listener "+ listener +
  1024. " with filter "+ filter + " and handback "+ handback);
  1025. }
  1026. notifBroadcaster.addNotificationListener(listener, filter, handback);
  1027. }
  1028. /**
  1029. * Removes the specified listener from this CommunicatorServer.
  1030. * Note that if the listener has been registered with different
  1031. * handback objects or notification filters, all entries corresponding
  1032. * to the listener will be removed.
  1033. *
  1034. * @param listener The listener object to be removed.
  1035. *
  1036. * @exception ListenerNotFoundException The listener is not registered.
  1037. */
  1038. public void removeNotificationListener(NotificationListener listener)
  1039. throws ListenerNotFoundException {
  1040. if (isDebugOn()) {
  1041. debug("removeNotificationListener","Removing listener "+ listener);
  1042. }
  1043. notifBroadcaster.removeNotificationListener(listener);
  1044. }
  1045. /**
  1046. * Returns an array of MBeanNotificationInfo objects describing
  1047. * the notification types sent by this CommunicatorServer.
  1048. * There is only one type of notifications sent by the CommunicatorServer:
  1049. * it is <tt>{@link javax.management.AttributeChangeNotification}</tt>,
  1050. * sent when the <tt>State</tt> attribute of this CommunicatorServer
  1051. * changes.
  1052. */
  1053. public MBeanNotificationInfo[] getNotificationInfo() {
  1054. // Initialize notifInfos on first call to getNotificationInfo()
  1055. //
  1056. if (notifInfos == null) {
  1057. notifInfos = new MBeanNotificationInfo[1];
  1058. String[] notifTypes = {
  1059. AttributeChangeNotification.ATTRIBUTE_CHANGE};
  1060. notifInfos[0] = new MBeanNotificationInfo( notifTypes,
  1061. AttributeChangeNotification.class.getName(),
  1062. "Sent to notify that the value of the State attribute "+
  1063. "of this CommunicatorServer instance has changed.");
  1064. }
  1065. return notifInfos;
  1066. }
  1067. /**
  1068. *
  1069. */
  1070. private void sendStateChangeNotification(int oldState, int newState) {
  1071. String oldStateString = getStringForState(oldState);
  1072. String newStateString = getStringForState(newState);
  1073. String message = new StringBuffer().append(dbgTag)
  1074. .append(" The value of attribute State has changed from ")
  1075. .append(oldState).append(" (").append(oldStateString)
  1076. .append(") to ").append(newState).append(" (")
  1077. .append(newStateString).append(").").toString();
  1078. notifCount++;
  1079. AttributeChangeNotification notif =
  1080. new AttributeChangeNotification(this, // source
  1081. notifCount, // sequence number
  1082. System.currentTimeMillis(), // time stamp
  1083. message, // message
  1084. "State", // attribute name
  1085. "int", // attribute type
  1086. new Integer(oldState), // old value
  1087. new Integer(newState) ); // new value
  1088. if (isDebugOn()) {
  1089. debug("sendStateChangeNotification",
  1090. "Sending AttributeChangeNotification #"+ notifCount +
  1091. " with message: "+ message);
  1092. }
  1093. notifBroadcaster.sendNotification(notif);
  1094. }
  1095. /**
  1096. *
  1097. */
  1098. private static String getStringForState(int s) {
  1099. switch (s) {
  1100. case ONLINE: return "ONLINE";
  1101. case STARTING: return "STARTING";
  1102. case OFFLINE: return "OFFLINE";
  1103. case STOPPING: return "STOPPING";
  1104. default: return "UNDEFINED";
  1105. }
  1106. }
  1107. //
  1108. // MBeanRegistration
  1109. //
  1110. /**
  1111. * Preregister method of connector.
  1112. *
  1113. *@param server The <CODE>MBeanServer</CODE> in which the MBean will
  1114. * be registered.
  1115. *@param name The object name of the MBean.
  1116. *
  1117. *@return The name of the MBean registered.
  1118. *
  1119. *@exception java.langException This exception should be caught by
  1120. * the <CODE>MBeanServer</CODE> and re-thrown
  1121. * as an <CODE>MBeanRegistrationException</CODE>.
  1122. */
  1123. public ObjectName preRegister(MBeanServer server, ObjectName name)
  1124. throws java.lang.Exception {
  1125. objectName = name;
  1126. synchronized (this) {
  1127. if (bottomMBS != null) {
  1128. throw new IllegalArgumentException("connector already " +
  1129. "registered in an MBean " +
  1130. "server");
  1131. }
  1132. topMBS = bottomMBS = server;
  1133. }
  1134. dbgTag = makeDebugTag();
  1135. return name;
  1136. }
  1137. /**
  1138. *
  1139. *@param registrationDone Indicates whether or not the MBean has been
  1140. * successfully registered in the <CODE>MBeanServer</CODE>.
  1141. * The value false means that the registration phase has failed.
  1142. */
  1143. public void postRegister(Boolean registrationDone) {
  1144. if (!registrationDone.booleanValue()) {
  1145. synchronized (this) {
  1146. topMBS = bottomMBS = null;
  1147. }
  1148. }
  1149. }
  1150. /**
  1151. * Stop the connector.
  1152. *
  1153. * @exception java.langException This exception should be caught by
  1154. * the <CODE>MBeanServer</CODE> and re-thrown
  1155. * as an <CODE>MBeanRegistrationException</CODE>.
  1156. */
  1157. public void preDeregister() throws java.lang.Exception {
  1158. synchronized (this) {
  1159. topMBS = bottomMBS = null;
  1160. }
  1161. objectName = null ;
  1162. final int cstate = getState();
  1163. if ((cstate == ONLINE) || ( cstate == STARTING)) {
  1164. stop() ;
  1165. }
  1166. }
  1167. /**
  1168. * Do nothing.
  1169. */
  1170. public void postDeregister(){
  1171. }
  1172. /**
  1173. * Load a class using the default loader repository
  1174. **/
  1175. Class loadClass(String className)
  1176. throws ClassNotFoundException {
  1177. try {
  1178. return Class.forName(className);
  1179. } catch (ClassNotFoundException e) {
  1180. final ClassLoaderRepository clr =
  1181. MBeanServerFactory.getClassLoaderRepository(bottomMBS);
  1182. if (clr == null) throw new ClassNotFoundException(className);
  1183. return clr.loadClass(className);
  1184. }
  1185. }
  1186. //
  1187. // Debug stuff
  1188. //
  1189. /**
  1190. */
  1191. int infoType;
  1192. /**
  1193. */
  1194. boolean isTraceOn() {
  1195. return Trace.isSelected(Trace.LEVEL_TRACE, infoType);
  1196. }
  1197. /**
  1198. */
  1199. void trace(String clz, String func, String info) {
  1200. Trace.send(Trace.LEVEL_TRACE, infoType, clz, func, info);
  1201. }
  1202. /**
  1203. */
  1204. boolean isDebugOn() {
  1205. return Trace.isSelected(Trace.LEVEL_DEBUG, infoType);
  1206. }
  1207. /**
  1208. */
  1209. void debug(String clz, String func, String info) {
  1210. Trace.send(Trace.LEVEL_DEBUG, infoType, clz, func, info);
  1211. }
  1212. /**
  1213. */
  1214. void debug(String clz, String func, Throwable exception) {
  1215. Trace.send(Trace.LEVEL_DEBUG, infoType, clz, func, exception);
  1216. }
  1217. /**
  1218. */
  1219. void trace(String func, String info) {
  1220. trace(dbgTag, func, info);
  1221. }
  1222. /**
  1223. */
  1224. void debug(String func, String info) {
  1225. debug(dbgTag, func, info);
  1226. }
  1227. /**
  1228. */
  1229. void debug(String func, Throwable exception) {
  1230. debug(dbgTag, func, exception);
  1231. }
  1232. }