PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/jain-slee/resources/jcc/jcc-camel-provider/java/src/main/java/org/mobicents/jcc/inap/AbstractConnection.java

http://mobicents.googlecode.com/
Java | 521 lines | 364 code | 67 blank | 90 comment | 36 complexity | 73dc95aeddfbf22b4a54506cb8d68362 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. /*
  23. * File Name : AbstractConnection.java
  24. *
  25. * The Java Call Control API for CAMEL 2
  26. *
  27. * The source code contained in this file is in in the public domain.
  28. * It can be used in any project or product without prior permission,
  29. * license or royalty payments. There is NO WARRANTY OF ANY KIND,
  30. * EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION,
  31. * THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  32. * AND DATA ACCURACY. We do not warrant or make any representations
  33. * regarding the use of the software or the results thereof, including
  34. * but not limited to the correctness, accuracy, reliability or
  35. * usefulness of the software.
  36. */
  37. package org.mobicents.jcc.inap;
  38. import java.util.ArrayList;
  39. import java.util.HashMap;
  40. import javax.csapi.cc.jcc.EventFilter;
  41. import javax.csapi.cc.jcc.InvalidArgumentException;
  42. import javax.csapi.cc.jcc.InvalidStateException;
  43. import javax.csapi.cc.jcc.JccAddress;
  44. import javax.csapi.cc.jcc.JccCall;
  45. import javax.csapi.cc.jcc.JccConnection;
  46. import javax.csapi.cc.jcc.JccConnectionEvent;
  47. import javax.csapi.cc.jcc.JccConnectionListener;
  48. import javax.csapi.cc.jcc.JccEvent;
  49. import javax.csapi.cc.jcc.PrivilegeViolationException;
  50. import javax.csapi.cc.jcc.ResourceUnavailableException;
  51. import org.apache.log4j.Logger;
  52. import org.mobicents.jcc.inap.address.JccCalledPartyNumber;
  53. import org.mobicents.jcc.inap.protocol.Connect;
  54. import org.mobicents.protocols.ss7.tcap.api.TCAPException;
  55. import org.mobicents.protocols.ss7.tcap.api.TCAPProvider;
  56. import org.mobicents.protocols.ss7.tcap.api.TCAPSendException;
  57. import org.mobicents.protocols.ss7.tcap.api.tc.dialog.Dialog;
  58. import org.mobicents.protocols.ss7.tcap.api.tc.dialog.events.TCContinueRequest;
  59. import org.mobicents.protocols.ss7.tcap.api.tc.dialog.events.TCEndRequest;
  60. import org.mobicents.protocols.ss7.tcap.api.tc.dialog.events.TerminationType;
  61. import org.mobicents.protocols.ss7.tcap.asn.comp.Invoke;
  62. import org.mobicents.util.LocalTimer;
  63. import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
  64. import EDU.oswego.cs.dl.util.concurrent.Semaphore;
  65. /**
  66. *
  67. * @author Oleg Kulikov
  68. */
  69. public abstract class AbstractConnection implements JccConnection {
  70. public final static int IDLE_TIMEOUT = 5;
  71. public final static int AUTH_TIMEOUT = 5;
  72. public final static int ADDRESS_ANALYZE_TIMEOUT = 5;
  73. public final static int CALL_DELIVERY_TIMEOUT = 65;
  74. public final static int ALERTING_TIMEOUT = 65;
  75. public final static int CONNECTED_TIMEOUT = 1805;
  76. protected ConnectionID connectionID;
  77. protected volatile boolean isBlocked = false;
  78. protected JccAddress address;
  79. protected JccCallImpl call;
  80. protected volatile int state;
  81. protected volatile int cause;
  82. protected LocalTimer timer = new LocalTimer();
  83. protected Semaphore semaphore = new Semaphore(0);
  84. private QueuedExecutor applicationEventQueue = new QueuedExecutor();
  85. private QueuedExecutor signalingEventQueue = new QueuedExecutor();
  86. private final static HashMap states = new HashMap();
  87. private final static HashMap causes = new HashMap();
  88. private volatile boolean released = false;
  89. private String callID;
  90. protected TCAPProvider tcapProvider;
  91. protected Dialog tcapDialog;
  92. private final static Logger logger = Logger.getLogger(AbstractConnection.class);
  93. static {
  94. states.put(new Integer(JccConnection.IDLE), "IDLE");
  95. states.put(new Integer(JccConnection.ADDRESS_ANALYZE), "ADDRESS_ANALYZE");
  96. states.put(new Integer(JccConnection.ADDRESS_COLLECT), "ADDRESS_COLLECT");
  97. states.put(new Integer(JccConnection.ALERTING), "ALERTING");
  98. states.put(new Integer(JccConnection.AUTHORIZE_CALL_ATTEMPT), "AUTHORIZE_CALL_ATTEMPT");
  99. states.put(new Integer(JccConnection.CALL_DELIVERY), "CALL_DELIVERY");
  100. states.put(new Integer(JccConnection.CONNECTED), "CONNECTED");
  101. states.put(new Integer(JccConnection.DISCONNECTED), "DISCONNECTED");
  102. states.put(new Integer(JccConnection.FAILED), "FAILED");
  103. }
  104. static {
  105. causes.put(new Integer(JccConnectionEvent.CAUSE_BUSY), "CAUSE_BUSY");
  106. causes.put(new Integer(JccConnectionEvent.CAUSE_CALL_CANCELLED), "CAUSE_CALL_CANCELED");
  107. causes.put(new Integer(JccConnectionEvent.CAUSE_CALL_RESTRICTED), "CAUSE_CALL_RESTRICTED");
  108. causes.put(new Integer(JccConnectionEvent.CAUSE_DEST_NOT_OBTAINABLE), "CAUSE_DEST_NOT_OBTAINABLE");
  109. causes.put(new Integer(JccConnectionEvent.CAUSE_GENERAL_FAILURE), "CAUSE_GENERAL_FAILURE");
  110. causes.put(new Integer(JccConnectionEvent.CAUSE_INCOMPATIBLE_DESTINATION), "CAUSE_INCOMPATIBLE_DESTINATION");
  111. causes.put(new Integer(JccConnectionEvent.CAUSE_MORE_DIGITS_NEEDED), "CAUSE_MORE_DIGITS_NEEDED");
  112. causes.put(new Integer(JccConnectionEvent.CAUSE_NETWORK_CONGESTION), "CAUSE_NETWORK_CONGESTION");
  113. causes.put(new Integer(JccConnectionEvent.CAUSE_NETWORK_NOT_OBTAINABLE), "CAUSE_NETWORK_NOT_OBTAINABLE");
  114. causes.put(new Integer(JccConnectionEvent.CAUSE_NEW_CALL), "CAUSE_NEW_CALL");
  115. causes.put(new Integer(JccConnectionEvent.CAUSE_NORMAL), "CAUSE_NORMAL");
  116. causes.put(new Integer(JccConnectionEvent.CAUSE_NO_ANSWER), "CAUSE_NO_ANSWER");
  117. causes.put(new Integer(JccConnectionEvent.CAUSE_REDIRECTED), "CAUSE_REDIRECTED");
  118. causes.put(new Integer(JccConnectionEvent.CAUSE_RESOURCES_NOT_AVAILABLE), "CAUSE_RESOURCES_NOT_AVAILABLE");
  119. causes.put(new Integer(JccConnectionEvent.CAUSE_SNAPSHOT), "CAUSE_SNAPSHOT");
  120. causes.put(new Integer(JccConnectionEvent.CAUSE_TIMER_EXPIRY), "CAUSE_TIMER_EXPIRY");
  121. causes.put(new Integer(JccConnectionEvent.CAUSE_UNKNOWN), "CAUSE_UNKNOWN");
  122. causes.put(new Integer(JccConnectionEvent.CAUSE_USER_NOT_AVAILABLE), "CAUSE_USER_NOT_AVAILABLE");
  123. }
  124. /** Creates a new instance of AbstractConnection */
  125. public AbstractConnection(ConnectionID connectionID, JccCallImpl call, JccAddress address, TCAPProvider provider,Dialog tcapDialog) {
  126. this.connectionID = connectionID;
  127. this.call = call;
  128. this.address = address;
  129. this.state = JccConnection.IDLE;
  130. this.callID = call.callID;
  131. this.tcapDialog = tcapDialog;
  132. this.tcapProvider = provider;
  133. }
  134. public ConnectionID getID() {
  135. return connectionID;
  136. }
  137. /**
  138. * (Non Java-doc).
  139. * @see javax.csapi.cc.jcc.JccConnection#getAddress().
  140. */
  141. public JccAddress getAddress() {
  142. return address;
  143. }
  144. /**
  145. * (Non Java-doc).
  146. * @see javax.csapi.cc.jcc.JccConnection#getCall().
  147. */
  148. public JccCall getCall() {
  149. return call;
  150. }
  151. /**
  152. * (Non Java-doc).
  153. * @see javax.csapi.cc.jcc.JccConnection#getState().
  154. */
  155. public int getState() {
  156. return state;
  157. }
  158. /**
  159. * (Non Java-doc).
  160. * @see javax.csapi.cc.jcc.JccConnection#isBlocked().
  161. */
  162. public boolean isBlocked() {
  163. return isBlocked;
  164. }
  165. /**
  166. * (Non Java-doc).
  167. * @see javax.csapi.cc.jcc.JccConnection#release().
  168. */
  169. public void release(int causeCode) throws PrivilegeViolationException,
  170. ResourceUnavailableException, InvalidStateException, InvalidArgumentException {
  171. released = true;
  172. //send connect on to appropriate answer machine number
  173. JccEvent evt = new JccConnectionEventImpl(
  174. JccConnectionEvent.CONNECTION_FAILED,
  175. this,
  176. JccEvent.CAUSE_CALL_RESTRICTED);
  177. queueEvent(evt);
  178. if (isBlocked()) {
  179. resume();
  180. }
  181. JccCalledPartyNumber cpn = null;
  182. switch (causeCode) {
  183. case JccEvent.CAUSE_CALL_RESTRICTED:
  184. cpn = new JccCalledPartyNumber(call.provider, "9999");
  185. default:
  186. cpn = new JccCalledPartyNumber(call.provider, "9999");
  187. }
  188. if (logger.isDebugEnabled()) {
  189. logger.debug(this + "release(): connecting to " + cpn.getRouteAddress());
  190. }
  191. Connect connect = new Connect(cpn.getRouteAddress());
  192. Invoke component = this.tcapProvider.getComponentPrimitiveFactory().createTCInvokeRequest();
  193. try {
  194. component.setInvokeId(this.tcapDialog.getNewInvokeId());
  195. } catch (TCAPException e) {
  196. throw new RuntimeException("Cant create invoke id", e);
  197. }
  198. TCContinueRequest message = this.tcapProvider.getDialogPrimitiveFactory().createContinue(this.tcapDialog);
  199. message.setApplicationContextName(this.tcapDialog.getApplicationContextName());
  200. message.setUserInformation(this.tcapDialog.getUserInformation());
  201. try {
  202. this.tcapDialog.sendComponent(component);
  203. } catch (TCAPSendException e) {
  204. throw new RuntimeException("Cant send", e);
  205. }
  206. try {
  207. this.tcapDialog.send(message);
  208. } catch (TCAPSendException e) {
  209. throw new RuntimeException("Cant send", e);
  210. }
  211. //switch called and calling party addresses
  212. // SccpAddress calledPartyAddress = connectionID.getCallingPartyAddress();
  213. // SccpAddress callingPartyAddress = connectionID.getCalledPartyAddress();
  214. //
  215. // try {
  216. // call.provider.send(calledPartyAddress, callingPartyAddress, message);
  217. // } catch (IOException e) {
  218. // }
  219. }
  220. /**
  221. * (Non Java-doc).
  222. * @see javax.csapi.cc.jcc.JccConnection#continueProcessing().
  223. */
  224. public synchronized void continueProcessing()
  225. throws PrivilegeViolationException, ResourceUnavailableException, InvalidStateException {
  226. resume();
  227. }
  228. public synchronized void queueEvent(JccEvent event) {
  229. if (event.getID() == JccConnectionEvent.CONNECTION_FAILED) {
  230. logger.debug(this + "restarting signaling queue");
  231. if (signalingEventQueue != null) {
  232. signalingEventQueue.shutdownNow();
  233. signalingEventQueue = new QueuedExecutor();
  234. }
  235. }
  236. try {
  237. if (logger.isDebugEnabled()) {
  238. logger.debug(this + "queue event " + event);
  239. }
  240. if (signalingEventQueue != null) {
  241. signalingEventQueue.execute((Runnable) event);
  242. } else {
  243. logger.error(this + ", Unexpected event=" + event);
  244. }
  245. } catch (InterruptedException e) {
  246. }
  247. }
  248. protected void block() {
  249. this.isBlocked = true;
  250. try {
  251. if (logger.isDebugEnabled()) {
  252. logger.debug(this + "blocking processing in state=" + getStateName(state));
  253. }
  254. semaphore.acquire();
  255. this.isBlocked = false;
  256. if (logger.isDebugEnabled()) {
  257. logger.debug(this + "resuming processing in state=" + getStateName(state));
  258. }
  259. } catch (InterruptedException e) {
  260. this.isBlocked = false;
  261. if (logger.isDebugEnabled()) {
  262. logger.debug(this + "interrupted block in state=" + getStateName(state));
  263. }
  264. }
  265. }
  266. protected void resume() {
  267. if (isBlocked) {
  268. semaphore.release();
  269. }
  270. }
  271. /**
  272. * Handle InitialDP detection point.
  273. */
  274. public void onConnectionCreated() {
  275. logger.info(this + "CONNECTION_CREATED, " + getCauseName(cause));
  276. call.append(this);
  277. timer.schedule(new CancelTimeoutTask(this), IDLE_TIMEOUT);
  278. }
  279. public abstract void onAuthorizeCallAttempt();
  280. public abstract void onAddressCollect();
  281. public abstract void onAddressAnalyze(JccConnectionEventImpl evt);
  282. public abstract void onCallDelivery();
  283. public abstract void onAlerting();
  284. public abstract void onConnected();
  285. /**
  286. * Handle tc_abort event
  287. */
  288. public void onFailed() {
  289. logger.info(this + "FAILED, " + getCauseName(cause));
  290. if (logger.isDebugEnabled()) {
  291. logger.debug(this + "onFailed(): disable timer");
  292. }
  293. timer.stop();
  294. JccEvent event = new JccConnectionEventImpl(JccConnectionEvent.CONNECTION_DISCONNECTED, this, cause);
  295. queueEvent(event);
  296. if (logger.isDebugEnabled()) {
  297. logger.debug(this + "onFailed(): release all blocks");
  298. }
  299. resume();
  300. }
  301. public void onDisconnected() {
  302. logger.info(this + "DISCONNECTING, " + getCauseName(cause));
  303. if (logger.isDebugEnabled()) {
  304. logger.debug(this + "onDisconnected(): disable timer");
  305. }
  306. timer.stop();
  307. timer = null;
  308. if (logger.isDebugEnabled()) {
  309. logger.debug(this + "onDisconnected(): release all blocks");
  310. }
  311. if (isBlocked()) {
  312. resume();
  313. }
  314. semaphore = null;
  315. if (released) {
  316. return;
  317. }
  318. if (logger.isDebugEnabled()) {
  319. logger.debug(this + "onDisconnected(): ending TCAP dialogue");
  320. }
  321. TCEndRequest message = this.tcapProvider.getDialogPrimitiveFactory().createEnd(this.tcapDialog);
  322. message.setTermination(TerminationType.Basic);
  323. try {
  324. this.tcapDialog.send(message);
  325. } catch (TCAPSendException e) {
  326. throw new RuntimeException(e);
  327. }
  328. //switch called and calling party addresses
  329. // SccpAddress calledPartyAddress = connectionID.getCallingPartyAddress();
  330. // SccpAddress callingPartyAddress = connectionID.getCalledPartyAddress();
  331. //
  332. // try {
  333. // call.provider.send(calledPartyAddress, callingPartyAddress, message);
  334. // } catch (IOException e) {
  335. // logger.error("Network error", e);
  336. // }
  337. //call = null;
  338. }
  339. protected void notifyDisconnectImmediately(ArrayList listeners, JccConnectionEvent event) {
  340. int count = listeners.size();
  341. for (int i = 0; i < count; i++) {
  342. Object[] ls = (Object[]) listeners.get(i);
  343. JccConnectionListener listener = (JccConnectionListener) ls[0];
  344. listener.connectionDisconnected(event);
  345. }
  346. }
  347. protected void forceDisconnect() {
  348. this.released = true;
  349. JccConnectionEventImpl event = new JccConnectionEventImpl(
  350. JccConnectionEvent.CONNECTION_DISCONNECTED, this,
  351. JccConnectionEvent.CAUSE_TIMER_EXPIRY);
  352. try {
  353. onDisconnected();
  354. this.notifyDisconnectImmediately(call.connectionListeners, event);
  355. this.notifyDisconnectImmediately(call.provider.connectionListeners, event);
  356. } finally {
  357. close();
  358. }
  359. }
  360. protected void close() {
  361. if (logger.isDebugEnabled()) {
  362. logger.debug(this + "onDisconnected(): shutdown application event queue");
  363. }
  364. try {
  365. applicationEventQueue.shutdownNow();
  366. applicationEventQueue = null;
  367. } catch (Exception e) {
  368. }
  369. if (logger.isDebugEnabled()) {
  370. logger.debug(this + "onDisconnected(): shutdown signaling event queue");
  371. }
  372. try {
  373. signalingEventQueue.shutdownNow();
  374. signalingEventQueue = null;
  375. } catch (Exception e) {
  376. }
  377. if (logger.isDebugEnabled()) {
  378. logger.debug(this + "onDisconnected(): removing connection reference");
  379. }
  380. call.remove(this);
  381. call = null;
  382. }
  383. protected void fireConnectionEvent(JccConnectionEvent event) {
  384. fireConnectionEvent(call.connectionListeners, event);
  385. fireConnectionEvent(call.provider.connectionListeners, event);
  386. }
  387. private void fireConnectionEvent(ArrayList listeners, JccConnectionEvent event) {
  388. AbstractConnection connection = (AbstractConnection) event.getConnection();
  389. int count = listeners.size();
  390. for (int i = 0; i < count; i++) {
  391. Object[] ls = (Object[]) listeners.get(i);
  392. JccConnectionListener listener = (JccConnectionListener) ls[0];
  393. EventFilter filter = (EventFilter) ls[1];
  394. int disposition = filter.getEventDisposition(event);
  395. if (disposition == EventFilter.EVENT_BLOCK
  396. && event.getID() == JccConnectionEvent.CONNECTION_DISCONNECTED) {
  397. disposition = EventFilter.EVENT_NOTIFY;
  398. }
  399. switch (disposition) {
  400. case EventFilter.EVENT_DISCARD:
  401. if (logger.isDebugEnabled()) {
  402. logger.debug(this + "fire event " + event + ", disposition=event_discard");
  403. }
  404. break;
  405. case EventFilter.EVENT_BLOCK:
  406. if (logger.isDebugEnabled()) {
  407. logger.debug(this + "fire event " + event + ", disposition=event_block");
  408. }
  409. try {
  410. applicationEventQueue.execute(new EventProducer(listener, event));
  411. } catch (InterruptedException e) {
  412. }
  413. block();
  414. break;
  415. case EventFilter.EVENT_NOTIFY:
  416. if (logger.isDebugEnabled()) {
  417. logger.debug(this + "fire event " + event + ", disposition=event_notify");
  418. }
  419. try {
  420. applicationEventQueue.execute(new EventProducer(listener, event));
  421. } catch (InterruptedException e) {
  422. }
  423. break;
  424. }
  425. }
  426. }
  427. public static synchronized String getStateName(int state) {
  428. return (String) states.get(new Integer(state));
  429. }
  430. public static synchronized String getCauseName(int cause) {
  431. return (String) causes.get(new Integer(cause));
  432. }
  433. @Override
  434. public String toString() {
  435. return "(call_id=" + callID + ", address=" + address.toString() + ") ";
  436. }
  437. private class CancelTimeoutTask implements Runnable {
  438. private JccConnection connection;
  439. public CancelTimeoutTask(JccConnection connection) {
  440. this.connection = connection;
  441. }
  442. public void run() {
  443. logger.debug("Timer expired. state=" + getStateName(state) + ", Cancel call");
  444. if (isBlocked()) {
  445. resume();
  446. }
  447. JccConnectionEvent evt = new JccConnectionEventImpl(
  448. JccConnectionEvent.CONNECTION_FAILED,
  449. connection,
  450. JccConnectionEvent.CAUSE_TIMER_EXPIRY);
  451. queueEvent(evt);
  452. }
  453. };
  454. }