JBoss.orgCommunity Documentation
Diameter CCA Resource Adaptor Type is defined by Mobicents team as part of effort to standarize RA Types.
Diameter CCA Type 2.6.0-SNAPSHOT defines two types of activities:
This type of activity represents client side of credit control session. It is a source of answers to credit control requests issued with this activity. It is also source of re-authentication requests.
This activity type can be created with call to one of methods of CreditControlProvider. It ends once underlying credit control session ends. State machine for client credit control can be found here and here .
This type of activity represents server side of credit control session. It is source of credit control requests issued from client side and answers to re-auth requests.
This activity type is created explicitly for incoming requests by Resource Adaptor. It ends once underlying credit control session ends. State machine for server credit control can be found here and here
Both activities define methods required to properly function and expose necessary information to JSLEE services. Common part for each is defined as follows:
public CreditControlSessionState getState();
public String getSessionId();
public CreditControlAVPFactory getCCAAvpFactory();
public CreditControlMessageFactory getCCAMessageFactory();
returns current state of credit control session. State directly follows definition from credit control rfc .
returns session Id of underlying diameter session.
returns AVP factory capable of creating specifc AVPs for credit control. It also exposes means of accessing base AVP factory.
returns message factory capable of creating credit control messages. It also exposes means of accessing base factory.
Client type activity interface is defined as follows:
CreditControlRequest createCreditControlRequest();
void sendCreditControlRequest(CreditControlRequest ccr) throws IOException;
void sendInitialCreditControlRequest(CreditControlRequest ccr) throws IOException;
void sendReAuthAnswer(ReAuthAnswer rar) throws IOException;
void sendUpdateCreditControlRequest(CreditControlRequest ccr) throws IOException;
void sendTerminationCreditControlRequest(CreditControlRequest ccr) throws IOException;
Creates credit control request for this activity. Fills AVPs appropriate for this session..
sends credit control request, does not perform any other operations.
sends credit control request. Ensures that its initial request by setting proper AVP .
sends credit control request. Ensures that its update request by setting proper AVP .
sends credit control request. Ensures that its termination request by setting proper AVP .
sends re-authentication answer on this session.
Server type activity interface is defined as follows:
CreditControlAnswer createCreditControlAnswer();
void sendCreditControlAnswer(CreditControlAnswer cca) throws IOException;
void sendReAuthRequest(ReAuthRequest rar) throws IOException;
creates credit control answer for last received request.
sends credit control answer through this session.
sends re-authentication request through this session.
It is safe to type cast activities to interface defined in Base RA Type: net.java.slee.resource.diameter.base.DiameterActivity
Credit Control declares only two additional events, to those defined in Base RA Type, namely CreditControlAnswer and CreditControlRequest. However, it also reuses Base events.
Table 2.1. Events received on Server Activity
Name | Vendor | Version | Class |
---|---|---|---|
net.java.slee.resource. diameter.cca.events. CreditControlRequest | java.net | 0.8 | net.java.slee.resource. diameter.cca.events. CreditControlRequest |
net.java.slee.resource. diameter.base.events. ReAuthRequest | java.net | 0.8 | net.java.slee.resource. diameter.base.events. ReAuthRequest |
Table 2.2. Events received on Client Activity
Name | Vendor | Version | Class |
---|---|---|---|
net.java. slee.resource .diameter. cca.events. CreditControlAnswer | java.net | 0.8 | net.java. slee.resource .diameter .cca.events. CreditControlAnswer |
net.java. slee.resource .diameter. base.events. ReAuthAnswer | java.net | 0.8 | net.java. slee.resource .diameter .base.events. ReAuthAnswer |
Table 2.3. Events received on both activities
Name | Vendor | Version | Class |
---|---|---|---|
net.java.slee.resource. diameter.base.events. SessionTerminationRequest | java.net | 0.8 | net.java.slee.resource. diameter.base.events. SessionTerminationRequest |
net.java.slee.resource. diameter.base.events. SessionTerminationAnswer | java.net | 0.8 | net.java.slee.resource. diameter.base.events. SessionTerminationAnswer |
net.java.slee.resource. diameter.base.events. AbortSessionRequest | java.net | 0.8 | net.java.slee.resource. diameter.base.events. AbortSessionRequest |
net.java.slee.resource. diameter.base.events. AbortSessionAnswer | java.net | 0.8 | net.java.slee.resource. diameter.base.events. AbortSessionAnswer |
net.java.slee.resource. diameter.base.events. AccountingRequest | java.net | 0.8 | net.java.slee.resource. diameter.base.events. AccountingRequest |
net.java.slee.resource. diameter.base.events. AccountingAnswer | java.net | 0.8 | net.java.slee.resource. diameter.base.events. AccountingAnswer |
net.java.slee.resource. diameter.base.events. ErrorAnswer | java.net | 0.8 | net.java.slee.resource. diameter.base.events. ErrorAnswer |
net.java.slee.resource. diameter.base.events. ExtensionDiameterMessage | java.net | 0.8 | net.java.slee.resource. diameter.base.events. ExtensionDiameterMessage |
Spaces where introduced in Name
and Class
column values, to correctly render the table. Please remove them when using copy/paste.
Activity context interface factory is defined as follows:
package net.java.slee.resource.diameter.cca;
import javax.slee.ActivityContextInterface;
public interface CreditControlActivityContextInterfaceFactory {
public ActivityContextInterface getActivityContextInterface(CreditControlClientSession cccs);
public ActivityContextInterface getActivityContextInterface(CreditControlServerSession ccss);
}
Resource Adaptor SBB Interface provides SBBs with means of accessing RA objects required for interaction in DIAMETER world. It is defined as follows:
package net.java.slee.resource.diameter.cca;
import net.java.slee.resource.diameter.base.CreateActivityException;
import net.java.slee.resource.diameter.base.events.avp.DiameterIdentity;
public interface CreditControlProvider {
CreditControlClientSession createClientSession() throws CreateActivityException;
CreditControlClientSession createClientSession(DiameterIdentity destinationHost,
DiameterIdentity destinationRealm) throws CreateActivityException;
CreditControlMessageFactory getCreditControlMessageFactory();
CreditControlAVPFactory getCreditControlAVPFactory();
int getPeerCount();
DiameterIdentity[] getConnectedPeers();
}
Creates new client session. Its destination is unknown, its determined on send.
Creates new client session. Its destination is passed upon creation.
Retrieve default message factory.
Retrieve default AVP factory.
Get number of currently connected peers. This may change during runtime, depends on network situation.
Get currently connected peers. This may change during runtime, depends on network situation.
Simple client side requesting credits, with EVENT_TYPE credit control request:
private void doSendEventCCR(int currencyCode,int value) {
try {
//Create session.
CreditControlClientSession session = this.provider.createClientSession();
ActivityContextInterface localACI = this.acif.getActivityContextInterface(session);
localACI.attach(this.getSbbContext().getSbbLocalObject());
CreditControlRequest request = session.createCreditControlRequest();
List<DiameterAvp> avps = new ArrayList<DiameterAvp>();
avps.add(avpFactory.getBaseFactory().createAvp(Avp.ORIGIN_HOST,
("aaa://" + originIP + ":" + originPort).getBytes()));
avps.add(avpFactory.getBaseFactory().createAvp(Avp.ORIGIN_REALM,
originRealm.getBytes()));
//or dedicated:
//request.setDestinationHost(destinationHost);
//request.setDestinationRealm(destinationRealm);
avps.add(avpFactory.getBaseFactory().createAvp(Avp.DESTINATION_HOST,
("aaa://" + destinationIP + ":" + destinationPort).getBytes()));
avps.add(avpFactory.getBaseFactory().createAvp(Avp.DESTINATION_REALM,
destinationRealm.getBytes()));
//Event Type request has request type set to '4'
avps.add(avpFactory.getBaseFactory().createAvp(
CreditControlAVPCodes.CC_Request_Type, 4l));
avps.add(avpFactory.getBaseFactory().createAvp(
CreditControlAVPCodes.CC_Request_Number, 0l));
RequestedServiceUnitAvp rsu = this.avpFactory.createRequestedServiceUnit();
CcMoneyAvp ccMoney = this.avpFactory.createCcMoney();
ccMoney.setCurrencyCode(currencyCode);
UnitValueAvp unitValue = this.avpFactory.createUnitValue();
unitValue.setValueDigits(value);
ccMoney.setUnitValue(unitValue);
rsu.setCreditControlMoneyAvp(ccMoney);
avps.add(rsu);
avps.add(avpFactory.getBaseFactory().createAvp(
CreditControlAVPCodes.Requested_Action, 0));
//use extension avps to fill message or dedicated setters/getters
request.setExtensionAvps(avps.toArray(new DiameterAvp[avps.size()]));
// Now create and send
if (logger.isInfoEnabled())
logger.info("About to send:\n" + request);
session.sendCreditControlRequest(request);
} catch (Exception e) {
logger.error("Failed to create/send Credit-Control-Request.", e);
}
}
....
public void onCreditControlAnswer(CreditControlAnswer answer, ActivityContextInterface aci) {
logger.info("Received CCA with Result-Code[" + answer.getResultCode() + "].");
switch (answer.getCcRequestType().getValue()) {
case 1:
case 2:
case 3:
logger.error("Received 'session' credit control answer. Expecting EVENT_TYPE answer");
break;
case 4:
//result code 2xxx is success
if(answer.getResultCode()/1000 == 2 )
{
//assume msg is correct
GrantedServiceUnitAvp gsu = answer.getGrantedServiceUnit();
CcMoneyAvp money = gsu.getCreditControlMoneyAvp();
doSpendMoney(money);
}else
{
//error, this will pring formated msg dump.
logger.warn("Result of CC operation is a failure:\n"+answer);
}
break;
}
}
Server application to handle simple direct debiting:
public void onCreditControlRequest(CreditControlRequest request,
ActivityContextInterface aci) {
if (logger.isInfoEnabled())
logger.info("Received Credit-Control-Request (Application-Id[" + request.getHeader().getApplicationId() + "].");
// INITIAL_REQUEST(1), UPDATE_REQUEST(2), TERMINATION_REQUEST(3),
// EVENT_REQUEST(4)
CreditControlServerSession session = (CreditControlServerSession) aci.getActivity();
CreditControlAnswer answer = null;
if(request.getRequestedAction() == RequestedActionType.DIRECT_DEBITING)
{
switch (request.getCcRequestType().getValue()) {
case 1:
try {
if (logger.isInfoEnabled())
logger.info("Got INITIAL_REQUEST(1).");
if (getSentInitialAnswer()) {
logger.error("Error. Initial answer already sent! Aborting.");
return;
}
answer = session.createCreditControlAnswer();
if(userHasCredit(request.getUserName(),request.getRequestedServiceUnit()))
{
GrantedServiceUnitAvp gsu = chargeUser(request.getRequestedServiceUnit());
answer.setGrantedServiceUnit(gsu);
answer.setResultCode(2001);
}else
{
//4012 == CREDIT_LIMIT_REACHED
answer.setResultCode(4012);
}
if (logger.isInfoEnabled()) {
logger.info("Processed Credit-Control-Request:\n" + request);
logger.info("Sending Credit-Control-Answer:\n" + answer);
}
session.sendCreditControlAnswer(answer);
this.setSentInitialAnswer(true);
} catch (Exception e) {
logger.error("Failed to create/send Credit-Control-Answer to reply INITIAL_REQUEST(1).", e);
}
break;
case 2:
try {
if (logger.isInfoEnabled())
logger.info("Got UPDATE_REQUEST(2).");
if (getSentUpdateAnswer()) {
logger.error("Error. Update answer already sent! Aborting.");
return;
}
answer = session.createCreditControlAnswer();
if(userHasCredit(request.getUserName(),request.getRequestedServiceUnit()))
{
GrantedServiceUnitAvp gsu = chargeUser(request.getRequestedServiceUnit());
answer.setGrantedServiceUnit(gsu);
answer.setResultCode(2001);
}else
{
//4012 == CREDIT_LIMIT_REACHED
answer.setResultCode(4012);
}
if (logger.isInfoEnabled()) {
logger.info("Processed Credit-Control-Request:\n" + request);
logger.info("Sending Credit-Control-Answer:\n" + answer);
}
session.sendCreditControlAnswer(answer);
setSentUpdateAnswer(true);
} catch (Exception e) {
logger.error("Failed to create/send Credit-Control-Answer to reply UPDATE_REQUEST(2).", e);
}
break;
case 3:
try {
if (logger.isInfoEnabled())
logger.info("Got TERMINATION_REQUEST(3).");
if (getSentTerminationAnswer()) {
logger.error("Error. Termination answer already sent! Aborting.");
return;
}
answer = session.createCreditControlAnswer();
if(userHasCredit(request.getUserName(),request.getRequestedServiceUnit()))
{
GrantedServiceUnitAvp gsu = chargeUser(request.getRequestedServiceUnit());
answer.setGrantedServiceUnit(gsu);
answer.setResultCode(2001);
}else
{
//4012 == CREDIT_LIMIT_REACHED
answer.setResultCode(4012);
}
if (logger.isInfoEnabled()) {
logger.info("Processed Credit-Control-Request:\n" + request);
logger.info("Sending Credit-Control-Answer:\n" + answer);
}
session.sendCreditControlAnswer(answer);
setSentTerminationAnswer(true);
} catch (Exception e) {
logger.error("Failed to create/send Credit-Control-Answer to reply TERMINATION_REQUEST(3).", e);
}
break;
case 4:
try {
if (logger.isInfoEnabled())
logger.info("Got EVENT_REQUEST(4).");
answer = session.createCreditControlAnswer();
if(userHasCredit(request.getUserName(),request.getRequestedServiceUnit()))
{
GrantedServiceUnitAvp gsu = chargeUser(request.getRequestedServiceUnit());
answer.setGrantedServiceUnit(gsu);
answer.setResultCode(2001);
}else
{
//4012 == CREDIT_LIMIT_REACHED
answer.setResultCode(4012);
}
if (logger.isInfoEnabled())
logger.info("Sending Credit-Control-Answer:\n" + answer);
session.sendCreditControlAnswer(answer);
} catch (Exception e) {
logger.error("Failed to create/send Credit-Control-Answer to reply EVENT_REQUEST(4).", e);
}
break;
default:
logger.error("Unexpected CC-Request-Type in message: " + request.getCcRequestType() + ". Aborting...");
}
}else
{
answer = session.createCreditControlAnswer();
//4011 == DIAMETER_CREDIT_CONTROL_NOT_APPLICABLE
answer.setResultCode(4011);
session.sendCreditControlAnswer(answer);
}
}