All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mobicents.smsc.slee.services.mt.MtSbb Maven / Gradle / Ivy

There is a newer version: 7.4.179
Show newest version
/*
 * TeleStax, Open Source Cloud Communications  Copyright 2012. 
 * 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.mt;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;

import javax.slee.ActivityContextInterface;

import javolution.util.FastList;

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.datacoding.NationalLanguageIdentifier;
import org.mobicents.protocols.ss7.map.api.dialog.MAPAbortProviderReason;
import org.mobicents.protocols.ss7.map.api.dialog.MAPRefuseReason;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorCode;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessage;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageAbsentSubscriber;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageAbsentSubscriberSM;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageExtensionContainer;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageFacilityNotSup;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageSMDeliveryFailure;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageSubscriberBusyForMtSms;
import org.mobicents.protocols.ss7.map.api.errors.MAPErrorMessageSystemFailure;
import org.mobicents.protocols.ss7.map.api.errors.SMEnumeratedDeliveryFailureCause;
import org.mobicents.protocols.ss7.map.api.primitives.IMSI;
import org.mobicents.protocols.ss7.map.api.primitives.ISDNAddressString;
import org.mobicents.protocols.ss7.map.api.primitives.LMSI;
import org.mobicents.protocols.ss7.map.api.service.sms.ForwardShortMessageRequest;
import org.mobicents.protocols.ss7.map.api.service.sms.ForwardShortMessageResponse;
import org.mobicents.protocols.ss7.map.api.service.sms.MAPDialogSms;
import org.mobicents.protocols.ss7.map.api.service.sms.MtForwardShortMessageRequest;
import org.mobicents.protocols.ss7.map.api.service.sms.MtForwardShortMessageResponse;
import org.mobicents.protocols.ss7.map.api.service.sms.SMDeliveryOutcome;
import org.mobicents.protocols.ss7.map.api.service.sms.SM_RP_DA;
import org.mobicents.protocols.ss7.map.api.service.sms.SM_RP_OA;
import org.mobicents.protocols.ss7.map.api.service.sms.SmsSignalInfo;
import org.mobicents.protocols.ss7.map.api.smstpdu.AbsoluteTimeStamp;
import org.mobicents.protocols.ss7.map.api.smstpdu.AddressField;
import org.mobicents.protocols.ss7.map.api.smstpdu.CharacterSet;
import org.mobicents.protocols.ss7.map.api.smstpdu.DataCodingScheme;
import org.mobicents.protocols.ss7.map.api.smstpdu.NumberingPlanIdentification;
import org.mobicents.protocols.ss7.map.api.smstpdu.SmsDeliverTpdu;
import org.mobicents.protocols.ss7.map.api.smstpdu.TypeOfNumber;
import org.mobicents.protocols.ss7.map.api.smstpdu.UserData;
import org.mobicents.protocols.ss7.map.api.smstpdu.UserDataHeader;
import org.mobicents.protocols.ss7.map.api.smstpdu.UserDataHeaderElement;
import org.mobicents.protocols.ss7.map.smstpdu.UserDataImpl;
import org.mobicents.protocols.ss7.sccp.parameter.SccpAddress;
import org.mobicents.protocols.ss7.tcap.asn.ApplicationContextName;
import org.mobicents.slee.SbbLocalObjectExt;
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.DialogProviderAbort;
import org.mobicents.slee.resource.map.events.DialogReject;
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.RejectComponent;
import org.mobicents.smsc.cassandra.DBOperations_C2;
import org.mobicents.smsc.cassandra.DatabaseType;
import org.mobicents.smsc.cassandra.PersistenceException;
import org.mobicents.smsc.domain.MProcManagement;
import org.mobicents.smsc.domain.MapVersionCache;
import org.mobicents.smsc.domain.SmscPropertiesManagement;
import org.mobicents.smsc.domain.StoreAndForwordMode;
import org.mobicents.smsc.library.CdrGenerator;
import org.mobicents.smsc.library.ErrorCode;
import org.mobicents.smsc.library.MessageUtil;
import org.mobicents.smsc.library.Sms;
import org.mobicents.smsc.library.SmsSet;
import org.mobicents.smsc.library.SmsSetCache;
import org.mobicents.smsc.library.SmscProcessingException;
import org.mobicents.smsc.library.TargetAddress;
import org.mobicents.smsc.mproc.impl.MProcResult;
import org.mobicents.smsc.slee.resources.persistence.PersistenceRAInterface;
import org.mobicents.smsc.slee.resources.persistence.SmsSubmitData;

import com.cloudhopper.smpp.SmppConstants;
import com.cloudhopper.smpp.tlv.Tlv;
import com.cloudhopper.smpp.tlv.TlvConvertException;

/**
 *
 * @author amit bhayani
 * @author sergey vetyutnev
 * 
 */
public abstract class MtSbb extends MtCommonSbb implements MtForwardSmsInterface, ReportSMDeliveryStatusInterface2 {

	private static final String className = MtSbb.class.getSimpleName();

	private MapVersionCache mapVersionCache = MapVersionCache.getInstance();

	private static final int MASK_MAP_VERSION_1 = 0x01;
	private static final int MASK_MAP_VERSION_2 = 0x02;
	private static final int MASK_MAP_VERSION_3 = 0x04;

	private static Charset isoCharset = Charset.forName("ISO-8859-1");

	public MtSbb() {
		super(className);
	}

	/**
	 * Components Events override from MtCommonSbb that we care
	 */

	@Override
	public void onDialogAccept(DialogAccept event, ActivityContextInterface aci) {
		super.onDialogAccept(event, aci);

		if (!this.isNegotiatedMapVersionUsing()) {
			mapVersionCache.setMAPApplicationContextVersion(this.getNetworkNode().getGlobalTitle().getDigits(), event
					.getMAPDialog().getApplicationContext().getApplicationContextVersion());
		}
	}

	@Override
	public void onErrorComponent(ErrorComponent event, ActivityContextInterface aci) {
		try {
			super.onErrorComponent(event, aci);

			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onErrorComponent()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.onErrorComponent(), targetId="
						+ targetId);
				return;
			}

            MAPErrorMessage mapErrorMessage = event.getMAPErrorMessage();
            if (mapErrorMessage.isEmSubscriberBusyForMtSms()) {
                MAPErrorMessageSubscriberBusyForMtSms subscriberBusyForMtSms = mapErrorMessage.getEmSubscriberBusyForMtSms();
                this.onDeliveryError(smsSet, ErrorAction.subscriberBusy, ErrorCode.USER_BUSY,
                        "Error subscriberBusyForMtSms after MtForwardSM Request: " + subscriberBusyForMtSms.toString(), true,
                        mapErrorMessage, false);
            } else if (mapErrorMessage.isEmAbsentSubscriber()) {
                MAPErrorMessageAbsentSubscriber absentSubscriber = mapErrorMessage.getEmAbsentSubscriber();
                this.onDeliveryError(smsSet, ErrorAction.mobileNotReachableFlag, ErrorCode.ABSENT_SUBSCRIBER,
                        "Error absentSubscriber after MtForwardSM Request: " + absentSubscriber.toString(), true,
                        mapErrorMessage, false);
            } else if (mapErrorMessage.isEmAbsentSubscriberSM()) {
                MAPErrorMessageAbsentSubscriberSM absentSubscriber = mapErrorMessage.getEmAbsentSubscriberSM();
                this.onDeliveryError(smsSet, ErrorAction.mobileNotReachableFlag, ErrorCode.ABSENT_SUBSCRIBER,
                        "Error absentSubscriberSM after MtForwardSM Request: " + absentSubscriber.toString(), true,
                        mapErrorMessage, false);
            } else if (mapErrorMessage.isEmSMDeliveryFailure()) {
                MAPErrorMessageSMDeliveryFailure smDeliveryFailure = mapErrorMessage.getEmSMDeliveryFailure();
                if (smDeliveryFailure.getSMEnumeratedDeliveryFailureCause() == SMEnumeratedDeliveryFailureCause.memoryCapacityExceeded) {
                    this.onDeliveryError(smsSet, ErrorAction.memoryCapacityExceededFlag, ErrorCode.MESSAGE_QUEUE_FULL,
                            "Error smDeliveryFailure after MtForwardSM Request: " + smDeliveryFailure.toString(), true,
                            mapErrorMessage, false);
                } else {
                    this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.SENDING_SM_FAILED,
                            "Error smDeliveryFailure after MtForwardSM Request: " + smDeliveryFailure.toString(), true,
                            mapErrorMessage, false);
                }
            } else if (mapErrorMessage.isEmSystemFailure()) {
                // TODO: may be it is not a permanent case ???
                MAPErrorMessageSystemFailure systemFailure = mapErrorMessage.getEmSystemFailure();
                this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.SYSTEM_FAILURE,
                        "Error systemFailure after MtForwardSM Request: " + systemFailure.toString(), true, mapErrorMessage, false);
            } else if (mapErrorMessage.isEmFacilityNotSup()) {
                MAPErrorMessageFacilityNotSup facilityNotSup = mapErrorMessage.getEmFacilityNotSup();
                this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.FACILITY_NOT_SUPPORTED,
                        "Error facilityNotSup after MtForwardSM Request: " + facilityNotSup.toString(), true, mapErrorMessage, false);
            } else if (mapErrorMessage.isEmExtensionContainer()) {
                MAPErrorMessageExtensionContainer extensionContainer = mapErrorMessage.getEmExtensionContainer();
                switch ((int) (long) extensionContainer.getErrorCode()) {
                    case MAPErrorCode.dataMissing:
                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.DATA_MISSING,
                                "Error dataMissing after MtForwardSM Request: " + extensionContainer.toString(), true,
                                mapErrorMessage, false);
                        break;
                    case MAPErrorCode.unexpectedDataValue:
                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.UNEXPECTED_DATA,
                                "Error unexpectedDataValue after MtForwardSM Request: " + extensionContainer.toString(), true,
                                mapErrorMessage, false);
                        break;
//                    case MAPErrorCode.facilityNotSupported:
//                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.FACILITY_NOT_SUPPORTED,
//                                "Error facilityNotSupported after MtForwardSM Request: " + extensionContainer.toString(), true,
//                                mapErrorMessage);
//                        break;
                    case MAPErrorCode.unidentifiedSubscriber:
                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.UNDEFINED_SUBSCRIBER,
                                "Error unidentifiedSubscriber after MtForwardSM Request: " + extensionContainer.toString(),
                                true, mapErrorMessage, false);
                        break;
                    case MAPErrorCode.illegalSubscriber:
                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.ILLEGAL_SUBSCRIBER,
                                "Error illegalSubscriber after MtForwardSM Request: " + extensionContainer.toString(), true,
                                mapErrorMessage, false);
                        break;
                    case MAPErrorCode.illegalEquipment:
                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.ILLEGAL_EQUIPMENT,
                                "Error illegalEquipment after MtForwardSM Request: " + extensionContainer.toString(), true,
                                mapErrorMessage, false);
                        break;
                    default:
                        this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.SYSTEM_FAILURE,
                                "Error after MtForwardSM Request: " + extensionContainer.toString(), true, mapErrorMessage, false);
                        break;
                }
            } else {
                this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.SYSTEM_FAILURE,
                        "Error after MtForwardSM Request: " + mapErrorMessage, true, mapErrorMessage, false);
            }
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onErrorComponent() when fetching records and issuing events: "
							+ e1.getMessage(), e1);
		}
	}

	@Override
	public void onRejectComponent(RejectComponent event, ActivityContextInterface aci) {
		try {
			super.onRejectComponent(event, aci);

			String reason = this.getRejectComponentReason(event);

			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onRejectComponent()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.onRejectComponent(), targetId="
						+ targetId);
				return;
			}

            this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.HLR_REJECT_AFTER_ROUTING_INFO,
                    "onRejectComponent after MtForwardSM Request: " + reason != null ? reason.toString() : "", true, null,
                    false);
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogProviderAbort() when fetching records and issuing events: "
							+ e1.getMessage(), e1);
		}
	}

	/**
	 * Dialog Events override from MtCommonSbb that we care
	 */

	@Override
	public void onDialogReject(DialogReject evt, ActivityContextInterface aci) {

		try {
			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onDialogReject()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.onDialogReject(), targetId="
						+ targetId);
				return;
			}

			MAPRefuseReason mapRefuseReason = evt.getRefuseReason();

			if (mapRefuseReason == MAPRefuseReason.PotentialVersionIncompatibility
					&& evt.getMAPDialog().getApplicationContext().getApplicationContextVersion() != MAPApplicationContextVersion.version1 ) {
				if (logger.isWarningEnabled()) {
					this.logger.warning("Rx : Mt onDialogReject / PotentialVersionIncompatibility=" + evt);
				}

				MAPApplicationContextVersion newMAPApplicationContextVersion = MAPApplicationContextVersion.version1;
				if (this.isMAPVersionTested(newMAPApplicationContextVersion)) {
					// If version1 already tried this is error
					String reason = "Error condition when invoking sendMtSms() from onDialogReject()."
							+ newMAPApplicationContextVersion
							+ " already tried and DialogReject again suggests Version1";
					this.logger.severe(reason);

					ErrorCode smStatus = ErrorCode.MAP_SERVER_VERSION_ERROR;
					this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
					return;
				}
				this.setNegotiatedMapVersionUsing(false);
				this.setMAPVersionTested(newMAPApplicationContextVersion);

				mapVersionCache.setMAPApplicationContextVersion(this.getNetworkNode().getGlobalTitle().getDigits(),
						newMAPApplicationContextVersion);

				// possible a peer supports only MAP V1
				// Now send new ForwardSM with supported ACN (MAP V1)
				try {
					// Update cache
					this.sendMtSms(this.getMtFoSMSMAPApplicationContext(MAPApplicationContextVersion.version1),
							MessageProcessingState.resendAfterMapProtocolNegotiation, null, smsSet.getNetworkId());
					return;
				} catch (SmscProcessingException e) {
					String reason = "SmscPocessingException when invoking sendMtSms() from onDialogReject()-resendAfterMapProtocolNegotiation: "
							+ e.toString();
					this.logger.severe(reason, e);
					ErrorCode smStatus = ErrorCode.SC_SYSTEM_ERROR;
					try {
						smStatus = ErrorCode.fromInt(e.getSmppErrorCode());
					} catch (IllegalArgumentException e1) {
					}
					this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
					return;
				} catch (Throwable e) {
					String reason = "Exception when invoking sendMtSms() from onDialogReject()-resendAfterMapProtocolNegotiation: "
							+ e.toString();
					this.logger.severe(reason, e);
					ErrorCode smStatus = ErrorCode.SC_SYSTEM_ERROR;
					this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
					return;
				}
			}

			// If ACN not supported, lets use the new one suggested
			if (mapRefuseReason == MAPRefuseReason.ApplicationContextNotSupported) {

				String nodeDigits = this.getNetworkNode().getGlobalTitle().getDigits();

				if (logger.isWarningEnabled()) {
					this.logger.warning("Rx : Mt onDialogReject / ApplicationContextNotSupported for node "
							+ nodeDigits + " Event=" + evt);
				}

				// Now send new MtSMS with supported ACN
				ApplicationContextName tcapApplicationContextName = evt.getAlternativeApplicationContext();

				MAPApplicationContext supportedMAPApplicationContext = MAPApplicationContext
						.getInstance(tcapApplicationContextName.getOid());
				MAPApplicationContextVersion supportedMAPApplicationContextVersion = supportedMAPApplicationContext
						.getApplicationContextVersion();

				MAPApplicationContextVersion newMAPApplicationContextVersion = supportedMAPApplicationContextVersion;
				if (this.isMAPVersionTested(newMAPApplicationContextVersion)) {
					newMAPApplicationContextVersion = MAPApplicationContextVersion.version3;
					if (this.isMAPVersionTested(newMAPApplicationContextVersion)) {
						newMAPApplicationContextVersion = MAPApplicationContextVersion.version2;
						if (this.isMAPVersionTested(newMAPApplicationContextVersion)) {
							newMAPApplicationContextVersion = MAPApplicationContextVersion.version1;
							if (this.isMAPVersionTested(newMAPApplicationContextVersion)) {
								// If all versions are already tried this is
								// error
								String reason = "Error condition when invoking sendMtSms() from onDialogReject()."
										+ " all MAP versions are already tried and DialogReject again suggests Version1";
								this.logger.severe(reason);

								ErrorCode smStatus = ErrorCode.MAP_SERVER_VERSION_ERROR;
								this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
								return;
							}
						}
					}
				}
				this.setNegotiatedMapVersionUsing(false);
				this.setMAPVersionTested(newMAPApplicationContextVersion);

				mapVersionCache.setMAPApplicationContextVersion(this.getNetworkNode().getGlobalTitle().getDigits(),
						newMAPApplicationContextVersion);

				try {
					this.sendMtSms(this.getMtFoSMSMAPApplicationContext(newMAPApplicationContextVersion),
							MessageProcessingState.resendAfterMapProtocolNegotiation, null, smsSet.getNetworkId());
					return;
				} catch (SmscProcessingException e) {
					String reason = "SmscPocessingException when invoking sendMtSms() from onDialogReject()-resendAfterMapProtocolNegotiation: "
							+ e.toString();
					this.logger.severe(reason, e);
					ErrorCode smStatus = ErrorCode.SC_SYSTEM_ERROR;
					try {
						smStatus = ErrorCode.fromInt(e.getSmppErrorCode());
					} catch (IllegalArgumentException e1) {
					}
					this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
					return;
				} catch (Throwable e) {
					String reason = "Exception when invoking sendMtSms() from onDialogReject()-resendAfterMapProtocolNegotiation: "
							+ e.toString();
					this.logger.severe(reason, e);
					ErrorCode smStatus = ErrorCode.SC_SYSTEM_ERROR;
					this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
					return;
				}
			}

			super.onDialogReject(evt, aci);

			this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.MSC_REFUSES_SM,
					"onDialogReject after MT Request: " + mapRefuseReason != null ? mapRefuseReason.toString() : "",
					true, null, false);

		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogReject() when fetching records and issuing events: " + e1.getMessage(),
					e1);
		}
	}

	@Override
	public void onDialogProviderAbort(DialogProviderAbort evt, ActivityContextInterface aci) {
		try {
			super.onDialogProviderAbort(evt, aci);

			MAPAbortProviderReason abortProviderReason = evt.getAbortProviderReason();

			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onDialogProviderAbort()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.onDialogProviderAbort(), targetId="
						+ targetId);
				return;
			}

            this.onDeliveryError(
                    smsSet,
                    ErrorAction.permanentFailure,
                    ErrorCode.MSC_REFUSES_SM,
                    "onDialogProviderAbort after MtForwardSM Request: " + abortProviderReason != null ? abortProviderReason
                            .toString() : "", true, null, false);
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogProviderAbort() when fetching records and issuing events: "
							+ e1.getMessage(), e1);
		}
	}

	@Override
	public void onDialogUserAbort(DialogUserAbort evt, ActivityContextInterface aci) {
		try {
			super.onDialogUserAbort(evt, aci);

			String reason = getUserAbortReason(evt);

			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onDialogUserAbort()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.onDialogUserAbort(), targetId="
						+ targetId);
				return;
			}

            this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.MSC_REFUSES_SM,
                    "onDialogUserAbort after MtForwardSM Request: " + reason != null ? reason.toString() : "", true, null,
                    false);
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogUserAbort() when fetching records and issuing events: "
							+ e1.getMessage(), e1);
		}
	}

	@Override
	public void onDialogTimeout(DialogTimeout evt, ActivityContextInterface aci) {
		// TODO: may be it is not a permanent failure case ???

		try {
			super.onDialogTimeout(evt, aci);

			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onDialogTimeout()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.onDialogTimeout(), targetId="
						+ targetId);
				return;
			}

			this.onDeliveryError(smsSet, ErrorAction.temporaryFailure, ErrorCode.MSC_REFUSES_SM,
					"onDialogTimeout after MtForwardSM Request", true, null, false);
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogTimeout() when fetching records and issuing events: " + e1.getMessage(),
					e1);
		}
	}

	@Override
	public void onDialogDelimiter(DialogDelimiter evt, ActivityContextInterface aci) {
		try {
			super.onDialogDelimiter(evt, aci);

			SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
			if (smsDeliveryData == null) {
				this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onDialogDelimiter()");
				return;
			}
			String targetId = smsDeliveryData.getTargetId();
			SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
			if (smsSet == null) {
				this.logger.warning("In SmsDeliveryData CMP smsSet is missed - MtSbb.onDialogDelimiter(), targetId="
						+ targetId);
				return;
			}

			if (this.getTcEmptySent() != 0) {
				// Empty TC-BEGIN has been sent
				// We are sending MtForwardSM
				this.setTcEmptySent(0);

				SmsSignalInfo[] segments = this.getSegments();
				int messageSegmentNumber = this.getMessageSegmentNumber();
				if (messageSegmentNumber >= 0 && segments != null && messageSegmentNumber < segments.length) {
					SmsSignalInfo si = segments[messageSegmentNumber];
					if (si != null) {
						try {
							MAPDialogSms mapDialogSms = (MAPDialogSms) evt.getMAPDialog();
							SM_RP_DA sm_RP_DA = this.getSmRpDa();
							SM_RP_OA sm_RP_OA = this.getSmRpOa();

							boolean moreMessagesToSend = false;
							if (messageSegmentNumber < segments.length - 1) {
								moreMessagesToSend = true;
							}
							if (this.doGetCurrentMsgNum() < smsSet.getSmsCount() - 1) {
								moreMessagesToSend = true;
							}

							switch (mapDialogSms.getApplicationContext().getApplicationContextVersion()) {
							case version3:
								mapDialogSms.addMtForwardShortMessageRequest(sm_RP_DA, sm_RP_OA, si,
										moreMessagesToSend, null);
								if (this.logger.isInfoEnabled()) {
									this.logger.info("\nSending: MtForwardShortMessageRequest: sm_RP_DA=" + sm_RP_DA
											+ ", sm_RP_OA=" + sm_RP_OA + ", si=" + si + ", moreMessagesToSend="
											+ moreMessagesToSend);
								}
								break;
							case version2:
							case version1:
								mapDialogSms.addForwardShortMessageRequest(sm_RP_DA, sm_RP_OA, si, moreMessagesToSend);
								if (this.logger.isInfoEnabled()) {
									this.logger.info("\nSending: ForwardShortMessageRequest: sm_RP_DA=" + sm_RP_DA
											+ ", sm_RP_OA=" + sm_RP_OA + ", si=" + si + ", moreMessagesToSend="
											+ moreMessagesToSend);
								}
								break;
							default:
								break;
							}

							mapDialogSms.send();
						} catch (MAPException e) {
							logger.severe("Error while trying to send MtForwardShortMessageRequest", e);
						}
					}
				}
			} else if (this.getResponseReceived() == 1) {
				this.setResponseReceived(0);
				this.handleSmsResponse((MAPDialogSms) evt.getMAPDialog(), true);
			}
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogDelimiter() when fetching records and issuing events: "
							+ e1.getMessage(), e1);
		}
	}

	public void onDialogClose(DialogClose evt, ActivityContextInterface aci) {
		try {
			super.onDialogClose(evt, aci);

			if (this.getResponseReceived() == 1) {
				this.setResponseReceived(0);
				this.handleSmsResponse((MAPDialogSms) evt.getMAPDialog(), false);
			} else {

				SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
				if (smsDeliveryData == null) {
					this.logger.severe("smsDeliveryData CMP is missed - MtSbb.onDialogClose()");
					return;
				}
				String targetId = smsDeliveryData.getTargetId();
				SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
				if (smsSet == null) {
					this.logger.info("In SmsDeliveryData CMP smsSet is missed - MtSbb.onDialogClose(), targetId="
							+ targetId);
					return;
				}

				this.onDeliveryError(smsSet, ErrorAction.permanentFailure, ErrorCode.HLR_REJECT_AFTER_ROUTING_INFO,
						"DialogClose after Mt Request", false, null, false);
			}
		} catch (Throwable e1) {
			logger.severe(
					"Exception in MtSbb.onDialogClose() when fetching records and issuing events: " + e1.getMessage(),
					e1);
		}
	}

	/**
	 * SMS Event Handlers
	 */

	/**
	 * Received MT SMS. This is error we should never receive this
	 * 
	 * @param evt
	 * @param aci
	 */
	public void onForwardShortMessageRequest(ForwardShortMessageRequest evt, ActivityContextInterface aci) {
		this.logger.severe("\nReceived FORWARD_SHORT_MESSAGE_REQUEST = " + evt);
	}

	/**
	 * Received ACK for MT Forward SMS sent earlier
	 * 
	 * @param evt
	 * @param aci
	 */
	public void onForwardShortMessageResponse(ForwardShortMessageResponse evt, ActivityContextInterface aci) {
		if (this.logger.isFineEnabled()) {
			this.logger.fine("\nReceived FORWARD_SHORT_MESSAGE_RESPONSE = " + evt);
		}
		this.setResponseReceived(1);
	}

	/**
	 * Received MT SMS. This is error we should never receive this
	 * 
	 * @param evt
	 * @param aci
	 */
	public void onMtForwardShortMessageRequest(MtForwardShortMessageRequest evt, ActivityContextInterface aci) {
		this.logger.severe("\nReceived MT_FORWARD_SHORT_MESSAGE_REQUEST = " + evt);
	}

	/**
	 * Received ACK for MT Forward SMS sent earlier
	 * 
	 * @param evt
	 * @param aci
	 */
	public void onMtForwardShortMessageResponse(MtForwardShortMessageResponse evt, ActivityContextInterface aci) {
		if (this.logger.isFineEnabled()) {
			this.logger.fine("\nReceived MT_FORWARD_SHORT_MESSAGE_RESPONSE = " + evt);
		}

		this.setResponseReceived(1);
	}

	/**
	 * SBB Local Object Methods
	 * 
	 */

	@Override
    public void setupMtForwardShortMessageRequest(ISDNAddressString networkNode, String imsiData, LMSI lmsi, int networkId) {
        if (this.logger.isFineEnabled()) {
			this.logger.fine("\nmperforming setupMtForwardShortMessageRequest ISDNAddressString= " + networkNode);
		}

		SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
		if (smsDeliveryData == null) {
			this.logger.severe("smsDeliveryData CMP is missed - MtSbb.setupMtForwardShortMessageRequest()");
			return;
		}
		String targetId = smsDeliveryData.getTargetId();
		SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
		if (smsSet == null) {
			this.logger
					.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.setupMtForwardShortMessageRequest(), targetId="
							+ targetId);
			return;
		}

		SccpAddress networkNodeSccpAddress = this.getMSCSccpAddress(networkNode);

        IMSI imsi = this.mapParameterFactory.createIMSI(imsiData);
        SM_RP_DA sm_RP_DA = this.mapParameterFactory.createSM_RP_DA(imsi);
		SM_RP_OA sm_RP_OA = this.mapParameterFactory.createSM_RP_OA_ServiceCentreAddressOA(this
				.getServiceCenterAddressString(networkId));

		this.setNnn(networkNode);
		this.setNetworkNode(networkNodeSccpAddress);
		this.setSmRpDa(sm_RP_DA);
		this.setSmRpOa(sm_RP_OA);

		// Set cache with MAP version
		MAPApplicationContextVersion mapApplicationContextVersion = mapVersionCache
				.getMAPApplicationContextVersion(networkNode.getAddress());
		if (mapApplicationContextVersion == null) {
			mapApplicationContextVersion = MAPApplicationContextVersion.getInstance(smscPropertiesManagement
					.getMaxMapVersion());
		} else {
			this.setNegotiatedMapVersionUsing(true);
		}
		this.setMAPVersionTested(mapApplicationContextVersion);

        // dropaftersri pmproc rules
        boolean noMoreMessages = false;
        PersistenceRAInterface pers = this.getStore();
        TargetAddress lock = pers.obtainSynchroObject(new TargetAddress(smsSet));
        try {
            synchronized (lock) {
                long currentMsgNum = this.doGetCurrentMsgNum();
                Sms sms = smsSet.getSms(currentMsgNum);
                if (sms != null) {
                    while (true) {
                        MProcResult mProcResult = MProcManagement.getInstance().applyMProcImsiRequest(sms, imsiData,
                                networkNode.getAddress(), networkNode.getNumberingPlan().getIndicator(),
                                networkNode.getAddressNature().getIndicator());
                        if (mProcResult.isMessageDropped()) {
//                            if (logger.isInfoEnabled()) {
//                                logger.info("Sri-ImsiRequest: incoming messages are dropped by mProc rules, messages=[" + sms
//                                        + "]");
//                            }
                            this.onImsiDrop(sms, imsiData, networkNode);
                            if (currentMsgNum < smsSet.getSmsCount() - 1) {
                                // there are more messages to send in cache
                                currentMsgNum++;
                                this.doSetCurrentMsgNum(currentMsgNum);
                                sms = smsSet.getSms(currentMsgNum);
                                if (sms == null) {
                                    break;
                                }
                                continue;
                            } else {
                                noMoreMessages = true;
                                this.freeSmsSetSucceded(smsSet, pers);
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
        } finally {
            pers.releaseSynchroObject(lock);
        }

        if (noMoreMessages) {
            setupReportSMDeliveryStatusRequestSuccess(smsSet, true);
        } else {
            try {
                this.sendMtSms(this.getMtFoSMSMAPApplicationContext(mapApplicationContextVersion),
                        MessageProcessingState.firstMessageSending, null, smsSet.getNetworkId());
            } catch (SmscProcessingException e) {
                String reason = "SmscPocessingException when invoking sendMtSms() from setupMtForwardShortMessageRequest()-firstMessageSending: "
                        + e.toString();
                this.logger.severe(reason, e);
                ErrorCode smStatus = ErrorCode.SC_SYSTEM_ERROR;
                try {
                    smStatus = ErrorCode.fromInt(e.getSmppErrorCode());
                } catch (IllegalArgumentException e1) {
                }
                this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
            } catch (Throwable e) {
                String reason = "Exception when invoking sendMtSms() from setupMtForwardShortMessageRequest()-firstMessageSending: "
                        + e.toString();
                this.logger.severe(reason, e);
                ErrorCode smStatus = ErrorCode.SC_SYSTEM_ERROR;
                this.onDeliveryError(smsSet, ErrorAction.permanentFailure, smStatus, reason, true, null, false);
            }
        }
	}

	public void setupReportSMDeliveryStatusRequest(String destinationAddress, int ton, int npi,
			SMDeliveryOutcome sMDeliveryOutcome, String targetId, int networkId) {

		SbbLocalObjectExt sbbLocalObject = this.sbbContext.getSbbLocalObject().getParent();
		SriSbbLocalObject sriSbb = (SriSbbLocalObject) sbbLocalObject;
        sriSbb.setupReportSMDeliveryStatusRequest(destinationAddress, ton, npi, sMDeliveryOutcome, targetId, networkId);
	}

	/**
	 * CMPs
	 */
	public abstract void setSmsSubmitData(SmsSubmitData smsDeliveryData);

	public abstract SmsSubmitData getSmsSubmitData();

	public abstract void setCurrentMsgNum(long currentMsgNum);

	public abstract long getCurrentMsgNum();

	public abstract void setInformServiceCenterContainer(InformServiceCenterContainer informServiceCenterContainer);

	public abstract InformServiceCenterContainer getInformServiceCenterContainer();

	public abstract void setTcEmptySent(int tcEmptySent);

	public abstract int getTcEmptySent();

	public abstract void setResponseReceived(int responseReceived);

	public abstract int getResponseReceived();

	public abstract int getMapApplicationContextVersionsUsed();

	public abstract void setMapApplicationContextVersionsUsed(int mapApplicationContextVersions);

	public void doSetSmsSubmitData(SmsSubmitData smsDeliveryData) {
		this.setSmsSubmitData(smsDeliveryData);
	}

	public SmsSubmitData doGetSmsSubmitData() {
		return this.getSmsSubmitData();
	}

	public void doSetCurrentMsgNum(long currentMsgNum) {
		this.setCurrentMsgNum(currentMsgNum);
	}

	public long doGetCurrentMsgNum() {
		return this.getCurrentMsgNum();
	}

	public void doSetInformServiceCenterContainer(InformServiceCenterContainer informServiceCenterContainer) {
		this.setInformServiceCenterContainer(informServiceCenterContainer);
	}

	public InformServiceCenterContainer doGetInformServiceCenterContainer() {
		return this.getInformServiceCenterContainer();
	}

	/**
	 * Set the ISDNAddressString of network node where Mt SMS is to be submitted
	 * 
	 * @param networkNode
	 */
    public abstract void setNnn(ISDNAddressString nnn);

    public abstract ISDNAddressString getNnn();

	/**
	 * Set the counter as which SMS is sent. Max sending can be equal to
	 * messageSegmentCount
	 * 
	 * @param mesageSegmentNumber
	 */
	public abstract void setMessageSegmentNumber(int mesageSegmentNumber);

	public abstract int getMessageSegmentNumber();

	public abstract void setSegments(SmsSignalInfo[] segments);

	public abstract SmsSignalInfo[] getSegments();

	/**
	 * Destination Address
	 * 
	 * @param sm_rp_da
	 */
	public abstract void setSmRpDa(SM_RP_DA sm_rp_da);

	public abstract SM_RP_DA getSmRpDa();

    /**
     * Originating Address
     * 
     * @param sm_rp_oa
     */
    public abstract void setSmRpOa(SM_RP_OA sm_rp_oa);

    public abstract SM_RP_OA getSmRpOa();

    /**
     * NNN
     * 
     * @param networkNode
     */
    public abstract void setNetworkNode(SccpAddress sm_rp_oa);

    public abstract SccpAddress getNetworkNode();

	/**
	 * Private Methods
	 */

	private void handleSmsResponse(MAPDialogSms mapDialogSms, boolean continueDialog) {

		SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
		if (smsDeliveryData == null) {
			this.logger.severe("SmsDeliveryData CMP missed");
			return;
		}
		String targetId = smsDeliveryData.getTargetId();
		SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
		if (smsSet == null) {
			this.logger.severe("In SmsDeliveryData CMP smsSet is missed - MtSbb.handleSmsResponse(), targetId="
					+ targetId);
			return;
		}

		smscStatAggregator.updateMsgOutSentAll();
        smscStatAggregator.updateMsgOutSentSs7();

		PersistenceRAInterface pers = this.getStore();
		long currentMsgNum = this.doGetCurrentMsgNum();
		Sms sms = smsSet.getSms(currentMsgNum);

		// checking if there are yet message segments
		int messageSegmentNumber = this.getMessageSegmentNumber();
		SmsSignalInfo[] segments = this.getSegments();
		if (segments != null && messageSegmentNumber < segments.length - 1) {
            CdrGenerator.generateCdr(sms, CdrGenerator.CDR_PARTIAL, CdrGenerator.CDR_SUCCESS_NO_REASON, smscPropertiesManagement.getGenerateReceiptCdr(),
                    MessageUtil.isNeedWriteArchiveMessage(sms, smscPropertiesManagement.getGenerateCdr()));

			// we have more message parts to be sent yet
			messageSegmentNumber++;
			this.setMessageSegmentNumber(messageSegmentNumber);
			try {
	            smscStatAggregator.updateMsgOutTryAll();
	            smscStatAggregator.updateMsgOutTrySs7();

	            this.sendMtSms(mapDialogSms.getApplicationContext(), MessageProcessingState.nextSegmentSending,
						continueDialog ? mapDialogSms : null, smsSet.getNetworkId());
				return;
			} catch (SmscProcessingException e) {
				this.logger.severe(
						"SmscPocessingException when invoking sendMtSms() from handleSmsResponse()-nextSegmentSending: "
								+ e.toString(), e);
				this.onDeliveryError(smsSet, ErrorAction.temporaryFailure, ErrorCode.SYSTEM_FAILURE,
						"Error sendMtSms in handleSmsResponse(): ", true, null, false);
				return;
			}
		}

		// current message is sent
		// firstly sending of a positive response for transactional mode
        if (sms.getMessageDeliveryResultResponse() != null) {
            sms.getMessageDeliveryResultResponse().responseDeliverySuccess();
            sms.setMessageDeliveryResultResponse(null);
        }

		Date deliveryDate = new Date();
		try {
	        // pushing current message into an archive
			// we need to find if it is the last or single segment
			boolean isPartial = MessageUtil.isSmsNotLastSegment(sms);
            CdrGenerator.generateCdr(sms, isPartial ? CdrGenerator.CDR_PARTIAL : CdrGenerator.CDR_SUCCESS, CdrGenerator.CDR_SUCCESS_NO_REASON,
                    smscPropertiesManagement.getGenerateReceiptCdr(), MessageUtil.isNeedWriteArchiveMessage(sms, smscPropertiesManagement.getGenerateCdr()));

			if (smscPropertiesManagement.getDatabaseType() == DatabaseType.Cassandra_1) {
				pers.archiveDeliveredSms(sms, deliveryDate);
			} else {
                pers.c2_updateInSystem(sms, DBOperations_C2.IN_SYSTEM_SENT, smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast);
                sms.setDeliveryDate(deliveryDate);
                sms.getSmsSet().setStatus(ErrorCode.SUCCESS);
                if (MessageUtil.isNeedWriteArchiveMessage(sms, smscPropertiesManagement.getGenerateArchiveTable())) {
                    pers.c2_createRecordArchive(sms);
                }
			}

            // mproc rules applying for delivery phase
            MProcResult mProcResult = MProcManagement.getInstance().applyMProcDelivery(sms, false);
            FastList addedMessages = mProcResult.getMessageList();
            if (addedMessages != null) {
                for (FastList.Node n = addedMessages.head(), end = addedMessages.tail(); (n = n.getNext()) != end;) {
                    Sms smst = n.getValue();
                    TargetAddress ta = new TargetAddress(smst.getSmsSet().getDestAddrTon(), smst.getSmsSet().getDestAddrNpi(),
                            smst.getSmsSet().getDestAddr(), smst.getSmsSet().getNetworkId());
                    TargetAddress lock = SmsSetCache.getInstance().addSmsSet(ta);
                    try {
                        synchronized (lock) {
                            if (smscPropertiesManagement.getDatabaseType() == DatabaseType.Cassandra_1) {
                            } else {
                                boolean storeAndForwMode = MessageUtil.isStoreAndForward(smst);
                                if (!storeAndForwMode) {
                                    try {
                                        this.scheduler.injectSmsOnFly(smst.getSmsSet(), true);
                                    } catch (Exception e) {
                                        this.logger.severe(
                                                "Exception when runnung injectSmsOnFly() for applyMProcDelivery created messages in handleSmsResponse(): "
                                                        + e.getMessage(), e);
                                    }
                                } else {
                                    if (smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast) {
                                        try {
                                            smst.setStoringAfterFailure(true);
                                            this.scheduler.injectSmsOnFly(smst.getSmsSet(), true);
                                        } catch (Exception e) {
                                            this.logger.severe(
                                                    "Exception when runnung injectSmsOnFly() for applyMProcDelivery created messages in handleSmsResponse(): "
                                                            + e.getMessage(), e);
                                        }
                                    } else {
                                        smst.setStored(true);
                                        this.scheduler.setDestCluster(smst.getSmsSet());
                                        pers.c2_scheduleMessage_ReschedDueSlot(smst,
                                                smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast,
                                                true);
                                    }
                                }
                            }
                        }
                    } finally {
                        SmsSetCache.getInstance().removeSmsSet(lock);
                    }
                }
            }

			// adding a success receipt if it is needed
            int registeredDelivery = sms.getRegisteredDelivery();
            if (!smscPropertiesManagement.getReceiptsDisabling() && MessageUtil.isReceiptOnSuccess(registeredDelivery)) {
                TargetAddress ta = new TargetAddress(sms.getSourceAddrTon(), sms.getSourceAddrNpi(), sms.getSourceAddr(),
                        smsSet.getNetworkId());
                TargetAddress lock = SmsSetCache.getInstance().addSmsSet(ta);
                try {
                    synchronized (lock) {
                        Sms receipt;
                        if (smscPropertiesManagement.getDatabaseType() == DatabaseType.Cassandra_1) {
                            receipt = MessageUtil.createReceiptSms(sms, true);
                            SmsSet backSmsSet = pers.obtainSmsSet(ta);
                            receipt.setSmsSet(backSmsSet);
                            receipt.setStored(true);
                            pers.createLiveSms(receipt);
                            pers.setNewMessageScheduled(receipt.getSmsSet(), MessageUtil.computeDueDate(MessageUtil
                                    .computeFirstDueDelay(smscPropertiesManagement.getFirstDueDelay())));
                        } else {
                            receipt = MessageUtil.createReceiptSms(sms, true, ta,
                                    smscPropertiesManagement.getOrigNetworkIdForReceipts());
                            boolean storeAndForwMode = MessageUtil.isStoreAndForward(sms);
                            if (!storeAndForwMode) {
                                try {
                                    this.scheduler.injectSmsOnFly(receipt.getSmsSet(), true);
                                } catch (Exception e) {
                                    this.logger.severe(
                                            "Exception when runnung injectSmsOnFly() for receipt in handleSmsResponse(): "
                                                    + e.getMessage(), e);
                                }
                            } else {
                                if (smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast) {
                                    try {
                                        receipt.setStoringAfterFailure(true);
                                        this.scheduler.injectSmsOnFly(receipt.getSmsSet(), true);
                                    } catch (Exception e) {
                                        this.logger.severe(
                                                "Exception when runnung injectSmsOnFly() for receipt in handleSmsResponse(): "
                                                        + e.getMessage(), e);
                                    }
                                } else {
                                    receipt.setStored(true);
                                    this.scheduler.setDestCluster(receipt.getSmsSet());
                                    pers.c2_scheduleMessage_ReschedDueSlot(receipt,
                                            smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast, true);
                                }
                            }
                        }
                        this.logger.info("Adding a delivery receipt: source=" + receipt.getSourceAddr() + ", dest="
                                + receipt.getSmsSet().getDestAddr());
                    }
                } finally {
                    SmsSetCache.getInstance().removeSmsSet(lock);
                }
            }

		} catch (PersistenceException e1) {
			this.logger.severe(
					"PersistenceException when archiveDeliveredSms() in handleSmsResponse(): " + e1.getMessage(), e1);
			// we do not "return" here because even if storing into archive
			// database is failed
			// we will continue delivering process
		}

		TargetAddress lock = pers.obtainSynchroObject(new TargetAddress(smsSet));
		try {
			synchronized (lock) {
		        // marking the message in cache as delivered
		        smsSet.markSmsAsDelivered(currentMsgNum);

		        // now we are trying to sent other messages
                boolean moreMessages = false;
				if (currentMsgNum < smsSet.getSmsCount() - 1) {
					// there are more messages to send in cache
                    moreMessages = true;
					currentMsgNum++;
					this.doSetCurrentMsgNum(currentMsgNum);
                    sms = smsSet.getSms(currentMsgNum);

					// dropaftersri pmproc rules
                    if (sms != null) {
                        while (true) {
                            SM_RP_DA da = this.getSmRpDa();
                            ISDNAddressString networkNodeNumber = this.getNnn();
                            MProcResult mProcResult = MProcManagement.getInstance().applyMProcImsiRequest(sms,
                                    da.getIMSI().getData(), networkNodeNumber.getAddress(),
                                    networkNodeNumber.getNumberingPlan().getIndicator(),
                                    networkNodeNumber.getAddressNature().getIndicator());
                            if (mProcResult.isMessageDropped()) {
//                                if (logger.isInfoEnabled()) {
//                                    logger.info("Sri-ImsiRequest: incoming messages are dropped by mProc rules, messages=["
//                                            + sms + "]");
//                                }
                                this.onImsiDrop(sms, da.getIMSI().getData(), networkNodeNumber);
                                if (currentMsgNum < smsSet.getSmsCount() - 1) {
                                    // there are more messages to send in cache
                                    currentMsgNum++;
                                    this.doSetCurrentMsgNum(currentMsgNum);
                                    sms = smsSet.getSms(currentMsgNum);
                                    if (sms == null)
                                        break;
                                    if (smscPropertiesManagement.getDatabaseType() == DatabaseType.Cassandra_1) {
                                        this.startMessageDelivery(sms);
                                    } else {
                                        sms.setDeliveryCount(sms.getDeliveryCount() + 1);
                                    }
                                    continue;
                                } else {
                                    moreMessages = false;
                                    break;
                                }
                            } else {
                                break;
                            }
                        }

                        if (smscPropertiesManagement.getDatabaseType() == DatabaseType.Cassandra_1) {
                            this.startMessageDelivery(sms);
                        } else {
                            sms.setDeliveryCount(sms.getDeliveryCount() + 1);
                        }
                    }
				}

                if (moreMessages) {
                    try {
                        smscStatAggregator.updateMsgOutTryAll();
                        smscStatAggregator.updateMsgOutTrySs7();

                        this.sendMtSms(mapDialogSms.getApplicationContext(), MessageProcessingState.firstMessageSending,
                                continueDialog ? mapDialogSms : null, smsSet.getNetworkId());
                        return;
                    } catch (SmscProcessingException e) {
                        this.logger
                                .severe("SmscPocessingException when invoking sendMtSms() from handleSmsResponse(): "
                                        + e.toString(), e);
                    }
                }

                // no more messages are in cache now - lets check if there are
                // more messages in a database
                if (smscPropertiesManagement.getDatabaseType() == DatabaseType.Cassandra_1) {
					try {
						pers.fetchSchedulableSms(smsSet, true);
					} catch (PersistenceException e1) {
						this.logger.severe(
								"PersistenceException when invoking fetchSchedulableSms(smsSet) from handleSmsResponse(): "
										+ e1.toString(), e1);
					}
					if (smsSet.getSmsCount() > 0) {
						// there are more messages in a database - start
						// delivering of
						// those
						// messages
						currentMsgNum = 0;
						this.doSetCurrentMsgNum(currentMsgNum);

						try {
			                smscStatAggregator.updateMsgOutTryAll();
			                smscStatAggregator.updateMsgOutTrySs7();

                            this.sendMtSms(mapDialogSms.getApplicationContext(), MessageProcessingState.firstMessageSending, continueDialog ? mapDialogSms
                                    : null, smsSet.getNetworkId());
							return;
						} catch (SmscProcessingException e) {
							this.logger.severe(
									"SmscPocessingException when invoking sendMtSms() from handleSmsResponse(): "
											+ e.toString(), e);
						}
					}
				} else {
				}

				if (continueDialog) {
					try {
						mapDialogSms.close(false);
					} catch (MAPException e) {
						this.logger.severe(
								"MAPException when closing MAP dialog from handleSmsResponse(): " + e.toString(), e);
					}
				}

				// no more messages to send - remove smsSet
				this.freeSmsSetSucceded(smsSet, pers);
			}
		} finally {
			pers.releaseSynchroObject(lock);
		}

        setupReportSMDeliveryStatusRequestSuccess(smsSet,
                mapDialogSms.getApplicationContext().getApplicationContextVersion() != MAPApplicationContextVersion.version1);
	}

    private void setupReportSMDeliveryStatusRequestSuccess(SmsSet smsSet, boolean versionMore1) {
        InformServiceCenterContainer informServiceCenterContainer = this.getInformServiceCenterContainer();
        if (informServiceCenterContainer != null && informServiceCenterContainer.getMwStatus() != null
                && informServiceCenterContainer.getMwStatus().getScAddressNotIncluded() == false && versionMore1) {
            // sending a report to HLR of a success delivery
            this.setupReportSMDeliveryStatusRequest(smsSet.getDestAddr(), smsSet.getDestAddrTon(), smsSet.getDestAddrNpi(),
                    SMDeliveryOutcome.successfulTransfer, smsSet.getTargetId(), smsSet.getNetworkId());
        }
    }

    private String[] sliceMessage(String msg, DataCodingScheme dataCodingScheme, int nationalLanguageLockingShift,
            int nationalLanguageSingleShift) {
        int lenSolid = MessageUtil.getMaxSolidMessageCharsLength(dataCodingScheme);
        int lenSegmented = MessageUtil.getMaxSegmentedMessageCharsLength(dataCodingScheme);

        UserDataHeader udh = null;
        if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM7
                && (nationalLanguageLockingShift > 0 || nationalLanguageSingleShift > 0)) {
            udh = MessageUtil.getNationalLanguageIdentifierUdh(nationalLanguageLockingShift, nationalLanguageSingleShift);
            if (nationalLanguageLockingShift > 0) {
                lenSolid -= 3;
                lenSegmented -= 3;
            }
            if (nationalLanguageSingleShift > 0) {
                lenSolid -= 3;
                lenSegmented -= 3;
            }
        }

		int msgLenInChars = msg.length();
        if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM7 && msgLenInChars * 2 > lenSolid) {
            // GSM7 data coding. We need to care if some characters occupy two char places
            msgLenInChars = UserDataImpl.checkEncodedDataLengthInChars(msg, udh);
        }
		if (msgLenInChars <= lenSolid) {
            String[] res = new String[] { msg };
            return res;
		} else {
            if (dataCodingScheme.getCharacterSet() == CharacterSet.GSM7) {
                String[] res = UserDataImpl.sliceString(msg, lenSegmented, udh);
                return res;
            } else {
                ArrayList res = new ArrayList();
                int segmCnt = (msg.length() - 1) / lenSegmented + 1;
                for (int i1 = 0; i1 < segmCnt; i1++) {
                    if (i1 == segmCnt - 1) {
                        res.add(msg.substring(i1 * lenSegmented, msg.length()));
                    } else {
                        res.add(msg.substring(i1 * lenSegmented, (i1 + 1) * lenSegmented));
                    }
                }

                String[] ress = new String[res.size()];
                res.toArray(ress);
                return ress;
            }
        }
	}

    protected SmsSignalInfo createSignalInfo(Sms sms, String msg, byte[] udhData, boolean moreMessagesToSend,
            int messageReferenceNumber, int messageSegmentCount, int messageSegmentNumber, DataCodingScheme dataCodingScheme,
            int nationalLanguageLockingShift, int nationalLanguageSingleShift) throws MAPException {

        UserDataHeader userDataHeader;
        if (udhData != null) {
            userDataHeader = this.mapSmsTpduParameterFactory.createUserDataHeader(udhData);
        } else {
            userDataHeader = this.mapSmsTpduParameterFactory.createUserDataHeader();

            if (messageSegmentCount > 1) {
                UserDataHeaderElement concatenatedShortMessagesIdentifier = this.mapSmsTpduParameterFactory
                        .createConcatenatedShortMessagesIdentifier(messageReferenceNumber > 255, messageReferenceNumber,
                                messageSegmentCount, messageSegmentNumber);
                userDataHeader.addInformationElement(concatenatedShortMessagesIdentifier);
            }
            if (nationalLanguageLockingShift > 0) {
                NationalLanguageIdentifier nationalLanguageIdentifier = NationalLanguageIdentifier
                        .getInstance(nationalLanguageLockingShift);
                if (nationalLanguageIdentifier != null) {
                    UserDataHeaderElement nationalLanguageLockingShiftEl = this.mapSmsTpduParameterFactory
                            .createNationalLanguageLockingShiftIdentifier(nationalLanguageIdentifier);
                    userDataHeader.addInformationElement(nationalLanguageLockingShiftEl);
                }
            }
            if (nationalLanguageSingleShift > 0) {
                NationalLanguageIdentifier nationalLanguageIdentifier = NationalLanguageIdentifier
                        .getInstance(nationalLanguageSingleShift);
                if (nationalLanguageIdentifier != null) {
                    UserDataHeaderElement nationalLanguageSingleShiftEl = this.mapSmsTpduParameterFactory
                            .createNationalLanguageSingleShiftIdentifier(nationalLanguageIdentifier);
                    userDataHeader.addInformationElement(nationalLanguageSingleShiftEl);
                }
            }
        }

        UserData ud = this.mapSmsTpduParameterFactory.createUserData(msg, dataCodingScheme, userDataHeader, isoCharset);

		Date submitDate = sms.getSubmitDate();

		// TODO : TimeZone should be configurable
        AbsoluteTimeStamp serviceCentreTimeStamp = this.mapSmsTpduParameterFactory.createAbsoluteTimeStamp(
                (submitDate.getYear() % 100), (submitDate.getMonth() + 1), submitDate.getDate(), submitDate.getHours(),
                submitDate.getMinutes(), submitDate.getSeconds(), (submitDate.getTimezoneOffset() / 15));

        SmsDeliverTpdu smsDeliverTpdu = this.mapSmsTpduParameterFactory.createSmsDeliverTpdu(moreMessagesToSend, false,
                ((sms.getEsmClass() & SmppConstants.ESM_CLASS_REPLY_PATH_MASK) != 0), false,
                this.getSmsTpduOriginatingAddress(sms.getSourceAddrTon(), sms.getSourceAddrNpi(), sms.getSourceAddr()),
                this.mapSmsTpduParameterFactory.createProtocolIdentifier(sms.getProtocolId()), serviceCentreTimeStamp, ud);

        SmsSignalInfo smsSignalInfo = this.mapParameterFactory.createSmsSignalInfo(smsDeliverTpdu, isoCharset);

        return smsSignalInfo;
	}

	private void sendMtSms(MAPApplicationContext mapApplicationContext, MessageProcessingState messageProcessingState,
			MAPDialogSms mapDialogSms, int networkId) throws SmscProcessingException {

		SmsSubmitData smsDeliveryData = this.doGetSmsSubmitData();
		if (smsDeliveryData == null) {
			throw new SmscProcessingException("SmsDeliveryData CMP missed", -1, -1, null);
		}
		String targetId = smsDeliveryData.getTargetId();
		SmsSet smsSet = SmsSetCache.getInstance().getProcessingSmsSet(targetId);
		if (smsSet == null) {
			throw new SmscProcessingException("SmsSet is missed in ProcessingSmsSet cashe", -1, -1, null);
		}
		long msgNum = this.doGetCurrentMsgNum();
		Sms sms = smsSet.getSms(msgNum);

		if (sms == null) {
			throw new SmscProcessingException("SmsDeliveryData-sms is missed in CMP", -1, -1, null);
		}
		boolean moreMessagesToSend = false;
		if (msgNum < smsSet.getSmsCount() - 1) {
			moreMessagesToSend = true;
		}

		try {
			boolean newDialog = false;
			if (mapDialogSms == null) {
				newDialog = true;
				mapDialogSms = this.mapProvider.getMAPServiceSms().createNewDialog(mapApplicationContext,
						this.getServiceCenterSccpAddress(networkId), null, this.getNetworkNode(), null);
                mapDialogSms.setNetworkId(networkId);

				ActivityContextInterface mtFOSmsDialogACI = this.mapAcif.getActivityContextInterface(mapDialogSms);
				mtFOSmsDialogACI.attach(this.sbbContext.getSbbLocalObject());
			}

			SM_RP_DA sm_RP_DA = this.getSmRpDa();
			SM_RP_OA sm_RP_OA = this.getSmRpOa();

			SmsSignalInfo smsSignalInfo;
			if (messageProcessingState == MessageProcessingState.firstMessageSending) {

				DataCodingScheme dataCodingScheme = this.mapSmsTpduParameterFactory.createDataCodingScheme(sms.getDataCoding());
				Tlv sarMsgRefNum = sms.getTlvSet().getOptionalParameter(SmppConstants.TAG_SAR_MSG_REF_NUM);
				Tlv sarTotalSegments = sms.getTlvSet().getOptionalParameter(SmppConstants.TAG_SAR_TOTAL_SEGMENTS);
				Tlv sarSegmentSeqnum = sms.getTlvSet().getOptionalParameter(SmppConstants.TAG_SAR_SEGMENT_SEQNUM);
				SmsSignalInfo[] segments;
                if ((sms.getEsmClass() & SmppConstants.ESM_CLASS_UDHI_MASK) != 0) {
                    // message already contains UDH - we can not slice it
                    segments = new SmsSignalInfo[1];
                    segments[0] = this.createSignalInfo(sms, sms.getShortMessageText(), sms.getShortMessageBin(), moreMessagesToSend, 0, 1, 1,
                            dataCodingScheme, 0, 0);
				} else if (sarMsgRefNum != null && sarTotalSegments != null && sarSegmentSeqnum != null) {
					// we have tlv's that define message count/number/reference
					int messageSegmentCount = sarTotalSegments.getValueAsUnsignedByte();
					int messageSegmentNumber = sarSegmentSeqnum.getValueAsUnsignedByte();
					int messageReferenceNumber = sarMsgRefNum.getValueAsUnsignedShort();
					segments = new SmsSignalInfo[1];
                    segments[0] = this.createSignalInfo(sms, sms.getShortMessageText(), null, moreMessagesToSend,
                            messageReferenceNumber, messageSegmentCount, messageSegmentNumber, dataCodingScheme,
                            sms.getNationalLanguageLockingShift(), sms.getNationalLanguageSingleShift());
				} else {
					// possible a big message and segmentation
                    String[] segmentsByte;
                    segmentsByte = this.sliceMessage(sms.getShortMessageText(), dataCodingScheme,
                            sms.getNationalLanguageLockingShift(), sms.getNationalLanguageSingleShift());
                    segments = new SmsSignalInfo[segmentsByte.length];

					// TODO messageReferenceNumber should be generated
                    int messageReferenceNumber = (int)(msgNum + 1);

					for (int i1 = 0; i1 < segmentsByte.length; i1++) {
                        segments[i1] = this.createSignalInfo(sms, segmentsByte[i1], null, (i1 < segmentsByte.length - 1 ? true
                                : moreMessagesToSend), messageReferenceNumber, segmentsByte.length, i1 + 1, dataCodingScheme,
                                sms.getNationalLanguageLockingShift(), sms.getNationalLanguageSingleShift());
					}
				}

				this.setSegments(segments);
				smsSignalInfo = segments[0];
				this.setMessageSegmentNumber(0);
				if (segments.length > 1)
					moreMessagesToSend = true;
			} else {
				int messageSegmentNumber = this.getMessageSegmentNumber();
				SmsSignalInfo[] segments = this.getSegments();
				smsSignalInfo = segments[messageSegmentNumber];
				if (messageSegmentNumber < segments.length - 1)
					moreMessagesToSend = true;
			}

			long invokeId = 0;
			switch (mapDialogSms.getApplicationContext().getApplicationContextVersion()) {
			case version3:
				invokeId = mapDialogSms.addMtForwardShortMessageRequest(sm_RP_DA, sm_RP_OA, smsSignalInfo,
						moreMessagesToSend, null);
				if (this.logger.isInfoEnabled()) {
					this.logger.info("\nSending: MtForwardShortMessageRequest: sm_RP_DA=" + sm_RP_DA + ", sm_RP_OA="
							+ sm_RP_OA + ", si=" + smsSignalInfo + ", moreMessagesToSend=" + moreMessagesToSend);
				}
				break;
			case version2:
			case version1:
				invokeId = mapDialogSms.addForwardShortMessageRequest(sm_RP_DA, sm_RP_OA, smsSignalInfo,
						moreMessagesToSend);
				if (this.logger.isInfoEnabled()) {
					this.logger.info("\nSending: ForwardShortMessageRequest: sm_RP_DA=" + sm_RP_DA + ", sm_RP_OA="
							+ sm_RP_OA + ", si=" + smsSignalInfo + ", moreMessagesToSend=" + moreMessagesToSend);
				}
				break;
			default:
				break;
			}

			int messageUserDataLengthOnSend = mapDialogSms.getMessageUserDataLengthOnSend();
			int maxUserDataLength = mapDialogSms.getMaxUserDataLength();
			if (mapDialogSms.getApplicationContext().getApplicationContextVersion() != MAPApplicationContextVersion.version1
					&& newDialog
					&& messageUserDataLengthOnSend >= maxUserDataLength
							- SmscPropertiesManagement.getInstance().getMaxMessageLengthReducer()) {
				mapDialogSms.cancelInvocation(invokeId);
				this.setTcEmptySent(1);
			} else {
				this.setTcEmptySent(0);
			}

			mapDialogSms.send();

		} catch (MAPException e) {
			if (mapDialogSms != null)
				mapDialogSms.release();
            throw new SmscProcessingException("MAPException when sending MtForwardSM. \nSms=" + sms, -1, -1, null, e);
		} catch (TlvConvertException e) {
			if (mapDialogSms != null)
				mapDialogSms.release();
			throw new SmscProcessingException("TlvConvertException when sending MtForwardSM", -1, -1, null, e);
		}
	}

	private MAPApplicationContext getMtFoSMSMAPApplicationContext(
			MAPApplicationContextVersion mapApplicationContextVersion) {

		if (mapApplicationContextVersion == MAPApplicationContextVersion.version1) {
			return MAPApplicationContext.getInstance(MAPApplicationContextName.shortMsgMORelayContext,
					mapApplicationContextVersion);
		} else {
			return MAPApplicationContext.getInstance(MAPApplicationContextName.shortMsgMTRelayContext,
					mapApplicationContextVersion);
		}
	}

	private SccpAddress getMSCSccpAddress(ISDNAddressString networkNodeNumber) {
        return MessageUtil.getSccpAddress(sccpParameterFact, networkNodeNumber.getAddress(), networkNodeNumber.getAddressNature().getIndicator(),
                networkNodeNumber.getNumberingPlan().getIndicator(), smscPropertiesManagement.getMscSsn(), smscPropertiesManagement.getGlobalTitleIndicator(),
                smscPropertiesManagement.getTranslationType());

//		NumberingPlan np = MessageUtil.getSccpNumberingPlan(networkNodeNumber.getNumberingPlan().getIndicator());
//		NatureOfAddress na = MessageUtil.getSccpNatureOfAddress(networkNodeNumber.getAddressNature().getIndicator());
//
//        GlobalTitle gt = sccpParameterFact.createGlobalTitle(networkNodeNumber.getAddress(), 0, np, null, na);
//        return sccpParameterFact.createSccpAddress(RoutingIndicator.ROUTING_BASED_ON_GLOBAL_TITLE, gt, 0, smscPropertiesManagement.getMscSsn());
	}

	private AddressField getSmsTpduOriginatingAddress(int ton, int npi, String address) {
        return this.mapSmsTpduParameterFactory.createAddressField(TypeOfNumber.getInstance(ton),
                NumberingPlanIdentification.getInstance(npi), address);
	}

	protected boolean isNegotiatedMapVersionUsing() {
		int existingVersionsTried = this.getMapApplicationContextVersionsUsed();
		return (existingVersionsTried & 0x80) != 0;
	}

	protected void setNegotiatedMapVersionUsing(boolean val) {
		int existingVersionsTried = this.getMapApplicationContextVersionsUsed();
		if (val) {
			existingVersionsTried |= 0x80;
		} else {
			existingVersionsTried &= 0x7F;
		}
		this.setMapApplicationContextVersionsUsed(existingVersionsTried);
	}

	protected boolean isMAPVersionTested(MAPApplicationContextVersion vers) {
		if (vers == null)
			return false;
		int existingVersionsTried = this.getMapApplicationContextVersionsUsed();
		switch (vers.getVersion()) {
		case 1:
			return (existingVersionsTried & MASK_MAP_VERSION_1) != 0;
		case 2:
			return (existingVersionsTried & MASK_MAP_VERSION_2) != 0;
		case 3:
			return (existingVersionsTried & MASK_MAP_VERSION_3) != 0;
		}
		return false;
	}

	protected void setMAPVersionTested(MAPApplicationContextVersion vers) {
		int existingVersionsTried = this.getMapApplicationContextVersionsUsed();
		switch (vers.getVersion()) {
		case 1:
			existingVersionsTried |= MASK_MAP_VERSION_1;
			break;
		case 2:
			existingVersionsTried |= MASK_MAP_VERSION_2;
			break;
		case 3:
			existingVersionsTried |= MASK_MAP_VERSION_3;
			break;
		}
		this.setMapApplicationContextVersionsUsed(existingVersionsTried);
	}

	public enum MessageProcessingState {
		firstMessageSending, nextSegmentSending, resendAfterMapProtocolNegotiation,
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy