001 /* 002 * Created on Sep 17, 2010 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 005 * the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 011 * specific language governing permissions and limitations under the License. 012 * 013 * Copyright @2010-2011 the original author or authors. 014 */ 015 package org.fest.util; 016 017 import static org.fest.util.Collections.isEmpty; 018 import static org.fest.util.Strings.quote; 019 020 import java.util.Comparator; 021 import java.util.Iterator; 022 023 /** 024 * Implements {@link ComparisonStrategy} contract with a comparison strategy based on a {@link Comparator}. 025 * 026 * @author Joel Costigliola 027 */ 028 public class ComparatorBasedComparisonStrategy extends AbstractComparisonStrategy { 029 030 // A raw type is necessary because we can't make assumptions on object to be compared. 031 @SuppressWarnings("rawtypes") 032 private Comparator comparator; 033 034 /** 035 * Creates a new </code>{@link ComparatorBasedComparisonStrategy}</code> specifying the comparison strategy with given 036 * comparator. 037 * @param comparator the comparison strategy to use. 038 */ 039 public ComparatorBasedComparisonStrategy(@SuppressWarnings("rawtypes") Comparator comparator) { 040 this.comparator = comparator; 041 } 042 043 /** 044 * Returns true if given {@link Iterable} contains given value according to {@link #comparator}, false otherwise.<br> 045 * If given {@link Iterable} is null or empty, return false. 046 * 047 * @param iterable the {@link Iterable} to search value in 048 * @param value the object to look for in given {@link Iterable} 049 * @return true if given {@link Iterable} contains given value according to {@link #comparator}, false otherwise. 050 */ 051 @SuppressWarnings("unchecked") 052 public boolean iterableContains(Iterable<?> iterable, Object value) { 053 if (isEmpty(iterable)) return false; 054 for (Object element : iterable) { 055 // avoid comparison when objects are the same or both null 056 if (element == value) return true; 057 // both objects are not null => if one is then the other is not => compare next element with value 058 if (value == null || element == null) continue; 059 if (comparator.compare(element, value) == 0) return true; 060 } 061 return false; 062 } 063 064 /** 065 * Look for given value in given {@link Iterable} according to the {@link Comparator}, if value is found it is removed 066 * from it.<br> 067 * Does nothing if given {@link Iterable} is null (meaning no exception thrown). 068 * @param iterable the {@link Iterable} we want remove value from 069 * @param value object to remove from given {@link Iterable} 070 */ 071 @SuppressWarnings("unchecked") 072 public void iterableRemoves(Iterable<?> iterable, Object value) { 073 if (iterable == null) return; 074 Iterator<?> iterator = iterable.iterator(); 075 while (iterator.hasNext()) { 076 if (comparator.compare(iterator.next(), value) == 0) { 077 iterator.remove(); 078 } 079 } 080 } 081 082 /** 083 * Returns true if actual and other are equal according to {@link #comparator}, false otherwise.<br> 084 * Handles the cases where one of the parameter is null so that internal {@link #comparator} does not have too. 085 * 086 * @param actual the object to compare to other 087 * @param other the object to compare to actual 088 * @return true if actual and other are equal according to {@link #comparator}, false otherwise. 089 */ 090 @SuppressWarnings("unchecked") 091 public boolean areEqual(Object actual, Object other) { 092 if (actual == null) return other == null; 093 // actual is not null 094 if (other == null) return false; 095 // neither actual nor other are null 096 return comparator.compare(actual, other) == 0; 097 } 098 099 /** 100 * Returns any duplicate elements from the given {@link Iterable} according to {@link #comparator}. 101 * 102 * @param iterable the given {@link Iterable} we want to extract duplicate elements. 103 * @return an {@link Iterable} containing the duplicate elements of the given one. If no duplicates are found, an 104 * empty {@link Iterable} is returned. 105 */ 106 // overridden to write javadoc. 107 @Override 108 public Iterable<?> duplicatesFrom(Iterable<?> iterable) { 109 return super.duplicatesFrom(iterable); 110 } 111 112 @Override 113 public String toString() { 114 String comparatorSimpleClassName = comparator.getClass().getSimpleName(); 115 return quote(comparatorSimpleClassName.length() > 0 ? comparatorSimpleClassName : "anonymous comparator class"); 116 } 117 118 public Comparator<?> getComparator() { 119 return comparator; 120 } 121 122 @SuppressWarnings("unchecked") 123 public boolean stringStartsWith(String string, String prefix) { 124 if (string.length() < prefix.length()) return false; 125 String stringPrefix = string.substring(0, prefix.length()); 126 return comparator.compare(stringPrefix, prefix) == 0; 127 } 128 129 @SuppressWarnings("unchecked") 130 public boolean stringEndsWith(String string, String suffix) { 131 if (string.length() < suffix.length()) return false; 132 String stringSuffix = string.substring(string.length() - suffix.length()); 133 return comparator.compare(stringSuffix, suffix) == 0; 134 } 135 136 public boolean stringContains(String string, String sequence) { 137 int sequenceLength = sequence.length(); 138 for (int i = 0; i < string.length(); i++) { 139 String subString = string.substring(i); 140 if (subString.length() < sequenceLength) return false; 141 if (stringStartsWith(subString, sequence)) return true; 142 } 143 return false; 144 } 145 146 @SuppressWarnings("unchecked") 147 public boolean isGreaterThan(Object actual, Object other) { 148 return comparator.compare(actual, other) > 0; 149 } 150 151 }