001: /* Transform
002: *
003: * $Id: Transform.java 4841 2007-01-06 06:51:07Z gojomo $
004: *
005: * Created on September 26, 2006
006: *
007: * Copyright (C) 2006 Internet Archive.
008: *
009: * This file is part of the Heritrix web crawler (crawler.archive.org).
010: *
011: * Heritrix is free software; you can redistribute it and/or modify
012: * it under the terms of the GNU Lesser Public License as published by
013: * the Free Software Foundation; either version 2.1 of the License, or
014: * any later version.
015: *
016: * Heritrix is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019: * GNU Lesser Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser Public License
022: * along with Heritrix; if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: */
025: package org.archive.crawler.util;
026:
027: import java.util.AbstractCollection;
028: import java.util.Collection;
029: import java.util.Iterator;
030:
031: /**
032: * A transformation of a collection. The elements in the transform are based
033: * on the elements of some other collection; the original collection's
034: * elements are transformed using a specified transformer. Changes to the
035: * original collection are automatically reflected in the transform and
036: * vice-versa.
037: *
038: * <p>If the transformer returns null for a given original object, then that
039: * object will not be included in the transform. Thus the transform might
040: * be smaller than the original collection. Note that Transform instances
041: * can never contain the null element.
042: *
043: * <p>This collection implementation does not support the optional add
044: * operation.
045: *
046: * @author pjack
047: *
048: * @param <Original> the type of the original elements in the collection
049: * @param <Transformed> the type of the tranformed elements
050: */
051: public class Transform<Original, Transformed> extends
052: AbstractCollection<Transformed> {
053:
054: /** The original collection. */
055: final private Collection<? extends Original> delegate;
056:
057: /** Transforms the original objects. */
058: final private Transformer<Original, Transformed> transformer;
059:
060: /**
061: * Constructor.
062: *
063: * @param delegate The collection whose elements to transform.
064: * @param transformer Transforms the elements
065: */
066: public Transform(Collection<? extends Original> delegate,
067: Transformer<Original, Transformed> transformer) {
068: this .delegate = delegate;
069: this .transformer = transformer;
070: }
071:
072: public int size() {
073: int count = 0;
074: Iterator<Transformed> iter = iterator();
075: while (iter.hasNext()) {
076: iter.next();
077: count++;
078: }
079: return count;
080: }
081:
082: public Iterator<Transformed> iterator() {
083: return new TransformIterator<Original, Transformed>(delegate
084: .iterator(), transformer);
085: }
086:
087: /**
088: * Returns a transform containing only objects of a given class.
089: *
090: * @param <Target> the target class
091: * @param c the collection to transform
092: * @param cls the class of objects to return
093: * @return a collection containing only objects of class cls
094: */
095: public static <Target> Collection<Target> subclasses(
096: Collection<? extends Object> c, final Class<Target> cls) {
097: Transformer<Object, Target> t = new Transformer<Object, Target>() {
098: public Target transform(Object s) {
099: if (cls.isInstance(s)) {
100: return cls.cast(s);
101: } else {
102: return null;
103: }
104: }
105: };
106: return new Transform<Object, Target>(c, t);
107: }
108: }
109:
110: class TransformIterator<Original, Transformed> implements
111: Iterator<Transformed> {
112:
113: final private Iterator<? extends Original> iterator;
114: final private Transformer<Original, Transformed> transformer;
115: private Transformed next;
116:
117: public TransformIterator(Iterator<? extends Original> iterator,
118: Transformer<Original, Transformed> transformer) {
119: this .iterator = iterator;
120: this .transformer = transformer;
121: }
122:
123: public boolean hasNext() {
124: if (next != null) {
125: return true;
126: }
127: while (iterator.hasNext()) {
128: Original o = iterator.next();
129: next = transformer.transform(o);
130: if (next != null) {
131: return true;
132: }
133: }
134: return false;
135: }
136:
137: public Transformed next() {
138: if (!hasNext()) {
139: throw new IllegalStateException();
140: }
141: Transformed r = next;
142: next = null;
143: return r;
144: }
145:
146: // FIXME: this can break standard Iterator contract, for example
147: // transformIterator.next();
148: // if(transformIterator.hasNext()) {
149: // transformIterator.remove();
150: // }
151: // usual iterator contract is to remove the last object returned
152: // by next; in this case the subsequent
153: public void remove() {
154: iterator.remove();
155: }
156:
157: }
|