001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.types.resources;
019:
020: import java.util.Set;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.WeakHashMap;
024: import java.util.NoSuchElementException;
025: import java.util.ConcurrentModificationException;
026:
027: /**
028: * Helper class for ResourceCollections to return Iterators
029: * that fail on changes to the object.
030: * @since Ant 1.7
031: */
032: /*package-private*/class FailFast implements Iterator {
033: private static final WeakHashMap MAP = new WeakHashMap();
034:
035: /**
036: * Invalidate any in-use Iterators from the specified Object.
037: * @param o the parent Object.
038: */
039: static synchronized void invalidate(Object o) {
040: Set s = (Set) (MAP.get(o));
041: if (s != null) {
042: s.clear();
043: }
044: }
045:
046: private static synchronized void add(FailFast f) {
047: Set s = (Set) (MAP.get(f.parent));
048: if (s == null) {
049: s = new HashSet();
050: MAP.put(f.parent, s);
051: }
052: s.add(f);
053: }
054:
055: private static synchronized void remove(FailFast f) {
056: Set s = (Set) (MAP.get(f.parent));
057: if (s != null) {
058: s.remove(f);
059: }
060: }
061:
062: private static synchronized void failFast(FailFast f) {
063: Set s = (Set) (MAP.get(f.parent));
064: if (!s.contains(f)) {
065: throw new ConcurrentModificationException();
066: }
067: }
068:
069: private Object parent;
070: private Iterator wrapped;
071:
072: /**
073: * Construct a new FailFast Iterator wrapping the specified Iterator
074: * and dependent upon the specified parent Object.
075: * @param o the parent Object.
076: * @param i the wrapped Iterator.
077: */
078: FailFast(Object o, Iterator i) {
079: if (o == null) {
080: throw new IllegalArgumentException("parent object is null");
081: }
082: if (i == null) {
083: throw new IllegalArgumentException(
084: "cannot wrap null iterator");
085: }
086: parent = o;
087: if (i.hasNext()) {
088: wrapped = i;
089: add(this );
090: }
091: }
092:
093: /**
094: * Fulfill the Iterator contract.
095: * @return true if there are more elements.
096: */
097: public boolean hasNext() {
098: if (wrapped == null) {
099: return false;
100: }
101: failFast(this );
102: return wrapped.hasNext();
103: }
104:
105: /**
106: * Fulfill the Iterator contract.
107: * @return the next element.
108: * @throws NoSuchElementException if no more elements.
109: */
110: public Object next() {
111: if (wrapped == null || !wrapped.hasNext()) {
112: throw new NoSuchElementException();
113: }
114: failFast(this );
115: try {
116: return wrapped.next();
117: } finally {
118: if (!wrapped.hasNext()) {
119: wrapped = null;
120: remove(this );
121: }
122: }
123: }
124:
125: /**
126: * Fulfill the Iterator contract.
127: * @throws UnsupportedOperationException always.
128: */
129: public void remove() {
130: throw new UnsupportedOperationException();
131: }
132:
133: }
|