PageRenderTime 60ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jboss-5.1.0/cluster/src/main/org/jboss/ha/framework/server/JChannelFactory.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1100 lines | 675 code | 135 blank | 290 comment | 118 complexity | 429651b5bdd9734584d9707d10f61850 MD5 | raw file
  1. /*
  2. * JBoss, Home of Professional Open Source.
  3. * Copyright 2008, Red Hat Middleware LLC, and individual contributors
  4. * as indicated by the @author tags. See the copyright.txt file in the
  5. * distribution for a full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.jboss.ha.framework.server;
  23. import java.net.InetAddress;
  24. import java.rmi.dgc.VMID;
  25. import java.rmi.server.UID;
  26. import java.security.AccessController;
  27. import java.util.HashMap;
  28. import java.util.HashSet;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Set;
  32. import java.util.concurrent.Executor;
  33. import javax.management.MBeanRegistration;
  34. import javax.management.MBeanServer;
  35. import javax.management.ObjectName;
  36. import org.jboss.bootstrap.spi.util.ServerConfigUtil;
  37. import org.jboss.logging.Logger;
  38. import org.jboss.system.ServiceMBean;
  39. import org.jboss.util.loading.ContextClassLoaderSwitcher;
  40. import org.jgroups.Channel;
  41. import org.jgroups.ChannelException;
  42. import org.jgroups.ChannelListenerAdapter;
  43. import org.jgroups.Event;
  44. import org.jgroups.Global;
  45. import org.jgroups.JChannel;
  46. import org.jgroups.conf.ConfiguratorFactory;
  47. import org.jgroups.conf.ProtocolData;
  48. import org.jgroups.conf.ProtocolStackConfigurator;
  49. import org.jgroups.jmx.JmxConfigurator;
  50. import org.jgroups.protocols.TP;
  51. import org.jgroups.stack.IpAddress;
  52. import org.jgroups.stack.Protocol;
  53. import org.jgroups.stack.ProtocolStack;
  54. import org.jgroups.util.DefaultThreadFactory;
  55. import org.jgroups.util.LazyThreadFactory;
  56. import org.jgroups.util.ThreadDecorator;
  57. import org.jgroups.util.ThreadFactory;
  58. import org.jgroups.util.ThreadManager;
  59. import org.jgroups.util.Util;
  60. /**
  61. * Extension to the JGroups JChannelFactory that supports a number of
  62. * JBoss AS-specific behaviors:
  63. * <p>
  64. * <ul>
  65. * <li>Passing a config event to newly created channels containing
  66. * "additional_data" that will be associated with the JGroups
  67. * <code>IpAddress</code> for the peer. Used to provide logical addresses
  68. * to cluster peers that remain consistent across channel and server restarts.</li>
  69. * <li>Never returns instances of {@link org.jgroups.mux.MuxChannel} from
  70. * the <code>createMultiplexerChannel</code> methods. Instead always returns
  71. * a channel with a shared transport protocol.</li>
  72. * <li>Configures the channel's thread pools and thread factories to ensure
  73. * that application thread context classloaders don't leak to the channel
  74. * threads.</li>
  75. * </ul>
  76. * </p>
  77. *
  78. * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
  79. * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
  80. *
  81. * @version $Revision: 86596 $
  82. */
  83. public class JChannelFactory extends org.jgroups.JChannelFactory
  84. implements JChannelFactoryMBean, MBeanRegistration
  85. {
  86. protected static final Logger log = Logger.getLogger(JChannelFactory.class);
  87. public static final String UNSHARED_TRANSPORT_NAME_BASE = "unnamed_";
  88. private static final int CREATED = ServiceMBean.CREATED;
  89. private static final int STARTING = ServiceMBean.STARTING;
  90. private static final int STARTED = ServiceMBean.STARTED;
  91. private static final int STOPPING = ServiceMBean.STOPPING;
  92. private static final int STOPPED = ServiceMBean.STOPPED;
  93. private static final int DESTROYED = ServiceMBean.DESTROYED;
  94. private static final int FAILED = ServiceMBean.FAILED;
  95. private InetAddress nodeAddress;
  96. private String nodeName;
  97. private int namingServicePort = -1;
  98. private int state = ServiceMBean.UNREGISTERED;
  99. private boolean assignLogicalAddresses = true;
  100. private boolean manageNewThreadClassLoader = true;
  101. private boolean manageReleasedThreadClassLoader = false;
  102. private boolean addMissingSingletonName = true;
  103. private boolean domainSet;
  104. private final ContextClassLoaderSwitcher classLoaderSwitcher;
  105. private final Set<String> registeredChannels = new HashSet<String>();
  106. public JChannelFactory()
  107. {
  108. this.classLoaderSwitcher = (ContextClassLoaderSwitcher) AccessController.doPrivileged(ContextClassLoaderSwitcher.INSTANTIATOR);
  109. }
  110. /**
  111. * Always throws <code>ChannelException</code>; this method is not supported.
  112. */
  113. @Override
  114. public Channel createChannel() throws ChannelException
  115. {
  116. throw new ChannelException("No-arg createChannel() is not supported");
  117. }
  118. @Override
  119. public Channel createChannel(Object properties) throws ChannelException
  120. {
  121. checkStarted();
  122. @SuppressWarnings("deprecation")
  123. Channel channel = super.createChannel(properties);
  124. if (manageNewThreadClassLoader || manageReleasedThreadClassLoader)
  125. {
  126. fixChannelThreadManagement(channel);
  127. }
  128. if (assignLogicalAddresses)
  129. {
  130. setChannelUniqueId(channel);
  131. }
  132. // can't register in JMX as we don't have a channel name
  133. return channel;
  134. }
  135. /**
  136. * Create a {@link Channel} using the specified stack. Channel will use a
  137. * shared transport if the <code>singleton-name</code> attribute is
  138. * set on the stack's transport protocol.
  139. *
  140. * @param stack_name the name of the stack
  141. * @return the channel
  142. *
  143. * @throws Exception
  144. */
  145. @Override
  146. public Channel createChannel(String stack_name) throws Exception
  147. {
  148. checkStarted();
  149. String props=stack_name != null? getConfig(stack_name) : null;
  150. if (props == null)
  151. {
  152. log.warn("No protocol stack found with name " + stack_name +
  153. "; creating default channel");
  154. return createChannel();
  155. }
  156. JChannel channel = new JChannel(props);
  157. if (manageNewThreadClassLoader || manageReleasedThreadClassLoader)
  158. {
  159. fixChannelThreadManagement(channel);
  160. }
  161. if (assignLogicalAddresses)
  162. {
  163. setChannelUniqueId(channel);
  164. }
  165. // can't register in JMX as we don't have a channel name
  166. return channel;
  167. }
  168. /**
  169. * Creates and returns a shared transport Channel configured with the specified
  170. * {@link #getConfig(String) protocol stack configuration}.
  171. * <p>
  172. * <emphasis>NOTE:</emphasis> The implementation of this method is somewhat
  173. * different from what is described in
  174. * {@link org.jgroups.ChannelFactory#createMultiplexerChannel(String, String)}.
  175. * The returned channel will not be an instance of
  176. * <code>org.jgroups.mux.MuxChannel</code>; rather a channel that uses a
  177. * shared transport will be returned. This will be the case whether or
  178. * not the protocol stack specified by <code>stack_name</code> includes
  179. * a <code>singleton_name</code> attribute in its
  180. * {@link org.jgroups.protocols.TP transport protocol} configuration. If no
  181. * <code>singleton_name</code> attribute is present, this factory will create
  182. * a synthetic one by prepending "unnamed_" to the provided
  183. * <code>id</code> param and will use that for the returned channel's
  184. * transport protocol. (Note this will not effect the protocol stack
  185. * configuration named by <code>stack_name</code>; i.e. another request
  186. * that passes the same <code>stack_name</code> will not inherit the
  187. * synthetic singleton name.)
  188. *
  189. * @param stack_name
  190. * The name of the stack to be used. All stacks are defined in
  191. * the configuration with which the factory is configured (see
  192. * {@link #setMultiplexerConfig(Object)} for example. If
  193. * clients attempt to create a Channel for an undefined stack
  194. * name an Exception will be thrown.
  195. * @param id Only used if the transport protocol configuration for the
  196. * specified stack does not include the <code>singleton_name</code>
  197. * attribute; then it is used to create a synthetic singleton-name
  198. * for the channel's protocol stack.
  199. *
  200. * @return An implementation of Channel configured with a shared transport.
  201. *
  202. * @throws IllegalStateException if the specified protocol stack does not
  203. * declare a <code>singleton_name</code> and
  204. * {@link #getAddMissingSingletonName()} returns
  205. * <code>false</code>.
  206. * @throws ChannelException
  207. */
  208. @Override
  209. public Channel createMultiplexerChannel(String stack_name, String id) throws Exception
  210. {
  211. checkStarted();
  212. String configStr = getConfig(stack_name);
  213. if (configStr == null)
  214. throw new IllegalStateException("Unknown stack_name " + stack_name);
  215. ProtocolStackConfigurator config = ConfiguratorFactory.getStackConfigurator(configStr);
  216. Map<String, String> tpProps = getTransportProperties(config);
  217. if (!tpProps.containsKey(Global.SINGLETON_NAME))
  218. {
  219. if (addMissingSingletonName)
  220. {
  221. String singletonName = UNSHARED_TRANSPORT_NAME_BASE + stack_name;
  222. log.warn("Config for " + stack_name + " does not include " +
  223. "singleton_name; adding a name of " + singletonName +
  224. ". You should configure a singleton_name for this stack.");
  225. config = addSingletonName(config, singletonName);
  226. log.debug("Stack config after adding singleton_name is " + config.getProtocolStackString());
  227. tpProps = getTransportProperties(config);
  228. }
  229. else
  230. {
  231. throw new IllegalStateException("Config for " + stack_name + " does not include " +
  232. "singleton_name and MuxChannels are not supported.");
  233. }
  234. }
  235. JChannel channel = new JChannel(config);
  236. if (manageNewThreadClassLoader || manageReleasedThreadClassLoader)
  237. {
  238. fixChannelThreadManagement(channel);
  239. }
  240. if (assignLogicalAddresses)
  241. {
  242. setChannelUniqueId(channel);
  243. }
  244. if (isExposeChannels() && id != null && id.length() > 0)
  245. {
  246. registerChannel(channel, id);
  247. }
  248. return channel;
  249. }
  250. /**
  251. * Creates and returns a shared transport Channel configured with the specified
  252. * {@link #getConfig(String) protocol stack configuration}.
  253. *
  254. * See {@link #createMultiplexerChannel(String, String)}; the additional
  255. * attributes specified in this overloaded version of that method are ignored.
  256. *
  257. * @param register_for_state_transfer ignored in JBoss AS. Treated as <code>false</code>.
  258. *
  259. * @param substate_id ignored in JBoss AS
  260. *
  261. * @return An implementation of Channel configured with a shared transport.
  262. *
  263. *
  264. * @throws IllegalStateException if the specified protocol stack does not
  265. * declare a <code>singleton_name</code> and
  266. * {@link #getAddMissingSingletonName()} returns
  267. * <code>false</code>.
  268. * @throws ChannelException
  269. */
  270. @Override
  271. public Channel createMultiplexerChannel(String stack_name, String id, boolean register_for_state_transfer, String substate_id) throws Exception
  272. {
  273. return createMultiplexerChannel(stack_name, id);
  274. }
  275. @Override
  276. public void setDomain(String domain)
  277. {
  278. super.setDomain(domain);
  279. domainSet = true;
  280. }
  281. /**
  282. * Get any logical name assigned to this server; if not null this value
  283. * will be the value of the
  284. * {@link #setAssignLogicalAddresses(boolean) logical address} assigned
  285. * to the channels this factory creates.
  286. *
  287. * @return the logical name for this server, or <code>null</code>.
  288. */
  289. public String getNodeName()
  290. {
  291. return nodeName;
  292. }
  293. /**
  294. * Sets the logical name assigned to this server; if not null this value
  295. * will be the value of the
  296. * {@link #setAssignLogicalAddresses(boolean) logical address} assigned
  297. * to the channels this factory creates.
  298. *
  299. * @param nodeName the logical name for this server, or <code>null</code>.
  300. */
  301. public void setNodeName(String nodeName)
  302. {
  303. this.nodeName = nodeName;
  304. }
  305. /**
  306. * Gets the address to which this server is bound; typically the value
  307. * passed to <code>-b</code> when JBoss is started. Used in combination
  308. * with {@link #getNamingServicePort() the naming service port} to create
  309. * a logical name for this server if no {@link #SetNodeName(String) node name}
  310. * is specified.
  311. *
  312. * @return the address to which this server is bound, or <code>null</code>
  313. * if not set
  314. */
  315. public InetAddress getNodeAddress()
  316. {
  317. return nodeAddress;
  318. }
  319. /**
  320. * Sets the address to which this server is bound; typically the value
  321. * passed to <code>-b</code> when JBoss is started. Used in combination
  322. * with {@link #getNamingServicePort() the naming service port} to create
  323. * a logical name for this server if no {@link #SetNodeName(String) node name}
  324. * is specified.
  325. *
  326. * @param nodeAddress the address to which this server is bound,
  327. * or <code>null</code>
  328. */
  329. public void setNodeAddress(InetAddress nodeAddress)
  330. {
  331. this.nodeAddress = nodeAddress;
  332. }
  333. /**
  334. * Gets the port on which this server's naming service is listening. Used in
  335. * combination with {@link #getNodeAddress() the server bind address} to create
  336. * a logical name for this server if no {@link #SetNodeName(String) node name}
  337. * is specified.
  338. *
  339. * @return the port on which JNDI is listening, or <code>-1</code> if not set.
  340. */
  341. public int getNamingServicePort()
  342. {
  343. return namingServicePort;
  344. }
  345. /**
  346. * Sets the port on which this server's naming service is listening. Used in
  347. * combination with {@link #getNodeAddress() the server bind address} to create
  348. * a logical name for this server if no {@link #SetNodeName(String) node name}
  349. * is specified.
  350. *
  351. * @param jndiPort the port on which JNDI is listening.
  352. */
  353. public void setNamingServicePort(int jndiPort)
  354. {
  355. this.namingServicePort = jndiPort;
  356. }
  357. /**
  358. * Gets whether this factory should create a "logical address" (or use
  359. * one set via {@link #setNodeName(String)} and assign it to
  360. * any newly created <code>Channel</code> as JGroups "additional_data".
  361. *
  362. * @see #setAssignLogicalAddresses(boolean)
  363. */
  364. public boolean getAssignLogicalAddresses()
  365. {
  366. return assignLogicalAddresses;
  367. }
  368. /**
  369. * Sets whether this factory should create a "logical address" (or use
  370. * one set via {@link #setNodeName(String)} and assign it to
  371. * any newly created <code>Channel</code> as JGroups "additional_data".
  372. * <p>
  373. * Any such logical address will be used by <code>HAPartition</code>
  374. * to assign a name to the <code>ClusterNode</code> object representing
  375. * this node. If a logical address is not set, the <code>ClusterNode</code>
  376. * will use the address and port JGroups is using to receive messages to
  377. * create its name.
  378. * </p>
  379. * <p>
  380. * Default is <code>true</code>.
  381. * </p>
  382. */
  383. public void setAssignLogicalAddresses(boolean logicalAddresses)
  384. {
  385. this.assignLogicalAddresses = logicalAddresses;
  386. }
  387. /**
  388. * Gets whether this factory should update the standard JGroups
  389. * thread factories to ensure application classloaders do not leak to
  390. * newly created channel threads.
  391. *
  392. * @return <code>true</code> if the factories should be updated.
  393. * Default is <code>true</code>.
  394. */
  395. public boolean getManageNewThreadClassLoader()
  396. {
  397. return manageNewThreadClassLoader;
  398. }
  399. /**
  400. * Sets whether this factory should update the standard JGroups
  401. * thread factories to ensure application classloaders do not leak to
  402. * newly created channel threads. This should only be set to <code>false</code>
  403. * if a JGroups release is used that itself prevents such classloader leaks.
  404. *
  405. * @param manage <code>true</code> if the factories should be updated.
  406. */
  407. public void setManageNewThreadClassLoader(boolean manage)
  408. {
  409. this.manageNewThreadClassLoader = manage;
  410. }
  411. /**
  412. * Gets whether this factory should update the standard JGroups
  413. * thread pools to ensure application classloaders have not leaked to
  414. * threads returned to the pool.
  415. *
  416. * @return <code>true</code> if the pools should be updated.
  417. * Default is <code>false</code>.
  418. */
  419. public boolean getManageReleasedThreadClassLoader()
  420. {
  421. return manageReleasedThreadClassLoader;
  422. }
  423. /**
  424. * Sets whether this factory should update the standard JGroups
  425. * thread pools to ensure application classloaders have not leaked to
  426. * threads returned to the pool.
  427. * <p>
  428. * There is a small performance cost to enabling this, and applications
  429. * can prevent any need to enable it by properly restoring the thread
  430. * context classloader if they change it. Therefore, by default this
  431. * is set to <code>false</code>.
  432. * </p>
  433. *
  434. * @param manage <code>true</code> if the factories should be updated.
  435. */
  436. public void setManageReleasedThreadClassLoader(boolean manage)
  437. {
  438. this.manageReleasedThreadClassLoader = manage;
  439. }
  440. /**
  441. * Gets whether {@link #createMultiplexerChannel(String, String)} should
  442. * create a synthetic singleton name attribute for a channel's transport
  443. * protocol if one isn't configured. If this is <code>false</code> and
  444. * no <code>singleton_name</code> is configured,
  445. * {@link #createMultiplexerChannel(String, String)} will throw an
  446. * <code>IllegalStateException</code>.
  447. *
  448. * @return <code>true</code> if synthetic singleton names should be created.
  449. * Default is <code>true</code>.
  450. */
  451. public boolean getAddMissingSingletonName()
  452. {
  453. return addMissingSingletonName;
  454. }
  455. /**
  456. * Sets whether {@link #createMultiplexerChannel(String, String)} should
  457. * create a synthetic singleton name attribute for a channel's transport
  458. * protocol if one isn't configured.
  459. *
  460. * @param addMissingSingletonName <code>true</code> if synthetic singleton
  461. * names should be created.
  462. */
  463. public void setAddMissingSingletonName(boolean addMissingSingletonName)
  464. {
  465. this.addMissingSingletonName = addMissingSingletonName;
  466. }
  467. @Override
  468. public void create() throws Exception
  469. {
  470. if (state == CREATED || state == STARTING || state == STARTED
  471. || state == STOPPING || state == STOPPED)
  472. {
  473. log.debug("Ignoring create call; current state is " + getStateString());
  474. return;
  475. }
  476. log.debug("Creating JChannelFactory");
  477. try
  478. {
  479. super.create();
  480. state = CREATED;
  481. }
  482. catch (Exception e)
  483. {
  484. log.debug("Initialization failed JChannelFactory", e);
  485. throw e;
  486. }
  487. log.debug("Created JChannelFactory");
  488. }
  489. @Override
  490. public void start() throws Exception
  491. {
  492. if (state == STARTING || state == STARTED || state == STOPPING)
  493. {
  494. log.debug("Ignoring start call; current state is " + getStateString());
  495. return;
  496. }
  497. if (state != CREATED && state != STOPPED && state != FAILED)
  498. {
  499. log.debug("Start requested before create, calling create now");
  500. create();
  501. }
  502. state = STARTING;
  503. log.debug("Starting JChannelFactory");
  504. try
  505. {
  506. super.start();
  507. }
  508. catch (Exception e)
  509. {
  510. state = FAILED;
  511. log.debug("Starting failed JChannelFactory", e);
  512. throw e;
  513. }
  514. state = STARTED;
  515. log.debug("Started JChannelFactory");
  516. }
  517. @Override
  518. public void stop()
  519. {
  520. if (state != STARTED)
  521. {
  522. log.debug("Ignoring stop call; current state is " + getStateString());
  523. return;
  524. }
  525. state = STOPPING;
  526. log.debug("Stopping JChannelFactory");
  527. try
  528. {
  529. super.stop();
  530. }
  531. catch (Throwable e)
  532. {
  533. state = FAILED;
  534. log.warn("Stopping failed JChannelFactory", e);
  535. return;
  536. }
  537. state = STOPPED;
  538. log.debug("Stopped JChannelFactory");
  539. }
  540. @Override
  541. public void destroy()
  542. {
  543. if (state == DESTROYED)
  544. {
  545. log.debug("Ignoring destroy call; current state is " + getStateString());
  546. return;
  547. }
  548. if (state == STARTED)
  549. {
  550. log.debug("Destroy requested before stop, calling stop now");
  551. stop();
  552. }
  553. log.debug("Destroying JChannelFactory");
  554. // DON'T call super.destroy() as that may deregister the JMX proxy
  555. // to this pojo service, leading to ugliness when the proxy is destroyed
  556. try
  557. {
  558. Set<String> toUnregister = null;
  559. synchronized (registeredChannels)
  560. {
  561. toUnregister = new HashSet<String>(registeredChannels);
  562. }
  563. for (String channelId : toUnregister)
  564. {
  565. unregister(channelId);
  566. }
  567. }
  568. catch (Throwable t)
  569. {
  570. log.warn("Destroying failed JChannelFactory", t);
  571. }
  572. state = DESTROYED;
  573. log.debug("Destroyed JChannelFactory");
  574. }
  575. // ------------------------------------------------------- MBeanRegistration
  576. public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception
  577. {
  578. setServer(server);
  579. if (!domainSet || getDomain() == null)
  580. {
  581. setDomain(name.getDomain());
  582. }
  583. return name;
  584. }
  585. public void postRegister(Boolean registrationDone)
  586. {
  587. if (registrationDone != null && registrationDone.booleanValue()
  588. && state == ServiceMBean.UNREGISTERED)
  589. {
  590. state = ServiceMBean.REGISTERED;
  591. }
  592. }
  593. public void preDeregister() throws Exception
  594. {
  595. }
  596. public void postDeregister()
  597. {
  598. setServer(null);
  599. if (state == ServiceMBean.DESTROYED)
  600. state = ServiceMBean.UNREGISTERED;
  601. }
  602. /**
  603. * Gets the classloader that channel threads should be set to if
  604. * {@link #getManageNewThreadClassloader()} or {@link #getManageReleasedThreadClassLoader()}
  605. * are <code>true</code>.
  606. * <p>
  607. * This implementation returns this class' classloader.
  608. *
  609. * @return the classloader.
  610. */
  611. protected ClassLoader getDefaultChannelThreadContextClassLoader()
  612. {
  613. return getClass().getClassLoader();
  614. }
  615. // ----------------------------------------------------------------- Private
  616. private void checkStarted()
  617. {
  618. if (state != ServiceMBean.STARTED)
  619. throw new IllegalStateException("Cannot use factory; state is " + getStateString());
  620. }
  621. private void setChannelUniqueId(Channel channel)
  622. {
  623. IpAddress address = (IpAddress) channel.getLocalAddress();
  624. if (address == null)
  625. {
  626. // We push the independent name in the protocol stack before connecting to the cluster
  627. if (this.nodeName == null || "".equals(this.nodeName)) {
  628. this.nodeName = generateUniqueNodeName();
  629. }
  630. log.debug("Passing unique node id " + nodeName + " to the channel as additional data");
  631. HashMap<String, byte[]> staticNodeName = new HashMap<String, byte[]>();
  632. staticNodeName.put("additional_data", this.nodeName.getBytes());
  633. channel.down(new Event(Event.CONFIG, staticNodeName));
  634. }
  635. else if (address.getAdditionalData() == null)
  636. {
  637. if (channel.isConnected())
  638. {
  639. throw new IllegalStateException("Underlying JChannel was " +
  640. "connected before additional_data was set");
  641. }
  642. }
  643. else if (this.nodeName == null || "".equals(this.nodeName))
  644. {
  645. this.nodeName = new String(address.getAdditionalData());
  646. log.warn("Field nodeName was not set but mux channel already had " +
  647. "additional data -- setting nodeName to " + nodeName);
  648. }
  649. }
  650. private String getStateString()
  651. {
  652. return ServiceMBean.states[state];
  653. }
  654. private String generateUniqueNodeName ()
  655. {
  656. // we first try to find a simple meaningful name:
  657. // 1st) "local-IP:JNDI_PORT" if JNDI is running on this machine
  658. // 2nd) "local-IP:JMV_GUID" otherwise
  659. // 3rd) return a fully GUID-based representation
  660. //
  661. // Before anything we determine the local host IP (and NOT name as this could be
  662. // resolved differently by other nodes...)
  663. // But use the specified node address for multi-homing
  664. String hostIP = null;
  665. InetAddress address = ServerConfigUtil.fixRemoteAddress(nodeAddress);
  666. if (address == null)
  667. {
  668. log.debug ("unable to create a GUID for this cluster, check network configuration is correctly setup (getLocalHost has returned an exception)");
  669. log.debug ("using a full GUID strategy");
  670. return new VMID().toString();
  671. }
  672. else
  673. {
  674. hostIP = address.getHostAddress();
  675. }
  676. // 1st: is JNDI up and running?
  677. //
  678. if (namingServicePort > 0)
  679. {
  680. // we can proceed with the JNDI trick!
  681. return hostIP + ":" + namingServicePort;
  682. }
  683. else
  684. {
  685. log.warn("JNDI has been found but the service wasn't started. Most likely, " +
  686. "HAPartition bean is missing dependency on JBoss Naming. " +
  687. "Instead using host based UID strategy for defining a node " +
  688. "GUID for the cluster.");
  689. }
  690. // 2nd: host-GUID strategy
  691. //
  692. String uid = new UID().toString();
  693. return hostIP + ":" + uid;
  694. }
  695. private Map<String, String> getTransportProperties(ProtocolStackConfigurator config)
  696. {
  697. Map<String, String> tpProps = null;
  698. try
  699. {
  700. ProtocolData[] protocols=config.getProtocolStack();
  701. ProtocolData transport=protocols[0];
  702. tpProps = transport.getParameters();
  703. }
  704. catch (UnsupportedOperationException uoe)
  705. {
  706. // JGroups version hasn't implemented ProtocolStackConfigurator.getProtocolStack()
  707. // So we do it ourselves
  708. String configStr = config.getProtocolStackString();
  709. String tpConfigStr = configStr.substring(configStr.indexOf('(') + 1, configStr.indexOf(')'));
  710. String[] params = tpConfigStr.split(";");
  711. tpProps = new HashMap<String, String>();
  712. for (String param : params)
  713. {
  714. String[] keyVal = param.split("=");
  715. if (keyVal.length != 2)
  716. throw new IllegalStateException("Invalid parameter " + param + " in stack " + configStr);
  717. tpProps.put(keyVal[0], keyVal[1]);
  718. }
  719. }
  720. return tpProps;
  721. }
  722. private ProtocolStackConfigurator addSingletonName(ProtocolStackConfigurator orig, String singletonName)
  723. throws ChannelException
  724. {
  725. ProtocolStackConfigurator result = null;
  726. try
  727. {
  728. ProtocolData[] protocols=orig.getProtocolStack();
  729. ProtocolData transport=protocols[0];
  730. Map<String, String> tpProps = transport.getParameters();
  731. tpProps.put(Global.SINGLETON_NAME, singletonName);
  732. // we've now updated the state of orig; just return it
  733. result = orig;
  734. }
  735. catch (UnsupportedOperationException uoe)
  736. {
  737. // JGroups version hasn't implemented ProtocolStackConfigurator.getProtocolStack()
  738. // So we do things manually via string manipulation
  739. String config = orig.getProtocolStackString();
  740. int idx = config.indexOf('(') + 1;
  741. StringBuilder builder = new StringBuilder(config.substring(0, idx));
  742. builder.append(Global.SINGLETON_NAME);
  743. builder.append('=');
  744. builder.append(singletonName);
  745. builder.append(';');
  746. builder.append(config.substring(idx));
  747. result = ConfiguratorFactory.getStackConfigurator(builder.toString());
  748. }
  749. return result;
  750. }
  751. private void fixChannelThreadManagement(Channel channel) throws ChannelException
  752. {
  753. if (!(channel instanceof JChannel))
  754. {
  755. log.debug("Cannot fix thread pools for unknown Channel type " + channel.getClass().getName());
  756. return;
  757. }
  758. JChannel jchannel = (JChannel) channel;
  759. ProtocolStack stack = jchannel.getProtocolStack();
  760. List<Protocol> protocols = stack.getProtocols();
  761. TP tp = null;
  762. for (int i = protocols.size() - 1; i >= 0; i--)
  763. {
  764. if (protocols.get(i) instanceof TP)
  765. {
  766. tp = (TP) protocols.get(i);
  767. break;
  768. }
  769. }
  770. ClassLoader defaultTCCL = getDefaultChannelThreadContextClassLoader();
  771. ThreadDecoratorImpl threadDecorator = new ThreadDecoratorImpl(defaultTCCL);
  772. if (manageNewThreadClassLoader)
  773. {
  774. fixProtocolThreadFactories(tp, threadDecorator);
  775. }
  776. if (manageReleasedThreadClassLoader)
  777. {
  778. fixTransportThreadPools(tp, threadDecorator);
  779. }
  780. }
  781. private void fixProtocolThreadFactories(TP tp, ThreadDecoratorImpl threadDecorator)
  782. {
  783. ThreadFactory stackFactory = tp.getThreadFactory();
  784. if (stackFactory == null)
  785. {
  786. stackFactory = new DefaultThreadFactory(Util.getGlobalThreadGroup(), "", false);
  787. tp.setThreadFactory(stackFactory);
  788. }
  789. fixThreadManager(stackFactory, threadDecorator, "TP.getThreadFactory()");
  790. log.debug("Fixed thread factory for " + tp);
  791. ThreadFactory timerFactory = tp.getTimerThreadFactory();
  792. if (timerFactory == null)
  793. {
  794. timerFactory = new LazyThreadFactory(Util.getGlobalThreadGroup(), "Timer", true, true);
  795. tp.setTimerThreadFactory(timerFactory);
  796. }
  797. fixThreadManager(timerFactory, threadDecorator, "TP.getTimerThreadFactory()");
  798. log.debug("Fixed timer thread factory for " + tp);
  799. ThreadGroup pool_thread_group = null;
  800. if (tp.isDefaulThreadPoolEnabled())
  801. {
  802. ThreadFactory defaultPoolFactory = tp.getDefaultThreadPoolThreadFactory();
  803. if (defaultPoolFactory == null)
  804. {
  805. pool_thread_group=new ThreadGroup(Util.getGlobalThreadGroup(), "Thread Pools");
  806. defaultPoolFactory = new DefaultThreadFactory(pool_thread_group, "Incoming", false, true);
  807. tp.setThreadFactory(defaultPoolFactory);
  808. }
  809. fixThreadManager(defaultPoolFactory, threadDecorator, "TP.getDefaultThreadPoolThreadFactory()");
  810. log.debug("Fixed default pool thread factory for " + tp);
  811. }
  812. if (tp.isOOBThreadPoolEnabled())
  813. {
  814. ThreadFactory oobPoolFactory = tp.getOOBThreadPoolThreadFactory();
  815. if (oobPoolFactory == null)
  816. {
  817. if (pool_thread_group == null)
  818. pool_thread_group=new ThreadGroup(Util.getGlobalThreadGroup(), "Thread Pools");
  819. oobPoolFactory = new DefaultThreadFactory(pool_thread_group, "OOB", false, true);
  820. tp.setThreadFactory(oobPoolFactory);
  821. }
  822. fixThreadManager(oobPoolFactory, threadDecorator, "TP.getOOBThreadPoolThreadFactory()");
  823. log.debug("Fixed oob pool thread factory for " + tp);
  824. }
  825. Map<ThreadFactory, Protocol> factories= new HashMap<ThreadFactory, Protocol>();
  826. Protocol tmp=tp.getUpProtocol();
  827. while(tmp != null) {
  828. ThreadFactory f=tmp.getThreadFactory();
  829. if(f != null && !factories.containsKey(f))
  830. {
  831. factories.put(f, tmp);
  832. }
  833. tmp=tmp.getUpProtocol();
  834. }
  835. for (Map.Entry<ThreadFactory, Protocol> entry : factories.entrySet())
  836. {
  837. fixThreadManager(entry.getKey(), threadDecorator, entry.getValue().getClass().getSimpleName() + ".getThreadFactory()");
  838. }
  839. log.debug("Fixed Protocol thread factories");
  840. }
  841. private void fixTransportThreadPools(TP tp, ThreadDecoratorImpl threadDecorator)
  842. {
  843. Executor threadPool = tp.getDefaultThreadPool();
  844. if (tp.isDefaulThreadPoolEnabled())
  845. {
  846. fixThreadManager(threadPool, threadDecorator, "TP.getDefaultThreadPool()");
  847. log.debug("Fixed default thread pool for " + tp);
  848. }
  849. threadPool = tp.getOOBThreadPool();
  850. if (tp.isOOBThreadPoolEnabled())
  851. {
  852. fixThreadManager(threadPool, threadDecorator, "TP.getOOBThreadPool()");
  853. log.debug("Fixed OOB thread pool for " + tp);
  854. }
  855. }
  856. private void fixThreadManager(Object manager, ThreadDecoratorImpl decorator, String managerSource)
  857. {
  858. if (manager instanceof ThreadManager)
  859. {
  860. ThreadManager threadManager = (ThreadManager) manager;
  861. ThreadDecorator existing = threadManager.getThreadDecorator();
  862. if (existing instanceof ThreadDecoratorImpl)
  863. {
  864. // already been handled
  865. return;
  866. }
  867. else if (existing != null)
  868. {
  869. // someone else has added one; integrate with it
  870. decorator.setParent(existing);
  871. }
  872. threadManager.setThreadDecorator(decorator);
  873. }
  874. else
  875. {
  876. log.warn(managerSource + " is not a ThreadManager");
  877. }
  878. }
  879. /**
  880. * Sets the context class loader on <code>thread</code> to the classloader
  881. * in effect when this factory was instantiated.
  882. *
  883. * @param thread the thread to set
  884. */
  885. private void setDefaultThreadContextClassLoader(Thread thread, ClassLoader classLoader)
  886. {
  887. classLoaderSwitcher.setContextClassLoader(thread, classLoader);
  888. }
  889. private void registerChannel(JChannel ch, String channelId) throws Exception
  890. {
  891. if(getServer() != null)
  892. {
  893. // Register for channel closed notification so we can unregister
  894. JmxDeregistrationChannelListener listener = new JmxDeregistrationChannelListener(channelId);
  895. ch.addChannelListener(listener);
  896. JmxConfigurator.registerChannel(ch, getServer(), getDomain(), channelId, isExposeProtocols());
  897. synchronized (registeredChannels)
  898. {
  899. registeredChannels.add(channelId);
  900. }
  901. }
  902. }
  903. private void unregister(String channelId)
  904. {
  905. if(getServer() != null && registeredChannels.contains(channelId))
  906. {
  907. String oname = getDomain() + ":type=channel,cluster=" + channelId;
  908. try
  909. {
  910. getServer().unregisterMBean(new ObjectName(oname));
  911. oname = getDomain() + ":type=protocol,cluster=" + channelId + ",*";
  912. JmxConfigurator.unregister(getServer(), oname);
  913. synchronized (registeredChannels)
  914. {
  915. registeredChannels.remove(channelId);
  916. }
  917. }
  918. catch(Exception e)
  919. {
  920. log.error("failed unregistering " + oname, e);
  921. }
  922. }
  923. }
  924. private class ThreadDecoratorImpl implements ThreadDecorator
  925. {
  926. private final ClassLoader classloader;
  927. private ThreadDecorator parent;
  928. private ThreadDecoratorImpl(ClassLoader classloader)
  929. {
  930. this.classloader = classloader;
  931. }
  932. public void threadCreated(Thread thread)
  933. {
  934. if (parent != null)
  935. parent.threadCreated(thread);
  936. setDefaultThreadContextClassLoader(thread, classloader);
  937. }
  938. public void threadReleased(Thread thread)
  939. {
  940. if (parent != null)
  941. parent.threadCreated(thread);
  942. setDefaultThreadContextClassLoader(thread, classloader);
  943. }
  944. public ThreadDecorator getParent()
  945. {
  946. return parent;
  947. }
  948. public void setParent(ThreadDecorator parent)
  949. {
  950. this.parent = parent;
  951. }
  952. }
  953. private class JmxDeregistrationChannelListener extends ChannelListenerAdapter
  954. {
  955. private final String channelId;
  956. JmxDeregistrationChannelListener(String channelId)
  957. {
  958. this.channelId = channelId;
  959. }
  960. public void channelClosed(Channel channel)
  961. {
  962. unregister(channelId);
  963. }
  964. }
  965. }