PageRenderTime 26ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/StackImpl.java

http://mobicents.googlecode.com/
Java | 493 lines | 404 code | 48 blank | 41 comment | 78 complexity | 44d12897ec5e2305433e73411f8cea31 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 2010, 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.jdiameter.client.impl;
  23. import static org.jdiameter.client.impl.helpers.ExtensionPoint.ControllerLayer;
  24. import static org.jdiameter.client.impl.helpers.ExtensionPoint.StackLayer;
  25. import static org.jdiameter.client.impl.helpers.ExtensionPoint.TransportLayer;
  26. import static org.jdiameter.client.impl.helpers.Parameters.Assembler;
  27. import static org.jdiameter.common.api.concurrent.IConcurrentFactory.ScheduledExecServices.ProcessingMessageTimer;
  28. import java.io.IOException;
  29. import java.util.List;
  30. import java.util.concurrent.CountDownLatch;
  31. import java.util.concurrent.ScheduledExecutorService;
  32. import java.util.concurrent.TimeUnit;
  33. import java.util.concurrent.locks.Lock;
  34. import java.util.concurrent.locks.ReentrantLock;
  35. import org.jdiameter.api.AvpDataException;
  36. import org.jdiameter.api.BaseSession;
  37. import org.jdiameter.api.Configuration;
  38. import org.jdiameter.api.DisconnectCause;
  39. import org.jdiameter.api.IllegalDiameterStateException;
  40. import org.jdiameter.api.InternalException;
  41. import org.jdiameter.api.MetaData;
  42. import org.jdiameter.api.Mode;
  43. import org.jdiameter.api.NetworkReqListener;
  44. import org.jdiameter.api.Peer;
  45. import org.jdiameter.api.PeerState;
  46. import org.jdiameter.api.PeerTable;
  47. import org.jdiameter.api.RouteException;
  48. import org.jdiameter.api.SessionFactory;
  49. import org.jdiameter.api.app.StateChangeListener;
  50. import org.jdiameter.api.validation.Dictionary;
  51. import org.jdiameter.api.validation.ValidatorLevel;
  52. import org.jdiameter.client.api.IAssembler;
  53. import org.jdiameter.client.api.IContainer;
  54. import org.jdiameter.client.api.IMessage;
  55. import org.jdiameter.client.api.IMetaData;
  56. import org.jdiameter.client.api.StackState;
  57. import org.jdiameter.client.api.controller.IPeer;
  58. import org.jdiameter.client.api.controller.IPeerTable;
  59. import org.jdiameter.client.impl.helpers.Parameters;
  60. import org.jdiameter.common.api.concurrent.IConcurrentFactory;
  61. import org.jdiameter.common.api.data.ISessionDatasource;
  62. import org.jdiameter.common.api.statistic.IStatisticProcessor;
  63. import org.jdiameter.common.api.timer.ITimerFacility;
  64. import org.slf4j.Logger;
  65. import org.slf4j.LoggerFactory;
  66. /**
  67. * Use stack extension point
  68. *
  69. * @author erick.svenson@yahoo.com
  70. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  71. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  72. */
  73. public class StackImpl implements IContainer, StackImplMBean {
  74. private static final Logger log = LoggerFactory.getLogger(StackImpl.class);
  75. protected IAssembler assembler;
  76. protected IConcurrentFactory concurrentFactory;
  77. protected Configuration config;
  78. protected IPeerTable peerManager;
  79. protected StackState state = StackState.IDLE;
  80. protected Lock lock = new ReentrantLock();
  81. /**
  82. * Use for processing request time-out tasks (for all active peers)
  83. */
  84. protected ScheduledExecutorService scheduledFacility;
  85. @SuppressWarnings("unchecked")
  86. public SessionFactory init(Configuration config) throws IllegalDiameterStateException, InternalException {
  87. lock.lock();
  88. if (log.isInfoEnabled()) {
  89. log.info("(-)(-)(-)(-)(-) Starting " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
  90. }
  91. try {
  92. if (state != StackState.IDLE) {
  93. throw new IllegalDiameterStateException();
  94. }
  95. try {
  96. Class assemblerClass = Class.forName(config.getStringValue(Assembler.ordinal(), (String) Assembler.defValue()));
  97. assembler = (IAssembler) assemblerClass.getConstructor(Configuration.class).newInstance(config);
  98. // register common instances
  99. assembler.registerComponentInstance(this);
  100. assembler.registerComponentInstance(config);
  101. }
  102. catch (Exception e) {
  103. throw new InternalException(e);
  104. }
  105. this.config = config;
  106. this.concurrentFactory = (IConcurrentFactory) assembler.getComponentInstance(IConcurrentFactory.class);
  107. try {
  108. Configuration[] dictionaryConfigs = config.getChildren(Parameters.Dictionary.ordinal());
  109. // Initialize with default values
  110. String dictionaryClassName = (String) Parameters.DictionaryClass.defValue();
  111. Boolean validatorEnabled = (Boolean) Parameters.DictionaryEnabled.defValue();
  112. ValidatorLevel validatorSendLevel = ValidatorLevel.fromString((String) Parameters.DictionarySendLevel.defValue());
  113. ValidatorLevel validatorReceiveLevel = ValidatorLevel.fromString((String) Parameters.DictionaryReceiveLevel.defValue());
  114. if (dictionaryConfigs != null && dictionaryConfigs.length > 0) {
  115. Configuration dictionaryConfiguration = dictionaryConfigs[0];
  116. dictionaryClassName = dictionaryConfiguration.getStringValue(Parameters.DictionaryClass.ordinal(), (String) Parameters.DictionaryClass.defValue());
  117. validatorEnabled = dictionaryConfiguration.getBooleanValue(Parameters.DictionaryEnabled.ordinal(), (Boolean) Parameters.DictionaryEnabled.defValue());
  118. validatorSendLevel = ValidatorLevel.fromString(dictionaryConfiguration.getStringValue(Parameters.DictionarySendLevel.ordinal(),
  119. (String) Parameters.DictionarySendLevel.defValue()));
  120. validatorReceiveLevel = ValidatorLevel.fromString(dictionaryConfiguration.getStringValue(Parameters.DictionaryReceiveLevel.ordinal(),
  121. (String) Parameters.DictionaryReceiveLevel.defValue()));
  122. }
  123. createDictionary(dictionaryClassName, validatorEnabled, validatorSendLevel, validatorReceiveLevel);
  124. }
  125. catch (Exception e) {
  126. throw new InternalException(e);
  127. }
  128. // create manager
  129. this.peerManager = (IPeerTable) assembler.getComponentInstance(IPeerTable.class);
  130. this.peerManager.setAssembler(assembler);
  131. this.state = StackState.CONFIGURED;
  132. }
  133. finally {
  134. lock.unlock();
  135. }
  136. if (log.isInfoEnabled()) {
  137. log.info("(-)(-)(-)(-)(-) Started " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
  138. }
  139. return (SessionFactory) assembler.getComponentInstance(SessionFactory.class);
  140. }
  141. private void createDictionary(String clazz, boolean validatorEnabled, ValidatorLevel validatorSendLevel, ValidatorLevel validatorReceiveLevel)
  142. throws InternalException {
  143. // Defer call to singleton
  144. DictionarySingleton.init(clazz, validatorEnabled, validatorSendLevel, validatorReceiveLevel);
  145. }
  146. public SessionFactory getSessionFactory() throws IllegalDiameterStateException {
  147. if (state == StackState.CONFIGURED || state == StackState.STARTED) {
  148. // FIXME: When possible, get rid of IoC here.
  149. return (SessionFactory) assembler.getComponentInstance(SessionFactory.class);
  150. }
  151. else {
  152. throw new IllegalDiameterStateException();
  153. }
  154. }
  155. public Dictionary getDictionary() throws IllegalDiameterStateException {
  156. return DictionarySingleton.getDictionary();
  157. }
  158. public void start() throws IllegalDiameterStateException, InternalException {
  159. lock.lock();
  160. try {
  161. if (state != StackState.STOPPED && state != StackState.CONFIGURED) {
  162. throw new IllegalDiameterStateException();
  163. }
  164. scheduledFacility = concurrentFactory.getScheduledExecutorService(ProcessingMessageTimer.name());
  165. assembler.getComponentInstance(ISessionDatasource.class).start();
  166. assembler.getComponentInstance(IStatisticProcessor.class).start();
  167. assembler.getComponentInstance(ITimerFacility.class);
  168. startPeerManager();
  169. state = StackState.STARTED;
  170. }
  171. finally {
  172. lock.unlock();
  173. }
  174. }
  175. @SuppressWarnings("unchecked")
  176. public void start(final Mode mode, long timeOut, TimeUnit timeUnit) throws IllegalDiameterStateException, InternalException {
  177. lock.lock();
  178. try {
  179. if (state != StackState.STOPPED && state != StackState.CONFIGURED) {
  180. throw new IllegalDiameterStateException();
  181. }
  182. scheduledFacility = concurrentFactory.getScheduledExecutorService(ProcessingMessageTimer.name());
  183. assembler.getComponentInstance(IStatisticProcessor.class).start();
  184. assembler.getComponentInstance(ISessionDatasource.class).start();
  185. assembler.getComponentInstance(ITimerFacility.class);
  186. List<Peer> peerTable = peerManager.getPeerTable();
  187. // considering only "to connect" peers are on the table at this time...
  188. final CountDownLatch barrier = new CountDownLatch(Mode.ANY_PEER.equals(mode) ? Math.min(peerTable.size(), 1) : peerTable.size());
  189. StateChangeListener listener = new AbstractStateChangeListener() {
  190. public void stateChanged(Enum oldState, Enum newState) {
  191. if (PeerState.OKAY.equals(newState)) {
  192. barrier.countDown();
  193. }
  194. }
  195. };
  196. for (Peer p : peerTable) {
  197. ((IPeer) p).addStateChangeListener(listener);
  198. }
  199. startPeerManager();
  200. try {
  201. barrier.await(timeOut, timeUnit);
  202. if (barrier.getCount() != 0) {
  203. throw new InternalException("TimeOut");
  204. }
  205. state = StackState.STARTED;
  206. }
  207. catch (InterruptedException e) {
  208. throw new InternalException("TimeOut");
  209. }
  210. finally {
  211. for (Peer p : peerTable) {
  212. ((IPeer) p).remStateChangeListener(listener);
  213. }
  214. }
  215. }
  216. finally {
  217. lock.unlock();
  218. }
  219. }
  220. private void startPeerManager() throws InternalException {
  221. try {
  222. if (peerManager != null) {
  223. peerManager.start();
  224. }
  225. getMetaData().unwrap(IMetaData.class).updateLocalHostStateId();
  226. }
  227. catch (Exception e) {
  228. throw new InternalException(e);
  229. }
  230. }
  231. @SuppressWarnings("unchecked")
  232. public void stop(long timeOut, TimeUnit timeUnit, int disconnectCause) throws IllegalDiameterStateException, InternalException {
  233. lock.lock();
  234. try {
  235. if (state == StackState.STARTED || state == StackState.CONFIGURED) {
  236. if (log.isInfoEnabled()) {
  237. log.info("(-)(-)(-)(-)(-) Stopping " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
  238. }
  239. List<Peer> peerTable = peerManager.getPeerTable();
  240. final CountDownLatch barrier = new CountDownLatch(peerTable.size());
  241. StateChangeListener listener = new AbstractStateChangeListener() {
  242. public void stateChanged(Enum oldState, Enum newState) {
  243. if (PeerState.DOWN.equals(newState)) {
  244. barrier.countDown();
  245. }
  246. }
  247. };
  248. for (Peer p : peerTable) {
  249. if (p.getState(PeerState.class).equals(PeerState.DOWN)) {
  250. barrier.countDown();
  251. }
  252. else {
  253. ((IPeer) p).addStateChangeListener(listener);
  254. }
  255. }
  256. if (peerManager != null) {
  257. try {
  258. peerManager.stopping(disconnectCause);
  259. }
  260. catch (Exception e) {
  261. log.warn("Stopping error", e);
  262. }
  263. }
  264. try {
  265. barrier.await(timeOut, timeUnit);
  266. if (barrier.getCount() != 0) {
  267. throw new InternalException("TimeOut");
  268. }
  269. }
  270. catch (InterruptedException e) {
  271. throw new InternalException("TimeOut");
  272. }
  273. finally {
  274. state = StackState.STOPPED;
  275. for (Peer p : peerTable) {
  276. ((IPeer) p).remStateChangeListener(listener);
  277. }
  278. }
  279. assembler.getComponentInstance(ISessionDatasource.class).stop();
  280. assembler.getComponentInstance(IStatisticProcessor.class).stop();
  281. try {
  282. if (peerManager != null) {
  283. peerManager.stopped();
  284. }
  285. // Clear all timeout tasks
  286. if (scheduledFacility != null) {
  287. concurrentFactory.shutdownNow(scheduledFacility);
  288. }
  289. }
  290. catch (Exception e) {
  291. log.warn("Stopped error", e);
  292. }
  293. state = StackState.STOPPED;
  294. if (log.isInfoEnabled()) {
  295. log.info("(-)(-)(-)(-)(-) Stopped " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
  296. }
  297. }
  298. }
  299. finally {
  300. lock.unlock();
  301. }
  302. }
  303. public void destroy() {
  304. // Be friendly
  305. if (state == StackState.STARTED) {
  306. log.warn("Calling destroy() with Stack in STARTED state. Calling stop(REBOOTING) before, please do it yourself with the proper cause.");
  307. stop(DisconnectCause.REBOOTING);
  308. }
  309. lock.lock();
  310. try {
  311. if (peerManager != null) {
  312. peerManager.destroy();
  313. }
  314. if (assembler != null) {
  315. assembler.destroy();
  316. }
  317. if (scheduledFacility != null) {
  318. concurrentFactory.shutdownNow(scheduledFacility);
  319. }
  320. }
  321. catch (Exception e) {
  322. log.warn("Destroy error", e);
  323. }
  324. finally {
  325. state = StackState.IDLE;
  326. lock.unlock();
  327. }
  328. }
  329. public boolean isActive() {
  330. return state == StackState.STARTED;
  331. }
  332. public java.util.logging.Logger getLogger() {
  333. return java.util.logging.Logger.getAnonymousLogger();
  334. }
  335. public MetaData getMetaData() {
  336. if (state == StackState.IDLE) {
  337. throw new IllegalStateException("Meta data not defined");
  338. }
  339. return (MetaData) assembler.getComponentInstance(IMetaData.class);
  340. }
  341. @SuppressWarnings("unchecked")
  342. public <T extends BaseSession> T getSession(String sessionId, Class<T> clazz) throws InternalException {
  343. if (getState() == StackState.IDLE) {
  344. throw new InternalException("Illegal state of stack");
  345. }
  346. BaseSession bs = assembler.getComponentInstance(ISessionDatasource.class).getSession(sessionId);
  347. return bs != null ? (T) bs : null;
  348. }
  349. public boolean isWrapperFor(Class<?> aClass) throws InternalException {
  350. boolean isWrap = aClass == PeerTable.class;
  351. if (!isWrap) {
  352. isWrap = assembler.getChilds()[StackLayer.id()].getComponentInstance(aClass) != null;
  353. }
  354. if (!isWrap) {
  355. isWrap = assembler.getChilds()[ControllerLayer.id()].getComponentInstance(aClass) != null;
  356. }
  357. if (!isWrap) {
  358. isWrap = assembler.getChilds()[TransportLayer.id()].getComponentInstance(aClass) != null;
  359. }
  360. return isWrap;
  361. }
  362. @SuppressWarnings("unchecked")
  363. public <T> T unwrap(Class<T> aClass) throws InternalException {
  364. Object unwrapObject = null;
  365. if (aClass == PeerTable.class) {
  366. unwrapObject = assembler.getComponentInstance(aClass);
  367. }
  368. // TODO: "layers" should be removed....
  369. if (unwrapObject == null) {
  370. unwrapObject = assembler.getChilds()[StackLayer.id()].getComponentInstance(aClass);
  371. }
  372. if (unwrapObject == null) {
  373. unwrapObject = assembler.getChilds()[ControllerLayer.id()].getComponentInstance(aClass);
  374. }
  375. if (unwrapObject == null) {
  376. unwrapObject = assembler.getChilds()[TransportLayer.id()].getComponentInstance(aClass);
  377. }
  378. return (T) unwrapObject;
  379. }
  380. // Extended methods
  381. public StackState getState() {
  382. return state;
  383. }
  384. public Configuration getConfiguration() {
  385. return config;
  386. }
  387. public IAssembler getAssemblerFacility() {
  388. return assembler;
  389. }
  390. public void sendMessage(IMessage message) throws RouteException, AvpDataException, IllegalDiameterStateException, IOException {
  391. peerManager.sendMessage(message);
  392. }
  393. public void addSessionListener(String sessionId, NetworkReqListener listener) {
  394. peerManager.addSessionReqListener(sessionId, listener);
  395. }
  396. public void removeSessionListener(String sessionId) {
  397. peerManager.removeSessionListener(sessionId);
  398. }
  399. public ScheduledExecutorService getScheduledFacility() {
  400. return scheduledFacility;
  401. }
  402. public IConcurrentFactory getConcurrentFactory() {
  403. return this.concurrentFactory;
  404. }
  405. public String configuration() {
  406. return config != null ? config.toString() : "not set";
  407. }
  408. public String metaData() {
  409. try {
  410. return getMetaData().toString();
  411. }
  412. catch (Exception exc) {
  413. return "not set";
  414. }
  415. }
  416. public String peerDescription(String name) {
  417. try {
  418. for (Peer p : unwrap(PeerTable.class).getPeerTable()) {
  419. if (p.getUri().getFQDN().equals(name)) {
  420. return p.toString();
  421. }
  422. }
  423. }
  424. catch (InternalException e) {
  425. log.debug("InternalException", e);
  426. }
  427. return "not set";
  428. }
  429. public String peerList() {
  430. try {
  431. return unwrap(PeerTable.class).getPeerTable().toString();
  432. }
  433. catch (InternalException e) {
  434. return "not set";
  435. }
  436. }
  437. public void stop(int disconnectCause) {
  438. try {
  439. stop(10, TimeUnit.SECONDS, disconnectCause);
  440. }
  441. catch (Exception e) {
  442. log.debug("Exception", e);
  443. }
  444. }
  445. }