| @@ -26,8 +26,13 @@ import java.util.Collections; | |||||
| import java.util.Iterator; | import java.util.Iterator; | ||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.NoSuchElementException; | import java.util.NoSuchElementException; | ||||
| import java.util.Optional; | |||||
| import java.util.Spliterator; | |||||
| import java.util.Spliterators; | |||||
| import java.util.Stack; | import java.util.Stack; | ||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | |||||
| import java.util.stream.StreamSupport; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| @@ -61,10 +66,8 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| public static final Iterator<Resource> EMPTY_ITERATOR = Collections.emptyIterator(); | public static final Iterator<Resource> EMPTY_ITERATOR = Collections.emptyIterator(); | ||||
| private class MyCollection extends AbstractCollection<Resource> { | private class MyCollection extends AbstractCollection<Resource> { | ||||
| private Collection<Resource> cached; | |||||
| private volatile Collection<Resource> cached; | |||||
| MyCollection() { | |||||
| } | |||||
| @Override | @Override | ||||
| public int size() { | public int size() { | ||||
| return getCache().size(); | return getCache().size(); | ||||
| @@ -74,45 +77,41 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| return getCache().iterator(); | return getCache().iterator(); | ||||
| } | } | ||||
| private synchronized Collection<Resource> getCache() { | private synchronized Collection<Resource> getCache() { | ||||
| Collection<Resource> coll = cached; | |||||
| if (coll == null) { | |||||
| coll = new ArrayList<>(); | |||||
| new MyIterator().forEachRemaining(coll::add); | |||||
| if (cache) { | |||||
| cached = coll; | |||||
| } | |||||
| if (cached == null) { | |||||
| cached = internalResources().collect(Collectors.toList()); | |||||
| } | } | ||||
| return coll; | |||||
| return cached; | |||||
| } | } | ||||
| private class MyIterator implements Iterator<Resource> { | |||||
| private Iterator<ResourceCollection> rci = getNested().iterator(); | |||||
| private Iterator<Resource> ri = null; | |||||
| } | |||||
| @Override | |||||
| public boolean hasNext() { | |||||
| boolean result = ri != null && ri.hasNext(); | |||||
| while (!result && rci.hasNext()) { | |||||
| ri = rci.next().iterator(); | |||||
| result = ri.hasNext(); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| @Override | |||||
| public Resource next() { | |||||
| if (!hasNext()) { | |||||
| throw new NoSuchElementException(); | |||||
| } | |||||
| return ri.next(); | |||||
| private class MyIterator implements Iterator<Resource> { | |||||
| private Iterator<ResourceCollection> rci = getNested().iterator(); | |||||
| private Iterator<Resource> ri; | |||||
| @Override | |||||
| public boolean hasNext() { | |||||
| boolean result = ri != null && ri.hasNext(); | |||||
| while (!result && rci.hasNext()) { | |||||
| ri = rci.next().iterator(); | |||||
| result = ri.hasNext(); | |||||
| } | } | ||||
| @Override | |||||
| public void remove() { | |||||
| throw new UnsupportedOperationException(); | |||||
| return result; | |||||
| } | |||||
| @Override | |||||
| public Resource next() { | |||||
| if (!hasNext()) { | |||||
| throw new NoSuchElementException(); | |||||
| } | } | ||||
| return ri.next(); | |||||
| } | |||||
| @Override | |||||
| public void remove() { | |||||
| throw new UnsupportedOperationException(); | |||||
| } | } | ||||
| } | } | ||||
| private List<ResourceCollection> rc; | private List<ResourceCollection> rc; | ||||
| private Collection<Resource> coll; | |||||
| private Optional<Collection<Resource>> cacheColl = Optional.empty(); | |||||
| private volatile boolean cache = false; | private volatile boolean cache = false; | ||||
| /** | /** | ||||
| @@ -156,7 +155,7 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| } | } | ||||
| rc.add(c); | rc.add(c); | ||||
| invalidateExistingIterators(); | invalidateExistingIterators(); | ||||
| coll = null; | |||||
| cacheColl = Optional.empty(); | |||||
| setChecked(false); | setChecked(false); | ||||
| } | } | ||||
| @@ -170,7 +169,7 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| return getRef().iterator(); | return getRef().iterator(); | ||||
| } | } | ||||
| validate(); | validate(); | ||||
| return new FailFast(this, coll.iterator()); | |||||
| return new FailFast(this, cacheColl.map(Iterable::iterator).orElseGet(MyIterator::new)); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -183,7 +182,7 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| return getRef().size(); | return getRef().size(); | ||||
| } | } | ||||
| validate(); | validate(); | ||||
| return coll.size(); | |||||
| return cacheColl.isPresent() ? cacheColl.get().size() : (int) internalResources().count(); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -196,8 +195,7 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| return getRef().isFilesystemOnly(); | return getRef().isFilesystemOnly(); | ||||
| } | } | ||||
| validate(); | validate(); | ||||
| return getNested().stream() | |||||
| .allMatch(ResourceCollection::isFilesystemOnly); | |||||
| return getNested().stream().allMatch(ResourceCollection::isFilesystemOnly); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -210,11 +208,8 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| return getRef().toString(); | return getRef().toString(); | ||||
| } | } | ||||
| validate(); | validate(); | ||||
| if (coll == null || coll.isEmpty()) { | |||||
| return ""; | |||||
| } | |||||
| return coll.stream().map(Object::toString) | |||||
| .collect(Collectors.joining(File.pathSeparator)); | |||||
| final Stream<?> stream = cache ? cacheColl.get().stream() : getNested().stream(); | |||||
| return stream.map(String::valueOf).collect(Collectors.joining(File.pathSeparator)); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -227,17 +222,13 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| @Override | @Override | ||||
| protected void dieOnCircularReference(Stack<Object> stk, Project p) | protected void dieOnCircularReference(Stack<Object> stk, Project p) | ||||
| throws BuildException { | throws BuildException { | ||||
| if (isChecked()) { | |||||
| return; | |||||
| } | |||||
| if (isReference()) { | if (isReference()) { | ||||
| super.dieOnCircularReference(stk, p); | super.dieOnCircularReference(stk, p); | ||||
| } else { | |||||
| for (ResourceCollection resourceCollection : getNested()) { | |||||
| if (resourceCollection instanceof DataType) { | |||||
| pushAndInvokeCircularReferenceCheck((DataType) resourceCollection, stk, p); | |||||
| } | |||||
| } | |||||
| return; | |||||
| } | |||||
| if (!isChecked()) { | |||||
| getNested().stream().filter(DataType.class::isInstance).map(DataType.class::cast) | |||||
| .forEach(dt -> pushAndInvokeCircularReferenceCheck(dt, stk, p)); | |||||
| setChecked(true); | setChecked(true); | ||||
| } | } | ||||
| } | } | ||||
| @@ -259,10 +250,17 @@ public class Resources extends DataType implements AppendableResourceCollection | |||||
| private synchronized void validate() { | private synchronized void validate() { | ||||
| dieOnCircularReference(); | dieOnCircularReference(); | ||||
| coll = (coll == null) ? new MyCollection() : coll; | |||||
| if (cache && !cacheColl.isPresent()) { | |||||
| cacheColl = Optional.of(new MyCollection()); | |||||
| } | |||||
| } | } | ||||
| private synchronized List<ResourceCollection> getNested() { | private synchronized List<ResourceCollection> getNested() { | ||||
| return rc == null ? Collections.emptyList() : rc; | return rc == null ? Collections.emptyList() : rc; | ||||
| } | } | ||||
| private synchronized Stream<Resource> internalResources() { | |||||
| return StreamSupport.stream( | |||||
| Spliterators.spliteratorUnknownSize(new MyIterator(), Spliterator.NONNULL), false); | |||||
| } | |||||
| } | } | ||||