/* * 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.protocols.ss7.sccp.impl.router; import javolution.text.CharArray; import javolution.xml.XMLFormat; import javolution.xml.stream.XMLStreamException; import org.apache.log4j.Logger; import org.mobicents.protocols.ss7.indicator.GlobalTitleIndicator; import org.mobicents.protocols.ss7.indicator.RoutingIndicator; import org.mobicents.protocols.ss7.sccp.LoadSharingAlgorithm; import org.mobicents.protocols.ss7.sccp.OriginationType; import org.mobicents.protocols.ss7.sccp.Rule; import org.mobicents.protocols.ss7.sccp.RuleType; import org.mobicents.protocols.ss7.sccp.impl.parameter.BCDEvenEncodingScheme; import org.mobicents.protocols.ss7.sccp.impl.parameter.BCDOddEncodingScheme; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0001Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0010Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0011Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0100Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.SccpAddressImpl; import org.mobicents.protocols.ss7.sccp.parameter.EncodingScheme; import org.mobicents.protocols.ss7.sccp.parameter.EncodingSchemeType; import org.mobicents.protocols.ss7.sccp.parameter.GlobalTitle; import org.mobicents.protocols.ss7.sccp.parameter.GlobalTitle0001; import org.mobicents.protocols.ss7.sccp.parameter.GlobalTitle0010; import org.mobicents.protocols.ss7.sccp.parameter.GlobalTitle0011; import org.mobicents.protocols.ss7.sccp.parameter.GlobalTitle0100; import org.mobicents.protocols.ss7.sccp.parameter.SccpAddress; import java.io.Serializable; /** * @author amit bhayani * @author sergey vetyutnev */ public class RuleImpl implements Rule, Serializable { private static final char CHAR_WILD_CARD_ALL = '*'; private static final char CHAR_WILD_CARD_SINGLE = '?'; private static final char CHAR_MASK_SEPARATOR = '/'; private static final String WILD_CARD_ALL = "*"; private static final String WILD_CARD_SINGLE = "?"; private static final String MASK_SEPARATOR = "/"; private static final String MASK_KEEP = "K"; private static final String MASK_REPLACE = "R"; private static final String MASK_IGNORE = "-"; private static final String NETWORK_ID = "networkId"; private static final Logger logger = Logger.getLogger(RuleImpl.class); /** * */ private static final long serialVersionUID = 2147449454267320237L; private static final String RULEID = "ruleId"; private static final String RULETYPE = "ruleType"; private static final String ORIGINATING_TYPE = "originatingType"; private static final String LS_ALGO = "loadSharingAlgo"; private static final String PATTERN = "patternSccpAddress"; private static final String OPEN_BRACKET = "("; private static final String CLOSE_BRACKET = ")"; private static final String PRIMARY_ADDRESS = "paddress"; private static final String SECONDARY_ADDRESS = "saddress"; private static final String NEW_CALLING_PARTY_ADDRESS = "ncpaddress"; private static final String MASK = "mask"; private static final String PATTERN_CALLING_ADDRESS = "patternCallingAddress"; private static final String SEPARATOR = ";"; private RuleType ruleType = RuleType.SOLITARY; private LoadSharingAlgorithm loadSharingAlgo = LoadSharingAlgorithm.Undefined; private OriginationType originationType = OriginationType.ALL; /** Pattern used for selecting rule */ private SccpAddress pattern; private SccpAddress patternCallingAddress; private int ruleId; /** Translation method */ private int primaryAddressId = 0; private int secondaryAddressId = 0; private Integer newCallingPartyAddressId = null; private int networkId; private String mask = null; private String[] maskPattern = null; public static final int MIN_SIGNIFICANT_SSN = 1; public static final int MAX_SIGNIFICANT_SSN = 255; public RuleImpl() { } /** * Creates new routing rule. * */ public RuleImpl( RuleType ruleType, LoadSharingAlgorithm loadSharingAlgo, OriginationType originationType, SccpAddress pattern, String mask, int networkId, SccpAddress patternCallingAddress) { this.ruleType = ruleType; this.pattern = pattern; this.mask = mask; this.networkId = networkId; this.setLoadSharingAlgorithm(loadSharingAlgo); this.setOriginationType(originationType); // Calling SCCP Address this.patternCallingAddress = patternCallingAddress; configure(); } /** * @return the mask */ public String getMask() { return mask; } /** * @return the ruleId */ public int getRuleId() { return ruleId; } /** * @param ruleId the ruleId to set */ public void setRuleId(int ruleId) { this.ruleId = ruleId; } public RuleType getRuleType() { return ruleType; } public void setRuleType(RuleType ruleType) { this.ruleType = ruleType; } public LoadSharingAlgorithm getLoadSharingAlgorithm() { return loadSharingAlgo; } public void setLoadSharingAlgorithm(LoadSharingAlgorithm loadSharingAlgo) { if (loadSharingAlgo == null) this.loadSharingAlgo = LoadSharingAlgorithm.Undefined; else this.loadSharingAlgo = loadSharingAlgo; } public OriginationType getOriginationType() { return originationType; } public void setOriginationType(OriginationType originationType) { this.originationType = originationType; } public SccpAddress getPattern() { return pattern; } private void configure() { this.maskPattern = this.mask.split("/"); } public int getPrimaryAddressId() { return primaryAddressId; } public void setPrimaryAddressId(int primaryAddressId) { this.primaryAddressId = primaryAddressId; } public int getSecondaryAddressId() { return secondaryAddressId; } public void setSecondaryAddressId(int secondaryAddressId) { this.secondaryAddressId = secondaryAddressId; } public Integer getNewCallingPartyAddressId() { return newCallingPartyAddressId; } public void setNewCallingPartyAddressId(Integer newCallingPartyAddressId) { this.newCallingPartyAddressId = newCallingPartyAddressId; } public int getNetworkId() { return networkId; } public void setNetworkId(int networkId) { this.networkId = networkId; } public SccpAddress getPatternCallingAddress() { return patternCallingAddress; } /** * Translate specified address according to the rule. * * @param address the origin address * @param ruleAddress the address from the rule * @return translated address */ public SccpAddress translate(SccpAddress address, SccpAddress ruleAddress) { String digits = address.getGlobalTitle().getDigits(); String patternDigits = pattern.getGlobalTitle().getDigits(); String primaryDigits = ruleAddress.getGlobalTitle().getDigits(); // step #1. translate digits String translatedDigits = translateDigits(digits, maskPattern, patternDigits.split(MASK_SEPARATOR), primaryDigits.split(MASK_SEPARATOR)); // step #2. translate global title GlobalTitle gt = null; if (translatedDigits != null && !translatedDigits.equals("")) { GlobalTitleIndicator gti = ruleAddress.getAddressIndicator().getGlobalTitleIndicator(); GlobalTitle primaryGt = ruleAddress.getGlobalTitle(); gt = createNewGT(gti, primaryGt, translatedDigits); if (gt == null) { // lets use GT from received address gt = createNewGT(address.getAddressIndicator().getGlobalTitleIndicator(), address.getGlobalTitle(), translatedDigits); } } int ssn = address.getSubsystemNumber(); if (ruleAddress.getSubsystemNumber() > 0) ssn = ruleAddress.getSubsystemNumber(); SccpAddress sccpAddress = new SccpAddressImpl(ruleAddress.getAddressIndicator().getRoutingIndicator(), gt,ruleAddress.getSignalingPointCode(), ssn); // This is translated message sccpAddress.setTranslated(true); return sccpAddress; } private GlobalTitle createNewGT(GlobalTitleIndicator gti, GlobalTitle primaryGt, String translatedDigits) { GlobalTitle gt = null; switch (gti) { case GLOBAL_TITLE_INCLUDES_NATURE_OF_ADDRESS_INDICATOR_ONLY: gt = new GlobalTitle0001Impl(translatedDigits, ((GlobalTitle0001) primaryGt).getNatureOfAddress()); break; case GLOBAL_TITLE_INCLUDES_TRANSLATION_TYPE_NUMBERING_PLAN_AND_ENCODING_SCHEME: final GlobalTitle0011 globalTitle0011 = (GlobalTitle0011) primaryGt; gt = new GlobalTitle0011Impl(translatedDigits, globalTitle0011.getTranslationType(), getEncodingScheme(globalTitle0011.getEncodingScheme(),translatedDigits), globalTitle0011.getNumberingPlan()); break; case GLOBAL_TITLE_INCLUDES_TRANSLATION_TYPE_NUMBERING_PLAN_ENCODING_SCHEME_AND_NATURE_OF_ADDRESS: final GlobalTitle0100 globalTitle0100 = (GlobalTitle0100) primaryGt; gt = new GlobalTitle0100Impl(translatedDigits, globalTitle0100.getTranslationType(), getEncodingScheme(globalTitle0100.getEncodingScheme(),translatedDigits), globalTitle0100.getNumberingPlan(), globalTitle0100.getNatureOfAddress()); break; case GLOBAL_TITLE_INCLUDES_TRANSLATION_TYPE_ONLY: gt = new GlobalTitle0010Impl(translatedDigits, ((GlobalTitle0010) primaryGt).getTranslationType()); break; case NO_GLOBAL_TITLE_INCLUDED: // Use Global Title from received address break; } return gt; } private EncodingScheme getEncodingScheme(final EncodingScheme scheme, String translatedDigits){ //not a good thing but... //in case odd/even we need to adjust it, since translation may change ES... //in case of specific schemes, its up to them, EncodingSchemeType type = scheme.getType(); if(type == EncodingSchemeType.BCD_EVEN || type == EncodingSchemeType.BCD_ODD){ return translatedDigits.length() % 2 == 1 ? BCDOddEncodingScheme.INSTANCE : BCDEvenEncodingScheme.INSTANCE; } else { return scheme; } } public boolean matches(SccpAddress address, SccpAddress callingAddress, boolean isMtpOriginated, int msgNetworkId) { if (logger.isTraceEnabled()) { logger.trace(String.format("Matching rule Id=%s Rule=[%s]", this.getRuleId(), this.toString())); } // checking NetworkId if (this.networkId != msgNetworkId) { if (logger.isTraceEnabled()) { logger.trace(String.format("networkId didn't match. Pattern networkId=%s Address networkId=%s Return False", this.networkId, msgNetworkId)); } return false; } // Rule is for GTT only if (address.getAddressIndicator().getRoutingIndicator() == RoutingIndicator.ROUTING_BASED_ON_DPC_AND_SSN) { if (logger.isDebugEnabled()) { logger.debug("RoutingIndicator == ROUTING_BASED_ON_DPC_AND_SSN. Return"); } return false; } // checking firstly about rule OriginationType boolean isOriginationTypeCorrect = true; if (this.getOriginationType() == OriginationType.LOCAL && isMtpOriginated) { isOriginationTypeCorrect = false; } if (this.getOriginationType() == OriginationType.REMOTE && !isMtpOriginated) { isOriginationTypeCorrect = false; } if (!isOriginationTypeCorrect) { if (logger.isTraceEnabled()) { logger.trace(String.format( "OriginationType didn't match. Pattern OriginationType=%s Address isMtpOriginated=%s Return False", this.getOriginationType(), isMtpOriginated)); } return false; } // SSN if present flag is set in pattern - must match address SSN & flag if (!isSsnMatch(address, pattern)) { return false; } if ( !matchGt( address, pattern ) ) { return false; // Called GT didn't match. No point in going forward to match calling } if ( patternCallingAddress == null || callingAddress == null) { // callingAddress or pattern is null then we consider it a match return true; } // SSN matching for calling address just as for called address if ( !isSsnMatch( callingAddress, patternCallingAddress ) ) { return false; } // finally match on calling GT return matchGt( callingAddress, patternCallingAddress ); } private boolean matchGt( SccpAddress address, SccpAddress patternAddress ) { // Routing on GTT GlobalTitleIndicator gti = address.getAddressIndicator().getGlobalTitleIndicator(); GlobalTitle patternGT = patternAddress.getGlobalTitle(); switch (gti) { case GLOBAL_TITLE_INCLUDES_NATURE_OF_ADDRESS_INDICATOR_ONLY: GlobalTitle0001 gt = (GlobalTitle0001) address.getGlobalTitle(); if (!(patternGT instanceof GlobalTitle0001)) { if (logger.isDebugEnabled()) { logger.debug("patternGT not instanceof GlobalTitle0001. Return False"); } return false; } // nature of address must match if (((GlobalTitle0001) patternGT).getNatureOfAddress() != gt.getNatureOfAddress()) { if (logger.isDebugEnabled()) { logger.debug(String.format("Noa didn't match. Pattern Noa=%s Address Noad=%s Return False", ((GlobalTitle0001) patternGT).getNatureOfAddress(), gt.getNatureOfAddress())); } return false; } // digits must match if (!matchPattern(gt.getDigits(), patternGT.getDigits())) { if (logger.isDebugEnabled()) { logger.debug(String.format("digits didn't match. Pattern digits=%s Address Digits=%s Return False", patternGT.getDigits(), gt.getDigits())); } return false; } // all conditions passed return true; case GLOBAL_TITLE_INCLUDES_TRANSLATION_TYPE_NUMBERING_PLAN_AND_ENCODING_SCHEME: GlobalTitle0011 gt1 = (GlobalTitle0011) address.getGlobalTitle(); if (!(patternGT instanceof GlobalTitle0011)) { if (logger.isDebugEnabled()) { logger.debug("patternGT not instanceof GlobalTitle0011. Return False"); } return false; } // translation type should match if (((GlobalTitle0011) patternGT).getTranslationType() != gt1.getTranslationType()) { if (logger.isDebugEnabled()) { logger.debug(String.format("TT didn't match. Pattern TT=%s Address TT=%s Return False", ((GlobalTitle0011) patternGT).getTranslationType(), gt1.getTranslationType())); } return false; } // numbering plan should match if (((GlobalTitle0011) patternGT).getNumberingPlan() != gt1.getNumberingPlan()) { if (logger.isDebugEnabled()) { logger.debug(String.format("Np didn't match. Pattern Np=%s Address Np=%s Return False", ((GlobalTitle0011) patternGT).getNumberingPlan(), gt1.getNumberingPlan())); } return false; } // digits must match if (!matchPattern(gt1.getDigits(), patternGT.getDigits())) { if (logger.isDebugEnabled()) { logger.debug(String.format("digits didn't match. Pattern digits=%s Address Digits=%s Return False", patternGT.getDigits(), gt1.getDigits())); } return false; } // all conditions passed return true; case GLOBAL_TITLE_INCLUDES_TRANSLATION_TYPE_NUMBERING_PLAN_ENCODING_SCHEME_AND_NATURE_OF_ADDRESS: GlobalTitle0100 gt2 = (GlobalTitle0100) address.getGlobalTitle(); if (!(patternGT instanceof GlobalTitle0100)) { if (logger.isDebugEnabled()) { logger.debug("patternGT not instanceof GlobalTitle0100. Return False"); } return false; } // translation type should match if (((GlobalTitle0100) patternGT).getTranslationType() != gt2.getTranslationType()) { if (logger.isDebugEnabled()) { logger.debug(String.format("TT didn't match. Pattern TT=%s Address TT=%s Return False", ((GlobalTitle0100) patternGT).getTranslationType(), gt2.getTranslationType())); } return false; } // numbering plan should match if (((GlobalTitle0100) patternGT).getNumberingPlan() != gt2.getNumberingPlan()) { if (logger.isDebugEnabled()) { logger.debug(String.format("Np didn't match. Pattern Np=%s Address Np=%s Return False", ((GlobalTitle0100) patternGT).getNumberingPlan(), gt2.getNumberingPlan())); } return false; } // nature of address must match if (((GlobalTitle0100) patternGT).getNatureOfAddress() != gt2.getNatureOfAddress()) { if (logger.isDebugEnabled()) { logger.debug(String.format("Noa didn't match. Pattern Noa=%s Address Noa=%s Return False", ((GlobalTitle0100) patternGT).getNatureOfAddress(), gt2.getNatureOfAddress())); } return false; } // digits must match if (!matchPattern(gt2.getDigits(), patternAddress.getGlobalTitle().getDigits())) { if (logger.isDebugEnabled()) { logger.debug(String.format("digits didn't match. Pattern digits=%s Address Digits=%s Return False", patternGT.getDigits(), gt2.getDigits())); } return false; } // all conditions passed return true; case GLOBAL_TITLE_INCLUDES_TRANSLATION_TYPE_ONLY: GlobalTitle0010 gt3 = (GlobalTitle0010) address.getGlobalTitle(); if (!(patternGT instanceof GlobalTitle0010)) { if (logger.isDebugEnabled()) { logger.debug("patternGT not instanceof GlobalTitle0010. Return False"); } return false; } // translation type should match if (((GlobalTitle0010) patternGT).getTranslationType() != gt3.getTranslationType()) { if (logger.isDebugEnabled()) { logger.debug(String.format("TT didn't match. Pattern TT=%s Address TT=%s Return False", ((GlobalTitle0010) patternGT).getTranslationType(), gt3.getTranslationType())); } return false; } // digits must match if (!matchPattern(gt3.getDigits(), patternAddress.getGlobalTitle().getDigits())) { if (logger.isDebugEnabled()) { logger.debug(String.format("digits didn't match. Pattern digits=%s Address Digits=%s Return False", patternGT.getDigits(), gt3.getDigits())); } return false; } // all conditions passed return true; default: return false; } } /** * Checks if SSN matches between rule address pattern and provided destination address. SSN is assumed to always match in * case it has insignificant value or pattern AI SSNPresent flag is set to false. * * @param address - a provided address to match * @param pattern - a rule pattern address * @return true if SSN is present in both pattern and received addresses and they are the same or pattern has SSN flag unset * in AI (bit 7)(isSsnPresent = false for pattern) or pattern SSN value is insignificant */ private boolean isSsnMatch(SccpAddress address, SccpAddress pattern) { if (!isSsnSignificant(pattern.getSubsystemNumber()) || !pattern.getAddressIndicator().isSSNPresent()) { if (logger.isTraceEnabled()) { logger.trace(String.format("SSN is not present or insignificant [%s]. Assume SSN matches. Return True", pattern.getSubsystemNumber())); } return true; } if (pattern.getAddressIndicator().isSSNPresent() && address.getAddressIndicator().isSSNPresent()) { if (address.getSubsystemNumber() == pattern.getSubsystemNumber()) { return true; } } if (logger.isTraceEnabled()) { logger.trace(String.format( "SSN didn't match. Pattern: isSsnPresent=%s, SSN=%s Address: isSsnPresent=%s, SSN=%s Return False", pattern.getAddressIndicator().isSSNPresent(), pattern.getSubsystemNumber(), address.getAddressIndicator() .isSSNPresent(), address.getSubsystemNumber())); } return false; } /** * Checks if provided SSN value is a meaningful value = between 1 and 255. SSN=0 is for management messages and is not * perceived as significant value * * @param ssn SSN value to check * @return true if SSN value is within significant range */ private boolean isSsnSignificant(int ssn) { return (MIN_SIGNIFICANT_SSN <= ssn && ssn <= MAX_SIGNIFICANT_SSN); } private String translateDigits(String digits, String[] masks, String[] patternDigits, String[] addressDigits) { StringBuffer translatedDigits = new StringBuffer(); String[] digitComponents = new String[patternDigits.length]; int offset = 0; for (int count = 0; count < patternDigits.length; count++) { if (patternDigits[count].equals(WILD_CARD_ALL)) { digitComponents[count] = digits.substring(offset, digits.length()); break; } else { digitComponents[count] = digits.substring(offset, offset + patternDigits[count].length()); } offset += patternDigits[count].length(); } for (int count = 0; count < patternDigits.length; count++) { if (masks[count].equals(MASK_KEEP)) { if (digitComponents[count] != null) { // Check if digits is null? This is possible if user // specified pattern like */5555 where all the digits are // consumed translatedDigits.append(digitComponents[count]); } } else if (masks[count].equals(MASK_REPLACE)) { // If its not padding if (!addressDigits[count].contains(MASK_IGNORE)) { translatedDigits.append(addressDigits[count]); } } else { // TODO Throw exception or return original digits only? } } return translatedDigits.toString(); } private boolean matchPattern(String digitsStr, String patternStr) { char[] digits = digitsStr.toLowerCase().toCharArray(); char[] pattern = patternStr.toLowerCase().toCharArray(); int j = 0; for (int i = 0; i < pattern.length; i++) { if (j >= digits.length) { // Pattern has more digits to match than digits; // special case where pattern can be xxxxx/* and digits are xxxxx so this should match. if (pattern[j] == CHAR_MASK_SEPARATOR && pattern[j + 1] == CHAR_WILD_CARD_ALL) { return true; } // return false return false; } if (pattern[i] == CHAR_WILD_CARD_ALL) { return true; } else if (pattern[i] == CHAR_WILD_CARD_SINGLE) { j++; continue; } else if (pattern[i] == CHAR_MASK_SEPARATOR) { continue; } else if (pattern[i] != digits[j]) { return false; } else { j++; } } if (j == digits.length) { // We compared all the digits and all of them matched, this Rule // matches. return true; } return false; } /** * XML Serialization/Deserialization */ protected static final XMLFormat<RuleImpl> RULE_XML = new XMLFormat<RuleImpl>(RuleImpl.class) { public void read(javolution.xml.XMLFormat.InputElement xml, RuleImpl rule) throws XMLStreamException { rule.ruleType = RuleType.getInstance(xml.getAttribute(RULETYPE, RuleType.SOLITARY.getValue())); rule.loadSharingAlgo = LoadSharingAlgorithm.getInstance(xml.getAttribute(LS_ALGO, LoadSharingAlgorithm.Undefined.getValue())); rule.originationType = OriginationType .getInstance(xml.getAttribute(ORIGINATING_TYPE, OriginationType.ALL.getValue())); rule.mask = xml.getAttribute(MASK).toString(); rule.primaryAddressId = xml.getAttribute(PRIMARY_ADDRESS).toInt(); rule.secondaryAddressId = xml.getAttribute(SECONDARY_ADDRESS).toInt(); rule.networkId = xml.getAttribute(NETWORK_ID, 0); CharArray cha = xml.getAttribute(NEW_CALLING_PARTY_ADDRESS); if (cha != null) rule.newCallingPartyAddressId = cha.toInt(); else rule.newCallingPartyAddressId = null; rule.pattern = xml.get(PATTERN, SccpAddressImpl.class); rule.patternCallingAddress = xml.get(PATTERN_CALLING_ADDRESS, SccpAddressImpl.class); rule.configure(); } public void write(RuleImpl rule, javolution.xml.XMLFormat.OutputElement xml) throws XMLStreamException { xml.setAttribute(RULETYPE, rule.ruleType.getValue()); xml.setAttribute(LS_ALGO, rule.loadSharingAlgo.getValue()); xml.setAttribute(ORIGINATING_TYPE, rule.originationType.getValue()); xml.setAttribute(MASK, rule.mask); xml.setAttribute(PRIMARY_ADDRESS, rule.primaryAddressId); xml.setAttribute(SECONDARY_ADDRESS, rule.secondaryAddressId); xml.setAttribute(NETWORK_ID, rule.networkId); if (rule.newCallingPartyAddressId != null) xml.setAttribute(NEW_CALLING_PARTY_ADDRESS, rule.newCallingPartyAddressId); xml.add((SccpAddressImpl)rule.pattern, PATTERN, SccpAddressImpl.class); if ( rule.patternCallingAddress != null ) xml.add( ( SccpAddressImpl ) rule.patternCallingAddress, PATTERN_CALLING_ADDRESS, SccpAddressImpl.class ); } }; public String toString() { StringBuffer buff = new StringBuffer(); buff.append(RULEID); buff.append(OPEN_BRACKET); buff.append(ruleId); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); buff.append(RULETYPE); buff.append(OPEN_BRACKET); buff.append(ruleType.getValue()); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); if (this.ruleType == RuleType.LOADSHARED) { buff.append(LS_ALGO); buff.append(OPEN_BRACKET); buff.append(this.loadSharingAlgo.getValue()); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); } buff.append(ORIGINATING_TYPE); buff.append(OPEN_BRACKET); buff.append(this.originationType.getValue()); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); buff.append(PATTERN); buff.append(OPEN_BRACKET); buff.append(pattern.toString()); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); buff.append(PRIMARY_ADDRESS); buff.append(OPEN_BRACKET); buff.append(primaryAddressId); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); buff.append(SECONDARY_ADDRESS); buff.append(OPEN_BRACKET); buff.append(secondaryAddressId); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); if (newCallingPartyAddressId != null) { buff.append(NEW_CALLING_PARTY_ADDRESS); buff.append(OPEN_BRACKET); buff.append(newCallingPartyAddressId); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); } buff.append(MASK); buff.append(OPEN_BRACKET); buff.append(this.mask); buff.append(CLOSE_BRACKET); buff.append(SEPARATOR); buff.append(NETWORK_ID); buff.append(OPEN_BRACKET); buff.append(this.networkId); buff.append(CLOSE_BRACKET); if ( patternCallingAddress != null ) { buff.append(SEPARATOR); buff.append(PATTERN_CALLING_ADDRESS); buff.append(OPEN_BRACKET); buff.append( patternCallingAddress.toString() ); buff.append(CLOSE_BRACKET); } return buff.toString(); } }