Java tutorial
/** * Copyright (C) 2010 Tim Harsch harschware@yahoo.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package harschware.collections.ranges; import harschware.collections.sequences.Sequence; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.builder.CompareToBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; /** * * * @author harschware * * @see http://gleichmann.wordpress.com/2008/01/21/declarative-programming-a-range-type-for-java/ * @see http://martinfowler.com/eaaDev/Range.html * @see http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/math/Range.html * * @param <T> */ @SuppressWarnings("unchecked") public class ValidRange<T extends Comparable> extends Range<T> { private ValidRange(final T start, final T end) { super(start, end); }; /** * package private factory method - used only by abstract parent * * @param <S> * @param start * @param end * @return */ static <S extends Comparable> Range<S> newInstance(S start, S end) { Range<S> newRange = new ValidRange(start, end); return newRange; } // end method @Override public boolean before(T value) { return end.compareTo(value) < 0; } // end method @Override public boolean after(T value) { return start.compareTo(value) > 0; } // end method @Override public boolean contains(T value) { return start.compareTo(value) <= 0 && end.compareTo(value) >= 0; } // end method @Override public boolean contains(Range<T> arg) { if (arg == EmptyRange.INSTANCE) return false; return contains(arg.getStart()) && contains(arg.getEnd()); } // end contains range @Override public boolean overlaps(Range<T> arg) { return arg.contains(start) || arg.contains(end); } // end method /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("["); sb.append(start); sb.append(","); sb.append(end); sb.append("]"); return sb.toString(); } // end method @Override public final boolean equals(Object o) { if (!(o instanceof ValidRange<?>)) return false; final ValidRange<?> other = (ValidRange<?>) o; return equal(getStart(), other.getStart()) && equal(getEnd(), other.getEnd()); } // end method private static final boolean equal(Object o1, Object o2) { if (o1 == null) { return o2 == null; } return o1.equals(o2); } // end method @Override public int hashCode() { return new HashCodeBuilder(17, 13).append(this.start).append(this.end).toHashCode(); } // end method @Override public int compareTo(Range<T> other) { return new CompareToBuilder().append(this.start, other.getStart()).append(this.end, other.getEnd()) .toComparison(); } // end method @Override public boolean isEmpty() { if (this.equals(EmptyRange.INSTANCE)) return true; return false; } // end method @Override public Iterator<T> iterator() { try { start.getClass(); } catch (NullPointerException npe) { return new EmptyIterator(); } // end try/catch Sequence<T> sequence = this.getSequence(start); return new RangeIterator(sequence, end); } // end method private Sequence<T> getSequence(T newStart) { Sequence<T> sequence = null; Class<? extends Comparable> startClazz = start.getClass(); String className = "harschware.collections.sequences." + startClazz.getSimpleName() + "Sequence"; logger.debug("Sequence strategy '" + className + "' chosen for '" + startClazz.getCanonicalName() + "'"); try { Class clazz = Class.forName(className); sequence = (Sequence<T>) clazz.getDeclaredConstructor(startClazz).newInstance(newStart); } catch (Exception e) { throw new UnsupportedOperationException("No Sequence found for type " + startClazz); } // end try/catch return sequence; } // end method @Override public Range<T> gap(Range<T> arg) { if (this.overlaps(arg)) return (Range<T>) EmptyRange.INSTANCE; Range<T> lower, higher; if (this.compareTo(arg) < 0) { lower = this; higher = arg; } else { lower = arg; higher = this; } // end if Sequence<T> lowSeq = getSequence(lower.getEnd()); Sequence<T> highSeq = getSequence(higher.getStart()); return ValidRange.create(lowSeq.next().value(), highSeq.previous().value()); } // end method @Override public boolean abuts(Range<T> arg) { return !this.overlaps(arg) && this.gap(arg).isEmpty(); } // end method @Override public boolean partitionedBy(Collection<Range<T>> ranges) { // need a copy so as not to disturb the order of the input collection logger.debug("partitionedBy making list copy of input collection"); List<Range<T>> listCopy = new ArrayList<Range<T>>(ranges); return Range.sortAndCollapse(listCopy).equals(this); } // end method } // end class