1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18 package org.apache.tools.ant.types.resources;
19
20 import java.util.Set;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.WeakHashMap;
24 import java.util.NoSuchElementException;
25 import java.util.ConcurrentModificationException;
26
27 /**
28 * Helper class for ResourceCollections to return Iterators
29 * that fail on changes to the object.
30 * @since Ant 1.7
31 */
32 /*package-private*/ class FailFast implements Iterator {
33 private static final WeakHashMap MAP = new WeakHashMap();
34
35 /**
36 * Invalidate any in-use Iterators from the specified Object.
37 * @param o the parent Object.
38 */
39 static synchronized void invalidate(Object o) {
40 Set s = (Set) (MAP.get(o));
41 if (s != null) {
42 s.clear();
43 }
44 }
45
46 private static synchronized void add(FailFast f) {
47 Set s = (Set) (MAP.get(f.parent));
48 if (s == null) {
49 s = new HashSet();
50 MAP.put(f.parent, s);
51 }
52 s.add(f);
53 }
54
55 private static synchronized void remove(FailFast f) {
56 Set s = (Set) (MAP.get(f.parent));
57 if (s != null) {
58 s.remove(f);
59 }
60 }
61
62 private static synchronized void failFast(FailFast f) {
63 Set s = (Set) (MAP.get(f.parent));
64 if (!s.contains(f)) {
65 throw new ConcurrentModificationException();
66 }
67 }
68
69 private Object parent;
70 private Iterator wrapped;
71
72 /**
73 * Construct a new FailFast Iterator wrapping the specified Iterator
74 * and dependent upon the specified parent Object.
75 * @param o the parent Object.
76 * @param i the wrapped Iterator.
77 */
78 FailFast(Object o, Iterator i) {
79 if (o == null) {
80 throw new IllegalArgumentException("parent object is null");
81 }
82 if (i == null) {
83 throw new IllegalArgumentException("cannot wrap null iterator");
84 }
85 parent = o;
86 if (i.hasNext()) {
87 wrapped = i;
88 add(this);
89 }
90 }
91
92 /**
93 * Fulfill the Iterator contract.
94 * @return true if there are more elements.
95 */
96 public boolean hasNext() {
97 if (wrapped == null) {
98 return false;
99 }
100 failFast(this);
101 return wrapped.hasNext();
102 }
103
104 /**
105 * Fulfill the Iterator contract.
106 * @return the next element.
107 * @throws NoSuchElementException if no more elements.
108 */
109 public Object next() {
110 if (wrapped == null || !wrapped.hasNext()) {
111 throw new NoSuchElementException();
112 }
113 failFast(this);
114 try {
115 return wrapped.next();
116 } finally {
117 if (!wrapped.hasNext()) {
118 wrapped = null;
119 remove(this);
120 }
121 }
122 }
123
124 /**
125 * Fulfill the Iterator contract.
126 * @throws UnsupportedOperationException always.
127 */
128 public void remove() {
129 throw new UnsupportedOperationException();
130 }
131
132 }
133