/*
* TeleStax, Open Source Cloud Communications Copyright 2012.
* TeleStax and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.mobicents.smsc.slee.services.alert;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.slee.ActivityContextInterface;
import javax.slee.ActivityEndEvent;
import javax.slee.CreateException;
import javax.slee.EventContext;
import javax.slee.InitialEventSelector;
import javax.slee.RolledBackContext;
import javax.slee.Sbb;
import javax.slee.SbbContext;
import javax.slee.ServiceID;
import javax.slee.facilities.Tracer;
import javax.slee.resource.ResourceAdaptorTypeID;
import javax.slee.serviceactivity.ServiceActivity;
import javax.slee.serviceactivity.ServiceStartedEvent;
import org.mobicents.protocols.ss7.map.api.MAPApplicationContext;
import org.mobicents.protocols.ss7.map.api.MAPApplicationContextName;
import org.mobicents.protocols.ss7.map.api.MAPApplicationContextVersion;
import org.mobicents.protocols.ss7.map.api.MAPException;
import org.mobicents.protocols.ss7.map.api.MAPParameterFactory;
import org.mobicents.protocols.ss7.map.api.MAPProvider;
import org.mobicents.protocols.ss7.map.api.primitives.AddressString;
import org.mobicents.protocols.ss7.map.api.primitives.ISDNAddressString;
import org.mobicents.protocols.ss7.map.api.service.sms.AlertServiceCentreRequest;
import org.mobicents.protocols.ss7.map.api.service.sms.MAPDialogSms;
import org.mobicents.slee.SbbContextExt;
import org.mobicents.slee.resource.map.MAPContextInterfaceFactory;
import org.mobicents.slee.resource.map.events.DialogAccept;
import org.mobicents.slee.resource.map.events.DialogClose;
import org.mobicents.slee.resource.map.events.DialogDelimiter;
import org.mobicents.slee.resource.map.events.DialogNotice;
import org.mobicents.slee.resource.map.events.DialogProviderAbort;
import org.mobicents.slee.resource.map.events.DialogReject;
import org.mobicents.slee.resource.map.events.DialogRelease;
import org.mobicents.slee.resource.map.events.DialogRequest;
import org.mobicents.slee.resource.map.events.DialogTimeout;
import org.mobicents.slee.resource.map.events.DialogUserAbort;
import org.mobicents.slee.resource.map.events.ErrorComponent;
import org.mobicents.slee.resource.map.events.InvokeTimeout;
import org.mobicents.slee.resource.map.events.RejectComponent;
import org.mobicents.smsc.cassandra.PersistenceException;
import org.mobicents.smsc.domain.SmscPropertiesManagement;
import org.mobicents.smsc.library.SbbStates;
import org.mobicents.smsc.library.Sms;
import org.mobicents.smsc.library.SmsSet;
import org.mobicents.smsc.library.SmsSetCache;
import org.mobicents.smsc.library.TargetAddress;
import org.mobicents.smsc.slee.resources.persistence.PersistenceRAInterface;
import org.mobicents.smsc.slee.resources.scheduler.SchedulerRaSbbInterface;
/**
*
* @author amit bhayani
* @author sergey vetyutnev
*
*/
public abstract class AlertSbb implements Sbb {
private static final ResourceAdaptorTypeID PERSISTENCE_ID = new ResourceAdaptorTypeID("PersistenceResourceAdaptorType", "org.mobicents", "1.0");
private static final String PERSISTENCE_LINK = "PersistenceResourceAdaptor";
private static final ResourceAdaptorTypeID SCHEDULER_ID = new ResourceAdaptorTypeID("SchedulerResourceAdaptorType", "org.mobicents", "1.0");
private static final String SCHEDULER_LINK = "SchedulerResourceAdaptor";
protected Tracer logger;
protected SbbContextExt sbbContext;
protected MAPContextInterfaceFactory mapAcif;
protected MAPProvider mapProvider;
protected MAPParameterFactory mapParameterFactory;
protected PersistenceRAInterface persistence;
protected SchedulerRaSbbInterface scheduler = null;
public AlertSbb() {
}
public PersistenceRAInterface getStore() {
return this.persistence;
}
/**
* MAP Components Events
*/
public void onInvokeTimeout(InvokeTimeout evt, ActivityContextInterface aci) {
this.logger.severe("\nRx : onInvokeTimeout" + evt);
}
public void onErrorComponent(ErrorComponent event, ActivityContextInterface aci) {
this.logger.severe("\nRx : onErrorComponent" + event);
}
public void onRejectComponent(RejectComponent event, ActivityContextInterface aci) {
this.logger.severe("\nRx : onRejectComponent" + event);
}
/**
* Dialog Events
*/
public void onDialogDelimiter(DialogDelimiter evt, ActivityContextInterface aci) {
if (logger.isFineEnabled()) {
this.logger.fine("\nRx : onDialogDelimiter=" + evt);
}
}
public void onDialogAccept(DialogAccept evt, ActivityContextInterface aci) {
if (logger.isFineEnabled()) {
this.logger.fine("\nRx : onDialogAccept=" + evt);
}
}
public void onDialogReject(DialogReject evt, ActivityContextInterface aci) {
this.logger.severe("\nRx : onDialogReject=" + evt);
}
public void onDialogUserAbort(DialogUserAbort evt, ActivityContextInterface aci) {
this.logger.severe("\nRx : onDialogUserAbort=" + evt);
}
public void onDialogProviderAbort(DialogProviderAbort evt, ActivityContextInterface aci) {
this.logger.severe("\nRx : onDialogProviderAbort=" + evt);
}
public void onDialogClose(DialogClose evt, ActivityContextInterface aci) {
if (logger.isFineEnabled()) {
this.logger.fine("\nRx : onDialogClose" + evt);
}
}
public void onDialogNotice(DialogNotice evt, ActivityContextInterface aci) {
if (logger.isWarningEnabled()) {
this.logger.warning("\nRx : onDialogNotice" + evt);
}
}
public void onDialogTimeout(DialogTimeout evt, ActivityContextInterface aci) {
this.logger.severe("\nRx : onDialogTimeout" + evt);
}
public void onDialogRequest(DialogRequest evt, ActivityContextInterface aci) {
if (logger.isFineEnabled()) {
this.logger.fine("\nRx : onDialogRequest" + evt);
}
}
public void onDialogRelease(DialogRelease evt, ActivityContextInterface aci) {
if (logger.isFineEnabled()) {
this.logger.fine("\nRx : onDialogRelease" + evt);
}
}
public void onAlertServiceCentreRequest(AlertServiceCentreRequest evt, ActivityContextInterface aci) {
if (this.logger.isFineEnabled()) {
this.logger.fine("\nReceived onAlertServiceCentreRequest= " + evt);
}
try {
MAPDialogSms mapDialogSms = evt.getMAPDialog();
MAPApplicationContext mapApplicationContext = mapDialogSms.getApplicationContext();
if (mapApplicationContext.getApplicationContextVersion() == MAPApplicationContextVersion.version2) {
// Send back response only for V2
mapDialogSms.addAlertServiceCentreResponse(evt.getInvokeId());
if (this.logger.isFineEnabled()) {
this.logger.fine("\nSending AlertServiceCentreResponse");
}
mapDialogSms.close(false);
} else {
mapDialogSms.release();
}
this.setupAlert(evt.getMsisdn(), evt.getServiceCentreAddress(), mapDialogSms.getNetworkId());
} catch (MAPException e) {
logger.severe("Exception while trying to send back AlertServiceCentreResponse", e);
}
}
private void setupAlert(ISDNAddressString msisdn, AddressString serviceCentreAddress, int networkId) {
PersistenceRAInterface pers = this.getStore();
SmscPropertiesManagement smscPropertiesManagement = SmscPropertiesManagement.getInstance();
// checking if SMSC is paused
if (smscPropertiesManagement.isDeliveryPause())
return;
// checking if database is available
if (!pers.isDatabaseAvailable())
return;
int addrTon = msisdn.getAddressNature().getIndicator();
int addrNpi = msisdn.getNumberingPlan().getIndicator();
String addr = msisdn.getAddress();
TargetAddress lock = pers.obtainSynchroObject(new TargetAddress(addrTon, addrNpi, addr, networkId));
try {
synchronized (lock) {
try {
long dueSlot = 0;
SmsSet smsSet0 = new SmsSet();
smsSet0.setDestAddr(addr);
smsSet0.setDestAddrNpi(addrNpi);
smsSet0.setDestAddrTon(addrTon);
smsSet0.setNetworkId(networkId);
SmsSet smsSet1 = SmsSetCache.getInstance().getProcessingSmsSet(smsSet0.getTargetId());
if (smsSet1 != null) {
// message is already in process
if (logger.isInfoEnabled()) {
logger.info(String
.format("\nReceived AlertServiceCentre for MSISDN=%s but the delivering for this dest is already in progress",
addr));
}
return;
}
dueSlot = pers.c2_getDueSlotForTargetId(smsSet0.getTargetId());
if (dueSlot != 0 && dueSlot > pers.c2_getCurrentDueSlot()
&& pers.c2_checkDueSlotWritingPossibility(dueSlot) == dueSlot) {
pers.c2_registerDueSlotWriting(dueSlot);
try {
if (dueSlot != 0 && dueSlot > pers.c2_getCurrentDueSlot()) {
SmsSet smsSet = pers.c2_getRecordListForTargeId(dueSlot, smsSet0.getTargetId());
if (smsSet != null) {
if (logger.isInfoEnabled()) {
logger.info(String
.format("\nReceived AlertServiceCentre for MSISDN=%s, SmsSet was loaded with %d messages",
addr, smsSet.getSmsCount()));
}
for (int i1 = 0; i1 < smsSet.getSmsCount(); i1++) {
Sms sms = smsSet.getSms(i1);
sms.setInvokedByAlert(true);
}
ArrayList<SmsSet> lstS = new ArrayList<SmsSet>();
lstS.add(smsSet);
ArrayList<SmsSet> lst = pers.c2_sortRecordList(lstS);
if (lst.size() > 0) {
smsSet = lst.get(0);
smsSet.setProcessingStarted();
this.scheduler.injectSmsDatabase(smsSet);
}
} else {
if (logger.isInfoEnabled()) {
logger.info(String
.format("\nReceived AlertServiceCentre for MSISDN=%s, dueSlot was scheduled but no SmsSet was loaded",
addr));
}
}
} else {
if (logger.isInfoEnabled()) {
logger.info(String
.format("\nReceived AlertServiceCentre for MSISDN=%s but no dueSlot was scheduled or the scheduled dueSlot will come soon - 2",
addr));
}
}
} finally {
pers.c2_unregisterDueSlotWriting(dueSlot);
}
} else {
if (logger.isInfoEnabled()) {
logger.info(String
.format("\nReceived AlertServiceCentre for MSISDN=%s but no dueSlot was scheduled or the scheduled dueSlot will come soon - 1",
addr));
}
}
} catch (PersistenceException e) {
this.logger.severe("PersistenceException when setupAlert()" + e.getMessage(), e);
} catch (Exception e) {
this.logger.severe("Exception when setupAlert()" + e.getMessage(), e);
}
}
} finally {
pers.releaseSynchroObject(lock);
}
}
/**
* Life cycle
*/
@Override
public void sbbActivate() {
// TODO Auto-generated method stub
}
@Override
public void sbbCreate() throws CreateException {
// TODO Auto-generated method stub
}
@Override
public void sbbExceptionThrown(Exception arg0, Object arg1, ActivityContextInterface arg2) {
// TODO Auto-generated method stub
}
@Override
public void sbbLoad() {
// TODO Auto-generated method stub
}
@Override
public void sbbPassivate() {
// TODO Auto-generated method stub
}
@Override
public void sbbPostCreate() throws CreateException {
// TODO Auto-generated method stub
}
@Override
public void sbbRemove() {
// TODO Auto-generated method stub
}
@Override
public void sbbRolledBack(RolledBackContext arg0) {
// TODO Auto-generated method stub
}
@Override
public void sbbStore() {
// TODO Auto-generated method stub
}
@Override
public void setSbbContext(SbbContext sbbContext) {
this.sbbContext = (SbbContextExt) sbbContext;
try {
Context ctx = (Context) new InitialContext().lookup("java:comp/env");
this.mapAcif = (MAPContextInterfaceFactory) ctx.lookup("slee/resources/map/2.0/acifactory");
this.mapProvider = (MAPProvider) ctx.lookup("slee/resources/map/2.0/provider");
this.mapParameterFactory = this.mapProvider.getMAPParameterFactory();
this.logger = this.sbbContext.getTracer(AlertSbb.class.getSimpleName());
this.persistence = (PersistenceRAInterface) this.sbbContext.getResourceAdaptorInterface(PERSISTENCE_ID, PERSISTENCE_LINK);
this.scheduler = (SchedulerRaSbbInterface) this.sbbContext.getResourceAdaptorInterface(SCHEDULER_ID, SCHEDULER_LINK);
} catch (Exception ne) {
logger.severe("Could not set SBB context:", ne);
}
}
@Override
public void unsetSbbContext() {
// TODO Auto-generated method stub
}
public void onServiceStartedEvent(ServiceStartedEvent event, ActivityContextInterface aci, EventContext eventContext) {
ServiceID serviceID = event.getService();
this.logger.info("Rx: onServiceStartedEvent: event=" + event + ", serviceID=" + serviceID);
SbbStates.setAlertServiceState(true);
}
public void onActivityEndEvent(ActivityEndEvent event, ActivityContextInterface aci, EventContext eventContext) {
boolean isServiceActivity = (aci.getActivity() instanceof ServiceActivity);
if (isServiceActivity) {
this.logger.info("Rx: onActivityEndEvent: event=" + event + ", isServiceActivity=" + isServiceActivity);
SbbStates.setAlertServiceState(false);
}
}
/**
* Initial event selector method to check if the Event should initalize the
*/
public InitialEventSelector initialEventSelect(InitialEventSelector ies) {
Object event = ies.getEvent();
DialogRequest dialogRequest = null;
if (event instanceof DialogRequest) {
dialogRequest = (DialogRequest) event;
if (MAPApplicationContextName.shortMsgAlertContext == dialogRequest.getMAPDialog().getApplicationContext()
.getApplicationContextName()) {
ies.setInitialEvent(true);
ies.setActivityContextSelected(true);
} else {
ies.setInitialEvent(false);
}
}
return ies;
}
}