blob: b77d2d83a40926954d14c55c4d16b044c3ae160b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.types.resources;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Supplier;
import org.apache.tools.ant.types.Resource;
/**
* Resource collection which load underlying resource collection only on demand
* with support for caching
*/
public class LazyResourceCollectionWrapper extends
AbstractResourceCollectionWrapper {
/** List of cached resources */
private final List<Resource> cachedResources = new ArrayList<>();
private Iterator<Resource> filteringIterator;
private final Supplier<Iterator<Resource>> filteringIteratorSupplier =
() -> new FilteringIterator(getResourceCollection().iterator());
@Override
protected Iterator<Resource> createIterator() {
if (isCache()) {
if (filteringIterator == null) {
// no worry of thread safety here, see function's contract
filteringIterator = filteringIteratorSupplier.get();
}
return new CachedIterator(filteringIterator);
}
return filteringIteratorSupplier.get();
}
@Override
protected int getSize() {
// to compute the size, just iterate: the iterator will take care of
// caching
final Iterator<Resource> it = createIterator();
int size = 0;
while (it.hasNext()) {
it.next();
size++;
}
return size;
}
/**
* Specify if the resource should be filtered or not. This function should
* be overridden in order to define the filtering algorithm
*
* @param r resource considered for filtration
* @return whether the resource should be filtered or not
*/
protected boolean filterResource(final Resource r) {
return false;
}
private class FilteringIterator implements Iterator<Resource> {
Resource next = null;
boolean ended = false;
protected final Iterator<Resource> it;
FilteringIterator(final Iterator<Resource> it) {
this.it = it;
}
@Override
public boolean hasNext() {
if (ended) {
return false;
}
while (next == null) {
if (!it.hasNext()) {
ended = true;
return false;
}
next = it.next();
if (filterResource(next)) {
next = null;
}
}
return true;
}
@Override
public Resource next() {
if (!hasNext()) {
throw new UnsupportedOperationException();
}
final Resource r = next;
next = null;
return r;
}
}
/**
* Iterator that will put in the shared cache array list the selected
* resources
*/
private class CachedIterator implements Iterator<Resource> {
int cursor = 0;
private final Iterator<Resource> it;
/**
* Default constructor
*
* @param it
* the iterator which will provide the resources to put in
* cache
*/
public CachedIterator(final Iterator<Resource> it) {
this.it = it;
}
@Override
public boolean hasNext() {
synchronized (cachedResources) {
// have we already cached the next entry ?
if (cachedResources.size() > cursor) {
return true;
}
// does the wrapped iterator any more resource ?
if (!it.hasNext()) {
return false;
}
// put in cache the next resource
final Resource r = it.next();
cachedResources.add(r);
}
return true;
}
@Override
public Resource next() {
// first check that we have some to deliver
if (!hasNext()) {
throw new NoSuchElementException();
}
synchronized (cachedResources) {
// return the cached entry as hasNext should have put one for
// this iterator
return cachedResources.get(cursor++);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}