PageRenderTime 69ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/jain-slee/resources/diameter-cca/ra/src/main/java/org/mobicents/slee/resource/diameter/cca/DiameterCCAResourceAdaptor.java

http://mobicents.googlecode.com/
Java | 1116 lines | 698 code | 201 blank | 217 comment | 94 complexity | f17387a20cff4a2b5a8d8445bd4a1978 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.slee.resource.diameter.cca;
  23. import static org.jdiameter.client.impl.helpers.Parameters.MessageTimeOut;
  24. import java.util.ArrayList;
  25. import java.util.List;
  26. import javax.management.ObjectName;
  27. import javax.slee.Address;
  28. import javax.slee.facilities.EventLookupFacility;
  29. import javax.slee.facilities.Tracer;
  30. import javax.slee.resource.ActivityFlags;
  31. import javax.slee.resource.ActivityHandle;
  32. import javax.slee.resource.ConfigProperties;
  33. import javax.slee.resource.ConfigProperties.Property;
  34. import javax.slee.resource.EventFlags;
  35. import javax.slee.resource.FailureReason;
  36. import javax.slee.resource.FireableEventType;
  37. import javax.slee.resource.InvalidConfigurationException;
  38. import javax.slee.resource.Marshaler;
  39. import javax.slee.resource.ReceivableService;
  40. import javax.slee.resource.ResourceAdaptor;
  41. import javax.slee.resource.ResourceAdaptorContext;
  42. import javax.slee.resource.SleeEndpoint;
  43. import javax.transaction.InvalidTransactionException;
  44. import javax.transaction.SystemException;
  45. import javax.transaction.Transaction;
  46. import net.java.slee.resource.diameter.Validator;
  47. import net.java.slee.resource.diameter.base.CreateActivityException;
  48. import net.java.slee.resource.diameter.base.DiameterActivity;
  49. import net.java.slee.resource.diameter.base.DiameterAvpFactory;
  50. import net.java.slee.resource.diameter.base.DiameterException;
  51. import net.java.slee.resource.diameter.base.DiameterMessageFactory;
  52. import net.java.slee.resource.diameter.base.events.DiameterMessage;
  53. import net.java.slee.resource.diameter.base.events.avp.DiameterIdentity;
  54. import net.java.slee.resource.diameter.cca.CreditControlAVPFactory;
  55. import net.java.slee.resource.diameter.cca.CreditControlClientSession;
  56. import net.java.slee.resource.diameter.cca.CreditControlMessageFactory;
  57. import net.java.slee.resource.diameter.cca.CreditControlProvider;
  58. import net.java.slee.resource.diameter.cca.CreditControlServerSession;
  59. import net.java.slee.resource.diameter.cca.events.CreditControlMessage;
  60. import net.java.slee.resource.diameter.cca.events.CreditControlRequest;
  61. import org.jboss.mx.util.MBeanServerLocator;
  62. import org.jdiameter.api.Answer;
  63. import org.jdiameter.api.ApplicationId;
  64. import org.jdiameter.api.Message;
  65. import org.jdiameter.api.Peer;
  66. import org.jdiameter.api.PeerTable;
  67. import org.jdiameter.api.Request;
  68. import org.jdiameter.api.Session;
  69. import org.jdiameter.api.SessionFactory;
  70. import org.jdiameter.api.Stack;
  71. import org.jdiameter.api.cca.ClientCCASession;
  72. import org.jdiameter.api.cca.ServerCCASession;
  73. import org.jdiameter.client.api.ISessionFactory;
  74. import org.jdiameter.server.impl.app.cca.ServerCCASessionImpl;
  75. import org.mobicents.diameter.stack.DiameterListener;
  76. import org.mobicents.diameter.stack.DiameterStackMultiplexerMBean;
  77. import org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor;
  78. import org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptorContext;
  79. import org.mobicents.slee.resource.diameter.AbstractClusteredDiameterActivityManagement;
  80. import org.mobicents.slee.resource.diameter.DiameterActivityManagement;
  81. import org.mobicents.slee.resource.diameter.LocalDiameterActivityManagement;
  82. import org.mobicents.slee.resource.diameter.ValidatorImpl;
  83. import org.mobicents.slee.resource.diameter.base.DiameterActivityHandle;
  84. import org.mobicents.slee.resource.diameter.base.DiameterActivityImpl;
  85. import org.mobicents.slee.resource.diameter.base.DiameterAvpFactoryImpl;
  86. import org.mobicents.slee.resource.diameter.base.DiameterBaseMarshaler;
  87. import org.mobicents.slee.resource.diameter.base.DiameterMessageFactoryImpl;
  88. import org.mobicents.slee.resource.diameter.base.EventIDFilter;
  89. import org.mobicents.slee.resource.diameter.base.events.ErrorAnswerImpl;
  90. import org.mobicents.slee.resource.diameter.base.events.ExtensionDiameterMessageImpl;
  91. import org.mobicents.slee.resource.diameter.base.handlers.DiameterRAInterface;
  92. import org.mobicents.slee.resource.diameter.cca.events.CreditControlAnswerImpl;
  93. import org.mobicents.slee.resource.diameter.cca.events.CreditControlRequestImpl;
  94. import org.mobicents.slee.resource.diameter.cca.handlers.CreditControlSessionFactory;
  95. /**
  96. * Mobicents Diameter Credit-Control Application Resource Adaptor.
  97. *
  98. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  99. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  100. */
  101. public class DiameterCCAResourceAdaptor implements ResourceAdaptor, DiameterListener,DiameterRAInterface, FaultTolerantResourceAdaptor<String, DiameterActivity> {
  102. private static final long serialVersionUID = 1L;
  103. // Config Properties Names ---------------------------------------------
  104. private static final String AUTH_APPLICATION_IDS = "authApplicationIds";
  105. private static final String DEFAULT_VALIDITY_TIME = "defaultValidityTime";
  106. private static final String DEFAULT_TX_TIMER_VALUE = "defaultTxTimerValue";
  107. // Config Properties Values --------------------------------------------
  108. private List<ApplicationId> authApplicationIds;
  109. // Validity and TxTimer values (in seconds)
  110. protected long defaultValidityTime = 30;
  111. protected long defaultTxTimerValue = 10;
  112. /**
  113. * caches the eventIDs, avoiding lookup in container
  114. */
  115. public final EventIDCache eventIdCache = new EventIDCache();
  116. /**
  117. * tells the RA if an event with a specified ID should be filtered or not
  118. */
  119. private final EventIDFilter eventIDFilter = new EventIDFilter();
  120. /**
  121. * The ResourceAdaptorContext interface is implemented by the SLEE. It provides the Resource
  122. * Adaptor with the required capabilities in the SLEE to execute its work. The ResourceAdaptorCon-
  123. * text object holds references to a number of objects that are of interest to many Resource Adaptors. A
  124. * resource adaptor object is provided with a ResourceAdaptorContext object when the setResour-
  125. * ceAdaptorContext method of the ResourceAdaptor interface is invoked on the resource adaptor
  126. * object.
  127. */
  128. private ResourceAdaptorContext raContext;
  129. /**
  130. * FT/HA version of RA context.
  131. */
  132. private FaultTolerantResourceAdaptorContext<String, DiameterActivity> ftRAContext;
  133. /**
  134. * The SLEE endpoint defines the contract between the SLEE and the resource
  135. * adaptor that enables the resource adaptor to deliver events
  136. * asynchronously to SLEE endpoints residing in the SLEE. This contract
  137. * serves as a generic contract that allows a wide range of resources to be
  138. * plugged into a SLEE environment via the resource adaptor architecture.
  139. * For further information see JSLEE v1.1 Specification Page 307 The
  140. * sleeEndpoint will be initialized in entityCreated() method.
  141. */
  142. private transient SleeEndpoint sleeEndpoint = null;
  143. /**
  144. * A tracer is represented in the SLEE by the Tracer interface. Notification sources access the Tracer Facil-
  145. * ity through a Tracer object that implements the Tracer interface. A Tracer object can be obtained by
  146. * SBBs via the SbbContext interface, by resource adaptor entities via the ResourceAdaptorContext
  147. * interface, and by profiles via the ProfileContext interface.
  148. */
  149. private Tracer tracer;
  150. // Diameter Specific Properties ----------------------------------------
  151. private Stack stack;
  152. private SessionFactory sessionFactory = null;
  153. private long messageTimeout = 5000;
  154. private long activityRemoveDelay = 30000;
  155. private ObjectName diameterMultiplexerObjectName = null;
  156. private DiameterStackMultiplexerMBean diameterMux = null;
  157. private DiameterAvpFactory baseAvpFactory = null;
  158. private CreditControlAVPFactory ccaAvpFactory = null;
  159. private DiameterMessageFactory baseMessageFactory = null;
  160. private CreditControlMessageFactory ccaMessageFactory = null;
  161. protected CreditControlSessionFactory ccaSessionFactory = null;
  162. protected DiameterBaseMarshaler marshaler = new DiameterBaseMarshaler();
  163. /**
  164. * The EventLookupFacility is used to look up the event id of incoming events
  165. */
  166. private transient EventLookupFacility eventLookup = null;
  167. /**
  168. * The list of activities stored in this resource adaptor. If this resource
  169. * adaptor were a distributed and highly available solution, this storage
  170. * were one of the candidates for distribution.
  171. */
  172. //private transient ConcurrentHashMap<ActivityHandle, DiameterActivity> activities = null;
  173. private DiameterActivityManagement activities;
  174. /**
  175. * A link to the CreditControlProvider which then will be exposed to Sbbs
  176. */
  177. protected transient CreditControlProviderImpl raProvider = null;
  178. /**
  179. * for all events we are interested in knowing when the event failed to be processed
  180. */
  181. private static final int EVENT_FLAGS = getEventFlags();
  182. private static int getEventFlags() {
  183. int eventFlags = EventFlags.REQUEST_EVENT_UNREFERENCED_CALLBACK;
  184. eventFlags = EventFlags.setRequestProcessingFailedCallback(eventFlags);
  185. eventFlags = EventFlags.setRequestProcessingSuccessfulCallback(eventFlags);
  186. return eventFlags;
  187. }
  188. private static final int DEFAULT_ACTIVITY_FLAGS = ActivityFlags.REQUEST_ENDED_CALLBACK;
  189. private static final int MARSHALABLE_ACTIVITY_FLAGS = ActivityFlags.setSleeMayMarshal(DEFAULT_ACTIVITY_FLAGS);
  190. // Aux vars ------------------------------------------------------------
  191. private static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{};
  192. private static final String[] EMPTY_STRING_ARRAY = new String[]{};
  193. public DiameterCCAResourceAdaptor() {
  194. // TODO: Initialize any default values.
  195. }
  196. // Lifecycle methods ---------------------------------------------------
  197. public void setResourceAdaptorContext(ResourceAdaptorContext context) {
  198. this.raContext = context;
  199. this.tracer = context.getTracer("DiameterCCAResourceAdaptor");
  200. this.sleeEndpoint = context.getSleeEndpoint();
  201. this.eventLookup = context.getEventLookupFacility();
  202. this.raProvider = new CreditControlProviderImpl(this);
  203. }
  204. public void unsetResourceAdaptorContext() {
  205. this.raContext = null;
  206. this.tracer = null;
  207. this.sleeEndpoint = null;
  208. this.eventLookup = null;
  209. }
  210. // FT Lifecycle methods -----------------------------------------------------
  211. /*
  212. * (non-Javadoc)
  213. * @see org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor#setFaultTolerantResourceAdaptorContext
  214. * (org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptorContext)
  215. */
  216. public void setFaultTolerantResourceAdaptorContext(FaultTolerantResourceAdaptorContext<String, DiameterActivity> ctx) {
  217. this.ftRAContext = ctx;
  218. }
  219. /*
  220. * (non-Javadoc)
  221. * @see org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor#unsetFaultTolerantResourceAdaptorContext()
  222. */
  223. public void unsetFaultTolerantResourceAdaptorContext() {
  224. this.ftRAContext = null;
  225. //clear this.activities ??
  226. }
  227. // FT methods ---------------------------------------------------------------
  228. /*
  229. * (non-Javadoc)
  230. * @see org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor#dataRemoved(java.io.Serializable)
  231. */
  232. public void dataRemoved(String arg0) {
  233. this.activities.remove(getActivityHandle(arg0));
  234. }
  235. /* (non-Javadoc)
  236. * @see org.mobicents.slee.resource.cluster.FaultTolerantResourceAdaptor#failOver(java.io.Serializable)
  237. */
  238. public void failOver(String arg0) {
  239. throw new UnsupportedOperationException();
  240. }
  241. // Lifecycle again
  242. public void raActive() {
  243. if(tracer.isFineEnabled()) {
  244. tracer.fine("Diameter CCA RA :: raActive.");
  245. }
  246. try {
  247. if(tracer.isInfoEnabled()) {
  248. tracer.info("Activating Diameter CCA RA Entity");
  249. }
  250. this.diameterMultiplexerObjectName = new ObjectName("diameter.mobicents:service=DiameterStackMultiplexer");
  251. Object object = MBeanServerLocator.locateJBoss().invoke(this.diameterMultiplexerObjectName, "getMultiplexerMBean", EMPTY_OBJECT_ARRAY, EMPTY_STRING_ARRAY);
  252. if(object instanceof DiameterStackMultiplexerMBean) {
  253. this.diameterMux = (DiameterStackMultiplexerMBean) object;
  254. }
  255. // Initialize stack
  256. initStack();
  257. // Initialize activities mgmt
  258. initActivitiesMgmt();
  259. // Initialize factories
  260. this.baseAvpFactory = new DiameterAvpFactoryImpl();
  261. this.ccaAvpFactory = new CreditControlAVPFactoryImpl(baseAvpFactory);
  262. this.baseMessageFactory = new DiameterMessageFactoryImpl(stack);
  263. this.ccaMessageFactory = new CreditControlMessageFactoryImpl(baseMessageFactory, null, stack, ccaAvpFactory);
  264. // Setup session factories
  265. this.sessionFactory = this.stack.getSessionFactory();
  266. this.ccaSessionFactory = new CreditControlSessionFactory(sessionFactory, this, defaultDirectDebitingFailureHandling, defaultCreditControlFailureHandling, defaultValidityTime, defaultTxTimerValue);
  267. // Register CCA App Session Factories
  268. ((ISessionFactory) sessionFactory).registerAppFacory(ServerCCASession.class, this.ccaSessionFactory);
  269. ((ISessionFactory) sessionFactory).registerAppFacory(ClientCCASession.class, this.ccaSessionFactory);
  270. }
  271. catch (Exception e) {
  272. tracer.severe("Error Activating Diameter CCA RA Entity", e);
  273. throw new RuntimeException(e);//??
  274. }
  275. }
  276. public void raStopping() {
  277. if(tracer.isFineEnabled()) {
  278. tracer.fine("Diameter CCA RA :: raStopping.");
  279. }
  280. try {
  281. diameterMux.unregisterListener(this);
  282. }
  283. catch (Exception e) {
  284. tracer.severe("Failed to unregister CCA RA from Diameter Mux.", e);
  285. }
  286. //synchronized (this.activities) {
  287. // for (ActivityHandle activityHandle : activities.keySet()) {
  288. // try {
  289. // if(tracer.isInfoEnabled()) {
  290. // tracer.info("Ending activity [" + activityHandle + "]");
  291. // }
  292. //
  293. // activities.get(activityHandle).endActivity();
  294. // }
  295. // catch (Exception e) {
  296. // tracer.severe("Error Deactivating Activity", e);
  297. // }
  298. // }
  299. //}
  300. if(tracer.isFineEnabled()) {
  301. tracer.fine("Diameter CCA RA :: entityDeactivating completed.");
  302. }
  303. }
  304. public void raInactive() {
  305. if(tracer.isFineEnabled()) {
  306. tracer.fine("Diameter CCA RA :: entityDeactivated.");
  307. }
  308. //synchronized (this.activities) {
  309. // activities.clear();
  310. //}
  311. activities = null;
  312. if(tracer.isInfoEnabled()) {
  313. tracer.info("Diameter CCA RA :: INACTIVE completed.");
  314. }
  315. }
  316. public void raConfigure(ConfigProperties properties) {
  317. if (tracer.isFineEnabled()) {
  318. tracer.fine("Diameter CCA RA :: raConfigure");
  319. }
  320. parseApplicationIds((String) properties.getProperty(AUTH_APPLICATION_IDS).getValue());
  321. Property dvtProp = properties.getProperty(DEFAULT_VALIDITY_TIME);
  322. defaultValidityTime = (Long) (dvtProp != null ? dvtProp.getValue() : defaultValidityTime);
  323. Property dttProp = properties.getProperty(DEFAULT_TX_TIMER_VALUE);
  324. defaultTxTimerValue = (Long) (dttProp != null ? dttProp.getValue() : defaultTxTimerValue);
  325. if(tracer.isInfoEnabled()) {
  326. tracer.info("Resource Adaptor Configured. Supported Applications: " + authApplicationIds);
  327. }
  328. }
  329. private void parseApplicationIds(String appIdsStr) {
  330. if(appIdsStr != null) {
  331. appIdsStr = appIdsStr.replaceAll(" ", "");
  332. String[] appIdsStrings = appIdsStr.split(",");
  333. authApplicationIds = new ArrayList<ApplicationId>();
  334. for(String appId : appIdsStrings) {
  335. String[] vendorAndAppId = appId.split(":");
  336. authApplicationIds.add(ApplicationId.createByAuthAppId(Long.valueOf(vendorAndAppId[0]), Long.valueOf(vendorAndAppId[1])));
  337. }
  338. }
  339. }
  340. public void raUnconfigure() {
  341. // Clean up!
  342. this.activities = null;
  343. this.raContext = null;
  344. this.eventLookup = null;
  345. this.raProvider = null;
  346. this.sleeEndpoint = null;
  347. this.stack = null;
  348. }
  349. // Configuration management methods ------------------------------------
  350. public void raVerifyConfiguration(ConfigProperties properties) throws InvalidConfigurationException {
  351. // TODO Auto-generated method stub
  352. }
  353. public void raConfigurationUpdate(ConfigProperties properties) {
  354. // this ra does not support config update while entity is active
  355. }
  356. // Interface access methods --------------------------------------------
  357. public Object getResourceAdaptorInterface(String className) {
  358. // this ra implements a single ra type
  359. return raProvider;
  360. }
  361. /*
  362. * (non-Javadoc)
  363. * @see javax.slee.resource.ResourceAdaptor#getMarshaler()
  364. */
  365. public Marshaler getMarshaler() {
  366. return marshaler;
  367. }
  368. // Event filtering methods ---------------------------------------------
  369. public void serviceActive(ReceivableService serviceInfo) {
  370. eventIDFilter.serviceActive(serviceInfo);
  371. }
  372. public void serviceStopping(ReceivableService serviceInfo) {
  373. eventIDFilter.serviceStopping(serviceInfo);
  374. }
  375. public void serviceInactive(ReceivableService serviceInfo) {
  376. eventIDFilter.serviceInactive(serviceInfo);
  377. }
  378. // Mandatory callback methods ------------------------------------------
  379. public void queryLiveness(ActivityHandle handle) {
  380. tracer.info("Diameter CCA RA :: queryLiveness :: handle[" + handle + "].");
  381. if(!(handle instanceof DiameterActivityHandle)) {
  382. return;
  383. }
  384. DiameterActivityImpl activity = (DiameterActivityImpl) activities.get((DiameterActivityHandle)handle);
  385. if (activity != null && !activity.isValid()) {
  386. try {
  387. sleeEndpoint.endActivity(handle);
  388. }
  389. catch (Exception e) {
  390. tracer.severe("Failure ending non-live activity.", e);
  391. }
  392. }
  393. }
  394. public Object getActivity(ActivityHandle handle) {
  395. if(tracer.isFineEnabled()) {
  396. tracer.fine("Diameter CCA RA :: getActivity :: handle[" + handle + "].");
  397. }
  398. if(!(handle instanceof DiameterActivityHandle)){
  399. return null;
  400. }
  401. return this.activities.get((DiameterActivityHandle)handle);
  402. }
  403. public ActivityHandle getActivityHandle(Object activity) {
  404. if(tracer.isFineEnabled()) {
  405. tracer.fine("Diameter CCA RA :: getActivityHandle :: activity[" + activity + "].");
  406. }
  407. if (!(activity instanceof DiameterActivity)) {
  408. return null;
  409. }
  410. DiameterActivityImpl inActivity = (DiameterActivityImpl) activity;
  411. return inActivity.getActivityHandle();
  412. }
  413. public void administrativeRemove(ActivityHandle handle) {
  414. // TODO what to do here?
  415. }
  416. // Optional callback methods -------------------------------------------
  417. public void eventProcessingFailed(ActivityHandle handle, FireableEventType eventType, Object event, Address address, ReceivableService service, int flags, FailureReason reason) {
  418. if(tracer.isFineEnabled()) {
  419. tracer.fine("Diameter CCA RA :: eventProcessingFailed :: handle[" + handle + "], eventType[" + eventType + "], event[" + event + "], address[" + address + "], flags[" + flags + "], reason[" + reason + "].");
  420. }
  421. if(!(handle instanceof DiameterActivityHandle)) {
  422. return;
  423. }
  424. processAfterEventDelivery(handle, eventType, event, address, service, flags);
  425. }
  426. public void eventProcessingSuccessful(ActivityHandle handle, FireableEventType eventType, Object event, Address address, ReceivableService service, int flags) {
  427. if(tracer.isFineEnabled()) {
  428. tracer.fine("Diameter CCA RA :: eventProcessingSuccessful :: handle[" + handle + "], eventType[" + eventType + "], event[" + event + "], address[" + address + "], flags[" + flags + "].");
  429. }
  430. if(!(handle instanceof DiameterActivityHandle)) {
  431. return;
  432. }
  433. processAfterEventDelivery(handle, eventType, event, address, service, flags);
  434. }
  435. public void eventUnreferenced(ActivityHandle handle, FireableEventType eventType, Object event, Address address, ReceivableService service, int flags) {
  436. if(tracer.isFineEnabled()) {
  437. tracer.fine("Diameter CCA RA :: eventUnreferenced :: handle[" + handle + "], eventType[" + eventType + "], event[" + event + "], address[" + address + "], service[" + service + "], flags[" + flags + "].");
  438. }
  439. if(!(handle instanceof DiameterActivityHandle)) {
  440. return;
  441. }
  442. processAfterEventDelivery(handle, eventType, event, address, service, flags);
  443. }
  444. private void processAfterEventDelivery(ActivityHandle handle, FireableEventType eventType, Object event, Address address, ReceivableService service, int flags) {
  445. DiameterActivityImpl activity = (DiameterActivityImpl) getActivity(handle);
  446. if (activity != null) {
  447. synchronized (activity) {
  448. if (activity.isTerminateAfterProcessing()) {
  449. activity.endActivity();
  450. }
  451. }
  452. }
  453. }
  454. public void activityEnded(ActivityHandle handle) {
  455. if(tracer.isFineEnabled()) {
  456. tracer.fine("Diameter CCA RA :: activityEnded :: handle[" + handle + ".");
  457. }
  458. if(!(handle instanceof DiameterActivityHandle)){
  459. return;
  460. }
  461. if(this.activities != null) {
  462. synchronized (this.activities) {
  463. this.activities.remove((DiameterActivityHandle)handle);
  464. }
  465. }
  466. }
  467. public void activityUnreferenced(ActivityHandle handle) {
  468. if(tracer.isFineEnabled()) {
  469. tracer.fine("Diameter CCA RA :: activityUnreferenced :: handle[" + handle + "].");
  470. }
  471. if(!(handle instanceof DiameterActivityHandle)){
  472. return;
  473. }
  474. this.activityEnded(handle);
  475. }
  476. // Event and Activities management -------------------------------------
  477. public boolean fireEvent(Object event, ActivityHandle handle, FireableEventType eventID, Address address, boolean useFiltering, boolean transacted) {
  478. if (useFiltering && eventIDFilter.filterEvent(eventID)) {
  479. if (tracer.isFineEnabled()) {
  480. tracer.fine("Event " + eventID + " filtered");
  481. }
  482. }
  483. else if (eventID == null) {
  484. tracer.severe("Event ID for " + eventID + " is unknown, unable to fire.");
  485. }
  486. else {
  487. if (tracer.isFineEnabled()) {
  488. tracer.fine("Firing event " + event + " on handle " + handle);
  489. }
  490. try {
  491. Object o = getActivity(handle);
  492. if(o == null) {
  493. Transaction t = raContext.getSleeTransactionManager().getTransaction();
  494. throw new IllegalStateException("TX[ "+t+" ] No activity for handle: "+handle);
  495. }
  496. if(o instanceof CreditControlServerSessionImpl && event instanceof CreditControlRequest) {
  497. ((CreditControlServerSessionImpl)o).fetchCurrentState((CreditControlRequest)event);
  498. }
  499. this.raContext.getSleeEndpoint().fireEvent(handle, eventID, event, address, null, EVENT_FLAGS);
  500. return true;
  501. }
  502. catch (Exception e) {
  503. tracer.severe("Error firing event.", e);
  504. }
  505. }
  506. return false;
  507. }
  508. public void fireEvent(String sessionId, Message message) {
  509. DiameterMessage event = (DiameterMessage) createEvent(message);
  510. FireableEventType eventId = eventIdCache.getEventId(eventLookup, message);
  511. this.fireEvent(event, getActivityHandle(sessionId), eventId, null, true, message.isRequest());
  512. }
  513. /**
  514. * {@inheritDoc}
  515. */
  516. @Override
  517. public void endActivity(DiameterActivityHandle handle) {
  518. sleeEndpoint.endActivity(handle);
  519. }
  520. /**
  521. * {@inheritDoc}
  522. */
  523. @Override
  524. public void startActivityRemoveTimer(DiameterActivityHandle handle) {
  525. this.activities.startActivityRemoveTimer(handle);
  526. }
  527. /**
  528. * {@inheritDoc}
  529. */
  530. @Override
  531. public void stopActivityRemoveTimer(DiameterActivityHandle handle) {
  532. this.activities.stopActivityRemoveTimer(handle);
  533. }
  534. /**
  535. * {@inheritDoc}
  536. */
  537. @Override
  538. public void update(DiameterActivityHandle handle, DiameterActivity activity) {
  539. activities.update(handle, activity);
  540. }
  541. @Override
  542. public ApplicationId[] getSupportedApplications() {
  543. // not used
  544. return null;
  545. }
  546. /**
  547. * Create Event object from a JDiameter message (request or answer)
  548. *
  549. * @return a DiameterMessage object wrapping the request/answer
  550. */
  551. private DiameterMessage createEvent(Message message) {
  552. if (message == null) {
  553. throw new NullPointerException("Message argument cannot be null while creating event.");
  554. }
  555. if (message.isError()) {
  556. return new ErrorAnswerImpl(message);
  557. }
  558. switch (message.getCommandCode()) {
  559. case CreditControlMessage.commandCode: // CCR/CCA
  560. return message.isRequest() ? new CreditControlRequestImpl(message) : new CreditControlAnswerImpl(message);
  561. default:
  562. return new ExtensionDiameterMessageImpl(message);
  563. }
  564. }
  565. // Session Management --------------------------------------------------
  566. /**
  567. * Method for performing tasks when activity is created, such as informing SLEE about it and storing into internal map.
  568. *
  569. * @param ac the activity that has been created
  570. */
  571. private void activityCreated(DiameterActivity ac, boolean suspended) {
  572. try {
  573. // Inform SLEE that Activity Started
  574. DiameterActivityImpl activity = (DiameterActivityImpl) ac;
  575. if (suspended) {
  576. sleeEndpoint.startActivitySuspended(activity.getActivityHandle(), activity, MARSHALABLE_ACTIVITY_FLAGS);
  577. }
  578. else {
  579. sleeEndpoint.startActivity(activity.getActivityHandle(), activity, MARSHALABLE_ACTIVITY_FLAGS);
  580. }
  581. // Put it into our activites map
  582. activities.put(activity.getActivityHandle(), activity);
  583. if(tracer.isInfoEnabled()) {
  584. tracer.info("Activity started [" + activity.getActivityHandle() + "]");
  585. }
  586. }
  587. catch (Exception e) {
  588. tracer.severe("Error creating/starting activity.", e);
  589. }
  590. }
  591. // Others --------------------------------------------------------------
  592. /**
  593. * Retrieves the RA context
  594. */
  595. public ResourceAdaptorContext getRaContext() {
  596. return raContext;
  597. }
  598. // Private Methods -----------------------------------------------------
  599. /**
  600. * Initializes the RA Diameter Stack.
  601. *
  602. * @throws Exception
  603. */
  604. private synchronized void initStack() throws Exception {
  605. // Register in the Mux as app listener.
  606. this.diameterMux.registerListener(this, (ApplicationId[]) authApplicationIds.toArray(new ApplicationId[authApplicationIds.size()]));
  607. // Get the stack (should not mess with)
  608. this.stack = this.diameterMux.getStack();
  609. this.messageTimeout = this.stack.getMetaData().getConfiguration().getLongValue(MessageTimeOut.ordinal(), (Long) MessageTimeOut.defValue());
  610. if(tracer.isInfoEnabled()) {
  611. tracer.info("Diameter CCA RA :: Successfully initialized stack.");
  612. }
  613. }
  614. private void initActivitiesMgmt() {
  615. final DiameterRAInterface lst = this;
  616. if (this.ftRAContext.isLocal()) {
  617. // local mgmt;
  618. if(tracer.isInfoEnabled()) {
  619. tracer.info(raContext.getEntityName() + " -- running in local mode.");
  620. }
  621. this.activities = new LocalDiameterActivityManagement(this.raContext, activityRemoveDelay);
  622. }
  623. else {
  624. if(tracer.isInfoEnabled()) {
  625. tracer.info(raContext.getEntityName() + " -- running in cluster mode.");
  626. }
  627. final org.mobicents.slee.resource.cluster.ReplicatedData<String, DiameterActivity> clusteredData = this.ftRAContext.getReplicateData(true);
  628. // get special one
  629. this.activities = new AbstractClusteredDiameterActivityManagement(this.ftRAContext, activityRemoveDelay,this.raContext.getTracer(""), stack, this.raContext.getSleeTransactionManager(), clusteredData) {
  630. @Override
  631. protected void performBeforeReturn(DiameterActivityImpl activity) {
  632. // do all the dirty work;
  633. try {
  634. Session session = null;
  635. if (activity.getClass().equals(DiameterActivityImpl.class)) {
  636. // check as first. since it requires session recreation.
  637. session = this.diameterStack.getSessionFactory().getNewSession(activity.getSessionId());
  638. performBeforeReturnOnBase(activity, session);
  639. return;
  640. }
  641. else if (activity instanceof CreditControlClientSession) {
  642. CreditControlClientSessionImpl acc = (CreditControlClientSessionImpl) activity;
  643. ClientCCASession appSession = this.diameterStack.getSession(activity.getSessionId(), ClientCCASession.class);
  644. session = appSession.getSessions().get(0);
  645. performBeforeReturnOnBase(activity, session);
  646. performBeforeReturnCC(activity, session);
  647. acc.setSession(appSession);
  648. }
  649. else if (activity instanceof CreditControlServerSession) {
  650. CreditControlServerSessionImpl acc = (CreditControlServerSessionImpl) activity;
  651. ServerCCASession appSession = this.diameterStack.getSession(activity.getSessionId(), ServerCCASession.class);
  652. session = appSession.getSessions().get(0);
  653. performBeforeReturnOnBase(activity, session);
  654. performBeforeReturnCC(activity, session);
  655. acc.setSession(appSession);
  656. }
  657. else {
  658. throw new IllegalArgumentException("Unknown activity type: " + activity);
  659. }
  660. }
  661. catch (Exception e) {
  662. throw new DiameterException(e);
  663. }
  664. }
  665. private void performBeforeReturnOnBase(DiameterActivityImpl ac, Session session) {
  666. DiameterMessageFactoryImpl msgFactory = new DiameterMessageFactoryImpl(session, stack, new DiameterIdentity[] {});
  667. ac.setAvpFactory(baseAvpFactory);
  668. ac.setMessageFactory(msgFactory);
  669. ac.setCurrentWorkingSession(session);
  670. ac.setSessionListener(lst);
  671. }
  672. private void performBeforeReturnCC(DiameterActivityImpl ac, Session session) {
  673. CreditControlSessionImpl ccs = (CreditControlSessionImpl) ac;
  674. ccs.setCCAAvpFactory(ccaAvpFactory);
  675. ccs.setCCAMessageFactory(ccaMessageFactory);
  676. }
  677. @Override
  678. public DiameterActivity get(DiameterActivityHandle handle) {
  679. return super.get(handle);
  680. }
  681. @Override
  682. public void put(DiameterActivityHandle handle, DiameterActivity activity) {
  683. super.put(handle, activity);
  684. }
  685. @Override
  686. public DiameterActivity remove(DiameterActivityHandle handle) {
  687. return super.remove(handle);
  688. }
  689. };
  690. }
  691. }
  692. /**
  693. * Create the Diameter Activity Handle for an given session id
  694. *
  695. * @param sessionId the session identifier to create the activity handle from
  696. * @return a DiameterActivityHandle for the provided sessionId
  697. */
  698. protected DiameterActivityHandle getActivityHandle(String sessionId) {
  699. return new DiameterActivityHandle(sessionId);
  700. }
  701. // NetworkReqListener Implementation -----------------------------------
  702. public Answer processRequest(Request request) {
  703. // Here we receive initial request for which session does not exist!
  704. // Valid messages are:
  705. // * CCR - if we act as server, this is the message we receive
  706. // * NO other message should make it here, if it gets its an error ?
  707. //FIXME: baranowb: check if ACR is vald here also
  708. if(request.getCommandCode() == CreditControlRequest.commandCode) {
  709. DiameterActivity activity;
  710. try {
  711. activity = raProvider.createActivity(request);
  712. if(activity == null) {
  713. tracer.severe("Diameter CCA RA :: Failed to create session, Command-Code: " + request.getCommandCode() + ", Session-Id: " + request.getSessionId());
  714. }
  715. else {
  716. // We can only have server session?, but for sake error catching
  717. if(activity instanceof CreditControlServerSession) {
  718. CreditControlServerSessionImpl session = (CreditControlServerSessionImpl) activity;
  719. ((ServerCCASessionImpl)session.getSession()).processRequest(request);
  720. }
  721. }
  722. }
  723. catch (CreateActivityException e) {
  724. tracer.severe("Failure trying to create CCA Activity.", e);
  725. }
  726. }
  727. else {
  728. tracer.severe("Diameter CCA RA :: Received unexpected Request. Either its not CCR or session should exist to handle this, Command-Code: "+request.getCommandCode()+", Session-Id: "+request.getSessionId());
  729. }
  730. // Returning null so we can answer later
  731. return null;
  732. }
  733. public void receivedSuccessMessage(Request request, Answer answer) {
  734. // No answer should make it here, session should exist. It's an error, report it.
  735. tracer.severe("Diameter CCA RA :: Received unexpected Answer - RA should not get this, session should exist to handle it. Command-Code: " + answer.getCommandCode() + ", Session-Id: " + answer.getSessionId());
  736. }
  737. public void timeoutExpired(Request request) {
  738. // No timeout should make it here, session should exist. It's an error, report it.
  739. tracer.severe("Diameter CCA RA :: Received Timeout Message - RA should not get this, session should exist to handle it. Command-Code: " + request.getCommandCode() + ", Session-Id: " + request.getSessionId());
  740. }
  741. // CCA Session Creation Listener --------------------------------------
  742. private void sessionCreated(ClientCCASession ccClientSession) {
  743. // Make sure it's a new session and there's no activity created yet.
  744. if(this.getActivity(getActivityHandle(ccClientSession.getSessions().get(0).getSessionId())) != null) {
  745. tracer.warning( "Activity found for created Credit-Control Client Session. Shouldn't exist. Aborting." );
  746. return;
  747. }
  748. // Get Message Factories (for Base and CCA)
  749. DiameterMessageFactoryImpl baseMsgFactory = new DiameterMessageFactoryImpl(ccClientSession.getSessions().get(0),this.stack);
  750. CreditControlMessageFactory ccaMsgFactory = new CreditControlMessageFactoryImpl(baseMsgFactory, ccClientSession.getSessions().get(0), this.stack, this.ccaAvpFactory);
  751. // Create Client Activity
  752. CreditControlClientSessionImpl activity = new CreditControlClientSessionImpl(ccaMsgFactory, this.ccaAvpFactory, ccClientSession, null, null);
  753. //session.addStateChangeNotification(activity);
  754. activity.setSessionListener(this);
  755. activityCreated(activity, false /*true*/);
  756. }
  757. private void sessionCreated(ServerCCASession ccServerSession) {
  758. // Make sure it's a new session and there's no activity created yet.
  759. if(this.getActivity(getActivityHandle(ccServerSession.getSessions().get(0).getSessionId())) != null) {
  760. tracer.warning( "Activity found for created Credit-Control Server Session. Shouldn't exist. Aborting." );
  761. return;
  762. }
  763. // Get Message Factories (for Base and CCA)
  764. DiameterMessageFactoryImpl baseMsgFactory = new DiameterMessageFactoryImpl(ccServerSession.getSessions().get(0),this.stack);
  765. CreditControlMessageFactory ccaMsgFactory = new CreditControlMessageFactoryImpl(baseMsgFactory, ccServerSession.getSessions().get(0), this.stack, this.ccaAvpFactory);
  766. // Create Server Activity
  767. CreditControlServerSessionImpl activity = new CreditControlServerSessionImpl(ccaMsgFactory,this.ccaAvpFactory,ccServerSession,null,null);
  768. activity.setSessionListener(this);
  769. activityCreated(activity, false);
  770. }
  771. // Credit Control Provider Implementation ------------------------------------
  772. private class CreditControlProviderImpl implements CreditControlProvider {
  773. protected DiameterCCAResourceAdaptor ra = null;
  774. protected Validator validator = new ValidatorImpl();
  775. public CreditControlProviderImpl(DiameterCCAResourceAdaptor ra) {
  776. super();
  777. this.ra = ra;
  778. }
  779. public CreditControlClientSession createClientSession() throws CreateActivityException {
  780. Transaction suspended = null;
  781. try {
  782. //SUSPEND tx, in case of call from SBB it will be tx calls, meaning activity wont be visible until
  783. //this tx ends. can cause "no activity" in ra fire!
  784. if(raContext.getSleeTransactionManager().getTransaction() != null) {
  785. suspended = raContext.getSleeTransactionManager().suspend();
  786. }
  787. ClientCCASession session = ((ISessionFactory) stack.getSessionFactory()).getNewAppSession(null, ApplicationId.createByAuthAppId(CreditControlMessageFactory._CCA_VENDOR, CreditControlMessageFactory._CCA_AUTH_APP_ID), ClientCCASession.class, new Object[]{});
  788. if (session == null) {
  789. tracer.severe("Failure creating CCA Client Session (null).");
  790. return null;
  791. }
  792. sessionCreated(session);
  793. return (CreditControlClientSession) getActivity(getActivityHandle(session.getSessions().get(0).getSessionId()));
  794. }
  795. catch (Exception e) {
  796. throw new CreateActivityException(e);
  797. }
  798. finally {
  799. if(suspended != null) {
  800. try {
  801. raContext.getSleeTransactionManager().resume(suspended);
  802. }
  803. catch (InvalidTransactionException e) {
  804. tracer.severe("Error resuming transaction (" + suspended + ").", e);
  805. }
  806. catch (IllegalStateException e) {
  807. tracer.severe("Error resuming transaction (" + suspended + ").", e);
  808. }
  809. catch (SystemException e) {
  810. tracer.severe("Error resuming transaction (" + suspended + ").", e);
  811. }
  812. }
  813. }
  814. }
  815. //This method should be called only for CCR
  816. protected DiameterActivity createActivity(Request request) throws CreateActivityException {
  817. try {
  818. List<ApplicationId> appIds = request.getApplicationIdAvps();
  819. if(appIds == null || appIds.size() == 0) {
  820. throw new CreateActivityException("No App ids present in message");
  821. }
  822. ISessionFactory fct = ((ISessionFactory) stack.getSessionFactory());
  823. ServerCCASession session = fct.getNewAppSession(request.getSessionId(), ApplicationId.createByAuthAppId(CreditControlMessageFactory._CCA_VENDOR, CreditControlMessageFactory._CCA_AUTH_APP_ID), ServerCCASession.class, new Object[]{});
  824. if (session == null) {
  825. tracer.severe("Failure creating CCA Server Session (null).");
  826. return null;
  827. }
  828. sessionCreated(session);
  829. return (DiameterActivity) getActivity(getActivityHandle(session.getSessions().get(0).getSessionId()));
  830. }
  831. catch (Exception e) {
  832. throw new CreateActivityException(e);
  833. }
  834. }
  835. public CreditControlClientSession createClientSession(DiameterIdentity destinationHost, DiameterIdentity destinationRealm) throws CreateActivityException {
  836. CreditControlClientSessionImpl clientSession=(CreditControlClientSessionImpl) this.createClientSession();
  837. clientSession.setDestinationHost(destinationHost);
  838. clientSession.setDestinationRealm(destinationRealm);
  839. return clientSession;
  840. }
  841. public CreditControlAVPFactory getCreditControlAVPFactory() {
  842. return ccaAvpFactory;
  843. }
  844. public CreditControlMessageFactory getCreditControlMessageFactory() {
  845. return ccaMessageFactory;
  846. }
  847. public DiameterIdentity[] getConnectedPeers() {
  848. if (ra.stack != null) {
  849. try {
  850. // Get the list of peers from the stack
  851. List<Peer> peers = ra.stack.unwrap(PeerTable.class).getPeerTable();
  852. DiameterIdentity[] result = new DiameterIdentity[peers.size()];
  853. int i = 0;
  854. // Get each peer from the list and make a DiameterIdentity
  855. for (Peer peer : peers) {
  856. DiameterIdentity identity = new DiameterIdentity(peer.getUri().toString());
  857. result[i++] = identity;
  858. }
  859. return result;
  860. }
  861. catch (Exception e) {
  862. tracer.severe("Failure getting peer list.", e);
  863. }
  864. }
  865. return null;
  866. }
  867. public int getPeerCount() {
  868. DiameterIdentity[] connectedPeers = getConnectedPeers();
  869. return connectedPeers != null ? getConnectedPeers().length : -1;
  870. }
  871. /* (non-Javadoc)
  872. * @see net.java.slee.resource.diameter.cca.CreditControlProvider#getValidator()
  873. */
  874. @Override
  875. public Validator getValidator() {
  876. return this.validator;
  877. }
  878. }
  879. // Provisioning --------------------------------------------------------
  880. protected int defaultDirectDebitingFailureHandling = 0;
  881. protected int defaultCreditControlFailureHandling = 0;
  882. //////////////////////////
  883. // Provisioning Methods //
  884. //////////////////////////
  885. public long getMessageTimeout() {
  886. return messageTimeout;
  887. }
  888. public void setMessageTimeout(long messageTimeout) {
  889. this.messageTimeout = messageTimeout;
  890. }
  891. public int getDefaultDirectDebitingFailureHandling() {
  892. return defaultDirectDebitingFailureHandling;
  893. }
  894. public void setDefaultDirectDebitingFailureHandling(int defaultDirectDebitingFailureHandling) {
  895. this.defaultDirectDebitingFailureHandling = defaultDirectDebitingFailureHandling;
  896. }
  897. public int getDefaultCreditControlFailureHandling() {
  898. return defaultCreditControlFailureHandling;
  899. }
  900. public void setDefaultCreditControlFailureHandling(int defaultCreditControlFailureHandling) {
  901. this.defaultCreditControlFailureHandling = defaultCreditControlFailureHandling;
  902. }
  903. public long getDefaultValidityTime() {
  904. return defaultValidityTime;
  905. }
  906. public void setDefaultValidityTime(long defaultValidityTime) {
  907. this.defaultValidityTime = defaultValidityTime;
  908. }
  909. public long getDefaultTxTimerValue() {
  910. return defaultTxTimerValue;
  911. }
  912. public void setDefaultTxTimerValue(long defaultTxTimerValue) {
  913. this.defaultTxTimerValue = defaultTxTimerValue;
  914. }
  915. }