PageRenderTime 33ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gq/GqServerSessionImpl.java

http://mobicents.googlecode.com/
Java | 551 lines | 421 code | 47 blank | 83 comment | 55 complexity | 2ba3898ff2c952ec744c62885744542c 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.jdiameter.server.impl.app.gq;
  23. import static org.jdiameter.common.api.app.auth.ServerAuthSessionState.DISCONNECTED;
  24. import static org.jdiameter.common.api.app.auth.ServerAuthSessionState.IDLE;
  25. import static org.jdiameter.common.api.app.auth.ServerAuthSessionState.OPEN;
  26. import static org.jdiameter.server.impl.app.gq.Event.Type.RECEIVE_ASR_ANSWER;
  27. import static org.jdiameter.server.impl.app.gq.Event.Type.RECEIVE_AUTH_REQUEST;
  28. import static org.jdiameter.server.impl.app.gq.Event.Type.RECEIVE_STR_REQUEST;
  29. import static org.jdiameter.server.impl.app.gq.Event.Type.TIMEOUT_EXPIRES;
  30. import java.io.Serializable;
  31. import java.util.concurrent.locks.Lock;
  32. import java.util.concurrent.locks.ReentrantLock;
  33. import org.jdiameter.api.Answer;
  34. import org.jdiameter.api.EventListener;
  35. import org.jdiameter.api.IllegalDiameterStateException;
  36. import org.jdiameter.api.InternalException;
  37. import org.jdiameter.api.NetworkReqListener;
  38. import org.jdiameter.api.OverloadException;
  39. import org.jdiameter.api.Request;
  40. import org.jdiameter.api.RouteException;
  41. import org.jdiameter.api.app.AppAnswerEvent;
  42. import org.jdiameter.api.app.AppEvent;
  43. import org.jdiameter.api.app.AppRequestEvent;
  44. import org.jdiameter.api.app.AppSession;
  45. import org.jdiameter.api.app.StateChangeListener;
  46. import org.jdiameter.api.app.StateEvent;
  47. import org.jdiameter.api.auth.ServerAuthSessionListener;
  48. import org.jdiameter.api.auth.events.AbortSessionAnswer;
  49. import org.jdiameter.api.auth.events.AbortSessionRequest;
  50. import org.jdiameter.api.auth.events.ReAuthAnswer;
  51. import org.jdiameter.api.auth.events.ReAuthRequest;
  52. import org.jdiameter.api.auth.events.SessionTermAnswer;
  53. import org.jdiameter.api.auth.events.SessionTermRequest;
  54. import org.jdiameter.api.gq.GqServerSession;
  55. import org.jdiameter.client.api.ISessionFactory;
  56. import org.jdiameter.common.api.app.IAppSessionState;
  57. import org.jdiameter.common.api.app.auth.IAuthMessageFactory;
  58. import org.jdiameter.common.api.app.auth.IServerAuthActionContext;
  59. import org.jdiameter.common.api.app.auth.ServerAuthSessionState;
  60. import org.jdiameter.common.impl.app.AppAnswerEventImpl;
  61. import org.jdiameter.common.impl.app.auth.AbortSessionAnswerImpl;
  62. import org.jdiameter.common.impl.app.auth.AbortSessionRequestImpl;
  63. import org.jdiameter.common.impl.app.auth.AppAuthSessionImpl;
  64. import org.jdiameter.common.impl.app.auth.ReAuthAnswerImpl;
  65. import org.jdiameter.common.impl.app.auth.ReAuthRequestImpl;
  66. import org.jdiameter.common.impl.app.auth.SessionTermRequestImpl;
  67. import org.jdiameter.server.impl.app.auth.IServerAuthSessionData;
  68. import org.slf4j.Logger;
  69. import org.slf4j.LoggerFactory;
  70. /**
  71. * Server Gq Application session implementation
  72. *
  73. * @author <a href="mailto:webdev@web-ukraine.info"> Yulian Oifa </a>
  74. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  75. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  76. */
  77. public class GqServerSessionImpl extends AppAuthSessionImpl implements GqServerSession, EventListener<Request, Answer>, NetworkReqListener {
  78. protected static final Logger logger = LoggerFactory.getLogger(GqServerSessionImpl.class);
  79. protected IServerAuthSessionData sessionData;
  80. // Session State Handling ---------------------------------------------------
  81. private Lock sendAndStateLock = new ReentrantLock();
  82. // Factories and Listeners --------------------------------------------------
  83. protected transient IAuthMessageFactory factory;
  84. protected transient IServerAuthActionContext context;
  85. protected transient ServerAuthSessionListener listener;
  86. // Ts Timer -----------------------------------------------------------------
  87. protected final static String TIMER_NAME_TS = "GQ_TS";
  88. // Constructors -------------------------------------------------------------
  89. public GqServerSessionImpl(IServerAuthSessionData sessionData,ISessionFactory sf, ServerAuthSessionListener lst, IAuthMessageFactory fct, StateChangeListener<AppSession> scListener,IServerAuthActionContext context, long tsTimeout, boolean stateless) {
  90. super(sf,sessionData);
  91. super.appId = fct.getApplicationId();
  92. this.listener = lst;
  93. this.factory = fct;
  94. this.context = context;
  95. this.sessionData = sessionData;
  96. this.sessionData.setStateless(stateless);
  97. this.sessionData.setTsTimeout(tsTimeout);
  98. super.addStateChangeNotification(scListener);
  99. }
  100. // ServerAuthSession Implementation methods ---------------------------------
  101. public void sendAuthAnswer(AppAnswerEvent appAnswerEvent) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  102. send(null, appAnswerEvent);
  103. }
  104. public void sendReAuthRequest(ReAuthRequest reAuthRequest) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  105. send(null, reAuthRequest);
  106. }
  107. public void sendAbortSessionRequest(AbortSessionRequest abortSessionRequest) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  108. send(Event.Type.SEND_ASR_REQUEST, abortSessionRequest);
  109. }
  110. public void sendSessionTerminationAnswer(SessionTermAnswer sessionTermAnswer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  111. sendPost(Event.Type.SEND_STR_ANSWER, sessionTermAnswer);
  112. }
  113. protected void sendPost(Event.Type type, AppEvent event) throws InternalException {
  114. try {
  115. sendAndStateLock.lock();
  116. session.send(event.getMessage(), this);
  117. if (type != null) {
  118. handleEvent(new Event(type, event));
  119. }
  120. }
  121. catch (Exception e) {
  122. throw new InternalException(e);
  123. }
  124. finally {
  125. sendAndStateLock.unlock();
  126. }
  127. }
  128. protected void send(Event.Type type, AppEvent event) throws InternalException {
  129. try {
  130. sendAndStateLock.lock();
  131. if (type != null) {
  132. handleEvent(new Event(type, event));
  133. }
  134. session.send(event.getMessage(), this);
  135. }
  136. catch (Exception e) {
  137. throw new InternalException(e);
  138. }
  139. finally {
  140. sendAndStateLock.unlock();
  141. }
  142. }
  143. public boolean isStateless() {
  144. return sessionData.isStateless();
  145. }
  146. @SuppressWarnings("unchecked")
  147. protected void setState(ServerAuthSessionState newState) {
  148. IAppSessionState oldState = sessionData.getServerAuthSessionState();
  149. sessionData.setServerAuthSessionState(newState);
  150. for (StateChangeListener i : stateListeners) {
  151. i.stateChanged(this,(Enum) oldState, (Enum) newState);
  152. }
  153. }
  154. @SuppressWarnings("unchecked")
  155. public <E> E getState(Class<E> eClass) {
  156. return eClass == ServerAuthSessionState.class ? (E) sessionData.getServerAuthSessionState() : null;
  157. }
  158. public boolean handleEvent(StateEvent event) throws InternalException, OverloadException {
  159. return isStateless() ? handleEventForStatelessSession(event) : handleEventForStatefullSession(event);
  160. }
  161. public boolean handleEventForStatelessSession(StateEvent event) throws InternalException, OverloadException {
  162. try {
  163. switch (sessionData.getServerAuthSessionState()) {
  164. case IDLE:
  165. switch ((Event.Type) event.getType()) {
  166. case RECEIVE_AUTH_REQUEST:
  167. // Current State: IDLE
  168. // Event: Service-specific authorization request received, and successfully processed
  169. // Action: Send service specific answer
  170. // New State: IDLE
  171. listener.doAuthRequestEvent(this, (AppRequestEvent) event.getData());
  172. setState(IDLE);
  173. break;
  174. default:
  175. logger.debug("Unknown event {}", event.getType());
  176. break;
  177. }
  178. break;
  179. }
  180. }
  181. catch (Throwable t) {
  182. throw new InternalException(t);
  183. }
  184. return true;
  185. }
  186. public boolean handleEventForStatefullSession(StateEvent event) throws InternalException, OverloadException {
  187. ServerAuthSessionState state = sessionData.getServerAuthSessionState();
  188. ServerAuthSessionState oldState = state;
  189. try {
  190. switch (state) {
  191. case IDLE: {
  192. switch ((Event.Type) event.getType()) {
  193. case RECEIVE_AUTH_REQUEST:
  194. try {
  195. // Current State: IDLE
  196. // Event: Service-specific authorization request received, and user is authorized
  197. // Action: Send successful service specific answer
  198. // New State: OPEN
  199. listener.doAuthRequestEvent(this, (AppRequestEvent) event.getData());
  200. setState(OPEN);
  201. }
  202. catch (Exception e) {
  203. setState(IDLE);
  204. }
  205. break;
  206. case RECEIVE_STR_REQUEST:
  207. try {
  208. // Current State: ANY
  209. // Event: STR Received
  210. // Action: Send STA, Cleanup
  211. // New State: IDLE
  212. listener.doSessionTerminationRequestEvent(this, (SessionTermRequest) event.getData());
  213. }
  214. catch (Exception e) {
  215. logger.debug("Can not handle event", e);
  216. }
  217. break;
  218. case SEND_ASR_REQUEST:
  219. setState(DISCONNECTED);
  220. break;
  221. case SEND_STR_ANSWER:
  222. setState(IDLE);
  223. break;
  224. case TIMEOUT_EXPIRES:
  225. if (context != null) {
  226. context.accessTimeoutElapses(this);
  227. }
  228. setState(IDLE);
  229. break;
  230. default:
  231. logger.debug("Unknown event {}", event.getType());
  232. break;
  233. }
  234. break;
  235. }
  236. case OPEN: {
  237. switch ((Event.Type) event.getType()) {
  238. case RECEIVE_AUTH_REQUEST:
  239. try {
  240. // Current State: OPEN
  241. // Event: Service-specific authorization request received, and user is authorized
  242. // Action: Send successful service specific answer
  243. // New State: OPEN
  244. listener.doAuthRequestEvent(this, (AppRequestEvent) event.getData());
  245. }
  246. catch (Exception e) {
  247. // Current State: OPEN
  248. // Event: Service-specific authorization request received, and user is not authorized
  249. // Action: Send failed service specific answer, Cleanup
  250. // New State: IDLE
  251. setState(IDLE);
  252. }
  253. break;
  254. case RECEIVE_STR_REQUEST:
  255. try {
  256. listener.doSessionTerminationRequestEvent(this, (SessionTermRequest) event.getData());
  257. }
  258. catch (Exception e) {
  259. logger.debug("Can not handle event", e);
  260. }
  261. break;
  262. case SEND_ASR_REQUEST:
  263. // Current State: OPEN
  264. // Event: Home server wants to terminate the service
  265. // Action: Send ASR
  266. // New State: DISCON
  267. setState(DISCONNECTED);
  268. break;
  269. case SEND_STR_ANSWER:
  270. setState(IDLE);
  271. break;
  272. case TIMEOUT_EXPIRES:
  273. // Current State: OPEN
  274. // Event: Authorization-Lifetime (and Auth-Grace-Period) expires on home server.
  275. // Action: Cleanup
  276. // New State: IDLE
  277. // Current State: OPEN
  278. // Event: Session-Timeout expires on home server
  279. // Action: Cleanup
  280. // New State: IDLE
  281. if (context != null) {
  282. context.accessTimeoutElapses(this);
  283. }
  284. setState(IDLE);
  285. break;
  286. default:
  287. logger.debug("Unknown event {}", event.getType());
  288. break;
  289. }
  290. break;
  291. }
  292. case DISCONNECTED: {
  293. switch ((Event.Type) event.getType()) {
  294. case SEND_ASR_FAILURE:
  295. // Current State: DISCON
  296. // Event: Failure to send ASR
  297. // Action: Wait, Re-send ASR
  298. // New State: DISCON
  299. setState(DISCONNECTED);
  300. break;
  301. case RECEIVE_ASR_ANSWER:
  302. // Current State: DISCON
  303. // Event: ASR successfully sent and ASA Received with Result-Code
  304. // Action: Cleanup
  305. // New State: DISCON
  306. listener.doAbortSessionAnswerEvent(this, (AbortSessionAnswer) event.getData());
  307. //setState(IDLE);
  308. break;
  309. case RECEIVE_STR_REQUEST:
  310. try {
  311. listener.doSessionTerminationRequestEvent(this, (SessionTermRequest) event.getData());
  312. }
  313. catch (Exception e) {
  314. logger.debug("Can not handle event", e);
  315. }
  316. break;
  317. case SEND_STR_ANSWER:
  318. setState(IDLE);
  319. break;
  320. default:
  321. logger.debug("Unknown event {}", event.getType());
  322. break;
  323. }
  324. break;
  325. }
  326. default: {
  327. logger.debug("Unknown state {}", state);
  328. break;
  329. }
  330. }
  331. // post processing
  332. if (oldState != state) {
  333. if (OPEN.equals(state) && context != null) {
  334. if(context != null) {
  335. cancelTsTimer();
  336. startTsTimer();
  337. }
  338. }
  339. }
  340. }
  341. catch (Throwable t) {
  342. throw new InternalException(t);
  343. }
  344. return true;
  345. }
  346. public void receivedSuccessMessage(Request request, Answer answer) {
  347. AnswerDelivery rd = new AnswerDelivery();
  348. rd.session = this;
  349. rd.request = request;
  350. rd.answer = answer;
  351. super.scheduler.execute(rd);
  352. }
  353. public void timeoutExpired(Request request) {
  354. try {
  355. if (request.getCommandCode() == AbortSessionRequestImpl.code) {
  356. handleEvent(new Event(Event.Type.SEND_ASR_FAILURE, new AbortSessionRequestImpl(request)));
  357. }
  358. else {
  359. logger.debug("Timeout for unknown request {}", request);
  360. }
  361. }
  362. catch (Exception e) {
  363. logger.debug("Can not handle event", e);
  364. }
  365. }
  366. public Answer processRequest(Request request) {
  367. RequestDelivery rd = new RequestDelivery();
  368. rd.session = this;
  369. rd.request = request;
  370. super.scheduler.execute(rd);
  371. return null;
  372. }
  373. /*
  374. * (non-Javadoc)
  375. * @see org.jdiameter.common.impl.app.AppSessionImpl#isReplicable()
  376. */
  377. @Override
  378. public boolean isReplicable() {
  379. return true;
  380. }
  381. protected void startTsTimer() {
  382. try {
  383. sendAndStateLock.lock();
  384. sessionData.setTsTimerId(super.timerFacility.schedule(sessionData.getSessionId(), TIMER_NAME_TS, sessionData.getTsTimeout()));
  385. }
  386. finally {
  387. sendAndStateLock.unlock();
  388. }
  389. }
  390. protected void cancelTsTimer() {
  391. try {
  392. sendAndStateLock.lock();
  393. Serializable tsTimerId = sessionData.getTsTimerId();
  394. if(tsTimerId != null) {
  395. super.timerFacility.cancel(tsTimerId);
  396. sessionData.setTsTimerId(null);
  397. }
  398. }
  399. finally {
  400. sendAndStateLock.unlock();
  401. }
  402. }
  403. /*
  404. * (non-Javadoc)
  405. * @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String)
  406. */
  407. @Override
  408. public void onTimer(String timerName) {
  409. if(timerName.equals(TIMER_NAME_TS)) {
  410. try {
  411. sendAndStateLock.lock();
  412. sessionData.setTsTimerId(null);
  413. handleEvent(new Event(TIMEOUT_EXPIRES, null));
  414. }
  415. catch (Exception e) {
  416. logger.debug("Can not handle event", e);
  417. }
  418. finally {
  419. sendAndStateLock.unlock();
  420. }
  421. }
  422. }
  423. protected ReAuthAnswer createReAuthAnswer(Answer answer) {
  424. return new ReAuthAnswerImpl(answer);
  425. }
  426. protected ReAuthRequest createReAuthRequest(Request request) {
  427. return new ReAuthRequestImpl(request);
  428. }
  429. @Override
  430. public int hashCode() {
  431. final int prime = 31;
  432. int result = super.hashCode();
  433. result = prime * result + ((sessionData == null) ? 0 : sessionData.hashCode());
  434. return result;
  435. }
  436. @Override
  437. public boolean equals(Object obj) {
  438. if (this == obj)
  439. return true;
  440. if (!super.equals(obj))
  441. return false;
  442. if (getClass() != obj.getClass())
  443. return false;
  444. GqServerSessionImpl other = (GqServerSessionImpl) obj;
  445. if (sessionData == null) {
  446. if (other.sessionData != null)
  447. return false;
  448. }
  449. else if (!sessionData.equals(other.sessionData))
  450. return false;
  451. return true;
  452. }
  453. private class RequestDelivery implements Runnable {
  454. GqServerSession session;
  455. Request request;
  456. public void run() {
  457. if (request != null) {
  458. try {
  459. sendAndStateLock.lock();
  460. if (request.getCommandCode() == factory.getAuthMessageCommandCode()) {
  461. handleEvent(new Event(RECEIVE_AUTH_REQUEST, factory.createAuthRequest(request)));
  462. }
  463. else if (request.getCommandCode() == SessionTermRequestImpl.code) {
  464. handleEvent(new Event(RECEIVE_STR_REQUEST, new SessionTermRequestImpl(request)));
  465. }
  466. else {
  467. listener.doOtherEvent(session, factory.createAuthRequest(request), null);
  468. }
  469. }
  470. catch (Exception e) {
  471. logger.debug("Can not handle event", e);
  472. }
  473. finally {
  474. sendAndStateLock.unlock();
  475. }
  476. }
  477. }
  478. }
  479. private class AnswerDelivery implements Runnable {
  480. GqServerSession session;
  481. Answer answer;
  482. Request request;
  483. public void run() {
  484. try {
  485. sendAndStateLock.lock();
  486. if (request.getCommandCode() == ReAuthRequestImpl.code) {
  487. listener.doReAuthAnswerEvent(session,createReAuthRequest(request), createReAuthAnswer(answer));
  488. }
  489. else if (request.getCommandCode() == AbortSessionRequestImpl.code) {
  490. handleEvent(new Event(RECEIVE_ASR_ANSWER, new AbortSessionAnswerImpl(answer)));
  491. }
  492. else {
  493. listener.doOtherEvent(session, factory.createAuthRequest(request), new AppAnswerEventImpl(answer));
  494. }
  495. }
  496. catch (Exception e) {
  497. logger.debug("Can not handle event", e);
  498. }
  499. finally {
  500. sendAndStateLock.unlock();
  501. }
  502. }
  503. }
  504. }