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:
019: package org.apache.tools.ant.types.resources;
020:
021: import java.io.File;
022: import java.util.List;
023: import java.util.Stack;
024: import java.util.Vector;
025: import java.util.Iterator;
026: import java.util.Collection;
027: import java.util.Collections;
028: import java.util.AbstractCollection;
029: import java.util.NoSuchElementException;
030:
031: import org.apache.tools.ant.Project;
032: import org.apache.tools.ant.BuildException;
033: import org.apache.tools.ant.types.DataType;
034: import org.apache.tools.ant.types.ResourceCollection;
035:
036: /**
037: * Generic ResourceCollection: Either stores nested ResourceCollections,
038: * making no attempt to remove duplicates, or references another ResourceCollection.
039: * @since Ant 1.7
040: */
041: public class Resources extends DataType implements ResourceCollection {
042: /** static empty ResourceCollection */
043: public static final ResourceCollection NONE = new ResourceCollection() {
044: public boolean isFilesystemOnly() {
045: return true;
046: }
047:
048: public Iterator iterator() {
049: return EMPTY_ITERATOR;
050: }
051:
052: public int size() {
053: return 0;
054: }
055: };
056:
057: /** static empty Iterator */
058: public static final Iterator EMPTY_ITERATOR = new Iterator() {
059: public Object next() {
060: throw new NoSuchElementException();
061: }
062:
063: public boolean hasNext() {
064: return false;
065: }
066:
067: public void remove() {
068: throw new UnsupportedOperationException();
069: }
070: };
071:
072: private class MyCollection extends AbstractCollection {
073: private int size;
074:
075: MyCollection() {
076: size = 0;
077: for (Iterator rci = getNested().iterator(); rci.hasNext();) {
078: size += ((ResourceCollection) rci.next()).size();
079: }
080: }
081:
082: public int size() {
083: return size;
084: }
085:
086: public Iterator iterator() {
087: return new MyIterator();
088: }
089:
090: private class MyIterator implements Iterator {
091: private Iterator rci = getNested().iterator();
092: private Iterator ri = null;
093:
094: public boolean hasNext() {
095: boolean result = ri != null && ri.hasNext();
096: while (!result && rci.hasNext()) {
097: ri = ((ResourceCollection) rci.next()).iterator();
098: result = ri.hasNext();
099: }
100: return result;
101: }
102:
103: public Object next() {
104: if (!hasNext()) {
105: throw new NoSuchElementException();
106: }
107: return ri.next();
108: }
109:
110: public void remove() {
111: throw new UnsupportedOperationException();
112: }
113: }
114: }
115:
116: private Vector rc;
117: private Collection coll;
118:
119: /**
120: * Add a ResourceCollection.
121: * @param c the ResourceCollection to add.
122: */
123: public synchronized void add(ResourceCollection c) {
124: if (isReference()) {
125: throw noChildrenAllowed();
126: }
127: if (c == null) {
128: return;
129: }
130: if (rc == null) {
131: rc = new Vector();
132: }
133: rc.add(c);
134: FailFast.invalidate(this );
135: coll = null;
136: setChecked(false);
137: }
138:
139: /**
140: * Fulfill the ResourceCollection contract.
141: * @return an Iterator of Resources.
142: */
143: public synchronized Iterator iterator() {
144: if (isReference()) {
145: return getRef().iterator();
146: }
147: validate();
148: return new FailFast(this , coll.iterator());
149: }
150:
151: /**
152: * Fulfill the ResourceCollection contract.
153: * @return number of elements as int.
154: */
155: public synchronized int size() {
156: if (isReference()) {
157: return getRef().size();
158: }
159: validate();
160: return coll.size();
161: }
162:
163: /**
164: * Fulfill the ResourceCollection contract.
165: * @return true if all Resources represent files.
166: */
167: public boolean isFilesystemOnly() {
168: if (isReference()) {
169: return getRef().isFilesystemOnly();
170: }
171: validate();
172:
173: for (Iterator i = getNested().iterator(); i.hasNext();) {
174: if ((!((ResourceCollection) i.next()).isFilesystemOnly())) {
175: return false;
176: }
177: }
178: return true;
179: }
180:
181: /**
182: * Format this BaseResourceCollectionContainer as a String.
183: * @return a descriptive <code>String</code>.
184: */
185: public synchronized String toString() {
186: if (isReference()) {
187: return getCheckedRef().toString();
188: }
189: if (coll == null || coll.isEmpty()) {
190: return "";
191: }
192: StringBuffer sb = new StringBuffer();
193: for (Iterator i = coll.iterator(); i.hasNext();) {
194: if (sb.length() > 0) {
195: sb.append(File.pathSeparatorChar);
196: }
197: sb.append(i.next());
198: }
199: return sb.toString();
200: }
201:
202: /**
203: * Overrides the version of DataType to recurse on all DataType
204: * child elements that may have been added.
205: * @param stk the stack of data types to use (recursively).
206: * @param p the project to use to dereference the references.
207: * @throws BuildException on error.
208: */
209: protected void dieOnCircularReference(Stack stk, Project p)
210: throws BuildException {
211: if (isChecked()) {
212: return;
213: }
214: if (isReference()) {
215: super .dieOnCircularReference(stk, p);
216: } else {
217: for (Iterator i = getNested().iterator(); i.hasNext();) {
218: Object o = i.next();
219: if (o instanceof DataType) {
220: invokeCircularReferenceCheck((DataType) o, stk, p);
221: }
222: }
223: setChecked(true);
224: }
225: }
226:
227: /**
228: * Resolves references, allowing any ResourceCollection.
229: * @return the referenced ResourceCollection.
230: */
231: private ResourceCollection getRef() {
232: return (ResourceCollection) getCheckedRef(
233: ResourceCollection.class, "ResourceCollection");
234: }
235:
236: private synchronized void validate() {
237: dieOnCircularReference();
238: coll = (coll == null) ? new MyCollection() : coll;
239: }
240:
241: private synchronized List getNested() {
242: return rc == null ? Collections.EMPTY_LIST : rc;
243: }
244: }
|