/* * Telestax, Open Source Cloud Communications Copyright 2011-2017, * Telestax Inc 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.domain; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.SortedMap; import java.util.TreeMap; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.StandardMBean; import org.apache.log4j.Logger; import org.jboss.mx.util.MBeanServerLocator; import org.mobicents.smsc.library.CorrelationIdValue; import org.mobicents.smsc.library.Sms; import org.mobicents.smsc.mproc.MProcMessage; import org.mobicents.smsc.mproc.MProcNewMessage; import org.mobicents.smsc.mproc.MProcRule; import org.mobicents.smsc.mproc.MProcRuleFactory; import org.mobicents.smsc.mproc.MProcRuleMBean; import org.mobicents.smsc.mproc.MProcRuleRaProvider; import org.mobicents.smsc.mproc.ProcessingType; import org.mobicents.smsc.mproc.impl.MProcMessageHrImpl; import org.mobicents.smsc.mproc.impl.MProcMessageImpl; import org.mobicents.smsc.mproc.impl.MProcNewMessageImpl; import org.mobicents.smsc.mproc.impl.MProcResult; import org.mobicents.smsc.mproc.impl.MProcRuleOamMessages; import org.mobicents.smsc.mproc.impl.PersistenseCommonInterface; import org.mobicents.smsc.mproc.impl.PostArrivalProcessorImpl; import org.mobicents.smsc.mproc.impl.PostDeliveryProcessorImpl; import org.mobicents.smsc.mproc.impl.PostDeliveryTempFailureProcessorImpl; import org.mobicents.smsc.mproc.impl.PostHrSriProcessorImpl; import org.mobicents.smsc.mproc.impl.PostImsiProcessorImpl; import org.mobicents.smsc.mproc.impl.PostPreDeliveryProcessorImpl; import javolution.text.TextBuilder; import javolution.util.FastList; import javolution.xml.XMLBinding; import javolution.xml.XMLObjectReader; import javolution.xml.XMLObjectWriter; import javolution.xml.stream.XMLStreamException; /** * * @author sergey vetyutnev * */ public class MProcManagement implements MProcManagementMBean { private static final Logger logger = Logger.getLogger(MProcManagement.class); private static final String MPROC_LIST = "mprocList"; private static final String TAB_INDENT = "\t"; private static final String CLASS_ATTRIBUTE = "type"; private static final XMLBinding binding = new XMLBinding(); private static final String PERSIST_FILE_NAME = "mproc.xml"; private final String name; private String persistDir = null; protected FastList<MProcRule> mprocs = new FastList<MProcRule>(); private final TextBuilder persistFile = TextBuilder.newInstance(); private MBeanServer mbeanServer = null; private static MProcManagement instance = null; private SmscManagement smscManagement = null; private SmscPropertiesManagement smscPropertiesManagement = null; private MProcManagement(String name) { this.name = name; binding.setClassAttribute(CLASS_ATTRIBUTE); } public static MProcManagement getInstance(String name) { if (instance == null) { instance = new MProcManagement(name); } return instance; } public static MProcManagement getInstance() { return instance; } public String getName() { return name; } public String getPersistDir() { return persistDir; } public void setPersistDir(String persistDir) { this.persistDir = persistDir; } public SmscManagement getSmscManagement() { return smscManagement; } public void setSmscManagement(SmscManagement smscManagement) { this.smscManagement = smscManagement; } @Override public FastList<MProcRule> getMProcRules() { return mprocs; } @Override public MProcRule getMProcRuleById(int id) { FastList<MProcRule> cur = mprocs; for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.getId() == id) return rule; } return null; } private void resortRules(FastList<MProcRule> lst) { SortedMap<Integer, MProcRule> cur = new TreeMap<Integer, MProcRule>(); for (FastList.Node<MProcRule> n = lst.head(), end = lst.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); cur.put(rule.getId(), rule); } FastList<MProcRule> res = new FastList<MProcRule>(); res.addAll(cur.values()); this.mprocs = res; } @Override public MProcRule createMProcRule(int id, String ruleFactoryName, String parametersString) throws Exception { logger.info("createMProcRule: id=" + id + ", ruleFactoryName=" + ruleFactoryName + ", parametersString=" + parametersString); if (ruleFactoryName == null) { throw new Exception(String.format(MProcRuleOamMessages.CREATE_MPROC_RULE_FAIL_RULE_CLASS_NAME_NULL_VALUE)); } MProcRuleFactory ruleClass = null; if (this.smscManagement != null) { ruleClass = this.smscManagement.getRuleFactory(ruleFactoryName); } if (ruleClass == null) { throw new Exception(String.format(MProcRuleOamMessages.CREATE_MPROC_RULE_FAIL_RULE_CLASS_NOT_FOUND, ruleFactoryName)); } if (this.getMProcRuleById(id) != null) { throw new Exception(String.format(MProcRuleOamMessages.CREATE_MPROC_RULE_FAIL_ALREADY_EXIST, id)); } MProcRule mProcRule = ruleClass.createMProcRuleInstance(); mProcRule.setId(id); mProcRule.setInitialRuleParameters(parametersString); FastList<MProcRule> lstTag = new FastList<MProcRule>(this.mprocs); lstTag.add(mProcRule); this.resortRules(lstTag); this.store(); this.registerMProcRuleMbean(mProcRule); return mProcRule; } @Override public MProcRule modifyMProcRule(int mProcRuleId, String parametersString) throws Exception { logger.info("modifyMProcRule: id=" + mProcRuleId + ", parametersString=" + parametersString); MProcRule mProcRule = this.getMProcRuleById(mProcRuleId); if (mProcRule == null) { throw new Exception(String.format(MProcRuleOamMessages.MODIFY_MPROC_RULE_FAIL_NOT_EXIST, mProcRuleId)); } mProcRule.updateRuleParameters(parametersString); this.store(); return mProcRule; } @Override public MProcRule destroyMProcRule(int mProcRuleId) throws Exception { logger.info("destroyMProcRule: id=" + mProcRuleId); MProcRule mProcRule = this.getMProcRuleById(mProcRuleId); if (mProcRule == null) { throw new Exception(String.format(MProcRuleOamMessages.DESTROY_MPROC_RULE_FAIL_NOT_EXIST, mProcRuleId)); } FastList<MProcRule> lstTag = new FastList<MProcRule>(this.mprocs); lstTag.remove(mProcRule); this.resortRules(lstTag); this.store(); this.unregisterMProcRuleMbean(mProcRule.getId()); return mProcRule; } public MProcResult applyMProcArrival(final MProcRuleRaProvider anMProcRuleRa, Sms sms, PersistenseCommonInterface persistence) { if (this.mprocs.size() == 0) { FastList<Sms> res0 = new FastList<Sms>(); res0.add(sms); MProcResult res = new MProcResult(); res.setMessageList(res0); return res; } FastList<MProcRule> cur = this.mprocs; PostArrivalProcessorImpl pap = new PostArrivalProcessorImpl( this.smscPropertiesManagement.getDefaultValidityPeriodHours(), this.smscPropertiesManagement.getMaxValidityPeriodHours(), logger); MProcMessage message = new MProcMessageImpl(sms, null, persistence); try { for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.isForPostArrivalState() && rule.matchesPostArrival(message)) { if (logger.isDebugEnabled()) { logger.debug("MRule matches at Arrival phase to a message:\nrule: " + rule + "\nmessage: " + sms); } rule.onPostArrival(anMProcRuleRa, pap, message); } } } catch (Throwable e) { logger.error( "Exception when invoking rule.matches(message) or applyMProcArrival: " + e.getMessage(), e); MProcResult res = new MProcResult(); res.setMessageDropped(true); return res; } MProcResult res = new MProcResult();; FastList<Sms> res0 = new FastList<Sms>(); res.setMessageList(res0); FastList<MProcNewMessage> newMsgs = pap.getPostedMessages(); if (pap.isNeedDropMessage()) { res.setMessageDropped(true); } else if (pap.isNeedRejectMessage()) { res.setMessageRejected(true); res.setMapErrorCode(pap.getMapErrorCode()); res.setHttpErrorCode(pap.getHttpErrorCode()); res.setSmppErrorCode(pap.getSmppErrorCode()); } else { res0.add(sms); } for (FastList.Node<MProcNewMessage> n = newMsgs.head(), end = newMsgs.tail(); (n = n.getNext()) != end;) { MProcNewMessageImpl newMsg = (MProcNewMessageImpl) n.getValue(); res0.add(newMsg.getSmsContent()); } return res; } public MProcResult applyMProcHrSri(final MProcRuleRaProvider anMProcRuleRa, CorrelationIdValue correlationIdValue) { if (this.mprocs.size() == 0) { return new MProcResult(); } FastList<MProcRule> cur = this.mprocs; PostHrSriProcessorImpl pap = new PostHrSriProcessorImpl(logger); MProcMessage message = new MProcMessageHrImpl(correlationIdValue); try { for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.isForPostHrSriState() && rule.matchesPostHrSri(message)) { if (logger.isDebugEnabled()) { logger.debug("MRule matches at HrSri phase to a message:\nrule: " + rule + "\ncorrelationIdValue: " + correlationIdValue); } rule.onPostHrSri(anMProcRuleRa, pap, message); } } } catch (Throwable e) { logger.error("Exception when invoking rule.matches(message) or onPostHrSri(): " + e.getMessage(), e); return new MProcResult(); } MProcResult res = new MProcResult(); if (pap.isHrByPassed()) { res.setHrIsByPassed(true); } return res; } public MProcResult applyMProcPreDelivery(final MProcRuleRaProvider anMProcRuleRa, Sms sms, ProcessingType processingType) { if (this.mprocs.size() == 0) { return new MProcResult(); } FastList<MProcRule> cur = this.mprocs; PostPreDeliveryProcessorImpl pap = new PostPreDeliveryProcessorImpl(this.smscPropertiesManagement.getDefaultValidityPeriodHours(), this.smscPropertiesManagement.getMaxValidityPeriodHours(), logger); MProcMessage message = new MProcMessageImpl(sms, processingType, null); try { for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.isForPostPreDeliveryState() && rule.matchesPostPreDelivery(message)) { if (logger.isDebugEnabled()) { logger.debug("MRule matches at PreDelivery phase to a message:\nrule: " + rule + "\nmessage: " + sms); } rule.onPostPreDelivery(anMProcRuleRa, pap, message); } } } catch (Throwable e) { logger.error( "Exception when invoking rule.matches(message) or onPostPreDelivery(): " + e.getMessage(), e); return new MProcResult(); } FastList<MProcNewMessage> newMsgs = pap.getPostedMessages(); MProcResult res = new MProcResult(); FastList<Sms> res0 = new FastList<Sms>(); for (FastList.Node<MProcNewMessage> n = newMsgs.head(), end = newMsgs.tail(); (n = n.getNext()) != end;) { MProcNewMessageImpl newMsg = (MProcNewMessageImpl) n.getValue(); res0.add(newMsg.getSmsContent()); } res.setMessageList(res0); if (pap.isNeedDropMessages()) { res.setMessageDropped(true); } if (pap.isNeedRerouteMessages()) { res.setMessageIsRerouted(true); res.setNewNetworkId(pap.getNewNetworkId()); } return res; } public MProcResult applyMProcImsiRequest(final MProcRuleRaProvider anMProcRuleRa, Sms sms, String imsi, String nnnDigits, int nnnNumberingPlan, int nnnAddressNature) { if (this.mprocs.size() == 0) return new MProcResult(); FastList<MProcRule> cur = this.mprocs; PostImsiProcessorImpl pap = new PostImsiProcessorImpl(logger); MProcMessage message = new MProcMessageImpl(sms, ProcessingType.SS7_SRI, null); try { for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.isForPostImsiRequestState() && rule.matchesPostImsiRequest(message)) { if (logger.isDebugEnabled()) { logger.debug("MRule matches at ImsiRequest phase to a message:\nrule: " + rule + "\nmessage: " + sms); } rule.onPostImsiRequest(anMProcRuleRa, pap, message); } } } catch (Throwable e) { logger.error("Exception when invoking rule.matches(message) or applyMProcImsiRequest(): " + e.getMessage(), e); return new MProcResult(); } if (pap.isNeedDropMessages()) { MProcResult res = new MProcResult(); res.setMessageDropped(true); return res; } if (pap.isNeedRerouteMessages()) { MProcResult res = new MProcResult(); res.setMessageIsRerouted(true); res.setNewNetworkId(pap.getNewNetworkId()); return res; } return new MProcResult(); } public MProcResult applyMProcDelivery(final MProcRuleRaProvider anMProcRuleRa, Sms sms, boolean deliveryFailure, ProcessingType processingType) { if (this.mprocs.size() == 0) { return new MProcResult(); } FastList<MProcRule> cur = this.mprocs; PostDeliveryProcessorImpl pap = new PostDeliveryProcessorImpl( this.smscPropertiesManagement.getDefaultValidityPeriodHours(), this.smscPropertiesManagement.getMaxValidityPeriodHours(), logger, deliveryFailure); MProcMessage message = new MProcMessageImpl(sms, processingType, null); try { for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.isForPostDeliveryState() && rule.matchesPostDelivery(message)) { if (logger.isDebugEnabled()) { logger.debug("MRule matches at Delivery phase to a message:\nrule: " + rule + "\nmessage: " + sms); } rule.onPostDelivery(anMProcRuleRa, pap, message); } } } catch (Throwable e) { logger.error( "Exception when invoking rule.matches(message) or onPostDelivery(): " + e.getMessage(), e); return new MProcResult(); } FastList<MProcNewMessage> newMsgs = pap.getPostedMessages(); MProcResult res = new MProcResult(); FastList<Sms> res0 = new FastList<Sms>(); for (FastList.Node<MProcNewMessage> n = newMsgs.head(), end = newMsgs.tail(); (n = n.getNext()) != end;) { MProcNewMessageImpl newMsg = (MProcNewMessageImpl) n.getValue(); res0.add(newMsg.getSmsContent()); } res.setMessageList(res0); if (pap.isNeedRerouteMessages()) { res.setMessageIsRerouted(true); res.setNewNetworkId(pap.getNewNetworkId()); } return res; } public MProcResult applyMProcDeliveryTempFailure(final MProcRuleRaProvider anMProcRuleRa, Sms sms, ProcessingType processingType) { if (this.mprocs.size() == 0) { return new MProcResult(); } FastList<MProcRule> cur = this.mprocs; PostDeliveryTempFailureProcessorImpl pap = new PostDeliveryTempFailureProcessorImpl( this.smscPropertiesManagement.getDefaultValidityPeriodHours(), this.smscPropertiesManagement.getMaxValidityPeriodHours(), logger); MProcMessage message = new MProcMessageImpl(sms, processingType, null); try { for (FastList.Node<MProcRule> n = cur.head(), end = cur.tail(); (n = n.getNext()) != end;) { MProcRule rule = n.getValue(); if (rule.isForPostDeliveryTempFailureState() && rule.matchesPostDeliveryTempFailure(message)) { if (logger.isDebugEnabled()) { logger.debug("MRule matches at DeliveryTempFailure phase to a message:\nrule: " + rule + "\nmessage: " + sms); } rule.onPostDeliveryTempFailure(anMProcRuleRa, pap, message); } } } catch (Throwable e) { logger.error( "Exception when invoking rule.matches(message) or onPostDeliveryTempFailure(): " + e.getMessage(), e); return new MProcResult(); } FastList<MProcNewMessage> newMsgs = pap.getPostedMessages(); MProcResult res = new MProcResult(); FastList<Sms> res0 = new FastList<Sms>(); for (FastList.Node<MProcNewMessage> n = newMsgs.head(), end = newMsgs.tail(); (n = n.getNext()) != end;) { MProcNewMessageImpl newMsg = (MProcNewMessageImpl) n.getValue(); res0.add(newMsg.getSmsContent()); } res.setMessageList(res0); if (pap.isNeedDropMessages()) { res.setMessageDropped(true); } if (pap.isNeedRerouteMessages()) { res.setMessageIsRerouted(true); res.setNewNetworkId(pap.getNewNetworkId()); } return res; } public void start() throws Exception { this.smscPropertiesManagement = SmscPropertiesManagement.getInstance(); if (this.smscManagement != null) { for (MProcRuleFactory ruleFactory : this.smscManagement.getMProcRuleFactories2()) { this.bindAlias(ruleFactory); } } try { this.mbeanServer = MBeanServerLocator.locateJBoss(); } catch (Exception e) { } this.persistFile.clear(); if (persistDir != null) { this.persistFile.append(persistDir).append(File.separator).append(this.name).append("_") .append(PERSIST_FILE_NAME); } else { persistFile .append(System.getProperty(SmscManagement.SMSC_PERSIST_DIR_KEY, System.getProperty(SmscManagement.USER_DIR_KEY))).append(File.separator).append(this.name) .append("_").append(PERSIST_FILE_NAME); } logger.info(String.format("Loading MProcRule configuration from %s", persistFile.toString())); try { this.load(); } catch (FileNotFoundException e) { logger.warn(String.format("Failed to load the ProcRule configuration file. \n%s", e.getMessage())); } this.resortRules(this.mprocs); this.store(); for (MProcRule rule : this.mprocs) { this.registerMProcRuleMbean(rule); } } public void stop() { this.store(); for (MProcRule rule : this.mprocs) { this.unregisterMProcRuleMbean(rule.getId()); } } public void store() { try { XMLObjectWriter writer = XMLObjectWriter.newInstance(new FileOutputStream(persistFile.toString())); writer.setBinding(binding); writer.setIndentation(TAB_INDENT); writer.write(mprocs, MPROC_LIST, FastList.class); writer.close(); } catch (Exception e) { logger.error("Error while persisting the MProcRule state in file", e); } } public void load() throws FileNotFoundException { XMLObjectReader reader = null; try { reader = XMLObjectReader.newInstance(new FileInputStream(persistFile.toString())); reader.setBinding(binding); this.mprocs = reader.read(MPROC_LIST, FastList.class); reader.close(); } catch (XMLStreamException ex) { logger.info("Error while re-creating MProcRule from persisted file", ex); } } private void registerMProcRuleMbean(MProcRuleMBean mProcRule) { try { ObjectName esmeObjNname = new ObjectName(SmscManagement.JMX_DOMAIN + ":layer=MProcRule,name=" + mProcRule.getId()); StandardMBean esmeMxBean = new StandardMBean(mProcRule, MProcRuleMBean.class, true); if (this.mbeanServer != null) this.mbeanServer.registerMBean(esmeMxBean, esmeObjNname); } catch (InstanceAlreadyExistsException e) { logger.error(String.format("Error while registering MBean for MProcRule %d", mProcRule.getId()), e); } catch (MBeanRegistrationException e) { logger.error(String.format("Error while registering MBean for MProcRule %d", mProcRule.getId()), e); } catch (NotCompliantMBeanException e) { logger.error(String.format("Error while registering MBean for MProcRule %d", mProcRule.getId()), e); } catch (MalformedObjectNameException e) { logger.error(String.format("Error while registering MBean for MProcRule %d", mProcRule.getId()), e); } } private void unregisterMProcRuleMbean(int mProcRuleId) { try { ObjectName esmeObjNname = new ObjectName(SmscManagement.JMX_DOMAIN + ":layer=MProcRule,name=" + mProcRuleId); if (this.mbeanServer != null) this.mbeanServer.unregisterMBean(esmeObjNname); } catch (MBeanRegistrationException e) { logger.error(String.format("Error while unregistering MBean for MProcRule %d", mProcRuleId), e); } catch (InstanceNotFoundException e) { logger.error(String.format("Error while unregistering MBean for MProcRule %d", mProcRuleId), e); } catch (MalformedObjectNameException e) { logger.error(String.format("Error while unregistering MBean for MProcRule %d", mProcRuleId), e); } } protected void bindAlias(MProcRuleFactory ruleFactory) { Class<?> cls = ruleFactory.createMProcRuleInstance().getClass(); String alias = ruleFactory.getRuleClassName(); binding.setAlias(cls, alias); } }