001package org.biopax.paxtools.util; 002 003import org.apache.commons.logging.Log; 004import org.apache.commons.logging.LogFactory; 005 006import java.util.AbstractSet; 007import java.util.Iterator; 008import java.util.NoSuchElementException; 009import java.util.Set; 010 011/** 012 * Base class for implementing various filter sets. 013 * Filter sets are unmodifiable. 014 * @see ClassFilterSet for an implementation that filters classes. 015 */ 016 017public abstract class AbstractFilterSet<F, E> extends AbstractSet<E> implements Filter<F> 018{ 019 final Log log = LogFactory.getLog(ClassFilterSet.class); 020 021 int size = -1; 022 023 protected final Set<? extends F> baseSet; 024 025 026 public AbstractFilterSet(Set<? extends F> baseSet) 027 { 028 this.baseSet = baseSet; 029 030 } 031 032 /** 033 * This size operation runs on O(n) and should be avoided for large sets. 034 * It is possible to write a one pass more efficient abstract set but its 035 * initialization cost would be higher. 036 * @return the size of the list 037 */ 038 public int size() 039 { 040 if (size == -1) 041 { 042 int i = 0; 043 for (E e : this) 044 { 045 i++; 046 } 047 size = i; 048 } 049 return size; 050 } 051 052 @Override public boolean contains(Object o) 053 { 054 055 return baseSet.contains(o) && filter(((F) o)); 056 } 057 058 @Override public Iterator<E> iterator() 059 { 060 return new FilterIterator(baseSet.iterator()); 061 } 062 063 064 private class FilterIterator implements Iterator<E> 065 { 066 E next = null; 067 068 final Iterator<? extends F> base; 069 070 public FilterIterator(Iterator<? extends F> base) 071 { 072 this.base = base; 073 fetchNext(); 074 } 075 076 private void fetchNext() 077 { 078 F check; 079 next = null; 080 while (base.hasNext()) 081 { 082 check = base.next(); 083 if (filter(check)) 084 { 085 try 086 { 087 next = (E) check; 088 break; 089 } 090 catch (ClassCastException ce) 091 { 092 log.error("wrong use of filter set. Skipping.", ce); 093 } 094 return; 095 } 096 } 097 } 098 099 public boolean hasNext() 100 { 101 return next != null; 102 } 103 104 public E next() 105 { 106 if (hasNext()) 107 { 108 E value = next; 109 fetchNext(); 110 return value; 111 } else 112 { 113 throw new NoSuchElementException(); 114 } 115 } 116 117 public void remove() 118 { 119 throw new UnsupportedOperationException(); 120 } 121 } 122}