View Javadoc

1   /* Transform
2   *
3   * $Id: Transform.java 4841 2007-01-06 06:51:07Z gojomo $
4   *
5   * Created on September 26, 2006
6   *
7   * Copyright (C) 2006 Internet Archive.
8   *
9   * This file is part of the Heritrix web crawler (crawler.archive.org).
10  *
11  * Heritrix is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * any later version.
15  *
16  * Heritrix is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser Public License
22  * along with Heritrix; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25  package org.archive.crawler.util;
26  
27  import java.util.AbstractCollection;
28  import java.util.Collection;
29  import java.util.Iterator;
30  
31  
32  /***
33   * A transformation of a collection.  The elements in the transform are based
34   * on the elements of some other collection; the original collection's 
35   * elements are transformed using a specified transformer.  Changes to the
36   * original collection are automatically reflected in the transform and 
37   * vice-versa.
38   * 
39   * <p>If the transformer returns null for a given original object, then that
40   * object will not be included in the transform.  Thus the transform might
41   * be smaller than the original collection.  Note that Transform instances
42   * can never contain the null element.
43   * 
44   * <p>This collection implementation does not support the optional add
45   * operation.
46   * 
47   * @author pjack
48   *
49   * @param <Original>  the type of the original elements in the collection
50   * @param <Transformed>  the type of the tranformed elements
51   */
52  public class Transform<Original,Transformed> 
53  extends AbstractCollection<Transformed> {
54  
55      /*** The original collection. */
56      final private Collection<? extends Original> delegate;
57      
58      /*** Transforms the original objects. */
59      final private Transformer<Original,Transformed> transformer;
60      
61      /***
62       * Constructor.
63       * 
64       * @param delegate  The collection whose elements to transform.
65       * @param transformer  Transforms the elements
66       */
67      public Transform(Collection<? extends Original> delegate, 
68              Transformer<Original,Transformed> transformer) {
69          this.delegate = delegate;
70          this.transformer = transformer;
71      }
72      
73      public int size() {
74          int count = 0;
75          Iterator<Transformed> iter = iterator();
76          while (iter.hasNext()) {
77              iter.next();
78              count++;
79          }
80          return count;
81      }
82  
83      public Iterator<Transformed> iterator() {
84          return new TransformIterator<Original,Transformed>(
85                  delegate.iterator(), transformer);
86      }
87      
88      
89      /***
90       * Returns a transform containing only objects of a given class.
91       * 
92       * @param <Target>  the target class
93       * @param c    the collection to transform
94       * @param cls  the class of objects to return 
95       * @return  a collection containing only objects of class cls
96       */
97      public static <Target> Collection<Target> subclasses(
98              Collection<? extends Object> c, 
99              final Class<Target> cls) {
100         Transformer<Object,Target> t = new Transformer<Object,Target>() {
101             public Target transform(Object s) {
102                 if (cls.isInstance(s)) {
103                     return cls.cast(s);
104                 } else {
105                     return null;
106                 }
107             }
108         };
109         return new Transform<Object,Target>(c, t);
110     }
111 }
112 
113 
114 class TransformIterator<Original,Transformed> implements Iterator<Transformed> {
115 
116     final private Iterator<? extends Original> iterator;
117     final private Transformer<Original,Transformed> transformer;
118     private Transformed next;
119     
120     public TransformIterator(Iterator<? extends Original> iterator, 
121             Transformer<Original,Transformed> transformer) {
122         this.iterator = iterator;
123         this.transformer = transformer;
124     }
125     
126     public boolean hasNext() {
127         if (next != null) {
128             return true;
129         }
130         while (iterator.hasNext()) {
131             Original o = iterator.next();
132             next = transformer.transform(o);
133             if (next != null) {                
134                 return true;
135             }
136         }
137         return false;
138     }
139 
140     public Transformed next() {
141         if (!hasNext()) {
142             throw new IllegalStateException();
143         }
144         Transformed r = next;
145         next = null;
146         return r;
147     }
148 
149     // FIXME: this can break standard Iterator contract, for example
150     // transformIterator.next();
151     // if(transformIterator.hasNext()) {
152     //   transformIterator.remove();
153     // }
154     // usual iterator contract is to remove the last object returned
155     // by next; in this case the subsequent
156     public void remove() {
157         iterator.remove();
158     }
159     
160 }