package org.mobicents.slee.tests.diameter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.slee.ActivityContextInterface; import javax.slee.RolledBackContext; import javax.slee.SbbContext; import javax.slee.facilities.TimerEvent; import javax.slee.facilities.TimerFacility; import javax.slee.serviceactivity.ServiceActivity; import javax.slee.serviceactivity.ServiceActivityFactory; import net.java.slee.resource.diameter.base.DiameterAvpFactory; import net.java.slee.resource.diameter.base.DiameterMessageFactory; import net.java.slee.resource.diameter.base.DiameterProvider; import net.java.slee.resource.diameter.base.events.AccountingAnswer; import net.java.slee.resource.diameter.base.events.DiameterMessage; import net.java.slee.resource.diameter.base.events.avp.DiameterAvp; import net.java.slee.resource.diameter.base.events.avp.GroupedAvp; import org.apache.log4j.Logger; import org.jdiameter.api.Avp; import org.jdiameter.api.ResultCode; import org.mobicents.slee.resource.diameter.base.AccountingServerSessionActivityImpl; /** * * DiameterExampleSbb.java * * <br>Super project: mobicents * <br>11:34:16 PM May 26, 2008 * <br> * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a> * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a> * @author Erick Svenson */ public abstract class DiameterTestsSbb implements javax.slee.Sbb { private static Logger logger = Logger.getLogger( DiameterTestsSbb.class ); private SbbContext sbbContext = null; // This SBB's context private Context myEnv = null; // This SBB's environment private DiameterProvider provider = null; private DiameterMessageFactory messageFactory = null; private DiameterAvpFactory avpFactory = null; private TimerFacility timerFacility = null; private static class DiameterUser { String msisdn; String name; String imsi; Double balance; Double reserved; public DiameterUser( String msisdn, String name, String imsi, Double balance, Double reserved ) { this.msisdn = msisdn; this.name = name; this.msisdn = msisdn; this.balance = balance; this.reserved = reserved; } } private static HashMap<String, DiameterUser> users = new HashMap(); static { users.put( "00001000", new DiameterUser("00001000", "Alexandre Mendonca", "00001000", 1000.0, 0.0) ); users.put( "00001001", new DiameterUser("00001001", "Bartosz Baranowski", "00001001", 100.0, 0.0) ); users.put( "00001002", new DiameterUser("00001002", "Erick Svensson", "00001002", 0.0, 0.0) ); } public void setSbbContext( SbbContext context ) { logger.info( "sbbRolledBack invoked." ); this.sbbContext = context; try { myEnv = (Context) new InitialContext().lookup( "java:comp/env" ); provider = (DiameterProvider) myEnv.lookup("slee/resources/diameter-base-ra-acif"); logger.info( "Got Provider:" + provider ); messageFactory = provider.getDiameterMessageFactory(); logger.info( "Got Message Factory:" + provider ); avpFactory = provider.getDiameterAvpFactory(); logger.info( "Got AVP Factory:" + provider ); // Get the timer facility timerFacility = (TimerFacility) myEnv.lookup("slee/facilities/timer"); } catch ( Exception e ) { logger.error( "Unable to set sbb context.", e ); } } public void unsetSbbContext() { logger.info( "unsetSbbContext invoked." ); this.sbbContext = null; } public void sbbCreate() throws javax.slee.CreateException { logger.info( "sbbCreate invoked." ); } public void sbbPostCreate() throws javax.slee.CreateException { logger.info( "sbbPostCreate invoked." ); } public void sbbActivate() { logger.info( "sbbActivate invoked." ); } public void sbbPassivate() { logger.info( "sbbPassivate invoked." ); } public void sbbRemove() { logger.info( "sbbRemove invoked." ); } public void sbbLoad() { logger.info( "sbbLoad invoked." ); } public void sbbStore() { logger.info( "sbbStore invoked." ); } public void sbbExceptionThrown( Exception exception, Object event, ActivityContextInterface activity ) { logger.info( "sbbRolledBack invoked." ); } public void sbbRolledBack( RolledBackContext context ) { logger.info( "sbbRolledBack invoked." ); } protected SbbContext getSbbContext() { logger.info( "getSbbContext invoked." ); return sbbContext; } // ########################################################################## // ## EVENT HANDLERS ## // ########################################################################## public void onServiceStartedEvent( javax.slee.serviceactivity.ServiceStartedEvent event, ActivityContextInterface aci ) { logger.info( "onServiceStartedEvent invoked." ); try { // check if it's my service that is starting ServiceActivity sa = ( (ServiceActivityFactory) myEnv.lookup( "slee/serviceactivity/factory" ) ).getActivity(); if( sa.equals( aci.getActivity() ) ) { logger.info( "################################################################################" ); logger.info( "## D I A M E T E R T E S T A P P L I C A T I O N S B B E N G A G E D ##" ); logger.info( "################################################################################" ); messageFactory = provider.getDiameterMessageFactory(); avpFactory = provider.getDiameterAvpFactory(); logger.info( "Performing sanity check..." ); logger.info( "Provider [" + provider + "]" ); logger.info( "Message Factory [" + messageFactory + "]" ); logger.info( "AVP Factory [" + avpFactory + "]" ); logger.info( "# Check completed. Result: " + ((provider != null ? 1 : 0) + (messageFactory != null ? 1 : 0) + (avpFactory != null ? 1 : 0)) + "/3" ); logger.info( "Connected to " + provider.getPeerCount() + " peers." ); } } catch ( Exception e ) { logger.error( "Unable to handle service started event...", e ); } } public void onTimerEvent(TimerEvent event, ActivityContextInterface aci) { sendAccountingRequest(); } public void onAbortSessionRequest(net.java.slee.resource.diameter.base.events.AbortSessionRequest asr, ActivityContextInterface aci) { logger.info( "Abort-Session-Request received." ); } public void onAbortSessionAnswer(net.java.slee.resource.diameter.base.events.AbortSessionAnswer asa, ActivityContextInterface aci) { logger.info( "Abort-Session-Answer received." ); } public void onAccountingRequest(net.java.slee.resource.diameter.base.events.AccountingRequest acr, ActivityContextInterface aci) { long start = System.currentTimeMillis(); logger.info( "Accounting-Request received. [" + acr + "]" ); boolean actAsProxy = false; try { // Are we gonna act as a proxy? if(actAsProxy) { // In here we act as a "proxy". Just for testing we take the original message, // replace the Origin/Destination Host/Realm AVPs and send it to the emulator. boolean hasDestinationHost = false; boolean hasDestinationRealm = false; List<DiameterAvp> avps = new ArrayList<DiameterAvp>(); for(DiameterAvp avp : acr.getAvps()) { switch(avp.getCode()) { case Avp.ORIGIN_HOST: avps.add(avpFactory.createAvp(Avp.ORIGIN_HOST, "aaa://127.0.0.1:1812".getBytes() )); break; case Avp.ORIGIN_REALM: avps.add(avpFactory.createAvp(Avp.ORIGIN_REALM, "mobicents.org".getBytes() )); break; case Avp.DESTINATION_HOST: avps.add(avpFactory.createAvp(Avp.DESTINATION_HOST, "aaa://127.0.0.1:21812".getBytes() )); hasDestinationHost = true; break; case Avp.DESTINATION_REALM: avps.add(avpFactory.createAvp(Avp.DESTINATION_REALM, "mobicents.org".getBytes() )); hasDestinationRealm = true; break; default: avps.add(avp); } } if(!hasDestinationHost) avps.add(avpFactory.createAvp(Avp.DESTINATION_HOST, "127.0.0.1".getBytes() )); if(!hasDestinationRealm) avps.add(avpFactory.createAvp(Avp.DESTINATION_REALM, "mobicents.org".getBytes() )); logger.info( "AVPs ==> " + avps ); DiameterAvp[] avpArray = new DiameterAvp[avps.size()]; avpArray = avps.toArray(avpArray); logger.info( "Creating Custom Message..." ); DiameterMessage ms = messageFactory.createAccountingRequest(avpArray); logger.info( "Created Custom Message[" + ms + "]" ); logger.info( "Sending Custom Message..." ); provider.createActivity().sendMessage( ms ); logger.info( "Sent Custom Message[" + ms + "]" ); } else { // In here we act as a server... int subscriptionIdType = -1; String subscriptionIdData = ""; int unitType = -1; long valueDigits = -1; int exponent = 0; int requestedAction = -1; int serviceParameterType; int serviceParameterValue; int serviceParameterInfo; DiameterAvp subscriptionIdAvp = null; DiameterAvp requestedActionAvp = null; if(aci.getActivity() instanceof AccountingServerSessionActivityImpl) { for(DiameterAvp avp : acr.getAvps()) { switch ( avp.getCode() ) { case SUBSCRIPTION_ID: { // This should contain a SUBSCRIPTION_ID_TYPE and a SUBSCRIPTION_ID_DATA if(avp instanceof GroupedAvp) { GroupedAvp gAvp = (GroupedAvp)avp; for(DiameterAvp subAvp : gAvp.getExtensionAvps()) { switch(subAvp.getCode()) { case SUBSCRIPTION_ID_TYPE: subscriptionIdType = subAvp.intValue(); break; case SUBSCRIPTION_ID_DATA: subscriptionIdData = subAvp.stringValue(); break; } } } } break; case REQUESTED_SERVICE_UNIT: { // This should contain a UNIT_TYPE and a UNIT_VALUE if(avp instanceof GroupedAvp) { GroupedAvp gAvp = (GroupedAvp)avp; for(DiameterAvp subAvp : gAvp.getExtensionAvps()) { switch(subAvp.getCode()) { case UNIT_TYPE: unitType = subAvp.intValue(); break; case UNIT_VALUE: { // This should contain a VALUE_DIGITS if(subAvp instanceof GroupedAvp) { GroupedAvp gSubAvp = (GroupedAvp)subAvp; for(DiameterAvp subSubAvp : gSubAvp.getExtensionAvps()) { switch(subSubAvp.getCode()) { case VALUE_DIGITS: valueDigits = subSubAvp.longValue(); break; case EXPONENT: exponent = subSubAvp.intValue(); break; } } } break; } } } } } break; case REQUESTED_ACTION: requestedAction = avp.intValue(); requestedActionAvp = avp; break; case SERVICE_PARAMETER_TYPE: // We can discard this... break; case SERVICE_PARAMETER_VALUE: // We can discard this... break; case SERVICE_PARAMETER_INFO: // We can discard this... break; default: } } logger.info( "Subscription-Id-Type: " + subscriptionIdType ); logger.info( "Subscription-Id-Data: " + subscriptionIdData ); logger.info( "Unit-Type: " + unitType ); logger.info( "Value-Digits: " + valueDigits ); logger.info( "Exponent: " + exponent ); logger.info( "Requested-Action: " + requestedAction ); AccountingServerSessionActivityImpl assa = (AccountingServerSessionActivityImpl)aci.getActivity(); // Aditional AVPs container List<DiameterAvp> avps = new ArrayList<DiameterAvp>(); AccountingAnswer ans = null; double chargingValue = valueDigits * Math.pow( 10, exponent ); if(subscriptionIdType == 0 || subscriptionIdType == 1) { DiameterUser user = null; if( (user = users.get( subscriptionIdData )) == null ) { // Not a valid user. Reject it with DIAMETER_END_USER_NOT_FOUND. ans = assa.createAccountAnswer( acr, 5241 ); // Subscription ID DiameterAvp subscriptionIdTypeAvp = avpFactory.createAvp( 193, 555, subscriptionIdType ); DiameterAvp subscriptionIdDataAvp = avpFactory.createAvp( 193, 554, subscriptionIdData ); avps.add( avpFactory.createAvp( 193, 553, new DiameterAvp[]{subscriptionIdTypeAvp, subscriptionIdDataAvp} ) ); } else if(requestedAction == 0 && user.balance < chargingValue) { logger.info( "Received Direct Debit Request:" ); logger.info( "User ID " + subscriptionIdData + " (" + user.name + ")" ); logger.info( "Current Balance: " + user.balance ); logger.info( "Charging Value: " + chargingValue ); // Not able to provide the service. not enough balance. ans = assa.createAccountAnswer( acr, 4241 ); // Subscription ID DiameterAvp subscriptionIdTypeAvp = avpFactory.createAvp( 193, 555, subscriptionIdType ); DiameterAvp subscriptionIdDataAvp = avpFactory.createAvp( 193, 554, subscriptionIdData ); avps.add( avpFactory.createAvp( 193, 553, new DiameterAvp[]{subscriptionIdTypeAvp, subscriptionIdDataAvp} ) ); } else { boolean isError = false; // Refund Account? if(requestedAction == 1) { logger.info( "Received Refund Account Request:" ); logger.info( "User ID " + subscriptionIdData + " (" + user.name + ")" ); logger.info( "Old Balance: " + user.balance ); user.balance += chargingValue; logger.info( "New Balance: " + user.balance ); } else if(requestedAction == 0) { logger.info( "Received Direct Debit Request:" ); logger.info( "User ID " + subscriptionIdData + " (" + user.name + ")" ); logger.info( "Old Balance: " + user.balance ); user.balance -= chargingValue; logger.info( "New Balance: " + user.balance ); } else { logger.warn( "Unknown requested action (" + requestedAction + ")" ); DiameterAvp failedAvp = avpFactory.createAvp( 0, 279, new DiameterAvp[]{requestedActionAvp} ); ans = assa.createAccountAnswer( acr, ResultCode.INVALID_AVP_VALUE); avps.add( failedAvp ); isError = true; } if(!isError) { // It's OK. Let's answer with 2001 ans = assa.createAccountAnswer( acr, ResultCode.SUCCESS ); // Subscription ID DiameterAvp subscriptionIdTypeAvp = avpFactory.createAvp( 193, 555, subscriptionIdType ); DiameterAvp subscriptionIdDataAvp = avpFactory.createAvp( 193, 554, subscriptionIdData ); avps.add( avpFactory.createAvp( 193, 553, new DiameterAvp[]{subscriptionIdTypeAvp, subscriptionIdDataAvp} ) ); // Granted Service Unit DiameterAvp unitTypeAvp = avpFactory.createAvp( 193, 611, unitType ); DiameterAvp valueDigitsAvp = avpFactory.createAvp( 193, 617, valueDigits ); DiameterAvp unitValueAvp = avpFactory.createAvp( 193, 612, new DiameterAvp[]{valueDigitsAvp} ); avps.add( avpFactory.createAvp( 193, 602, new DiameterAvp[]{unitTypeAvp, unitValueAvp} ) ); // Cost Information DiameterAvp costAvp = avpFactory.createAvp( 193, 603, chargingValue ); DiameterAvp currencyCodeAvp = avpFactory.createAvp( 193, 544, 978 ); avps.add( avpFactory.createAvp( 193, 604, new DiameterAvp[]{costAvp, currencyCodeAvp} ) ); } } } DiameterAvp[] avpArray = new DiameterAvp[avps.size()]; avpArray = avps.toArray(avpArray); ans.setExtensionAvps( avpArray ); logger.info( "Sending Accounting-Answer [" + ans + "]" ); assa.sendAccountAnswer( ans ); logger.info( "Accounting-Answer sent." ); } } } catch (Exception e) { logger.error( "", e ); } long end = System.currentTimeMillis(); logger.info( "Accounting-Request proccessed. [" + (end-start) + "ms]" ); } public void onAccountingAnswer(net.java.slee.resource.diameter.base.events.AccountingAnswer aca, ActivityContextInterface aci) { logger.info( "Accounting-Answer received." ); } public void onCapabilitiesExchangeRequest(net.java.slee.resource.diameter.base.events.CapabilitiesExchangeRequest cer, ActivityContextInterface aci) { logger.info( "Capabilities-Exchange-Request received." ); } public void onCapabilitiesExchangeAnswer(net.java.slee.resource.diameter.base.events.CapabilitiesExchangeAnswer cea, ActivityContextInterface aci) { logger.info( "Capabilities-Exchange-Answer received." ); } public void onDeviceWatchdogRequest(net.java.slee.resource.diameter.base.events.DeviceWatchdogRequest dwr, ActivityContextInterface aci) { logger.info( "Device-Watchdog-Request received." ); } public void onDeviceWatchdogAnswer(net.java.slee.resource.diameter.base.events.DeviceWatchdogAnswer dwa, ActivityContextInterface aci) { logger.info( "Device-Watchdog-Answer received." ); } public void onDisconnectPeerRequest(net.java.slee.resource.diameter.base.events.DisconnectPeerRequest dpr, ActivityContextInterface aci) { logger.info( "Disconnect-Peer-Request received." ); } public void onDisconnectPeerAnswer(net.java.slee.resource.diameter.base.events.DisconnectPeerAnswer dpa, ActivityContextInterface aci) { logger.info( "Disconnect-Peer-Answer received." ); } public void onReAuthRequest(net.java.slee.resource.diameter.base.events.ReAuthRequest rar, ActivityContextInterface aci) { logger.info( "Re-Auth-Request received." ); } public void onReAuthAnswer(net.java.slee.resource.diameter.base.events.ReAuthAnswer raa, ActivityContextInterface aci) { logger.info( "Re-Auth-Answer received." ); } public void onSessionTerminationRequest(net.java.slee.resource.diameter.base.events.SessionTerminationRequest rar, ActivityContextInterface aci) { logger.info( "Session-Termination-Request received." ); } public void onSessionTerminationAnswer(net.java.slee.resource.diameter.base.events.SessionTerminationAnswer raa, ActivityContextInterface aci) { logger.info( "Session-Termination-Answer received." ); } public void onErrorAnswer(net.java.slee.resource.diameter.base.events.ErrorAnswer era, ActivityContextInterface aci) { logger.info( "Error-Answer received." ); } // ########################################################################## // ## PRIVATE METHODS ## // ########################################################################## private final static int SUBSCRIPTION_ID_TYPE = 555; private final static int SUBSCRIPTION_ID_DATA = 554; private final static int SUBSCRIPTION_ID = 553; private final static int UNIT_TYPE = 611; private final static int VALUE_DIGITS = 617; private final static int UNIT_VALUE = 612; private final static int EXPONENT = 616; private final static int REQUESTED_SERVICE_UNIT = 606; private final static int REQUESTED_ACTION = 615; // 0 = Direct Debit, 1 = Refund Account private final static int SERVICE_PARAMETER_TYPE = 608; private final static int SERVICE_PARAMETER_VALUE = 609; private final static int SERVICE_PARAMETER_INFO = 607; private void sendAccountingRequest() { try { List<DiameterAvp> avps = new ArrayList<DiameterAvp>(); avps.add(avpFactory.createAvp(Avp.SESSION_ID, "12345".getBytes() )); DiameterAvp avpVendorId = avpFactory.createAvp( Avp.VENDOR_ID, 193 ); DiameterAvp avpAcctApplicationId = avpFactory.createAvp( Avp.ACCT_APPLICATION_ID, 193 ); avps.add( avpFactory.createAvp( Avp.VENDOR_SPECIFIC_APPLICATION_ID, new DiameterAvp[]{avpVendorId, avpAcctApplicationId} ) ); avps.add(avpFactory.createAvp(Avp.ORIGIN_HOST, "aaa://127.0.0.1:1812".getBytes() )); avps.add(avpFactory.createAvp(Avp.ORIGIN_REALM, "mobicents.org".getBytes() )); avps.add(avpFactory.createAvp(Avp.DESTINATION_HOST, "aaa://127.0.0.1:21812".getBytes() )); avps.add(avpFactory.createAvp(Avp.DESTINATION_REALM, "mobicents.org".getBytes() )); // Subscription ID DiameterAvp subscriptionIdType = avpFactory.createAvp( 193, 555, 0 ); DiameterAvp subscriptionIdData = avpFactory.createAvp( 193, 554, "00001000" ); avps.add( avpFactory.createAvp( 193, 553, new DiameterAvp[]{subscriptionIdType, subscriptionIdData} ) ); // Requested Service Unit DiameterAvp unitType = avpFactory.createAvp( 193, 611, 2 ); DiameterAvp valueDigits = avpFactory.createAvp( 193, 617, 10L ); DiameterAvp unitValue = avpFactory.createAvp( 193, 612, new DiameterAvp[]{valueDigits} ); avps.add( avpFactory.createAvp( 193, 606, new DiameterAvp[]{unitType, unitValue} ) ); // Record Number and Type avps.add(avpFactory.createAvp(Avp.ACC_RECORD_NUMBER, 0 )); avps.add(avpFactory.createAvp(Avp.ACC_RECORD_TYPE, 1 )); // Requested action avps.add( avpFactory.createAvp( 193, 615, 0 ) ); // Service Parameter Type DiameterAvp serviceParameterType = avpFactory.createAvp( 193, 608, 0 ); DiameterAvp serviceParameterValue = avpFactory.createAvp( 193, 609, "510" ); avps.add( avpFactory.createAvp( 193, 607, new DiameterAvp[]{serviceParameterType, serviceParameterValue} ) ); // Service Parameter Type DiameterAvp serviceParameterType2 = avpFactory.createAvp( 193, 608, 14 ); DiameterAvp serviceParameterValue2 = avpFactory.createAvp( 193, 609, "20" ); avps.add( avpFactory.createAvp( 193, 607, new DiameterAvp[]{serviceParameterType2, serviceParameterValue2} ) ); DiameterAvp[] avpArray = new DiameterAvp[avps.size()]; avpArray = avps.toArray(avpArray); logger.info( "Creating Custom Message..." ); DiameterMessage ms = messageFactory.createAccountingRequest(avpArray); logger.info( "Created Custom Message[" + ms + "]" ); logger.info( "Sending Custom Message..." ); provider.createActivity().sendMessage( ms ); logger.info( "Sent Custom Message[" + ms + "]" ); } catch (Exception e) { logger.error( "", e ); } } }