/* * 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 org.mobicents.protocols.ss7.sccp.OriginationType; import java.util.Comparator; /** * <p> * A comparison function which imposes ordering on collection of {@link RuleImpl} based on the GT digits defined while creating * rule. The sorting algo is as defined bellow * </p> * <p> * <ol> * <li> * GT digits having no wildcard (* or ?) is always on top of the list. Between two GT digits, both having no wildcards, one with * shortest length is on top of list. For example Digit1 "123456" will be above Digit2 "1234567890" will be above Digit3 "999/*" * </li> * <li> * GT digits having wildcard ? is always above digits having wildcard *. For example Digit1 "800/????/9" will be above Digit2 * "999/*"</li> * <li> * Between two GT digits both having wildcard ?, one with least number of wildcard ? is on top of list. For example Digit1 * "800/????/9" is above Digit2 "800/?????/9"</li> * <li> * Between two GT digits both having equal number of wildcard ?, the digit who's first appearance of ? is after other, is on top * of list. For example between Digit1 "80/??/0/???/9" and Digit 2 "800/?????/9", Digit2 is above Digit1 * <li> * <li> * Between two GT digits both having wildcard *, the digit who's first appearance of * is after other. For example between Digit1 * 80* and Digit 2 800*, Digit 2 is above Digit 1 * </li> * </ol> * </p> * * * @author amit bhayani * */ public class RuleComparator implements Comparator<RuleImpl> { private static final String SECTION_SEPARTOR = "/"; private static final char WILDCARD_ANY = '*'; private static final String WILDCARD_ANY_STRING = "*"; private static final char WILDCARD_SINGLE = '?'; /* * (non-Javadoc) * * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare(RuleImpl o1, RuleImpl o2) { String digits1 = o1.getPattern().getGlobalTitle().getDigits(); String digits2 = o2.getPattern().getGlobalTitle().getDigits(); // Normalize rule. Remove all separator digits1 = digits1.replaceAll(SECTION_SEPARTOR, ""); digits2 = digits2.replaceAll(SECTION_SEPARTOR, ""); // If a rule 1 is not OriginationType.All and rule 2 is OriginationType.All we put rule 1 first if (o1.getOriginationType() != OriginationType.ALL && o2.getOriginationType() == OriginationType.ALL) return -1; if (o1.getOriginationType() == OriginationType.ALL && o2.getOriginationType() != OriginationType.ALL) return 1; // Check if digits are exactly same. In that case we sort based on the callingDigits if ( digits1.equals( digits2 )) { // if rule1 has calling party and rule2 doesn't then we put rule1 first if ( o1.getPatternCallingAddress() != null && o2.getPatternCallingAddress() == null ) { return -1; } else if ( o1.getPatternCallingAddress() == null && o2.getPatternCallingAddress() != null ) { return 1; } else if ( o1.getPatternCallingAddress() != null && o2.getPatternCallingAddress() != null ) { // both have calling party addresses. lets compare these 2 digits1 = o1.getPatternCallingAddress().getGlobalTitle().getDigits(); digits2 = o2.getPatternCallingAddress().getGlobalTitle().getDigits(); // Normalize rule. Remove all separator digits1 = digits1.replaceAll(SECTION_SEPARTOR, ""); digits2 = digits2.replaceAll(SECTION_SEPARTOR, ""); return compareDigits( digits1, digits2 ); } } return compareDigits( digits1, digits2 ); } private int compareDigits( String digits1, String digits2 ) { // If any digit is just wildcard "*" return 1 indicating it should be // below the other if (digits1.equals(WILDCARD_ANY_STRING)) { return 1; } else if (digits2.equals(WILDCARD_ANY_STRING)) { return -1; } // Truly speaking any digits will have just one asterisk max. int asterisksFound1 = this.numberOfAsterisks(digits1); int asterisksFound2 = this.numberOfAsterisks(digits2); if (asterisksFound1 == asterisksFound2) { // If both digits have "*", lets compare if there are wildcard "?" return compareQuestionMarks(digits1, digits2); } else if (asterisksFound1 < asterisksFound2) { // if digit 1 doesn't have *, return -1 indicating it should be // above other return -1; } return 1; } /** * Compare number of wildcards "?" in passed digits * * @param digits1 * @param digits2 * @return */ private int compareQuestionMarks(String digits1, String digits2) { int questionMarksFound1 = this.numberOfQuestionMarks(digits1); int questionMarksFound2 = this.numberOfQuestionMarks(digits2); if (questionMarksFound1 == questionMarksFound2) { // If both the digits have equal number of "?", compare the index of // first occurrence of "?" in both digits. Digits for which "?" // occurred after other is on top return compareQuestionMarksIndex(digits1, 0, digits2, 0); } else if (questionMarksFound1 < questionMarksFound2) { return -1; } return 1; } /** * * @param digits1 * @param fromIndex1 * @param digits2 * @param fromIndex2 * @return */ private int compareQuestionMarksIndex(String digits1, int fromIndex1, String digits2, int fromIndex2) { int index1 = digits1.indexOf(WILDCARD_SINGLE, fromIndex1); int index2 = digits2.indexOf(WILDCARD_SINGLE, fromIndex2); if (index1 == -1 && index2 == -1) { // If both digits have exactly same occurrence of "?", compare // lengths. Shortest length digit is above other return comapreLength(digits1, digits2); } else if (index1 == index2) { // Keep comparing occurrence of "?" till difference is reached compareQuestionMarksIndex(digits1, index1 + 1, digits2, index2 + 1); } else if (index1 < index2) { return 1; } return -1; } /** * Compare length of digits. Shorter length is above longer one * * @param digits1 * @param digits2 * @return */ private int comapreLength(String digits1, String digits2) { if (digits1.length() == digits2.length()) { return 0; } else if (digits1.length() < digits2.length()) { return 1; } else if (digits1.length() > digits2.length()) { return -1; } return digits1.compareTo(digits2); } /** * Returns number of '*' occured in passed digits * * @param digits * @return */ private int numberOfAsterisks(String digits) { int asterisksFound = 0; char[] chars = digits.toCharArray(); for (int i = 0; i < chars.length; i++) { if (chars[i] == WILDCARD_ANY) { asterisksFound++; } } return asterisksFound; } /** * Returns number of '?' occured in passed digits * * @param digits * @return */ private int numberOfQuestionMarks(String digits) { int questionMarksFound = 0; char[] chars = digits.toCharArray(); for (int i = 0; i < chars.length; i++) { if (chars[i] == WILDCARD_SINGLE) { questionMarksFound++; } } return questionMarksFound; } }