PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/acc/ServerAccSessionImpl.java

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