PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rx/ServerRxSessionImpl.java

http://mobicents.googlecode.com/
Java | 482 lines | 340 code | 50 blank | 92 comment | 40 complexity | 6200b60b7873abb359dcb02930791ffa 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.rx;
  23. import java.util.concurrent.locks.Lock;
  24. import java.util.concurrent.locks.ReentrantLock;
  25. import org.jdiameter.api.Answer;
  26. import org.jdiameter.api.AvpDataException;
  27. import org.jdiameter.api.EventListener;
  28. import org.jdiameter.api.IllegalDiameterStateException;
  29. import org.jdiameter.api.InternalException;
  30. import org.jdiameter.api.NetworkReqListener;
  31. import org.jdiameter.api.OverloadException;
  32. import org.jdiameter.api.Request;
  33. import org.jdiameter.api.RouteException;
  34. import org.jdiameter.api.app.AppAnswerEvent;
  35. import org.jdiameter.api.app.AppEvent;
  36. import org.jdiameter.api.app.AppRequestEvent;
  37. import org.jdiameter.api.app.AppSession;
  38. import org.jdiameter.api.app.StateChangeListener;
  39. import org.jdiameter.api.app.StateEvent;
  40. import org.jdiameter.api.rx.ServerRxSession;
  41. import org.jdiameter.api.rx.ServerRxSessionListener;
  42. import org.jdiameter.api.rx.events.RxAAAnswer;
  43. import org.jdiameter.api.rx.events.RxAARequest;
  44. import org.jdiameter.api.rx.events.RxAbortSessionAnswer;
  45. import org.jdiameter.api.rx.events.RxAbortSessionRequest;
  46. import org.jdiameter.api.rx.events.RxReAuthAnswer;
  47. import org.jdiameter.api.rx.events.RxReAuthRequest;
  48. import org.jdiameter.api.rx.events.RxSessionTermAnswer;
  49. import org.jdiameter.api.rx.events.RxSessionTermRequest;
  50. import org.jdiameter.client.api.ISessionFactory;
  51. import org.jdiameter.common.api.app.IAppSessionState;
  52. import org.jdiameter.common.api.app.rx.IRxMessageFactory;
  53. import org.jdiameter.common.api.app.rx.IServerRxSessionContext;
  54. import org.jdiameter.common.api.app.rx.ServerRxSessionState;
  55. import org.jdiameter.common.impl.app.AppAnswerEventImpl;
  56. import org.jdiameter.common.impl.app.AppRequestEventImpl;
  57. import org.jdiameter.common.impl.app.rx.AppRxSessionImpl;
  58. import org.slf4j.Logger;
  59. import org.slf4j.LoggerFactory;
  60. /**
  61. * 3GPP IMS Rx Reference Point Server session implementation
  62. *
  63. * @author <a href="mailto:richard.good@smilecoms.com"> Richard Good </a>
  64. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  65. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  66. */
  67. public class ServerRxSessionImpl extends AppRxSessionImpl implements ServerRxSession, NetworkReqListener, EventListener<Request, Answer> {
  68. private static final Logger logger = LoggerFactory.getLogger(ServerRxSessionImpl.class);
  69. // Session State Handling ---------------------------------------------------
  70. //protected boolean stateless = true;
  71. //protected ServerGxSessionState state = ServerGxSessionState.IDLE;
  72. protected Lock sendAndStateLock = new ReentrantLock();
  73. // Factories and Listeners --------------------------------------------------
  74. protected transient IRxMessageFactory factory = null;
  75. protected transient IServerRxSessionContext context = null;
  76. protected transient ServerRxSessionListener listener = null;
  77. protected long[] authAppIds = new long[]{4};
  78. //protected String originHost, originRealm;
  79. protected IServerRxSessionData sessionData;
  80. public ServerRxSessionImpl(IServerRxSessionData sessionData, IRxMessageFactory fct, ISessionFactory sf, ServerRxSessionListener lst, IServerRxSessionContext ctx, StateChangeListener<AppSession> stLst) {
  81. super(sf,sessionData);
  82. if (lst == null) {
  83. throw new IllegalArgumentException("Listener can not be null");
  84. }
  85. if (fct.getApplicationIds() == null) {
  86. throw new IllegalArgumentException("ApplicationId can not be less than zero");
  87. }
  88. context = ctx;
  89. authAppIds = fct.getApplicationIds();
  90. listener = lst;
  91. factory = fct;
  92. this.sessionData = sessionData;
  93. super.addStateChangeNotification(stLst);
  94. }
  95. public void sendAAAnswer(RxAAAnswer answer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  96. handleEvent(new Event(false, null, answer));
  97. }
  98. public void sendSessionTermAnswer(RxSessionTermAnswer answer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  99. handleEvent(new Event(false, null, answer));
  100. }
  101. public void sendReAuthRequest(RxReAuthRequest request) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  102. send(Event.Type.SEND_RAR, request, null);
  103. }
  104. public void sendAbortSessionRequest(RxAbortSessionRequest request) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  105. send(Event.Type.SEND_ASR, request, null);
  106. }
  107. public boolean isStateless() {
  108. return this.sessionData.isStateless();
  109. }
  110. @SuppressWarnings("unchecked")
  111. public <E> E getState(Class<E> stateType) {
  112. return stateType == ServerRxSessionState.class ? (E) this.sessionData.getServerRxSessionState() : null;
  113. }
  114. public boolean handleEvent(StateEvent event) throws InternalException, OverloadException {
  115. ServerRxSessionState newState = null;
  116. try {
  117. sendAndStateLock.lock();
  118. // Can be null if there is no state transition, transition to IDLE state should terminate this app session
  119. final Event localEvent = (Event) event;
  120. final ServerRxSessionState state = this.sessionData.getServerRxSessionState();
  121. //Its kind of awkward, but with two state on server side its easier to go through event types?
  122. //but for sake of FSM readability
  123. final Event.Type eventType = (Event.Type) localEvent.getType();
  124. switch (state) {
  125. case IDLE:
  126. switch (eventType) {
  127. case RECEIVE_AAR:
  128. listener.doAARequest(this, (RxAARequest) localEvent.getRequest());
  129. break;
  130. case RECEIVE_EVENT_REQUEST:
  131. // Current State: IDLE
  132. // Event: AA event request received and successfully processed
  133. // Action: Send AA event answer
  134. // New State: IDLE
  135. listener.doAARequest(this, (RxAARequest) localEvent.getRequest());
  136. break;
  137. // case SEND_EVENT_ANSWER:
  138. // // Current State: IDLE
  139. // // Event: AAR event request received and successfully processed
  140. // // Action: Send AA event answer
  141. // // New State: IDLE
  142. //
  143. // newState = ServerRxSessionState.IDLE;
  144. // dispatchEvent(localEvent.getAnswer());
  145. // break;
  146. case SEND_AAA:
  147. RxAAAnswer answer = (RxAAAnswer) localEvent.getAnswer();
  148. try {
  149. long resultCode = answer.getResultCodeAvp().getUnsigned32();
  150. // Current State: IDLE
  151. // Event: AA initial request received and successfully processed
  152. // Action: Send AAinitial answer
  153. // New State: OPEN
  154. if (isSuccess(resultCode)) {
  155. newState = ServerRxSessionState.OPEN;
  156. } // Current State: IDLE
  157. // Event: AA initial request received but not successfully processed
  158. // Action: Send AA initial answer with Result-Code != SUCCESS
  159. // New State: IDLE
  160. else {
  161. newState = ServerRxSessionState.IDLE;
  162. }
  163. dispatchEvent(localEvent.getAnswer());
  164. }
  165. catch (AvpDataException e) {
  166. throw new InternalException(e);
  167. }
  168. break;
  169. default:
  170. throw new InternalException("Wrong state: " + ServerRxSessionState.IDLE + " one event: " + eventType + " " + localEvent.getRequest() + " " + localEvent.getAnswer());
  171. }//end switch eventType
  172. break;
  173. case OPEN:
  174. switch (eventType) {
  175. case RECEIVE_AAR:
  176. listener.doAARequest(this, (RxAARequest) localEvent.getRequest());
  177. break;
  178. case SEND_AAA:
  179. RxAAAnswer answer = (RxAAAnswer) localEvent.getAnswer();
  180. try {
  181. if (isSuccess(answer.getResultCodeAvp().getUnsigned32())) {
  182. // Current State: OPEN
  183. // Event: AA update request received and successfully processed
  184. // Action: Send AA update answer
  185. // New State: OPEN
  186. }
  187. else {
  188. // Current State: OPEN
  189. // Event: AA update request received but not successfully processed
  190. // Action: Send AA update answer with Result-Code != SUCCESS
  191. // New State: IDLE
  192. // It's a failure, we wait for Tcc to fire -- FIXME: Alexandre: Should we?
  193. }
  194. }
  195. catch (AvpDataException e) {
  196. throw new InternalException(e);
  197. }
  198. dispatchEvent(localEvent.getAnswer());
  199. break;
  200. case RECEIVE_STR:
  201. listener.doSessionTermRequest(this, (RxSessionTermRequest) localEvent.getRequest());
  202. break;
  203. case SEND_STA:
  204. RxSessionTermAnswer STA = (RxSessionTermAnswer) localEvent.getAnswer();
  205. try {
  206. if (isSuccess(STA.getResultCodeAvp().getUnsigned32())) {
  207. // Current State: OPEN
  208. // Event: AA update request received and successfully processed
  209. // Action: Send AA update answer
  210. // New State: OPEN
  211. }
  212. else {
  213. // Current State: OPEN
  214. // Event: AA update request received but not successfully processed
  215. // Action: Send AA update answer with Result-Code != SUCCESS
  216. // New State: IDLE
  217. // It's a failure, we wait for Tcc to fire -- FIXME: Alexandre: Should we?
  218. }
  219. }
  220. catch (AvpDataException e) {
  221. throw new InternalException(e);
  222. }
  223. finally {
  224. newState = ServerRxSessionState.IDLE;
  225. }
  226. dispatchEvent(localEvent.getAnswer());
  227. break;
  228. case RECEIVE_RAA:
  229. listener.doReAuthAnswer(this, (RxReAuthRequest) localEvent.getRequest(), (RxReAuthAnswer) localEvent.getAnswer());
  230. break;
  231. case SEND_RAR:
  232. dispatchEvent(localEvent.getRequest());
  233. break;
  234. case RECEIVE_ASA:
  235. listener.doAbortSessionAnswer(this, (RxAbortSessionRequest) localEvent.getRequest(), (RxAbortSessionAnswer) localEvent.getAnswer());
  236. break;
  237. case SEND_ASR:
  238. dispatchEvent(localEvent.getRequest());
  239. break;
  240. }//end switch eventtype
  241. break;
  242. }
  243. return true;
  244. }
  245. catch (Exception e) {
  246. throw new InternalException(e);
  247. }
  248. finally {
  249. if (newState != null) {
  250. setState(newState);
  251. }
  252. sendAndStateLock.unlock();
  253. }
  254. }
  255. /*
  256. * (non-Javadoc)
  257. *
  258. * @see org.jdiameter.common.impl.app.AppSessionImpl#isReplicable()
  259. */
  260. @Override
  261. public boolean isReplicable() {
  262. return true;
  263. }
  264. public Answer processRequest(Request request) {
  265. RequestDelivery rd = new RequestDelivery();
  266. //rd.session = (ServerRxSession) LocalDataSource.INSTANCE.getSession(request.getSessionId());
  267. rd.session = this;
  268. rd.request = request;
  269. super.scheduler.execute(rd);
  270. return null;
  271. }
  272. public void receivedSuccessMessage(Request request, Answer answer) {
  273. AnswerDelivery rd = new AnswerDelivery();
  274. rd.session = this;
  275. rd.request = request;
  276. rd.answer = answer;
  277. super.scheduler.execute(rd);
  278. }
  279. /*
  280. * (non-Javadoc)
  281. *
  282. * @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String)
  283. */
  284. @Override
  285. public void onTimer(String timerName) {
  286. }
  287. public void timeoutExpired(Request request) {
  288. // context.timeoutExpired(request);
  289. //FIXME: Should we release ?
  290. }
  291. protected boolean isProvisional(long resultCode) {
  292. return resultCode >= 1000 && resultCode < 2000;
  293. }
  294. protected boolean isSuccess(long resultCode) {
  295. return resultCode >= 2000 && resultCode < 3000;
  296. }
  297. protected void setState(ServerRxSessionState newState) {
  298. setState(newState, true);
  299. }
  300. @SuppressWarnings("unchecked")
  301. protected void setState(ServerRxSessionState newState, boolean release) {
  302. IAppSessionState oldState = this.sessionData.getServerRxSessionState();
  303. this.sessionData.setServerRxSessionState(newState);
  304. for (StateChangeListener i : stateListeners) {
  305. i.stateChanged(this, (Enum) oldState, (Enum) newState);
  306. }
  307. if (newState == ServerRxSessionState.IDLE) {
  308. if (release) {
  309. // NOTE: do EVERYTHING before release.
  310. this.release();
  311. }
  312. }
  313. }
  314. @Override
  315. public void release() {
  316. if (isValid()) {
  317. try {
  318. this.sendAndStateLock.lock();
  319. super.release();
  320. }
  321. catch (Exception e) {
  322. logger.debug("Failed to release session", e);
  323. }
  324. finally {
  325. sendAndStateLock.unlock();
  326. }
  327. }
  328. else {
  329. logger.debug("Trying to release an already invalid session, with Session ID '{}'", getSessionId());
  330. }
  331. }
  332. protected void send(Event.Type type, AppRequestEvent request, AppAnswerEvent answer) throws InternalException {
  333. try {
  334. sendAndStateLock.lock();
  335. if (type != null) {
  336. handleEvent(new Event(type, request, answer));
  337. }
  338. }
  339. catch (Exception e) {
  340. throw new InternalException(e);
  341. }
  342. finally {
  343. sendAndStateLock.unlock();
  344. }
  345. }
  346. protected void dispatchEvent(AppEvent event) throws InternalException {
  347. try {
  348. session.send(event.getMessage(), this);
  349. // Store last destination information
  350. }
  351. catch (Exception e) {
  352. //throw new InternalException(e);
  353. logger.debug("Failure trying to dispatch event", e);
  354. }
  355. }
  356. private class RequestDelivery implements Runnable {
  357. ServerRxSession session;
  358. Request request;
  359. public void run() {
  360. try {
  361. switch (request.getCommandCode()) {
  362. case RxAARequest.code:
  363. handleEvent(new Event(true, factory.createAARequest(request), null));
  364. break;
  365. case RxSessionTermRequest.code:
  366. handleEvent(new Event(true, factory.createSessionTermRequest(request), null));
  367. break;
  368. default:
  369. listener.doOtherEvent(session, new AppRequestEventImpl(request), null);
  370. break;
  371. }
  372. }
  373. catch (Exception e) {
  374. logger.debug("Failed to process request message", e);
  375. }
  376. }
  377. }
  378. private class AnswerDelivery implements Runnable {
  379. ServerRxSession session;
  380. Answer answer;
  381. Request request;
  382. public void run() {
  383. try {
  384. // FIXME: baranowb: add message validation here!!!
  385. // We handle CCR, STR, ACR, ASR other go into extension
  386. switch (request.getCommandCode()) {
  387. case RxReAuthRequest.code:
  388. handleEvent(new Event(Event.Type.RECEIVE_RAA, factory.createReAuthRequest(request), factory.createReAuthAnswer(answer)));
  389. break;
  390. case RxAbortSessionRequest.code:
  391. handleEvent(new Event(Event.Type.RECEIVE_ASA, factory.createAbortSessionRequest(request), factory.createAbortSessionAnswer(answer)));
  392. break;
  393. default:
  394. listener.doOtherEvent(session, new AppRequestEventImpl(request), new AppAnswerEventImpl(answer));
  395. break;
  396. }
  397. }
  398. catch (Exception e) {
  399. logger.debug("Failed to process success message", e);
  400. }
  401. }
  402. }
  403. @Override
  404. public int hashCode() {
  405. final int prime = 31;
  406. int result = super.hashCode();
  407. result = prime * result + ((sessionData == null) ? 0 : sessionData.hashCode());
  408. return result;
  409. }
  410. @Override
  411. public boolean equals(Object obj) {
  412. if (this == obj) {
  413. return true;
  414. }
  415. if (!super.equals(obj)) {
  416. return false;
  417. }
  418. if (getClass() != obj.getClass()) {
  419. return false;
  420. }
  421. ServerRxSessionImpl other = (ServerRxSessionImpl) obj;
  422. if (sessionData == null) {
  423. if (other.sessionData != null) {
  424. return false;
  425. }
  426. }
  427. else if (!sessionData.equals(other.sessionData)) {
  428. return false;
  429. }
  430. return true;
  431. }
  432. }