PageRenderTime 86ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/sip-balancer/jar/src/main/java/org/mobicents/tools/sip/balancer/NodeRegisterImpl.java

http://mobicents.googlecode.com/
Java | 425 lines | 283 code | 52 blank | 90 comment | 50 complexity | 55489eac2ae6a74d25ce657f79a8f9a6 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * 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.mobicents.tools.sip.balancer;
  23. import java.net.InetAddress;
  24. import java.rmi.AlreadyBoundException;
  25. import java.rmi.NotBoundException;
  26. import java.rmi.RemoteException;
  27. import java.rmi.registry.LocateRegistry;
  28. import java.rmi.registry.Registry;
  29. import java.rmi.server.UnicastRemoteObject;
  30. import java.util.ArrayList;
  31. import java.util.Iterator;
  32. import java.util.Timer;
  33. import java.util.TimerTask;
  34. import java.util.concurrent.ConcurrentHashMap;
  35. import java.util.concurrent.CopyOnWriteArrayList;
  36. import java.util.logging.Level;
  37. import java.util.logging.Logger;
  38. /**
  39. * <p>
  40. * This is the placeholder for maintening information about alive nodes and
  41. * the relation between a Call-Id and its attributed node.
  42. * </p>
  43. *
  44. * @author M. Ranganathan
  45. * @author baranowb
  46. * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A>
  47. *
  48. */
  49. public class NodeRegisterImpl implements NodeRegister {
  50. private static Logger logger = Logger.getLogger(NodeRegisterImpl.class.getCanonicalName());
  51. public static final int POINTER_START = 0;
  52. private long nodeInfoExpirationTaskInterval = 5000;
  53. private long nodeExpiration = 5100;
  54. private Registry registry;
  55. private Timer taskTimer = new Timer();
  56. private TimerTask nodeExpirationTask = null;
  57. private InetAddress serverAddress = null;
  58. private String latestVersion = Integer.MIN_VALUE + "";
  59. private int numberOfOldServers, numberOfNewServers;
  60. BalancerRunner balancerRunner;
  61. public NodeRegisterImpl(InetAddress serverAddress) throws RemoteException {
  62. super();
  63. this.serverAddress = serverAddress;
  64. }
  65. /**
  66. * {@inheritDoc}
  67. */
  68. public boolean startRegistry(int rmiRegistryPort) {
  69. if(logger.isLoggable(Level.INFO)) {
  70. logger.info("Node registry starting...");
  71. }
  72. try {
  73. balancerRunner.balancerContext.aliveNodes = new CopyOnWriteArrayList<SIPNode>();;
  74. balancerRunner.balancerContext.jvmRouteToSipNode = new ConcurrentHashMap<String, SIPNode>();
  75. register(serverAddress, rmiRegistryPort);
  76. this.nodeExpirationTask = new NodeExpirationTimerTask();
  77. this.taskTimer.scheduleAtFixedRate(this.nodeExpirationTask,
  78. this.nodeInfoExpirationTaskInterval,
  79. this.nodeInfoExpirationTaskInterval);
  80. if(logger.isLoggable(Level.INFO)) {
  81. logger.info("Node expiration task created");
  82. logger.info("Node registry started");
  83. }
  84. } catch (Exception e) {
  85. logger.log(Level.SEVERE, "Unexpected exception while starting the registry", e);
  86. return false;
  87. }
  88. return true;
  89. }
  90. /**
  91. * {@inheritDoc}
  92. */
  93. public boolean stopRegistry() {
  94. if(logger.isLoggable(Level.INFO)) {
  95. logger.info("Stopping node registry...");
  96. }
  97. boolean isDeregistered = deregister(serverAddress);
  98. boolean taskCancelled = nodeExpirationTask.cancel();
  99. if(logger.isLoggable(Level.INFO)) {
  100. logger.info("Node Expiration Task cancelled " + taskCancelled);
  101. }
  102. balancerRunner.balancerContext.allNodesEver.clear();
  103. balancerRunner.balancerContext.allNodesEver = null;
  104. if(logger.isLoggable(Level.INFO)) {
  105. logger.info("Node registry stopped.");
  106. }
  107. return isDeregistered;
  108. }
  109. // ********* CLASS TO BE EXPOSED VIA RMI
  110. private class RegisterRMIStub extends UnicastRemoteObject implements NodeRegisterRMIStub {
  111. protected RegisterRMIStub() throws RemoteException {
  112. super();
  113. }
  114. /*
  115. * (non-Javadoc)
  116. * @see org.mobicents.tools.sip.balancer.NodeRegisterRMIStub#handlePing(java.util.ArrayList)
  117. */
  118. public void handlePing(ArrayList<SIPNode> ping) throws RemoteException {
  119. handlePingInRegister(ping);
  120. }
  121. /*
  122. * (non-Javadoc)
  123. * @see org.mobicents.tools.sip.balancer.NodeRegisterRMIStub#forceRemoval(java.util.ArrayList)
  124. */
  125. public void forceRemoval(ArrayList<SIPNode> ping)
  126. throws RemoteException {
  127. forceRemovalInRegister(ping);
  128. }
  129. public void switchover(String fromJvmRoute, String toJvmRoute) throws RemoteException {
  130. jvmRouteSwitchover(fromJvmRoute, toJvmRoute);
  131. }
  132. }
  133. // ***** SOME PRIVATE HELPERS
  134. private void register(InetAddress serverAddress, int rmiRegistryPort) {
  135. try {
  136. registry = LocateRegistry.createRegistry(rmiRegistryPort);
  137. registry.bind("SIPBalancer", new RegisterRMIStub());
  138. } catch (RemoteException e) {
  139. throw new RuntimeException("Failed to bind due to:", e);
  140. } catch (AlreadyBoundException e) {
  141. throw new RuntimeException("Failed to bind due to:", e);
  142. }
  143. }
  144. private boolean deregister(InetAddress serverAddress) {
  145. try {
  146. registry.unbind("SIPBalancer");
  147. return UnicastRemoteObject.unexportObject(registry, false);
  148. } catch (RemoteException e) {
  149. throw new RuntimeException("Failed to unbind due to", e);
  150. } catch (NotBoundException e) {
  151. throw new RuntimeException("Failed to unbind due to", e);
  152. }
  153. }
  154. // ***** NODE MGMT METHODS
  155. /**
  156. * {@inheritDoc}
  157. */
  158. public void unStickSessionFromNode(String callID) {
  159. if(logger.isLoggable(Level.FINEST)) {
  160. logger.finest("unsticked CallId " + callID + " from node " + null);
  161. }
  162. }
  163. /**
  164. * {@inheritDoc}
  165. */
  166. public SIPNode stickSessionToNode(String callID, SIPNode sipNode) {
  167. if(logger.isLoggable(Level.FINEST)) {
  168. logger.finest("sticking CallId " + callID + " to node " + null);
  169. }
  170. return null;
  171. }
  172. /**
  173. * {@inheritDoc}
  174. */
  175. public SIPNode getGluedNode(String callID) {
  176. if(logger.isLoggable(Level.FINEST)) {
  177. logger.finest("glueued node " + null + " for CallId " + callID);
  178. }
  179. return null;
  180. }
  181. /**
  182. * {@inheritDoc}
  183. */
  184. public boolean isSIPNodePresent(String host, int port, String transport, String version) {
  185. if(getNode(host, port, transport, version) != null) {
  186. return true;
  187. }
  188. return false;
  189. }
  190. /**
  191. * {@inheritDoc}
  192. */
  193. public SIPNode getNode(String host, int port, String transport, String version) {
  194. for (SIPNode node : balancerRunner.balancerContext.aliveNodes) {
  195. if(logger.isLoggable(Level.FINEST)) {
  196. logger.finest("node to check against " + node);
  197. }
  198. if(node.getIp().equals(host)) {
  199. Integer nodePort = (Integer) node.getProperties().get(transport + "Port");
  200. if(nodePort != null) {
  201. if(nodePort == port) {
  202. if(version == null) {
  203. return node;
  204. } else {
  205. String nodeVersion = (String) node.getProperties().get("version");
  206. if(version.equals(nodeVersion)) {
  207. return node;
  208. }
  209. }
  210. }
  211. }
  212. }
  213. }
  214. if(logger.isLoggable(Level.FINEST)) {
  215. logger.finest("checking if the node is still alive for " + host + ":" + port + "/" + transport + " : false");
  216. }
  217. return null;
  218. }
  219. class NodeExpirationTimerTask extends TimerTask {
  220. public void run() {
  221. if(logger.isLoggable(Level.FINEST)) {
  222. logger.finest("NodeExpirationTimerTask Running");
  223. }
  224. for (SIPNode node : balancerRunner.balancerContext.aliveNodes) {
  225. long expirationTime = node.getTimeStamp() + nodeExpiration;
  226. if (expirationTime < System
  227. .currentTimeMillis()) {
  228. InvocationContext ctx = balancerRunner.getInvocationContext(
  229. (String) node.getProperties().get("version"));
  230. balancerRunner.balancerContext.aliveNodes.remove(node);
  231. ctx.nodes.remove(node);
  232. ctx.balancerAlgorithm.nodeRemoved(node);
  233. if(logger.isLoggable(Level.INFO)) {
  234. logger.info("NodeExpirationTimerTask Run NSync["
  235. + node + "] removed. Last timestamp: " + node.getTimeStamp() +
  236. ", current: " + System.currentTimeMillis()
  237. + " diff=" + ((double)System.currentTimeMillis()-node.getTimeStamp() ) +
  238. "ms and tolerance=" + nodeExpiration + " ms");
  239. }
  240. } else {
  241. if(logger.isLoggable(Level.FINEST)) {
  242. logger.finest("node time stamp : " + expirationTime + " , current time : "
  243. + System.currentTimeMillis());
  244. }
  245. }
  246. }
  247. if(logger.isLoggable(Level.FINEST)) {
  248. logger.finest("NodeExpirationTimerTask Done");
  249. }
  250. }
  251. }
  252. /**
  253. * {@inheritDoc}
  254. */
  255. public void handlePingInRegister(ArrayList<SIPNode> ping) {
  256. for (SIPNode pingNode : ping) {
  257. String version = (String) pingNode.getProperties().get("version");
  258. InvocationContext ctx = balancerRunner.getInvocationContext(
  259. version);
  260. pingNode.updateTimerStamp();
  261. if(pingNode.getProperties().get("jvmRoute") != null) {
  262. // Let it leak, we will have 10-100 nodes, not a big deal if it leaks.
  263. // We need info about inactive nodes to do the failover
  264. balancerRunner.balancerContext.jvmRouteToSipNode.put(
  265. (String)pingNode.getProperties().get("jvmRoute"), pingNode);
  266. }
  267. SIPNode nodePresent = null;
  268. Iterator<SIPNode> nodesIterator = ctx.nodes.iterator();
  269. while (nodesIterator.hasNext() && nodePresent == null) {
  270. SIPNode node = (SIPNode) nodesIterator.next();
  271. if (node.equals(pingNode)) {
  272. nodePresent = node;
  273. }
  274. }
  275. // adding done afterwards to avoid ConcurrentModificationException when adding the node while going through the iterator
  276. if(nodePresent != null) {
  277. nodePresent.updateTimerStamp();
  278. if(logger.isLoggable(Level.FINE)) {
  279. logger.fine("Ping " + nodePresent.getTimeStamp());
  280. }
  281. } else {
  282. Integer current = Integer.parseInt(version);
  283. Integer latest = Integer.parseInt(latestVersion);
  284. latestVersion = Math.max(current, latest) + "";
  285. balancerRunner.balancerContext.aliveNodes.add(pingNode);
  286. ctx.nodes.add(pingNode);
  287. ctx.balancerAlgorithm.nodeAdded(pingNode);
  288. balancerRunner.balancerContext.allNodesEver.add(pingNode);
  289. pingNode.updateTimerStamp();
  290. if(logger.isLoggable(Level.INFO)) {
  291. logger.info("NodeExpirationTimerTask Run NSync["
  292. + pingNode + "] added");
  293. }
  294. }
  295. }
  296. }
  297. public String getLatestVersion() {
  298. return latestVersion;
  299. }
  300. /**
  301. * {@inheritDoc}
  302. */
  303. public void forceRemovalInRegister(ArrayList<SIPNode> ping) {
  304. for (SIPNode pingNode : ping) {
  305. InvocationContext ctx = balancerRunner.getInvocationContext(
  306. (String) pingNode.getProperties().get("version"));
  307. boolean nodePresent = false;
  308. Iterator<SIPNode> nodesIterator = balancerRunner.balancerContext.aliveNodes.iterator();
  309. while (nodesIterator.hasNext() && !nodePresent) {
  310. SIPNode node = (SIPNode) nodesIterator.next();
  311. if (node.equals(pingNode)) {
  312. nodePresent = true;
  313. }
  314. }
  315. // removal done afterwards to avoid ConcurrentModificationException when removing the node while goign through the iterator
  316. if(nodePresent) {
  317. balancerRunner.balancerContext.aliveNodes.remove(pingNode);
  318. ctx.balancerAlgorithm.nodeRemoved(pingNode);
  319. if(logger.isLoggable(Level.INFO)) {
  320. logger.info("NodeExpirationTimerTask Run NSync["
  321. + pingNode + "] forcibly removed due to a clean shutdown of a node. Numbers of nodes present in the balancer : "
  322. + balancerRunner.balancerContext.aliveNodes.size());
  323. }
  324. }
  325. }
  326. }
  327. /**
  328. * {@inheritDoc}
  329. */
  330. public InetAddress getAddress() {
  331. return this.serverAddress;
  332. }
  333. /**
  334. * {@inheritDoc}
  335. */
  336. public long getNodeExpiration() {
  337. return this.nodeExpiration;
  338. }
  339. /**
  340. * {@inheritDoc}
  341. */
  342. public long getNodeExpirationTaskInterval() {
  343. return this.nodeInfoExpirationTaskInterval;
  344. }
  345. /**
  346. * {@inheritDoc}
  347. */
  348. public void setNodeExpiration(long value) throws IllegalArgumentException {
  349. if (value < 15)
  350. throw new IllegalArgumentException("Value cant be less than 15");
  351. this.nodeExpiration = value;
  352. }
  353. /**
  354. * {@inheritDoc}
  355. */
  356. public void setNodeExpirationTaskInterval(long value) {
  357. if (value < 15)
  358. throw new IllegalArgumentException("Value cant be less than 15");
  359. this.nodeInfoExpirationTaskInterval = value;
  360. }
  361. public SIPNode[] getAllNodes() {
  362. return balancerRunner.balancerContext.aliveNodes.toArray(new SIPNode[]{});
  363. }
  364. public SIPNode getNextNode() throws IndexOutOfBoundsException {
  365. // TODO Auto-generated method stub
  366. return null;
  367. }
  368. public void jvmRouteSwitchover(String fromJvmRoute, String toJvmRoute) {
  369. for(InvocationContext ctx : balancerRunner.contexts.values()) {
  370. ctx.balancerAlgorithm.jvmRouteSwitchover(fromJvmRoute, toJvmRoute);
  371. }
  372. }
  373. }