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

/servers/jain-sip-ha/core/src/main/java/org/mobicents/ha/javax/sip/ClusteredSipStackImpl.java

http://mobicents.googlecode.com/
Java | 685 lines | 478 code | 44 blank | 163 comment | 133 complexity | 5df5e2518f04a2dd18ae9e2a68378d0b 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.mobicents.ha.javax.sip;
  23. import gov.nist.core.Separators;
  24. import gov.nist.core.StackLogger;
  25. import gov.nist.javax.sip.SipProviderImpl;
  26. import gov.nist.javax.sip.message.SIPRequest;
  27. import gov.nist.javax.sip.message.SIPResponse;
  28. import gov.nist.javax.sip.stack.MessageChannel;
  29. import gov.nist.javax.sip.stack.MobicentsHASIPClientTransaction;
  30. import gov.nist.javax.sip.stack.SIPClientTransaction;
  31. import gov.nist.javax.sip.stack.SIPDialog;
  32. import gov.nist.javax.sip.stack.SIPServerTransaction;
  33. import gov.nist.javax.sip.stack.SIPTransaction;
  34. import java.util.Properties;
  35. import java.util.StringTokenizer;
  36. import javax.sip.DialogState;
  37. import javax.sip.ListeningPoint;
  38. import javax.sip.ObjectInUseException;
  39. import javax.sip.PeerUnavailableException;
  40. import javax.sip.ProviderDoesNotExistException;
  41. import javax.sip.ServerTransaction;
  42. import javax.sip.SipException;
  43. import javax.sip.SipFactory;
  44. import javax.sip.SipProvider;
  45. import javax.sip.message.Request;
  46. import org.mobicents.ext.javax.sip.SipProviderFactory;
  47. import org.mobicents.ext.javax.sip.SipStackExtension;
  48. import org.mobicents.ext.javax.sip.TransactionFactory;
  49. import org.mobicents.ha.javax.sip.cache.SipCache;
  50. import org.mobicents.ha.javax.sip.cache.SipCacheException;
  51. import org.mobicents.ha.javax.sip.cache.SipCacheFactory;
  52. /**
  53. * This class extends the regular NIST SIP Stack Implementation to cache Dialogs in a replicated cache
  54. * and make use of Fault Tolerant Timers so that the NIST SIP Stack can be distributed in a cluster
  55. * and calls can be failed over
  56. *
  57. * This class will instantiate an instance of a class implementing the org.mobicents.ha.javax.sip.cache.SipCache interface to be able to set/get dialogs and txs into/from it.
  58. * The cache class name is retrieved through the Properties given to the Sip Stack upon creation under the following property name : org.mobicents.ha.javax.sip.CACHE_CLASS_NAME
  59. *
  60. * It will override all the calls to get/remove/put Dialogs and Txs so that we can fetch/remove/put them from/into the Cache
  61. * and populate the local datastructure of the NIST SIP Stack
  62. *
  63. * @author jean.deruelle@gmail.com
  64. * @author martins
  65. *
  66. */
  67. public abstract class ClusteredSipStackImpl extends gov.nist.javax.sip.SipStackImpl implements ClusteredSipStack, SipStackExtension {
  68. protected SipCache sipCache = null;
  69. protected LoadBalancerHeartBeatingService loadBalancerHeartBeatingService = null;
  70. protected ReplicationStrategy replicationStrategy = ReplicationStrategy.ConfirmedDialog;
  71. protected LoadBalancerElector loadBalancerElector = null;
  72. protected TransactionFactory transactionFactory = null;
  73. protected SipProviderFactory sipProviderFactory = null;
  74. protected boolean sendTryingRightAway;
  75. private boolean replicateApplicationData = false;
  76. public ClusteredSipStackImpl(Properties configurationProperties) throws PeerUnavailableException {
  77. super(configurationProperties);
  78. String lbHbServiceClassName = configurationProperties.getProperty(LoadBalancerHeartBeatingService.LB_HB_SERVICE_CLASS_NAME);
  79. if(lbHbServiceClassName != null) {
  80. try {
  81. loadBalancerHeartBeatingService = (LoadBalancerHeartBeatingService) Class.forName(lbHbServiceClassName).newInstance();
  82. } catch (Exception e) {
  83. String errmsg = "The loadBalancerHeartBeatingService class name: "
  84. + lbHbServiceClassName
  85. + " could not be instantiated. Ensure the " + LoadBalancerHeartBeatingService.LB_HB_SERVICE_CLASS_NAME + " property has been set correctly and that the class is on the classpath.";
  86. throw new PeerUnavailableException(errmsg, e);
  87. }
  88. // create the load balancer elector if specified
  89. String lbElectorClassName = configurationProperties.getProperty(LoadBalancerElector.IMPLEMENTATION_CLASS_NAME_PROPERTY);
  90. if(lbElectorClassName != null) {
  91. try {
  92. loadBalancerElector = (LoadBalancerElector) Class.forName(lbElectorClassName).newInstance();
  93. } catch (Exception e) {
  94. String errmsg = "The loadBalancerElector class name: "
  95. + lbElectorClassName
  96. + " could not be instantiated. Ensure the " + LoadBalancerElector.IMPLEMENTATION_CLASS_NAME_PROPERTY + " property has been set correctly and that the class is on the classpath.";
  97. throw new PeerUnavailableException(errmsg, e);
  98. }
  99. loadBalancerElector.setAddressFactory(SipFactory.getInstance().createAddressFactory());
  100. loadBalancerElector.setStackLogger(getStackLogger());
  101. loadBalancerElector.setService(loadBalancerHeartBeatingService);
  102. }
  103. }
  104. // allow the stack to provide its own SIPServerTransaction/SIPClientTransaction extension instances
  105. String transactionFactoryClassName = configurationProperties.getProperty(TRANSACTION_FACTORY_CLASS_NAME);
  106. if(transactionFactoryClassName != null) {
  107. try {
  108. transactionFactory = (TransactionFactory) Class.forName(transactionFactoryClassName).newInstance();
  109. transactionFactory.setSipStack(this);
  110. } catch (Exception e) {
  111. String errmsg = "The TransactionFactory class name: "
  112. + transactionFactoryClassName
  113. + " could not be instantiated. Ensure the " + TRANSACTION_FACTORY_CLASS_NAME + " property has been set correctly and that the class is on the classpath.";
  114. throw new PeerUnavailableException(errmsg, e);
  115. }
  116. }
  117. // allow the stack to provide its own SipProviderImpl extension instances
  118. String sipProviderFactoryClassName = configurationProperties.getProperty(SIP_PROVIDER_FACTORY_CLASS_NAME);
  119. if(sipProviderFactoryClassName != null) {
  120. try {
  121. sipProviderFactory = (SipProviderFactory) Class.forName(sipProviderFactoryClassName).newInstance();
  122. sipProviderFactory.setSipStack(this);
  123. } catch (Exception e) {
  124. String errmsg = "The SipProviderFactory class name: "
  125. + sipProviderFactoryClassName
  126. + " could not be instantiated. Ensure the " + SIP_PROVIDER_FACTORY_CLASS_NAME + " property has been set correctly and that the class is on the classpath.";
  127. throw new PeerUnavailableException(errmsg, e);
  128. }
  129. }
  130. this.sendTryingRightAway = Boolean.valueOf(
  131. configurationProperties.getProperty(SEND_TRYING_RIGHT_AWAY,"false")).booleanValue();
  132. String replicationStrategyProperty = configurationProperties.getProperty(ClusteredSipStack.REPLICATION_STRATEGY_PROPERTY);
  133. if(replicationStrategyProperty != null) {
  134. replicationStrategy = ReplicationStrategy.valueOf(replicationStrategyProperty);
  135. if(replicationStrategy == ReplicationStrategy.EarlyDialog && transactionFactory == null) {
  136. // when using EarlyDialog replication strategy we need to have an HA transaction factory to replicate transactions
  137. transactionFactory = new MobicentsHATransactionFactory();
  138. transactionFactory.setSipStack(this);
  139. }
  140. }
  141. // get/create the jboss cache instance to store all sip stack related data into it
  142. sipCache = SipCacheFactory.createSipCache(this, configurationProperties);
  143. try {
  144. sipCache.init();
  145. } catch (Exception e) {
  146. throw new PeerUnavailableException("Unable to initialize the SipCache", e);
  147. }
  148. if(loadBalancerHeartBeatingService != null) {
  149. loadBalancerHeartBeatingService.init(this, configurationProperties);
  150. }
  151. String replicateApplicationDataProperty = configurationProperties.getProperty(ClusteredSipStack.REPLICATE_APPLICATION_DATA);
  152. if(replicateApplicationDataProperty != null) {
  153. replicateApplicationData = Boolean.valueOf(replicateApplicationDataProperty);
  154. }
  155. // backward compatible hack to make sure old applications still replicate the app data if they don't use the new property
  156. if(replicateApplicationDataProperty == null && replicationStrategy == ReplicationStrategy.ConfirmedDialog) {
  157. replicateApplicationData = true;
  158. }
  159. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_INFO)) {
  160. getStackLogger().logInfo("Replication Strategy is " + replicationStrategy + " replicating application data " + replicateApplicationData);
  161. }
  162. }
  163. /*
  164. * (non-Javadoc)
  165. * @see gov.nist.javax.sip.SipStackImpl#start()
  166. */
  167. @Override
  168. public void start() throws ProviderDoesNotExistException, SipException {
  169. try {
  170. sipCache.start();
  171. } catch (Exception e) {
  172. throw new SipException("Unable to start the SipCache", e);
  173. }
  174. if(loadBalancerHeartBeatingService != null) {
  175. loadBalancerHeartBeatingService.start();
  176. }
  177. super.start();
  178. }
  179. public void closeAllTcpSockets() {
  180. ioHandler.closeAll();
  181. }
  182. /*
  183. * (non-Javadoc)
  184. * @see gov.nist.javax.sip.SipStackImpl#stop()
  185. */
  186. @Override
  187. public void stop() {
  188. super.stop();
  189. try {
  190. sipCache.stop();
  191. } catch (Exception e) {
  192. getStackLogger().logError("Unable to stop the SipCache", e);
  193. }
  194. if(loadBalancerHeartBeatingService != null) {
  195. loadBalancerHeartBeatingService.stop();
  196. }
  197. }
  198. /*
  199. * (non-Javadoc)
  200. * @see gov.nist.javax.sip.stack.SIPTransactionStack#createDialog(gov.nist.javax.sip.stack.SIPTransaction)
  201. */
  202. @Override
  203. public SIPDialog createDialog(SIPTransaction transaction) {
  204. if (sipCache.inLocalMode()) {
  205. return super.createDialog(transaction);
  206. }
  207. else {
  208. SIPDialog retval = null;
  209. if (transaction instanceof SIPClientTransaction) {
  210. final String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);
  211. retval = this.earlyDialogTable.get(dialogId);
  212. if (retval == null || (retval.getState() != null && retval.getState() != DialogState.EARLY)) {
  213. retval = (SIPDialog) HASipDialogFactory.createHASipDialog(replicationStrategy, transaction);
  214. this.earlyDialogTable.put(dialogId, retval);
  215. }
  216. } else {
  217. retval = (SIPDialog) HASipDialogFactory.createHASipDialog(replicationStrategy, transaction);
  218. }
  219. return retval;
  220. }
  221. }
  222. /*
  223. * (non-Javadoc)
  224. * @see gov.nist.javax.sip.stack.SIPTransactionStack#createDialog(gov.nist.javax.sip.stack.SIPClientTransaction, gov.nist.javax.sip.message.SIPResponse)
  225. */
  226. @Override
  227. public SIPDialog createDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {
  228. if (sipCache.inLocalMode()) {
  229. return super.createDialog(transaction,sipResponse);
  230. }
  231. else {
  232. final String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);
  233. SIPDialog retval = this.earlyDialogTable.get(dialogId);
  234. if (retval != null && sipResponse.isFinalResponse()) {
  235. this.earlyDialogTable.remove(dialogId);
  236. } else {
  237. retval = (SIPDialog) HASipDialogFactory.createHASipDialog(replicationStrategy, transaction, sipResponse);
  238. }
  239. return retval;
  240. }
  241. }
  242. /*
  243. * (non-Javadoc)
  244. * @see gov.nist.javax.sip.stack.SIPTransactionStack#createDialog(gov.nist.javax.sip.SipProviderImpl, gov.nist.javax.sip.message.SIPResponse)
  245. */
  246. @Override
  247. public SIPDialog createDialog(SipProviderImpl sipProvider,
  248. SIPResponse sipResponse) {
  249. if (sipCache.inLocalMode()) {
  250. return super.createDialog(sipProvider, sipResponse);
  251. }
  252. else {
  253. return (SIPDialog) HASipDialogFactory.createHASipDialog(replicationStrategy, sipProvider, sipResponse);
  254. }
  255. }
  256. /*
  257. * (non-Javadoc)
  258. * @see gov.nist.javax.sip.stack.SIPTransactionStack#getDialog(java.lang.String)
  259. */
  260. @Override
  261. public SIPDialog getDialog(String dialogId) {
  262. if (sipCache.inLocalMode()) {
  263. return super.getDialog(dialogId);
  264. }
  265. else {
  266. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  267. getStackLogger().logDebug("checking if the dialog " + dialogId + " is present in the local cache");
  268. }
  269. SIPDialog sipDialog = super.getDialog(dialogId);
  270. int nbToken = new StringTokenizer(dialogId, Separators.COLON).countTokens();
  271. // we should only check the cache for dialog Id where the remote tag is set since we support only established dialog failover
  272. // Issue 1378 : http://code.google.com/p/mobicents/issues/detail?id=1378
  273. // there can be more than 3 tokens if the callid part of the dialog id contains a COLON as well
  274. if(nbToken >= 3) {
  275. if(sipDialog == null ) {
  276. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  277. getStackLogger().logDebug("local dialog " + dialogId + " is null, checking in the distributed cache");
  278. }
  279. sipDialog = getDialogFromDistributedCache(dialogId);
  280. if(sipDialog != null) {
  281. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  282. getStackLogger().logDebug("dialog " + dialogId + " found in the distributed cache, storing it locally");
  283. }
  284. SIPDialog existingDialog = super.putDialog(sipDialog);
  285. // avoid returning wrong dialog if 2 threads try to recreate
  286. // the dialog after failover, we use the one that won the race
  287. if(existingDialog != null) {
  288. sipDialog = existingDialog;
  289. }
  290. } else {
  291. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  292. getStackLogger().logDebug("dialog " + dialogId + " not found in the distributed cache");
  293. }
  294. }
  295. } else {
  296. // we check for updates only if the dialog is confirmed
  297. if(sipDialog.getState() == DialogState.CONFIRMED) {
  298. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  299. getStackLogger().logDebug("local dialog " + dialogId + " is present locally " + sipDialog + " checking if it needs to be updated from the cache");
  300. }
  301. try {
  302. sipCache.updateDialog(sipDialog);
  303. } catch (SipCacheException e) {
  304. getStackLogger().logError("sipStack " + this + " problem updating dialog " + dialogId + " from the distributed cache", e);
  305. }
  306. }
  307. }
  308. }
  309. return sipDialog;
  310. }
  311. }
  312. /*
  313. * (non-Javadoc)
  314. * @see gov.nist.javax.sip.stack.SIPTransactionStack#putDialog(gov.nist.javax.sip.stack.SIPDialog)
  315. */
  316. @Override
  317. public SIPDialog putDialog(SIPDialog dialog) {
  318. return super.putDialog(dialog);
  319. // not needed it was causing the dialog to be put in the cache even for 1xx with a to tag
  320. // if (!sipCache.inLocalMode() && DialogState.CONFIRMED == dialog.getState()) {
  321. // // only replicate dialogs in confirmed state
  322. // putDialogIntoDistributedCache(dialog);
  323. // }
  324. }
  325. /*
  326. * (non-Javadoc)
  327. * @see gov.nist.javax.sip.stack.SIPTransactionStack#removeDialog(gov.nist.javax.sip.stack.SIPDialog)
  328. */
  329. @Override
  330. public void removeDialog(SIPDialog dialog) {
  331. if (!sipCache.inLocalMode()) {
  332. removeDialogFromDistributedCache(dialog.getDialogId());
  333. }
  334. super.removeDialog(dialog);
  335. }
  336. /*
  337. * (non-Javadoc)
  338. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#remoteDialogRemoval(java.lang.String)
  339. */
  340. public void remoteDialogRemoval(String dialogId) {
  341. // note we don't want a dialog terminated event, thus we need to go directly to map removal
  342. // assuming it's a confirmed dialog there is no chance it is on early dialogs too
  343. if (getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  344. getStackLogger().logDebug("sipStack " + this +
  345. " remote Dialog Removal of dialogId : " + dialogId);
  346. }
  347. SIPDialog sipDialog = super.dialogTable.remove(dialogId);
  348. if (sipDialog != null) {
  349. String mergeId = sipDialog.getMergeId();
  350. if (mergeId != null) {
  351. super.serverDialogMergeTestTable.remove(mergeId);
  352. }
  353. }
  354. }
  355. /**
  356. * Retrieve the dialog from the distributed cache
  357. * @param dialogId the id of the dialog to fetch
  358. * @return the SIPDialog from the distributed cache, null if nothing has been found in the cache
  359. */
  360. protected SIPDialog getDialogFromDistributedCache(String dialogId) {
  361. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  362. getStackLogger().logDebug("sipStack " + this + " checking if the dialog " + dialogId + " is present in the distributed cache");
  363. }
  364. // fetch the corresponding dialog from the cache instance
  365. SIPDialog sipDialog = null;
  366. try {
  367. sipDialog = sipCache.getDialog(dialogId);
  368. } catch (SipCacheException e) {
  369. getStackLogger().logError("sipStack " + this + " problem getting dialog " + dialogId + " from the distributed cache", e);
  370. }
  371. if(sipDialog != null) {
  372. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  373. getStackLogger().logDebug("sipStack " + this + " dialog " + dialogId + " was present in the distributed cache, initializing it after the load");
  374. }
  375. ((HASipDialog)sipDialog).initAfterLoad(this);
  376. }
  377. return sipDialog;
  378. }
  379. /**
  380. * Store the dialog into the distributed cache
  381. * @param dialog the dialog to store
  382. */
  383. protected void putDialogIntoDistributedCache(SIPDialog dialog) {
  384. String dialogId = dialog.getDialogId();
  385. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  386. getStackLogger().logDebug("sipStack " + this + " storing the dialog " + dialogId + " in the distributed cache");
  387. }
  388. // put the corresponding dialog into the cache instance
  389. try {
  390. sipCache.putDialog(dialog);
  391. } catch (SipCacheException e) {
  392. getStackLogger().logError("sipStack " + this + " problem storing the dialog " + dialogId + " into the distributed cache", e);
  393. }
  394. }
  395. /**
  396. * Remove the dialog from the distributed cache
  397. * @param dialogId the id of the dialog to remove
  398. */
  399. protected void removeDialogFromDistributedCache(String dialogId) {
  400. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  401. getStackLogger().logDebug("sipStack " + this + " removing the dialog " + dialogId + " from the distributed cache");
  402. }
  403. // remove the corresponding dialog from the cache instance
  404. // put the corresponding dialog into the cache instance
  405. try {
  406. sipCache.removeDialog(dialogId);
  407. } catch (SipCacheException e) {
  408. getStackLogger().logError("sipStack " + this + " problem removing dialog " + dialogId + " from the distributed cache", e);
  409. }
  410. }
  411. /*
  412. * (non-Javadoc)
  413. * @see gov.nist.javax.sip.stack.SIPTransactionStack#findTransaction(java.lang.String, boolean)
  414. */
  415. @Override
  416. public SIPTransaction findTransaction(String transactionId, boolean isServer) {
  417. if(sipCache.inLocalMode() || replicationStrategy != ReplicationStrategy.EarlyDialog) {
  418. return super.findTransaction(transactionId,isServer);
  419. }
  420. final String txId = transactionId.toLowerCase();
  421. SIPTransaction sipTransaction = super.findTransaction(txId, isServer);
  422. if(sipTransaction == null && transactionFactory != null) {
  423. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  424. getStackLogger().logDebug("local transaction " + txId + " server = " + isServer + " is null, checking in the distributed cache");
  425. }
  426. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  427. getStackLogger().logDebug("sipStack " + this + " checking if the transaction " + txId + " server = " + isServer + " is present in the distributed cache");
  428. }
  429. if(isServer) {
  430. // fetch the corresponding server transaction from the cache instance
  431. try {
  432. sipTransaction = sipCache.getServerTransaction(txId);
  433. if(sipTransaction != null) {
  434. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  435. getStackLogger().logDebug("sipStack " + this + " transaction " + txId + " server = " + isServer + " is present in the distributed cache");
  436. }
  437. SIPServerTransaction retval = serverTransactionTable.putIfAbsent(txId, (SIPServerTransaction) sipTransaction);
  438. if(retval != null) {
  439. sipTransaction = retval;
  440. }
  441. } else {
  442. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  443. getStackLogger().logDebug("sipStack " + this + " transaction " + txId + " server = " + isServer + " is not present in the distributed cache");
  444. }
  445. }
  446. } catch (SipCacheException e) {
  447. getStackLogger().logError("sipStack " + this + " problem getting transaction " + txId + " server = " + isServer + " from the distributed cache", e);
  448. }
  449. } else {
  450. // fetch the corresponding client transaction from the cache instance
  451. try {
  452. sipTransaction = sipCache.getClientTransaction(txId);
  453. if(sipTransaction != null) {
  454. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  455. getStackLogger().logDebug("sipStack " + this + " transaction " + txId + " server = " + isServer + " is present in the distributed cache");
  456. }
  457. SIPClientTransaction retval = clientTransactionTable.putIfAbsent(txId, (SIPClientTransaction) sipTransaction);
  458. if(retval != null) {
  459. sipTransaction = retval;
  460. } else {
  461. // start the transaction timer only when the transaction has been added to the stack
  462. // to avoid leaks on retransmissions
  463. ((MobicentsHASIPClientTransaction)sipTransaction).startTransactionTimerOnFailover();
  464. }
  465. } else {
  466. if(getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  467. getStackLogger().logDebug("sipStack " + this + " transaction " + txId + " server = " + isServer + " is not present in the distributed cache");
  468. }
  469. }
  470. } catch (SipCacheException e) {
  471. getStackLogger().logError("sipStack " + this + " problem getting transaction " + txId + " server = " + isServer + " from the distributed cache", e);
  472. }
  473. }
  474. }
  475. return sipTransaction;
  476. }
  477. @Override
  478. public void removeTransaction(SIPTransaction sipTransaction) {
  479. super.removeTransaction(sipTransaction);
  480. if(sipCache.inLocalMode()) {
  481. return;
  482. }
  483. if(transactionFactory != null && sipTransaction != null && replicationStrategy == ReplicationStrategy.EarlyDialog && sipTransaction.getMethod().equalsIgnoreCase(Request.INVITE)) {
  484. if(sipTransaction instanceof ServerTransaction) {
  485. // remove the corresponding server transaction from the cache instance
  486. try {
  487. sipCache.removeServerTransaction(sipTransaction.getTransactionId());
  488. } catch (SipCacheException e) {
  489. getStackLogger().logError("sipStack " + this + " problem getting transaction " + sipTransaction.getTransactionId() + " from the distributed cache", e);
  490. }
  491. } else {
  492. // remove the corresponding client transaction from the cache instance
  493. try {
  494. sipCache.removeClientTransaction(sipTransaction.getTransactionId());
  495. } catch (SipCacheException e) {
  496. getStackLogger().logError("sipStack " + this + " problem getting transaction " + sipTransaction.getTransactionId() + " from the distributed cache", e);
  497. }
  498. }
  499. }
  500. }
  501. @Override
  502. protected void removeTransactionHash(SIPTransaction sipTransaction) {
  503. super.removeTransactionHash(sipTransaction);
  504. if(sipCache.inLocalMode()) {
  505. return;
  506. }
  507. if(transactionFactory != null && sipTransaction != null && replicationStrategy == ReplicationStrategy.EarlyDialog && sipTransaction.getMethod().equalsIgnoreCase(Request.INVITE)) {
  508. if(sipTransaction instanceof ServerTransaction) {
  509. // remove the corresponding server transaction from the cache instance
  510. try {
  511. sipCache.removeServerTransaction(sipTransaction.getTransactionId());
  512. } catch (SipCacheException e) {
  513. getStackLogger().logError("sipStack " + this + " problem getting transaction " + sipTransaction.getTransactionId() + " from the distributed cache", e);
  514. }
  515. } else {
  516. // remove the corresponding client transaction from the cache instance
  517. try {
  518. sipCache.removeClientTransaction(sipTransaction.getTransactionId());
  519. } catch (SipCacheException e) {
  520. getStackLogger().logError("sipStack " + this + " problem getting transaction " + sipTransaction.getTransactionId() + " from the distributed cache", e);
  521. }
  522. }
  523. }
  524. }
  525. /*
  526. * (non-Javadoc)
  527. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#setSipCache(org.mobicents.ha.javax.sip.cache.SipCache)
  528. */
  529. public void setSipCache(SipCache sipCache) {
  530. this.sipCache = sipCache;
  531. }
  532. /*
  533. * (non-Javadoc)
  534. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#getSipCache()
  535. */
  536. public SipCache getSipCache() {
  537. return sipCache;
  538. }
  539. /*
  540. * (non-Javadoc)
  541. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#getLoadBalancerHeartBeatingService()
  542. */
  543. public LoadBalancerHeartBeatingService getLoadBalancerHeartBeatingService() {
  544. return loadBalancerHeartBeatingService;
  545. }
  546. /*
  547. * (non-Javadoc)
  548. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#getReplicationStrategy()
  549. */
  550. public ReplicationStrategy getReplicationStrategy() {
  551. return replicationStrategy;
  552. }
  553. /*
  554. * (non-Javadoc)
  555. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#getLoadBalancerElector()
  556. */
  557. public LoadBalancerElector getLoadBalancerElector() {
  558. return loadBalancerElector;
  559. }
  560. @Override
  561. public SIPClientTransaction createClientTransaction(SIPRequest sipRequest,
  562. MessageChannel encapsulatedMessageChannel) {
  563. if(sipCache.inLocalMode() || transactionFactory == null) {
  564. return super.createClientTransaction(sipRequest, encapsulatedMessageChannel);
  565. }
  566. return transactionFactory.createClientTransaction(sipRequest, encapsulatedMessageChannel);
  567. }
  568. @Override
  569. public SIPServerTransaction createServerTransaction(MessageChannel encapsulatedMessageChannel) {
  570. if(sipCache.inLocalMode() || transactionFactory == null) {
  571. return super.createServerTransaction(encapsulatedMessageChannel);
  572. }
  573. return transactionFactory.createServerTransaction(encapsulatedMessageChannel);
  574. }
  575. /**
  576. * @param sendTryingRightAway the sendTryingRightAway to set
  577. */
  578. public void setSendTryingRightAway(boolean sendTryingRightAway) {
  579. this.sendTryingRightAway = sendTryingRightAway;
  580. }
  581. /**
  582. * @return the sendTryingRightAway
  583. */
  584. public boolean isSendTryingRightAway() {
  585. return sendTryingRightAway;
  586. }
  587. public void addSipProvider(SipProviderImpl sipProvider) {
  588. sipProviders.add(sipProvider);
  589. }
  590. public void removeSipProvider(SipProviderImpl sipProvider) {
  591. sipProviders.remove(sipProvider);
  592. }
  593. /**
  594. * @return the replicateApplicationData
  595. */
  596. public boolean isReplicateApplicationData() {
  597. return replicateApplicationData;
  598. }
  599. /*
  600. * (non-Javadoc)
  601. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#remoteServerTransactionRemoval(java.lang.String)
  602. */
  603. public void remoteServerTransactionRemoval(String transactionId) {
  604. final String txId = transactionId.toLowerCase();
  605. // note we don't want a dialog terminated event, thus we need to go directly to map removal
  606. // assuming it's a confirmed dialog there is no chance it is on early dialogs too
  607. if (getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  608. getStackLogger().logDebug("sipStack " + this +
  609. " remote Server Transaction Removal of transaction Id : " + txId);
  610. }
  611. // the transaction id is set to lower case in the cache so it might not remove it correctly
  612. SIPServerTransaction sipServerTransaction = super.serverTransactionTable.remove(txId);
  613. if (sipServerTransaction != null) {
  614. super.removeFromMergeTable(sipServerTransaction);
  615. super.removePendingTransaction(sipServerTransaction);
  616. super.removeTransactionPendingAck(sipServerTransaction);
  617. }
  618. }
  619. /*
  620. * (non-Javadoc)
  621. * @see org.mobicents.ha.javax.sip.ClusteredSipStack#remoteClientTransactionRemoval(java.lang.String)
  622. */
  623. public void remoteClientTransactionRemoval(String transactionId) {
  624. final String txId = transactionId.toLowerCase();
  625. // note we don't want a dialog terminated event, thus we need to go directly to map removal
  626. // assuming it's a confirmed dialog there is no chance it is on early dialogs too
  627. if (getStackLogger().isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  628. getStackLogger().logDebug("sipStack " + this +
  629. " remote Client Transaction Removal of transaction Id : " + txId);
  630. }
  631. // the transaction id is set to lower case in the cache so it might not remove it correctly
  632. SIPClientTransaction sipClientTransaction = super.clientTransactionTable.remove(txId);
  633. }
  634. public SipProvider createSipProvider(ListeningPoint listeningPoint)
  635. throws ObjectInUseException {
  636. if (sipProviderFactory != null) {
  637. return sipProviderFactory.createSipProvider(listeningPoint);
  638. }
  639. return super.createSipProvider(listeningPoint);
  640. }
  641. }