/* * 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.submitsbb; import javax.slee.ActivityContextInterface; import javax.slee.CreateException; import javax.slee.RolledBackContext; import javax.slee.Sbb; import javax.slee.SbbContext; import javax.slee.facilities.Tracer; import javax.slee.resource.ResourceAdaptorTypeID; import org.mobicents.protocols.ss7.map.api.errors.MAPErrorCode; import org.mobicents.slee.ChildRelationExt; import org.mobicents.slee.SbbContextExt; import org.mobicents.smsc.cassandra.PersistenceException; import org.mobicents.smsc.domain.MProcManagement; import org.mobicents.smsc.domain.SmscCongestionControl; import org.mobicents.smsc.domain.SmscPropertiesManagement; import org.mobicents.smsc.domain.SmscStatAggregator; import org.mobicents.smsc.domain.StoreAndForwordMode; import org.mobicents.smsc.library.MessageUtil; import org.mobicents.smsc.library.Sms; import org.mobicents.smsc.library.SmsSetCache; import org.mobicents.smsc.library.SmscProcessingException; import org.mobicents.smsc.library.TargetAddress; import org.mobicents.smsc.mproc.MProcRuleRaProvider; import org.mobicents.smsc.mproc.impl.MProcResult; import org.mobicents.smsc.slee.resources.persistence.PersistenceRAInterface; import org.mobicents.smsc.slee.resources.scheduler.SchedulerRaSbbInterface; import org.mobicents.smsc.slee.services.charging.ChargingMedium; import org.mobicents.smsc.slee.services.charging.ChargingSbbLocalObject; import com.cloudhopper.smpp.SmppConstants; import javolution.util.FastList; /** * * @author sergey vetyutnev * */ public abstract class SubmitCommonSbb implements Sbb { public static SmscPropertiesManagement smscPropertiesManagement = SmscPropertiesManagement.getInstance(); private static final ResourceAdaptorTypeID PERSISTENCE_ID = new ResourceAdaptorTypeID("PersistenceResourceAdaptorType", "org.mobicents", "1.0"); private static final ResourceAdaptorTypeID SCHEDULE_ID = new ResourceAdaptorTypeID("SchedulerResourceAdaptorType", "org.mobicents", "1.0"); private static final String PERSISTENCE_LINK = "PersistenceResourceAdaptor"; private static final String SCHEDULE_LINK = "SchedulerResourceAdaptor"; public static final ResourceAdaptorTypeID MPROC_RATYPE_ID = new ResourceAdaptorTypeID("MProcResourceAdaptorType", "org.mobicents", "1.0"); private static final String MPROC_RA_LINK = "MProcResourceAdaptor"; protected Tracer logger; protected SbbContextExt sbbContext; protected PersistenceRAInterface persistence; protected SchedulerRaSbbInterface scheduler; private MProcRuleRaProvider itsMProcRa; private final String className; public SubmitCommonSbb(String className) { this.className = className; } // ********* // sbb overriding methods. // Loading of sbbContext and logger @Override public void setSbbContext(SbbContext sbbContext) { this.sbbContext = (SbbContextExt) sbbContext; this.logger = this.sbbContext.getTracer(this.className); // getClass().getSimpleName() try { this.persistence = (PersistenceRAInterface) this.sbbContext.getResourceAdaptorInterface(PERSISTENCE_ID, PERSISTENCE_LINK); this.scheduler = (SchedulerRaSbbInterface) this.sbbContext.getResourceAdaptorInterface(SCHEDULE_ID, SCHEDULE_LINK); itsMProcRa = (MProcRuleRaProvider) this.sbbContext.getResourceAdaptorInterface(MPROC_RATYPE_ID, MPROC_RA_LINK); } catch (Exception ne) { logger.severe("Could not set SBB context:", ne); } } @Override public void sbbLoad() { } @Override public void sbbStore() { } @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 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 unsetSbbContext() { itsMProcRa = null; } // ********* // getChargingSbbObject public abstract ChildRelationExt getChargingSbb(); protected ChargingSbbLocalObject getChargingSbbObject() { ChildRelationExt relation = getChargingSbb(); ChargingSbbLocalObject ret = (ChargingSbbLocalObject) relation.get(ChildRelationExt.DEFAULT_CHILD_NAME); if (ret == null) { try { ret = (ChargingSbbLocalObject) relation.create(ChildRelationExt.DEFAULT_CHILD_NAME); } catch (Exception e) { if (this.logger.isSevereEnabled()) { this.logger.severe("Exception while trying to creat ChargingSbb child", e); } } } return ret; } // ********* // general processing methods protected void checkSmscState(Sms sms, SmscCongestionControl smscCongestionControl, MaxActivityCountFactor maxActivityCountFactor) throws SmscProcessingException { // checking if SMSC is stopped if (smscPropertiesManagement.isSmscStopped()) { SmscProcessingException e = new SmscProcessingException("SMSC is stopped", SmppConstants.STATUS_SYSERR, MAPErrorCode.facilityNotSupported, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_STATE_STOPPED); e.setSkipErrorLogging(true); throw e; } // checking if SMSC is paused if (smscPropertiesManagement.isDeliveryPause() && (!MessageUtil.isStoreAndForward(sms) || smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast)) { SmscProcessingException e = new SmscProcessingException("SMSC is paused", SmppConstants.STATUS_SYSERR, MAPErrorCode.facilityNotSupported, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_STATE_PAUSED); e.setSkipErrorLogging(true); throw e; } // checking if cassandra database is available if (!persistence.isDatabaseAvailable() && MessageUtil.isStoreAndForward(sms)) { SmscProcessingException e = new SmscProcessingException("Database is unavailable", SmppConstants.STATUS_SYSERR, MAPErrorCode.facilityNotSupported, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_STATE_DATABASE_NOT_AVAILABLE); e.setSkipErrorLogging(true); throw e; } if (!MessageUtil.isStoreAndForward(sms) || smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast) { // checking if delivery query is overloaded int activityCount = SmsSetCache.getInstance().getProcessingSmsSetSize(); switch (maxActivityCountFactor) { case factor_12: int fetchMaxRows = (int) (smscPropertiesManagement.getMaxActivityCount() * 1.2); if (activityCount >= fetchMaxRows) { smscCongestionControl.registerMaxActivityCount1_2Threshold(); SmscProcessingException e = new SmscProcessingException("SMSC is overloaded", SmppConstants.STATUS_THROTTLED, MAPErrorCode.resourceLimitation, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_STATE_OVERLOADED); e.setSkipErrorLogging(true); throw e; } else { smscCongestionControl.registerMaxActivityCount1_2BackToNormal(); } break; case factor_14: fetchMaxRows = (int) (smscPropertiesManagement.getMaxActivityCount() * 1.4); if (activityCount >= fetchMaxRows) { smscCongestionControl.registerMaxActivityCount1_4Threshold(); SmscProcessingException e = new SmscProcessingException("SMSC is overloaded", SmppConstants.STATUS_THROTTLED, MAPErrorCode.resourceLimitation, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, SmscProcessingException.INTERNAL_ERROR_STATE_OVERLOADED); e.setSkipErrorLogging(true); throw e; } else { smscCongestionControl.registerMaxActivityCount1_4BackToNormal(); } break; } } } protected void forwardMessage(Sms sms0, boolean withCharging, SmscStatAggregator smscStatAggregator) throws SmscProcessingException { ChargingMedium chargingMedium = null; switch (sms0.getOriginationType()) { case SMPP: chargingMedium = ChargingMedium.TxSmppOrig; break; case SS7_MO: case SS7_HR: chargingMedium = ChargingMedium.MoOrig; break; case SIP: chargingMedium = ChargingMedium.TxSipOrig; break; case HTTP: chargingMedium = ChargingMedium.HttpOrig; break; } if (withCharging) { ChargingSbbLocalObject chargingSbb = getChargingSbbObject(); chargingSbb.setupChargingRequestInterface(chargingMedium, sms0); } else { // applying of MProc MProcResult mProcResult = MProcManagement.getInstance().applyMProcArrival(itsMProcRa, sms0, persistence); FastList<Sms> smss = mProcResult.getMessageList(); for (FastList.Node<Sms> n = smss.head(), end = smss.tail(); (n = n.getNext()) != end;) { Sms sms = n.getValue(); TargetAddress ta = new TargetAddress(sms.getSmsSet()); TargetAddress lock = persistence.obtainSynchroObject(ta); try { synchronized (lock) { boolean storeAndForwMode = MessageUtil.isStoreAndForward(sms); if (!storeAndForwMode) { try { this.scheduler.injectSmsOnFly(sms.getSmsSet(), true); } catch (Exception e) { throw new SmscProcessingException("Exception when runnung injectSmsOnFly(): " + e.getMessage(), SmppConstants.STATUS_SYSERR, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_INJECT_STORE_AND_FORWARD_NOT_SET); } } else { // store and forward if (smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast && sms.getScheduleDeliveryTime() == null) { try { sms.setStoringAfterFailure(true); this.scheduler.injectSmsOnFly(sms.getSmsSet(), true); } catch (Exception e) { throw new SmscProcessingException( "Exception when runnung injectSmsOnFly(): " + e.getMessage(), SmppConstants.STATUS_SYSERR, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_INJECT_STORE_AND_FORWARD_FAST); } } else { try { sms.setStored(true); this.scheduler.setDestCluster(sms.getSmsSet()); persistence.c2_scheduleMessage_ReschedDueSlot(sms, smscPropertiesManagement.getStoreAndForwordMode() == StoreAndForwordMode.fast, false); } catch (PersistenceException e) { throw new SmscProcessingException( "PersistenceException when storing LIVE_SMS : " + e.getMessage(), SmppConstants.STATUS_SUBMITFAIL, MAPErrorCode.systemFailure, SmscProcessingException.HTTP_ERROR_CODE_NOT_SET, null, e, SmscProcessingException.INTERNAL_ERROR_INJECT_STORE_AND_FORWARD_NORMAL); } } } } } finally { persistence.releaseSynchroObject(lock); } } if (mProcResult.isMessageRejected()) { sms0.setMessageDeliveryResultResponse(null); final SmscProcessingException e = new SmscProcessingException("Message is rejected by MProc rules.", getErrorCode(mProcResult.getSmppErrorCode(), SmppConstants.STATUS_SUBMITFAIL), getErrorCode(mProcResult.getMapErrorCode(), MAPErrorCode.systemFailure), getErrorCode(mProcResult.getHttpErrorCode(), SmscProcessingException.HTTP_ERROR_CODE_NOT_SET), null, SmscProcessingException.INTERNAL_ERROR_MPROC_REJECT); e.setSkipErrorLogging(true); if (logger.isInfoEnabled()) { logger.info("Incoming message is rejected by mProc rules, message=[" + sms0 + "]"); } throw e; } if (mProcResult.isMessageDropped()) { sms0.setMessageDeliveryResultResponse(null); smscStatAggregator.updateMsgInFailedAll(); if (logger.isInfoEnabled()) { logger.info("Incoming message is dropped by mProc rules, message=[" + sms0 + "]"); } return; } smscStatAggregator.updateMsgInReceivedAll(); switch (sms0.getOriginationType()) { case SMPP: smscStatAggregator.updateMsgInReceivedSmpp(); break; case SS7_MO: smscStatAggregator.updateMsgInReceivedSs7(); smscStatAggregator.updateMsgInReceivedSs7Mo(); break; case SS7_HR: smscStatAggregator.updateMsgInReceivedSs7(); smscStatAggregator.updateMsgInReceivedSs7Hr(); break; case SIP: smscStatAggregator.updateMsgInReceivedSip(); break; } } } public enum MaxActivityCountFactor { factor_12, factor_14, } private static int getErrorCode(final int anErrorCode, final int aDefaultErrorCode) { if (anErrorCode < 0) { return aDefaultErrorCode; } return anErrorCode; } }