PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rf/ServerRfSessionImpl.java

http://mobicents.googlecode.com/
Java | 502 lines | 365 code | 31 blank | 106 comment | 42 complexity | da1e90eaecabf16991698960c65bce4e 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.server.impl.app.rf;
  23. import static org.jdiameter.common.api.app.rf.ServerRfSessionState.IDLE;
  24. import static org.jdiameter.common.api.app.rf.ServerRfSessionState.OPEN;
  25. import java.io.Serializable;
  26. import org.jdiameter.api.Answer;
  27. import org.jdiameter.api.Avp;
  28. import org.jdiameter.api.EventListener;
  29. import org.jdiameter.api.IllegalDiameterStateException;
  30. import org.jdiameter.api.InternalException;
  31. import org.jdiameter.api.NetworkReqListener;
  32. import org.jdiameter.api.OverloadException;
  33. import org.jdiameter.api.Request;
  34. import org.jdiameter.api.ResultCode;
  35. import org.jdiameter.api.RouteException;
  36. import org.jdiameter.api.app.AppSession;
  37. import org.jdiameter.api.app.StateChangeListener;
  38. import org.jdiameter.api.app.StateEvent;
  39. import org.jdiameter.api.rf.ServerRfSession;
  40. import org.jdiameter.api.rf.ServerRfSessionListener;
  41. import org.jdiameter.api.rf.events.RfAccountingAnswer;
  42. import org.jdiameter.api.rf.events.RfAccountingRequest;
  43. import org.jdiameter.client.api.ISessionFactory;
  44. import org.jdiameter.common.api.app.IAppSessionState;
  45. import org.jdiameter.common.api.app.rf.IServerRfActionContext;
  46. import org.jdiameter.common.api.app.rf.ServerRfSessionState;
  47. import org.jdiameter.common.impl.app.rf.AppRfSessionImpl;
  48. import org.slf4j.Logger;
  49. import org.slf4j.LoggerFactory;
  50. /**
  51. * Server Accounting session implementation
  52. *
  53. * @author erick.svenson@yahoo.com
  54. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  55. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  56. */
  57. public class ServerRfSessionImpl extends AppRfSessionImpl implements EventListener<Request, Answer>, ServerRfSession, NetworkReqListener {
  58. //FIXME: verify this FSM
  59. private static final long serialVersionUID = 1L;
  60. private static final Logger logger = LoggerFactory.getLogger(ServerRfSessionImpl.class);
  61. // Session State Handling ---------------------------------------------------
  62. // Factories and Listeners --------------------------------------------------
  63. protected transient IServerRfActionContext context;
  64. protected transient ServerRfSessionListener listener;
  65. // Ts Timer -----------------------------------------------------------------
  66. protected static final String TIMER_NAME_TS = "TS";
  67. protected IServerRfSessionData sessionData;
  68. // Constructors -------------------------------------------------------------
  69. public ServerRfSessionImpl(IServerRfSessionData sessionData, ISessionFactory sessionFactory,
  70. ServerRfSessionListener serverSessionListener,
  71. IServerRfActionContext serverContextListener,StateChangeListener<AppSession> stLst, long tsTimeout, boolean stateless) {
  72. // TODO Auto-generated constructor stub
  73. super(sessionFactory,sessionData);
  74. this.listener = serverSessionListener;
  75. this.context = serverContextListener;
  76. this.sessionData = sessionData;
  77. this.sessionData.setTsTimeout(tsTimeout);
  78. this.sessionData.setStateless(stateless);
  79. super.addStateChangeNotification(stLst);
  80. }
  81. public void sendAccountAnswer(RfAccountingAnswer accountAnswer) throws InternalException, IllegalStateException, RouteException, OverloadException {
  82. try {
  83. session.send(accountAnswer.getMessage());
  84. /* TODO: Need to notify state change...
  85. if(isStateless() && isValid()) {
  86. session.release();
  87. }
  88. */
  89. }
  90. catch (IllegalDiameterStateException e) {
  91. throw new IllegalStateException(e);
  92. }
  93. }
  94. public boolean isStateless() {
  95. return this.sessionData.isStateless();
  96. }
  97. @SuppressWarnings("unchecked")
  98. protected void setState(IAppSessionState newState) {
  99. IAppSessionState oldState = this.sessionData.getServerRfSessionState();
  100. this.sessionData.setServerRfSessionState((ServerRfSessionState) newState);
  101. for (StateChangeListener i : stateListeners) {
  102. i.stateChanged(this,(Enum) oldState, (Enum) newState);
  103. }
  104. }
  105. public boolean handleEvent(StateEvent event) throws InternalException, OverloadException {
  106. return isStateless() ? handleEventForStatelessMode(event) : handleEventForStatefulMode(event);
  107. }
  108. public boolean handleEventForStatelessMode(StateEvent event) throws InternalException, OverloadException {
  109. try {
  110. //this will handle RTRs as well, no need to alter.
  111. final ServerRfSessionState state = this.sessionData.getServerRfSessionState();
  112. switch (state) {
  113. case IDLE: {
  114. switch ((Event.Type) event.getType()) {
  115. case RECEIVED_START_RECORD:
  116. // Current State: IDLE
  117. // Event: Accounting start request received, and successfully processed.
  118. // Action: Send accounting start answer
  119. // New State: IDLE
  120. if (listener != null) {
  121. try {
  122. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  123. }
  124. catch (Exception e) {
  125. logger.debug("Can not handle event", e);
  126. }
  127. }
  128. // TODO: This is unnecessary state change: setState(IDLE);
  129. break;
  130. case RECEIVED_EVENT_RECORD:
  131. // Current State: IDLE
  132. // Event: Accounting event request received, and successfully processed.
  133. // Action: Send accounting event answer
  134. // New State: IDLE
  135. if (listener != null) {
  136. try {
  137. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  138. }
  139. catch (Exception e) {
  140. logger.debug("Can not handle event", e);
  141. }
  142. }
  143. // FIXME: it is required, so we know it ends up again in IDLE!
  144. setState(IDLE);
  145. break;
  146. case RECEIVED_INTERIM_RECORD:
  147. // Current State: IDLE
  148. // Event: Interim record received, and successfully processed.
  149. // Action: Send accounting interim answer
  150. // New State: IDLE
  151. if (listener != null) {
  152. try {
  153. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  154. }
  155. catch (Exception e) {
  156. logger.debug("Can not handle event", e);
  157. }
  158. }
  159. // TODO: This is unnecessary state change: setState(IDLE);
  160. break;
  161. case RECEIVED_STOP_RECORD:
  162. // Current State: IDLE
  163. // Event: Accounting stop request received, and successfully processed
  164. // Action: Send accounting stop answer
  165. // New State: IDLE
  166. if (listener != null) {
  167. try {
  168. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  169. }
  170. catch (Exception e) {
  171. logger.debug("Can not handle event", e);
  172. }
  173. }
  174. // TODO: This is unnecessary state change: setState(IDLE);
  175. break;
  176. default:
  177. throw new IllegalStateException("Current state " + state + " action " + event.getType());
  178. }
  179. }
  180. }
  181. }
  182. catch (Exception e) {
  183. logger.debug("Can not process event", e);
  184. return false;
  185. }
  186. finally {
  187. // TODO: Since setState was removed, we are now using this to terminate. Correct?
  188. // We can't release here, answer needs to be sent through. done at send.
  189. // release();
  190. }
  191. return true;
  192. }
  193. public boolean handleEventForStatefulMode(StateEvent event) throws InternalException, OverloadException {
  194. try {
  195. if (((RfAccountingRequest) event.getData()).getMessage().isReTransmitted()) {
  196. try {
  197. setState(OPEN);
  198. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  199. // FIXME: should we do this before passing to lst?
  200. cancelTsTimer();
  201. startTsTimer();
  202. if (context != null) {
  203. context.sessionTimerStarted(this, null);
  204. }
  205. }
  206. catch (Exception e) {
  207. logger.debug("Can not handle event", e);
  208. setState(IDLE);
  209. }
  210. return true;
  211. }
  212. else {
  213. final ServerRfSessionState state = this.sessionData.getServerRfSessionState();
  214. switch (state) {
  215. case IDLE: {
  216. switch ((Event.Type) event.getType()) {
  217. case RECEIVED_START_RECORD:
  218. // Current State: IDLE
  219. // Event: Accounting start request received, and successfully processed.
  220. // Action: Send accounting start answer, Start Ts
  221. // New State: OPEN
  222. setState(OPEN);
  223. if (listener != null) {
  224. try {
  225. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  226. cancelTsTimer();
  227. startTsTimer();
  228. if (context != null) {
  229. context.sessionTimerStarted(this, null);
  230. }
  231. }
  232. catch (Exception e) {
  233. logger.debug("Can not handle event", e);
  234. setState(IDLE);
  235. }
  236. }
  237. break;
  238. case RECEIVED_EVENT_RECORD:
  239. // Current State: IDLE
  240. // Event: Accounting event request received, and
  241. // successfully processed.
  242. // Action: Send accounting event answer
  243. // New State: IDLE
  244. if (listener != null) {
  245. try {
  246. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  247. }
  248. catch (Exception e) {
  249. logger.debug("Can not handle event", e);
  250. }
  251. }
  252. break;
  253. }
  254. break;
  255. }
  256. case OPEN: {
  257. switch ((Event.Type) event.getType()) {
  258. case RECEIVED_INTERIM_RECORD:
  259. // Current State: OPEN
  260. // Event: Interim record received, and successfully
  261. // processed.
  262. // Action: Send accounting interim answer, Restart Ts
  263. // New State: OPEN
  264. try {
  265. listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
  266. cancelTsTimer();
  267. startTsTimer();
  268. if (context != null) {
  269. context.sessionTimerStarted(this, null);
  270. }
  271. }
  272. catch (Exception e) {
  273. logger.debug("Can not handle event", e);
  274. setState(IDLE);
  275. }
  276. break;
  277. case RECEIVED_STOP_RECORD:
  278. // Current State: OPEN
  279. // Event: Accounting stop request received, and
  280. // successfully
  281. // processed
  282. // Action: Send accounting stop answer, Stop Ts
  283. // New State: IDLE
  284. setState(IDLE);
  285. try {
  286. listener.doRfAccountingRequestEvent(this,
  287. (RfAccountingRequest) event.getData());
  288. cancelTsTimer();
  289. if (context != null) {
  290. context.sessionTimerCanceled(this, null);
  291. }
  292. }
  293. catch (Exception e) {
  294. logger.debug("Can not handle event", e);
  295. setState(IDLE);
  296. }
  297. break;
  298. }
  299. break;
  300. }
  301. }
  302. }
  303. }
  304. catch (Exception e) {
  305. logger.debug("Can not process event", e);
  306. return false;
  307. }
  308. return true;
  309. }
  310. private void startTsTimer() {
  311. // return scheduler.schedule(new Runnable() {
  312. // public void run() {
  313. // logger.debug("Ts timer expired");
  314. // if (context != null) {
  315. // try {
  316. // context.sessionTimeoutElapses(ServerRfSessionImpl.this);
  317. // }
  318. // catch (InternalException e) {
  319. // logger.debug("Failure on processing expired Ts", e);
  320. // }
  321. // }
  322. // setState(IDLE);
  323. // }
  324. // }, tsTimeout, TimeUnit.MILLISECONDS);
  325. try {
  326. sendAndStateLock.lock();
  327. this.sessionData.setTsTimerId(super.timerFacility.schedule(getSessionId(), TIMER_NAME_TS, this.sessionData.getTsTimeout()));
  328. }
  329. finally {
  330. sendAndStateLock.unlock();
  331. }
  332. }
  333. private void cancelTsTimer() {
  334. try{
  335. sendAndStateLock.lock();
  336. final Serializable tsTimerId = this.sessionData.getTsTimerId();
  337. if(tsTimerId != null) {
  338. super.timerFacility.cancel(tsTimerId);
  339. this.sessionData.setTsTimerId(null);
  340. }
  341. }
  342. finally {
  343. sendAndStateLock.unlock();
  344. }
  345. }
  346. /* (non-Javadoc)
  347. * @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String)
  348. */
  349. @Override
  350. public void onTimer(String timerName) {
  351. if(timerName.equals(TIMER_NAME_TS)) {
  352. if (context != null) {
  353. try {
  354. context.sessionTimeoutElapses(ServerRfSessionImpl.this);
  355. }
  356. catch (InternalException e) {
  357. logger.debug("Failure on processing expired Ts", e);
  358. }
  359. }
  360. setState(IDLE);
  361. }
  362. }
  363. protected Answer createStopAnswer(Request request) {
  364. Answer answer = request.createAnswer(ResultCode.SUCCESS);
  365. answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 4);
  366. answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
  367. return answer;
  368. }
  369. protected Answer createInterimAnswer(Request request) {
  370. Answer answer = request.createAnswer(ResultCode.SUCCESS);
  371. answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 3);
  372. answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
  373. return answer;
  374. }
  375. protected Answer createEventAnswer(Request request) {
  376. Answer answer = request.createAnswer(ResultCode.SUCCESS);
  377. answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 2);
  378. answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
  379. return answer;
  380. }
  381. protected Answer createStartAnswer(Request request) {
  382. Answer answer = request.createAnswer(ResultCode.SUCCESS);
  383. answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 1);
  384. answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
  385. return answer;
  386. }
  387. @SuppressWarnings("unchecked")
  388. public <E> E getState(Class<E> eClass) {
  389. return eClass == ServerRfSessionState.class ? (E) this.sessionData.getServerRfSessionState() : null;
  390. }
  391. public Answer processRequest(Request request) {
  392. if (request.getCommandCode() == RfAccountingRequest.code) {
  393. try {
  394. sendAndStateLock.lock();
  395. handleEvent(new Event(createAccountRequest(request)));
  396. }
  397. catch (Exception e) {
  398. logger.debug("Can not handle event", e);
  399. }
  400. finally {
  401. sendAndStateLock.unlock();
  402. }
  403. }
  404. else {
  405. try {
  406. listener.doOtherEvent(this, createAccountRequest(request), null);
  407. }
  408. catch (Exception e) {
  409. logger.debug("Can not handle event", e);
  410. }
  411. }
  412. return null;
  413. }
  414. public void receivedSuccessMessage(Request request, Answer answer) {
  415. if(request.getCommandCode() == RfAccountingRequest.code) {
  416. try {
  417. sendAndStateLock.lock();
  418. handleEvent(new Event(createAccountRequest(request)));
  419. }
  420. catch (Exception e) {
  421. logger.debug("Can not handle event", e);
  422. }
  423. finally {
  424. sendAndStateLock.unlock();
  425. }
  426. try {
  427. listener.doRfAccountingRequestEvent(this, createAccountRequest(request));
  428. }
  429. catch (Exception e) {
  430. logger.debug("Can not handle event", e);
  431. }
  432. }
  433. else {
  434. try {
  435. listener.doOtherEvent(this, createAccountRequest(request), createAccountAnswer(answer));
  436. }
  437. catch (Exception e) {
  438. logger.debug("Can not handle event", e);
  439. }
  440. }
  441. }
  442. public void timeoutExpired(Request request) {
  443. // FIXME: alexandre: We don't do anything here... are we even getting this on server?
  444. }
  445. /* (non-Javadoc)
  446. * @see org.jdiameter.common.impl.app.AppSessionImpl#isReplicable()
  447. */
  448. @Override
  449. public boolean isReplicable() {
  450. return true;
  451. }
  452. @Override
  453. public void release() {
  454. if (isValid()) {
  455. try {
  456. sendAndStateLock.lock();
  457. //TODO: cancel timer?
  458. super.release();
  459. }
  460. catch (Exception e) {
  461. logger.debug("Failed to release session", e);
  462. }
  463. finally {
  464. sendAndStateLock.unlock();
  465. }
  466. }
  467. else {
  468. logger.debug("Trying to release an already invalid session, with Session ID '{}'", getSessionId());
  469. }
  470. }
  471. }