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

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

http://mobicents.googlecode.com/
Java | 667 lines | 587 code | 46 blank | 34 comment | 61 complexity | e21372cfc8544c347062f7174d0aedc2 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 2006, 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.fsm;
  23. import static org.jdiameter.client.impl.fsm.FsmState.DOWN;
  24. import static org.jdiameter.client.impl.fsm.FsmState.REOPEN;
  25. import static org.jdiameter.client.impl.helpers.Parameters.CeaTimeOut;
  26. import static org.jdiameter.client.impl.helpers.Parameters.DpaTimeOut;
  27. import static org.jdiameter.client.impl.helpers.Parameters.DwaTimeOut;
  28. import static org.jdiameter.client.impl.helpers.Parameters.IacTimeOut;
  29. import static org.jdiameter.client.impl.helpers.Parameters.QueueSize;
  30. import static org.jdiameter.client.impl.helpers.Parameters.RecTimeOut;
  31. import java.util.Random;
  32. import java.util.concurrent.ConcurrentLinkedQueue;
  33. import java.util.concurrent.LinkedBlockingQueue;
  34. import java.util.concurrent.TimeUnit;
  35. import java.util.concurrent.locks.Lock;
  36. import java.util.concurrent.locks.ReentrantLock;
  37. import org.jdiameter.api.Configuration;
  38. import org.jdiameter.api.DisconnectCause;
  39. import org.jdiameter.api.Message;
  40. import org.jdiameter.api.OverloadException;
  41. import org.jdiameter.api.PeerState;
  42. import org.jdiameter.api.app.State;
  43. import org.jdiameter.api.app.StateChangeListener;
  44. import org.jdiameter.api.app.StateEvent;
  45. import org.jdiameter.api.validation.AvpNotAllowedException;
  46. import org.jdiameter.api.validation.Dictionary;
  47. import org.jdiameter.client.api.IMessage;
  48. import org.jdiameter.client.api.fsm.EventTypes;
  49. import org.jdiameter.client.api.fsm.FsmEvent;
  50. import org.jdiameter.client.api.fsm.IContext;
  51. import org.jdiameter.client.api.fsm.IStateMachine;
  52. import org.jdiameter.client.impl.DictionarySingleton;
  53. import org.jdiameter.common.api.concurrent.IConcurrentFactory;
  54. import org.jdiameter.common.api.statistic.IStatistic;
  55. import org.jdiameter.common.api.statistic.IStatisticManager;
  56. import org.jdiameter.common.api.statistic.IStatisticRecord;
  57. import org.slf4j.Logger;
  58. import org.slf4j.LoggerFactory;
  59. /**
  60. *
  61. * @author erick.svenson@yahoo.com
  62. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  63. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  64. */
  65. public class PeerFSMImpl implements IStateMachine {
  66. private static final Logger logger = LoggerFactory.getLogger(PeerFSMImpl.class);
  67. protected final Dictionary dictionary = DictionarySingleton.getDictionary();
  68. protected ConcurrentLinkedQueue<StateChangeListener> listeners;
  69. protected LinkedBlockingQueue<StateEvent> eventQueue;
  70. protected FsmState state = FsmState.DOWN;
  71. protected boolean watchdogSent;
  72. protected long timer;
  73. protected long CEA_TIMEOUT = 0, IAC_TIMEOUT = 0, REC_TIMEOUT = 0, DWA_TIMEOUT = 0, DPA_TIMEOUT = 0;
  74. protected final StateEvent timeOutEvent = new FsmEvent(EventTypes.TIMEOUT_EVENT);
  75. protected Random random = new Random();
  76. protected IConcurrentFactory concurrentFactory;
  77. protected Thread executor;
  78. protected IContext context;
  79. protected State[] states;
  80. protected int predefSize;
  81. private Lock lock = new ReentrantLock();
  82. protected IStatisticManager statisticFactory;
  83. protected IStatistic queueStat;
  84. protected IStatisticRecord timeSumm;
  85. protected IStatisticRecord timeCount;
  86. public PeerFSMImpl(IContext aContext, IConcurrentFactory concurrentFactory, Configuration config, IStatisticManager statisticFactory) {
  87. this.context = aContext;
  88. this.statisticFactory = statisticFactory;
  89. this.predefSize = config.getIntValue(QueueSize.ordinal(), (Integer) QueueSize.defValue());
  90. this.eventQueue = new LinkedBlockingQueue<StateEvent>(predefSize);
  91. this.listeners = new ConcurrentLinkedQueue<StateChangeListener>();
  92. loadTimeOuts(config);
  93. this.concurrentFactory = concurrentFactory;
  94. runQueueProcessing();
  95. }
  96. public IStatistic getStatistic() {
  97. //
  98. return queueStat;
  99. }
  100. public void removeStateChangeNotification(StateChangeListener stateChangeListener) {
  101. listeners.remove(stateChangeListener);
  102. }
  103. private void runQueueProcessing() {
  104. IStatisticRecord queueSize = statisticFactory.newCounterRecord(IStatisticRecord.Counters.QueueSize, new IStatisticRecord.IntegerValueHolder() {
  105. public int getValueAsInt() {
  106. return eventQueue.size();
  107. }
  108. public String getValueAsString() {
  109. return String.valueOf(getValueAsInt());
  110. }
  111. });
  112. this.timeSumm = statisticFactory.newCounterRecord("TimeSumm", "TimeSumm");
  113. this.timeCount = statisticFactory.newCounterRecord("TimeCount", "TimeCount");
  114. final IStatisticRecord messagePrcAverageTime = statisticFactory.newCounterRecord(IStatisticRecord.Counters.MessageProcessingTime,
  115. new IStatisticRecord.DoubleValueHolder() {
  116. public double getValueAsDouble() {
  117. if(queueStat == null) {
  118. return 0;
  119. }
  120. IStatisticRecord mpta = queueStat.getRecordByName(IStatisticRecord.Counters.MessageProcessingTime.name());
  121. org.jdiameter.api.StatisticRecord[] children = mpta.getChilds();
  122. if (children.length == 2 && children[1].getValueAsLong() != 0) {
  123. long count = children[1].getValueAsLong();
  124. return ((float) children[0].getValueAsLong()) / ((float) (count != 0 ? count : 1));
  125. }
  126. else {
  127. return 0;
  128. }
  129. }
  130. public String getValueAsString() {
  131. return String.valueOf(getValueAsDouble());
  132. }
  133. }, timeSumm, timeCount);
  134. queueStat = statisticFactory.newStatistic(context.getPeerDescription(), IStatistic.Groups.PeerFSM, queueSize, messagePrcAverageTime);
  135. executor = concurrentFactory.getThread("FSM-" + context.getPeerDescription(),
  136. new Runnable() {
  137. public void run() {
  138. while (executor != null) {
  139. StateEvent event;
  140. try {
  141. event = eventQueue.poll(100, TimeUnit.MILLISECONDS);
  142. }
  143. catch (InterruptedException e) {
  144. executor = null; //so we don't kill it totally!?
  145. logger.debug("Peer FSM stopped", e);
  146. break;
  147. }
  148. //FIXME: baranowb: why this lock is here?
  149. lock.lock();
  150. try {
  151. if (event != null) {
  152. if (event instanceof FsmEvent && queueStat != null && queueStat.isEnabled()) {
  153. timeSumm.inc(System.currentTimeMillis() - ((FsmEvent) event).getCreatedTime());
  154. timeCount.inc();
  155. }
  156. logger.debug("Process event [{}]. Peer State is [{}]", event, state);
  157. getStates()[state.ordinal()].processEvent(event);
  158. }
  159. if (timer != 0 && timer < System.currentTimeMillis()) {
  160. timer = 0;
  161. if(state != DOWN) { //without this check this event is fired in DOWN state.... it should not be.
  162. handleEvent(timeOutEvent); //FIXME: check why timer is not killed?
  163. }
  164. }
  165. }
  166. catch (Exception e) {
  167. logger.debug("Error during processing FSM event", e);
  168. }
  169. finally {
  170. lock.unlock();
  171. }
  172. }
  173. //this happens when peer FSM is down, lets remove stat
  174. statisticFactory.removeStatistic(queueStat);
  175. queueStat = null;
  176. }
  177. }
  178. );
  179. executor.start();
  180. }
  181. public double getQueueInfo() {
  182. return eventQueue.size() * 1.0 / predefSize;
  183. }
  184. protected void loadTimeOuts(Configuration config) {
  185. CEA_TIMEOUT = config.getLongValue(CeaTimeOut.ordinal(), (Long) CeaTimeOut.defValue());
  186. IAC_TIMEOUT = config.getLongValue(IacTimeOut.ordinal(), (Long) IacTimeOut.defValue());
  187. DWA_TIMEOUT = config.getLongValue(DwaTimeOut.ordinal(), (Long) DwaTimeOut.defValue());
  188. DPA_TIMEOUT = config.getLongValue(DpaTimeOut.ordinal(), (Long) DpaTimeOut.defValue());
  189. REC_TIMEOUT = config.getLongValue(RecTimeOut.ordinal(), (Long) RecTimeOut.defValue());
  190. }
  191. public void addStateChangeNotification(StateChangeListener stateChangeListener) {
  192. if (!listeners.contains(stateChangeListener)) {
  193. listeners.add(stateChangeListener);
  194. }
  195. }
  196. public void remStateChangeNotification(StateChangeListener stateChangeListener) {
  197. listeners.remove(stateChangeListener);
  198. }
  199. protected void switchToNextState(FsmState newState) {
  200. // Fix for Issue #3026 (http://code.google.com/p/mobicents/issues/detail?id=3026)
  201. // notify only when it's a new public state
  202. if (newState.getPublicState() != state.getPublicState()) {
  203. for (StateChangeListener l : listeners) {
  204. l.stateChanged(state.getPublicState(), newState.getPublicState());
  205. }
  206. }
  207. getStates()[state.ordinal()].exitAction();
  208. if(logger.isDebugEnabled()) {
  209. logger.debug("{} FSM switch state: {} -> {}", new Object[] {context.getPeerDescription(), state, newState});
  210. }
  211. state = newState;
  212. getStates()[state.ordinal()].entryAction();
  213. }
  214. public boolean handleEvent(StateEvent event) throws InternalError, OverloadException {
  215. //if (state.getPublicState() == PeerState.DOWN && event.encodeType(EventTypes.class) == EventTypes.START_EVENT) {
  216. if (logger.isDebugEnabled()) {
  217. logger.debug("Handling event with type [{}]", event.getType());
  218. }
  219. if(executor == null) {
  220. logger.debug("Executor is null so calling runQueueProcessing()");
  221. runQueueProcessing();
  222. }
  223. if (event.getData() != null && dictionary!= null && dictionary.isEnabled()) {
  224. boolean incoming = event.getType() == EventTypes.RECEIVE_MSG_EVENT;
  225. if(incoming) {
  226. logger.debug("Performing validation to INCOMING message since validator is ENABLED.");
  227. // outgoing are done elsewhere: see BaseSessionImpl
  228. try{
  229. dictionary.validate((Message) event.getData(), incoming);
  230. }
  231. catch(AvpNotAllowedException e) {
  232. logger.error("Failed to validate incoming message.", e);
  233. return false;
  234. }
  235. }
  236. }
  237. else {
  238. logger.debug("Not performing validation to message since validator is DISABLED.");
  239. }
  240. boolean rc;
  241. try {
  242. if(logger.isDebugEnabled()) {
  243. logger.debug("Placing message into linked blocking queue with remaining capacity: [{}].", eventQueue.remainingCapacity());
  244. }
  245. rc = eventQueue.offer(event, IAC_TIMEOUT, TimeUnit.MILLISECONDS);
  246. }
  247. catch (InterruptedException e) {
  248. throw new InternalError("Can not put event to FSM " + this.toString());
  249. }
  250. if (!rc) {
  251. throw new OverloadException("FSM overloaded");
  252. }
  253. return true;
  254. }
  255. protected void setInActiveTimer() {
  256. timer = IAC_TIMEOUT - 2 * 1000 + random.nextInt(5) * 1000 + System.currentTimeMillis();
  257. }
  258. public String toString() {
  259. return "PeerFSM{" + "context=" + context + ", state=" + state + '}';
  260. }
  261. public <E> E getState(Class<E> a) {
  262. if (a == PeerState.class) {
  263. return (E) state.getPublicState();
  264. }
  265. else {
  266. return null;
  267. }
  268. }
  269. protected abstract class MyState implements org.jdiameter.api.app.State {
  270. public void entryAction() {
  271. }
  272. public void exitAction() {
  273. }
  274. protected void doEndConnection() {
  275. if (context.isRestoreConnection()) {
  276. timer = REC_TIMEOUT + System.currentTimeMillis();
  277. switchToNextState(REOPEN);
  278. }
  279. else {
  280. switchToNextState(DOWN);
  281. }
  282. }
  283. protected void doDisconnect() {
  284. try {
  285. context.disconnect();
  286. }
  287. catch (Throwable e) {
  288. }
  289. }
  290. protected void setTimer(long value) {
  291. timer = value + System.currentTimeMillis();
  292. }
  293. protected String key(StateEvent event) {
  294. return ((FsmEvent) event).getKey();
  295. }
  296. protected IMessage message(StateEvent event) {
  297. return ((FsmEvent) event).getMessage();
  298. }
  299. protected EventTypes type(StateEvent event) {
  300. return (EventTypes) event.getType();
  301. }
  302. protected void clearTimer() {
  303. timer = 0;
  304. }
  305. }
  306. protected org.jdiameter.api.app.State[] getStates() {
  307. if (states == null) {
  308. states = new org.jdiameter.api.app.State[] { // todo merge and redesign with server fsm
  309. new MyState() // OKEY
  310. {
  311. public void entryAction() {
  312. setInActiveTimer();
  313. watchdogSent = false;
  314. }
  315. public boolean processEvent(StateEvent event) {
  316. switch (event.encodeType(EventTypes.class)) {
  317. case DISCONNECT_EVENT:
  318. timer = REC_TIMEOUT + System.currentTimeMillis();
  319. switchToNextState(FsmState.REOPEN);
  320. break;
  321. case TIMEOUT_EVENT:
  322. try {
  323. context.sendDwrMessage();
  324. setTimer(DWA_TIMEOUT);
  325. if (watchdogSent) {
  326. switchToNextState(FsmState.SUSPECT);
  327. }
  328. else {
  329. watchdogSent = true;
  330. }
  331. }
  332. catch (Throwable e) {
  333. logger.debug("Can not send DWR", e);
  334. doDisconnect();
  335. setTimer(REC_TIMEOUT);
  336. switchToNextState(FsmState.REOPEN);
  337. }
  338. break;
  339. case STOP_EVENT:
  340. try {
  341. if(event.getData() == null) {
  342. context.sendDprMessage(DisconnectCause.REBOOTING);
  343. }
  344. else {
  345. Integer disconnectCause = (Integer) event.getData();
  346. context.sendDprMessage(disconnectCause);
  347. }
  348. setTimer(DPA_TIMEOUT);
  349. switchToNextState(FsmState.STOPPING);
  350. }
  351. catch (Throwable e) {
  352. logger.debug("Can not send DPR", e);
  353. doDisconnect();
  354. switchToNextState(FsmState.DOWN);
  355. }
  356. break;
  357. case RECEIVE_MSG_EVENT:
  358. setInActiveTimer();
  359. context.receiveMessage(message(event));
  360. break;
  361. case DPR_EVENT:
  362. try {
  363. int code = context.processDprMessage(message(event));
  364. context.sendDpaMessage(message(event), code, null);
  365. }
  366. catch (Throwable e) {
  367. logger.debug("Can not send DPA", e);
  368. }
  369. doDisconnect();
  370. switchToNextState(FsmState.DOWN);
  371. break;
  372. case DWR_EVENT:
  373. setInActiveTimer();
  374. try {
  375. int code = context.processDwrMessage(message(event));
  376. context.sendDwaMessage(message(event), code, null);
  377. }
  378. catch (Throwable e) {
  379. logger.debug("Can not send DWA", e);
  380. doDisconnect();
  381. switchToNextState(FsmState.DOWN);
  382. }
  383. break;
  384. case DWA_EVENT:
  385. setInActiveTimer();
  386. watchdogSent = false;
  387. break;
  388. case SEND_MSG_EVENT:
  389. try {
  390. context.sendMessage(message(event));
  391. }
  392. catch (Throwable e) {
  393. logger.debug("Can not send message", e);
  394. doDisconnect();
  395. setTimer(REC_TIMEOUT);
  396. switchToNextState(FsmState.REOPEN);
  397. }
  398. break;
  399. default:
  400. logger.debug("Unknown event type: {} in state {}", event.encodeType(EventTypes.class), state);
  401. return false;
  402. }
  403. return true;
  404. }
  405. },
  406. new MyState() // SUSPECT
  407. {
  408. public boolean processEvent(StateEvent event) {
  409. switch (event.encodeType(EventTypes.class)) {
  410. case DISCONNECT_EVENT:
  411. setTimer(REC_TIMEOUT);
  412. switchToNextState(FsmState.REOPEN);
  413. break;
  414. case TIMEOUT_EVENT:
  415. doDisconnect();
  416. setTimer(REC_TIMEOUT);
  417. switchToNextState(FsmState.REOPEN);
  418. break;
  419. case STOP_EVENT:
  420. try {
  421. if(event.getData() == null) {
  422. context.sendDprMessage(DisconnectCause.REBOOTING);
  423. }
  424. else {
  425. Integer disconnectCause = (Integer) event.getData();
  426. context.sendDprMessage(disconnectCause);
  427. }
  428. setInActiveTimer();
  429. switchToNextState(FsmState.STOPPING);
  430. }
  431. catch (Throwable e) {
  432. logger.debug("Can not send DPR", e);
  433. doDisconnect();
  434. switchToNextState(FsmState.DOWN);
  435. }
  436. break;
  437. case DPR_EVENT:
  438. try {
  439. int code = context.processDprMessage(message(event));
  440. context.sendDpaMessage(message(event), code, null);
  441. }
  442. catch (Throwable e) {
  443. logger.debug("Can not send DPA", e);
  444. }
  445. doDisconnect();
  446. switchToNextState(FsmState.DOWN);
  447. break;
  448. case DWA_EVENT:
  449. switchToNextState(FsmState.OKAY);
  450. break;
  451. case DWR_EVENT:
  452. try {
  453. int code = context.processDwrMessage(message(event));
  454. context.sendDwaMessage(message(event), code, null);
  455. switchToNextState(FsmState.OKAY);
  456. }
  457. catch (Throwable e) {
  458. logger.debug("Can not send DWA", e);
  459. doDisconnect();
  460. switchToNextState(FsmState.DOWN);
  461. }
  462. break;
  463. case RECEIVE_MSG_EVENT:
  464. context.receiveMessage(message(event));
  465. switchToNextState(FsmState.OKAY);
  466. break;
  467. case SEND_MSG_EVENT:
  468. throw new RuntimeException("Connection is down");
  469. default:
  470. logger.debug("Unknown event type: {} in state {}", event.encodeType(EventTypes.class), state);
  471. return false;
  472. }
  473. return true;
  474. }
  475. },
  476. new MyState() // DOWN
  477. {
  478. public void entryAction() {
  479. clearTimer();
  480. executor = null;
  481. context.removeStatistics();
  482. }
  483. public boolean processEvent(StateEvent event) {
  484. switch (event.encodeType(EventTypes.class)) {
  485. case START_EVENT:
  486. try {
  487. context.createStatistics();
  488. context.connect();
  489. context.sendCerMessage();
  490. setTimer(CEA_TIMEOUT);
  491. switchToNextState(FsmState.INITIAL);
  492. }
  493. catch (Throwable e) {
  494. logger.debug("Connect error", e);
  495. setTimer(REC_TIMEOUT);
  496. switchToNextState(FsmState.REOPEN);
  497. }
  498. break;
  499. case SEND_MSG_EVENT:
  500. throw new RuntimeException("Connection is down");
  501. case STOP_EVENT:
  502. case DISCONNECT_EVENT:
  503. break;
  504. default:
  505. logger.debug("Unknown event type: {} in state {}", event.encodeType(EventTypes.class), state);
  506. return false;
  507. }
  508. return true;
  509. }
  510. },
  511. new MyState() // REOPEN
  512. {
  513. public boolean processEvent(StateEvent event) {
  514. switch (event.encodeType(EventTypes.class)) {
  515. case CONNECT_EVENT:
  516. try {
  517. context.sendCerMessage();
  518. setTimer(CEA_TIMEOUT);
  519. switchToNextState(FsmState.INITIAL);
  520. }
  521. catch(Throwable e) {
  522. logger.debug("Can not send CER", e);
  523. setTimer(REC_TIMEOUT);
  524. }
  525. break;
  526. case TIMEOUT_EVENT:
  527. try {
  528. context.connect();
  529. }
  530. catch (Exception e) {
  531. logger.debug("Timeout processed. Can not connect to {}", context.getPeerDescription());
  532. setTimer(REC_TIMEOUT);
  533. }
  534. break;
  535. case STOP_EVENT:
  536. clearTimer();
  537. doDisconnect();
  538. switchToNextState(FsmState.DOWN);
  539. break;
  540. case DISCONNECT_EVENT:
  541. break;
  542. case SEND_MSG_EVENT:
  543. throw new IllegalStateException("Connection is down");
  544. default:
  545. logger.debug("Unknown event type: {} in state {}", event.encodeType(EventTypes.class), state);
  546. return false;
  547. }
  548. return true;
  549. }
  550. },
  551. new MyState() // INITIAL
  552. {
  553. public void entryAction() {
  554. setTimer(CEA_TIMEOUT);
  555. }
  556. public boolean processEvent(StateEvent event) {
  557. switch (event.encodeType(EventTypes.class)) {
  558. case DISCONNECT_EVENT:
  559. setTimer(REC_TIMEOUT);
  560. switchToNextState(FsmState.REOPEN);
  561. break;
  562. case TIMEOUT_EVENT:
  563. doDisconnect();
  564. setTimer(REC_TIMEOUT);
  565. switchToNextState(FsmState.REOPEN);
  566. break;
  567. case STOP_EVENT:
  568. clearTimer();
  569. doDisconnect();
  570. switchToNextState(FsmState.DOWN);
  571. break;
  572. case CEA_EVENT:
  573. clearTimer();
  574. if (context.processCeaMessage(((FsmEvent) event).getKey(), ((FsmEvent) event).getMessage())) {
  575. switchToNextState(FsmState.OKAY);
  576. }
  577. else {
  578. doDisconnect();
  579. setTimer(REC_TIMEOUT);
  580. switchToNextState(FsmState.REOPEN);
  581. }
  582. break;
  583. case SEND_MSG_EVENT:
  584. throw new RuntimeException("Connection is down");
  585. default:
  586. logger.debug("Unknown event type: {} in state {}", event.encodeType(EventTypes.class), state);
  587. return false;
  588. }
  589. return true;
  590. }
  591. },
  592. new MyState() // STOPPING
  593. {
  594. public boolean processEvent(StateEvent event) {
  595. switch (event.encodeType(EventTypes.class)) {
  596. case TIMEOUT_EVENT:
  597. case DPA_EVENT:
  598. doDisconnect();
  599. switchToNextState(FsmState.DOWN);
  600. break;
  601. case RECEIVE_MSG_EVENT:
  602. context.receiveMessage(message(event));
  603. break;
  604. case SEND_MSG_EVENT:
  605. throw new RuntimeException("Stack now is stopping");
  606. case STOP_EVENT:
  607. case DISCONNECT_EVENT:
  608. doDisconnect();
  609. break;
  610. default:
  611. logger.debug("Unknown event type: {} in state {}", event.encodeType(EventTypes.class), state);
  612. return false;
  613. }
  614. return true;
  615. }
  616. },
  617. };
  618. }
  619. return states;
  620. }
  621. }