git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@958669 13f79535-47bb-0310-9956-ffa450edef68master
@@ -81,6 +81,11 @@ Fixed bugs: | |||||
case-insensitive file system. | case-insensitive file system. | ||||
Bugzilla Report 49041. | Bugzilla Report 49041. | ||||
* The <restrict> resource collection was checking every resource even if | |||||
we actually just want the first one, like in the exemple of use of | |||||
resourcelist in the documentation (getting the first available resource | |||||
from a mirror list). | |||||
Other changes: | Other changes: | ||||
-------------- | -------------- | ||||
@@ -0,0 +1,210 @@ | |||||
/* | |||||
* 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 | |||||
* | |||||
* http://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.io.File; | |||||
import java.util.Iterator; | |||||
import java.util.Stack; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.Project; | |||||
import org.apache.tools.ant.types.DataType; | |||||
import org.apache.tools.ant.types.Resource; | |||||
import org.apache.tools.ant.types.ResourceCollection; | |||||
/** | |||||
* Base class for a ResourceCollection that wraps a single nested | |||||
* ResourceCollection. | |||||
* @since Ant 1.8.2 | |||||
*/ | |||||
public abstract class AbstractResourceCollectionWrapper | |||||
extends DataType implements ResourceCollection, Cloneable { | |||||
private static final String ONE_NESTED_MESSAGE | |||||
= " expects exactly one nested resource collection."; | |||||
private ResourceCollection rc; | |||||
private boolean cache = true; | |||||
/** | |||||
* Set whether to cache collections. | |||||
* @param b boolean cache flag. | |||||
*/ | |||||
public synchronized void setCache(boolean b) { | |||||
cache = b; | |||||
} | |||||
/** | |||||
* Learn whether to cache collections. Default is <code>true</code>. | |||||
* @return boolean cache flag. | |||||
*/ | |||||
public synchronized boolean isCache() { | |||||
return cache; | |||||
} | |||||
/** | |||||
* Add a ResourceCollection to the container. | |||||
* @param c the ResourceCollection to add. | |||||
* @throws BuildException on error. | |||||
*/ | |||||
public synchronized void add(ResourceCollection c) throws BuildException { | |||||
if (isReference()) { | |||||
throw noChildrenAllowed(); | |||||
} | |||||
if (c == null) { | |||||
return; | |||||
} | |||||
if (rc != null) { | |||||
throw oneNested(); | |||||
} | |||||
rc = c; | |||||
if (Project.getProject(rc) == null) { | |||||
Project p = getProject(); | |||||
if (p != null) { | |||||
p.setProjectReference(rc); | |||||
} | |||||
} | |||||
setChecked(false); | |||||
} | |||||
/** | |||||
* Fulfill the ResourceCollection contract. | |||||
* @return an Iterator of Resources. | |||||
*/ | |||||
public final synchronized Iterator iterator() { | |||||
if (isReference()) { | |||||
return ((AbstractResourceCollectionWrapper) getCheckedRef()).iterator(); | |||||
} | |||||
dieOnCircularReference(); | |||||
return new FailFast(this, createIterator()); | |||||
} | |||||
/** | |||||
* Do create an iterator on the resource collection. The creation | |||||
* of the iterator is allowed to not be thread safe whereas the iterator | |||||
* itself should. The returned iterator will be wrapped into the FailFast | |||||
* one. | |||||
* | |||||
* @return the iterator on the resource collection | |||||
*/ | |||||
protected abstract Iterator createIterator(); | |||||
/** | |||||
* Fulfill the ResourceCollection contract. | |||||
* @return number of elements as int. | |||||
*/ | |||||
public synchronized int size() { | |||||
if (isReference()) { | |||||
return ((AbstractResourceCollectionWrapper) getCheckedRef()).size(); | |||||
} | |||||
dieOnCircularReference(); | |||||
return getSize(); | |||||
} | |||||
/** | |||||
* Do compute the size of the resource collection. The implementation of | |||||
* this function is allowed to be not thread safe. | |||||
* | |||||
* @return | |||||
*/ | |||||
protected abstract int getSize(); | |||||
/** | |||||
* Fulfill the ResourceCollection contract. | |||||
* @return whether this is a filesystem-only resource collection. | |||||
*/ | |||||
public synchronized boolean isFilesystemOnly() { | |||||
if (isReference()) { | |||||
return ((BaseResourceCollectionContainer) getCheckedRef()).isFilesystemOnly(); | |||||
} | |||||
dieOnCircularReference(); | |||||
if (rc == null || rc.isFilesystemOnly()) { | |||||
return true; | |||||
} | |||||
/* now check each Resource in case the child only | |||||
lets through files from any children IT may have: */ | |||||
for (Iterator i = createIterator(); i.hasNext();) { | |||||
Resource r = (Resource) i.next(); | |||||
if (r.as(FileProvider.class) == null) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Overrides the version of DataType to recurse on all DataType | |||||
* child elements that may have been added. | |||||
* @param stk the stack of data types to use (recursively). | |||||
* @param p the project to use to dereference the references. | |||||
* @throws BuildException on error. | |||||
*/ | |||||
protected synchronized void dieOnCircularReference(Stack stk, Project p) | |||||
throws BuildException { | |||||
if (isChecked()) { | |||||
return; | |||||
} | |||||
if (isReference()) { | |||||
super.dieOnCircularReference(stk, p); | |||||
} else { | |||||
if (rc instanceof DataType) { | |||||
pushAndInvokeCircularReferenceCheck((DataType) rc, stk, p); | |||||
} | |||||
setChecked(true); | |||||
} | |||||
} | |||||
/** | |||||
* Get the nested ResourceCollection. | |||||
* @return a ResourceCollection. | |||||
* @throws BuildException if no nested ResourceCollection has been provided. | |||||
*/ | |||||
protected final synchronized ResourceCollection getResourceCollection() { | |||||
dieOnCircularReference(); | |||||
if (rc == null) { | |||||
throw oneNested(); | |||||
} | |||||
return rc; | |||||
} | |||||
/** | |||||
* Format this BaseResourceCollectionWrapper as a String. | |||||
* @return a descriptive <code>String</code>. | |||||
*/ | |||||
public synchronized String toString() { | |||||
if (isReference()) { | |||||
return getCheckedRef().toString(); | |||||
} | |||||
if (getSize() == 0) { | |||||
return ""; | |||||
} | |||||
StringBuffer sb = new StringBuffer(); | |||||
for (Iterator i = createIterator(); i.hasNext();) { | |||||
if (sb.length() > 0) { | |||||
sb.append(File.pathSeparatorChar); | |||||
} | |||||
sb.append(i.next()); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
private BuildException oneNested() { | |||||
return new BuildException(super.toString() + ONE_NESTED_MESSAGE); | |||||
} | |||||
} |
@@ -17,16 +17,8 @@ | |||||
*/ | */ | ||||
package org.apache.tools.ant.types.resources; | package org.apache.tools.ant.types.resources; | ||||
import java.io.File; | |||||
import java.util.Stack; | |||||
import java.util.Iterator; | |||||
import java.util.Collection; | import java.util.Collection; | ||||
import org.apache.tools.ant.Project; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.types.DataType; | |||||
import org.apache.tools.ant.types.Resource; | |||||
import org.apache.tools.ant.types.ResourceCollection; | |||||
import java.util.Iterator; | |||||
/** | /** | ||||
* Base class for a ResourceCollection that wraps a single nested | * Base class for a ResourceCollection that wraps a single nested | ||||
@@ -34,165 +26,24 @@ import org.apache.tools.ant.types.ResourceCollection; | |||||
* @since Ant 1.7 | * @since Ant 1.7 | ||||
*/ | */ | ||||
public abstract class BaseResourceCollectionWrapper | public abstract class BaseResourceCollectionWrapper | ||||
extends DataType implements ResourceCollection, Cloneable { | |||||
private static final String ONE_NESTED_MESSAGE | |||||
= " expects exactly one nested resource collection."; | |||||
extends AbstractResourceCollectionWrapper { | |||||
private ResourceCollection rc; | |||||
private Collection coll = null; | private Collection coll = null; | ||||
private boolean cache = true; | |||||
/** | |||||
* Set whether to cache collections. | |||||
* @param b boolean cache flag. | |||||
*/ | |||||
public synchronized void setCache(boolean b) { | |||||
cache = b; | |||||
} | |||||
/** | |||||
* Learn whether to cache collections. Default is <code>true</code>. | |||||
* @return boolean cache flag. | |||||
*/ | |||||
public synchronized boolean isCache() { | |||||
return cache; | |||||
protected Iterator createIterator() { | |||||
return cacheCollection().iterator(); | |||||
} | } | ||||
/** | |||||
* Add a ResourceCollection to the container. | |||||
* @param c the ResourceCollection to add. | |||||
* @throws BuildException on error. | |||||
*/ | |||||
public synchronized void add(ResourceCollection c) throws BuildException { | |||||
if (isReference()) { | |||||
throw noChildrenAllowed(); | |||||
} | |||||
if (c == null) { | |||||
return; | |||||
} | |||||
if (rc != null) { | |||||
throw oneNested(); | |||||
} | |||||
rc = c; | |||||
if (Project.getProject(rc) == null) { | |||||
Project p = getProject(); | |||||
if (p != null) { | |||||
p.setProjectReference(rc); | |||||
} | |||||
} | |||||
setChecked(false); | |||||
} | |||||
/** | |||||
* Fulfill the ResourceCollection contract. | |||||
* @return an Iterator of Resources. | |||||
*/ | |||||
public final synchronized Iterator iterator() { | |||||
if (isReference()) { | |||||
return ((BaseResourceCollectionWrapper) getCheckedRef()).iterator(); | |||||
} | |||||
dieOnCircularReference(); | |||||
return new FailFast(this, cacheCollection().iterator()); | |||||
} | |||||
/** | |||||
* Fulfill the ResourceCollection contract. | |||||
* @return number of elements as int. | |||||
*/ | |||||
public synchronized int size() { | |||||
if (isReference()) { | |||||
return ((BaseResourceCollectionWrapper) getCheckedRef()).size(); | |||||
} | |||||
dieOnCircularReference(); | |||||
protected int getSize() { | |||||
return cacheCollection().size(); | return cacheCollection().size(); | ||||
} | } | ||||
/** | |||||
* Fulfill the ResourceCollection contract. | |||||
* @return whether this is a filesystem-only resource collection. | |||||
*/ | |||||
public synchronized boolean isFilesystemOnly() { | |||||
if (isReference()) { | |||||
return ((BaseResourceCollectionContainer) getCheckedRef()).isFilesystemOnly(); | |||||
} | |||||
dieOnCircularReference(); | |||||
if (rc == null || rc.isFilesystemOnly()) { | |||||
return true; | |||||
} | |||||
/* now check each Resource in case the child only | |||||
lets through files from any children IT may have: */ | |||||
for (Iterator i = cacheCollection().iterator(); i.hasNext();) { | |||||
Resource r = (Resource) i.next(); | |||||
if (r.as(FileProvider.class) == null) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Overrides the version of DataType to recurse on all DataType | |||||
* child elements that may have been added. | |||||
* @param stk the stack of data types to use (recursively). | |||||
* @param p the project to use to dereference the references. | |||||
* @throws BuildException on error. | |||||
*/ | |||||
protected synchronized void dieOnCircularReference(Stack stk, Project p) | |||||
throws BuildException { | |||||
if (isChecked()) { | |||||
return; | |||||
} | |||||
if (isReference()) { | |||||
super.dieOnCircularReference(stk, p); | |||||
} else { | |||||
if (rc instanceof DataType) { | |||||
pushAndInvokeCircularReferenceCheck((DataType) rc, stk, p); | |||||
} | |||||
setChecked(true); | |||||
} | |||||
} | |||||
/** | |||||
* Get the nested ResourceCollection. | |||||
* @return a ResourceCollection. | |||||
* @throws BuildException if no nested ResourceCollection has been provided. | |||||
*/ | |||||
protected final synchronized ResourceCollection getResourceCollection() { | |||||
dieOnCircularReference(); | |||||
if (rc == null) { | |||||
throw oneNested(); | |||||
} | |||||
return rc; | |||||
} | |||||
/** | /** | ||||
* Template method for subclasses to return a Collection of Resources. | * Template method for subclasses to return a Collection of Resources. | ||||
* @return Collection. | * @return Collection. | ||||
*/ | */ | ||||
protected abstract Collection getCollection(); | protected abstract Collection getCollection(); | ||||
/** | |||||
* Format this BaseResourceCollectionWrapper as a String. | |||||
* @return a descriptive <code>String</code>. | |||||
*/ | |||||
public synchronized String toString() { | |||||
if (isReference()) { | |||||
return getCheckedRef().toString(); | |||||
} | |||||
if (cacheCollection().size() == 0) { | |||||
return ""; | |||||
} | |||||
StringBuffer sb = new StringBuffer(); | |||||
for (Iterator i = coll.iterator(); i.hasNext();) { | |||||
if (sb.length() > 0) { | |||||
sb.append(File.pathSeparatorChar); | |||||
} | |||||
sb.append(i.next()); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
private synchronized Collection cacheCollection() { | private synchronized Collection cacheCollection() { | ||||
if (coll == null || !isCache()) { | if (coll == null || !isCache()) { | ||||
coll = getCollection(); | coll = getCollection(); | ||||
@@ -200,8 +51,4 @@ public abstract class BaseResourceCollectionWrapper | |||||
return coll; | return coll; | ||||
} | } | ||||
private BuildException oneNested() { | |||||
return new BuildException(super.toString() + ONE_NESTED_MESSAGE); | |||||
} | |||||
} | } |
@@ -0,0 +1,157 @@ | |||||
package org.apache.tools.ant.types.resources; | |||||
import java.util.ArrayList; | |||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.NoSuchElementException; | |||||
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 List cachedResources = new ArrayList(); | |||||
private FilteringIterator filteringIterator; | |||||
protected Iterator createIterator() { | |||||
Iterator iterator; | |||||
if (isCache()) { | |||||
if (filteringIterator == null) { | |||||
// no worry of thread safety here, see function's contract | |||||
filteringIterator = new FilteringIterator( | |||||
getResourceCollection().iterator()); | |||||
} | |||||
iterator = new CachedIterator(filteringIterator); | |||||
} else { | |||||
iterator = new FilteringIterator(getResourceCollection().iterator()); | |||||
} | |||||
return iterator; | |||||
} | |||||
protected int getSize() { | |||||
// to compute the size, just iterate: the iterator will take care of | |||||
// caching | |||||
Iterator 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 overrided in order to define the filtering algorithm | |||||
* | |||||
* @param r | |||||
* @return | |||||
*/ | |||||
protected boolean filterResource(Resource r) { | |||||
return false; | |||||
} | |||||
private class FilteringIterator implements Iterator { | |||||
Resource next = null; | |||||
boolean ended = false; | |||||
protected final Iterator it; | |||||
public FilteringIterator(Iterator it) { | |||||
this.it = it; | |||||
} | |||||
public boolean hasNext() { | |||||
if (ended) { | |||||
return false; | |||||
} | |||||
while (next == null) { | |||||
if (!it.hasNext()) { | |||||
ended = true; | |||||
return false; | |||||
} | |||||
next = (Resource) it.next(); | |||||
if (filterResource(next)) { | |||||
next = null; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
public Object next() { | |||||
if (!hasNext()) { | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
Resource r = next; | |||||
next = null; | |||||
return r; | |||||
} | |||||
public void remove() { | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
} | |||||
/** | |||||
* Iterator that will put in the shared cache array list the selected | |||||
* resources | |||||
*/ | |||||
private class CachedIterator implements Iterator { | |||||
int cusrsor = 0; | |||||
private final Iterator it; | |||||
/** | |||||
* Default constructor | |||||
* | |||||
* @param it | |||||
* the iterator which will provide the resources to put in | |||||
* cache | |||||
*/ | |||||
public CachedIterator(Iterator it) { | |||||
this.it = it; | |||||
} | |||||
public boolean hasNext() { | |||||
synchronized (cachedResources) { | |||||
// have we already cached the next entry ? | |||||
if (cachedResources.size() > cusrsor) { | |||||
return true; | |||||
} | |||||
// does the wrapped iterator any more resource ? | |||||
if (!it.hasNext()) { | |||||
return false; | |||||
} | |||||
// put in cache the next resource | |||||
Resource r = (Resource) it.next(); | |||||
cachedResources.add(r); | |||||
} | |||||
return true; | |||||
} | |||||
public Object 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(cusrsor++); | |||||
} | |||||
} | |||||
public void remove() { | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
} | |||||
} |
@@ -17,8 +17,6 @@ | |||||
*/ | */ | ||||
package org.apache.tools.ant.types.resources; | package org.apache.tools.ant.types.resources; | ||||
import java.util.ArrayList; | |||||
import java.util.Collection; | |||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.Stack; | import java.util.Stack; | ||||
@@ -37,23 +35,17 @@ import org.apache.tools.ant.types.resources.selectors.ResourceSelectorContainer; | |||||
public class Restrict | public class Restrict | ||||
extends ResourceSelectorContainer implements ResourceCollection { | extends ResourceSelectorContainer implements ResourceCollection { | ||||
private BaseResourceCollectionWrapper w = new BaseResourceCollectionWrapper() { | |||||
private LazyResourceCollectionWrapper w = new LazyResourceCollectionWrapper() { | |||||
/** | /** | ||||
* Restrict the nested ResourceCollection based on the nested selectors. | * Restrict the nested ResourceCollection based on the nested selectors. | ||||
* @return a Collection of Resources. | |||||
*/ | */ | ||||
protected Collection getCollection() { | |||||
ArrayList result = new ArrayList(); | |||||
outer: for (Iterator ri = w.getResourceCollection().iterator(); ri.hasNext();) { | |||||
Resource r = (Resource) ri.next(); | |||||
for (Iterator i = getSelectors(); i.hasNext();) { | |||||
if (!((ResourceSelector) (i.next())).isSelected(r)) { | |||||
continue outer; | |||||
} | |||||
protected boolean filterResource(Resource r) { | |||||
for (Iterator i = getSelectors(); i.hasNext();) { | |||||
if (!((ResourceSelector) (i.next())).isSelected(r)) { | |||||
return true; | |||||
} | } | ||||
result.add(r); | |||||
} | } | ||||
return result; | |||||
return false; | |||||
} | } | ||||
}; | }; | ||||
@@ -0,0 +1,180 @@ | |||||
/* | |||||
* 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 | |||||
* | |||||
* http://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.Arrays; | |||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.NoSuchElementException; | |||||
import junit.framework.TestCase; | |||||
import org.apache.tools.ant.types.Resource; | |||||
import org.apache.tools.ant.types.ResourceCollection; | |||||
public class LazyResourceCollectionTest extends TestCase { | |||||
private class StringResourceCollection implements ResourceCollection { | |||||
List resources = Arrays.asList(new Resource[] {}); | |||||
List createdIterators = new ArrayList(); | |||||
public int size() { | |||||
return resources.size(); | |||||
} | |||||
public Iterator iterator() { | |||||
StringResourceIterator it = new StringResourceIterator(); | |||||
createdIterators.add(it); | |||||
return it; | |||||
} | |||||
public boolean isFilesystemOnly() { | |||||
return false; | |||||
} | |||||
} | |||||
private class StringResourceIterator implements Iterator { | |||||
int cursor = 0; | |||||
public void remove() { | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
public Object next() { | |||||
if (cursor < 3) { | |||||
cursor++; | |||||
return new StringResource("r" + cursor); | |||||
} | |||||
return null; | |||||
} | |||||
public boolean hasNext() { | |||||
return cursor < 3; | |||||
} | |||||
} | |||||
public void testLazyLoading() throws Exception { | |||||
StringResourceCollection collectionTest = new StringResourceCollection(); | |||||
LazyResourceCollectionWrapper lazyCollection = new LazyResourceCollectionWrapper(); | |||||
lazyCollection.add(collectionTest); | |||||
Iterator it = lazyCollection.iterator(); | |||||
assertOneCreatedIterator(collectionTest); | |||||
StringResourceIterator stringResourceIterator = (StringResourceIterator) collectionTest.createdIterators | |||||
.get(0); | |||||
assertEquals("A resource was loaded without iterating", 1, | |||||
stringResourceIterator.cursor); | |||||
StringResource r = (StringResource) it.next(); | |||||
assertOneCreatedIterator(collectionTest); | |||||
assertEquals("r1", r.getValue()); | |||||
assertEquals("Iterating once load more than 1 resource", 2, | |||||
stringResourceIterator.cursor); | |||||
r = (StringResource) it.next(); | |||||
assertOneCreatedIterator(collectionTest); | |||||
assertEquals("r2", r.getValue()); | |||||
assertEquals("Iterating twice load more than 2 resources", 3, | |||||
stringResourceIterator.cursor); | |||||
r = (StringResource) it.next(); | |||||
assertOneCreatedIterator(collectionTest); | |||||
assertEquals("r3", r.getValue()); | |||||
assertEquals("Iterating 3 times load more than 3 resources", 3, | |||||
stringResourceIterator.cursor); | |||||
try { | |||||
it.next(); | |||||
fail("NoSuchElementException shoudl have been raised"); | |||||
} catch (NoSuchElementException e) { | |||||
// ok | |||||
} | |||||
} | |||||
private void assertOneCreatedIterator( | |||||
StringResourceCollection testCollection) { | |||||
assertEquals("More than one iterator has been created", 1, | |||||
testCollection.createdIterators.size()); | |||||
} | |||||
public void testCaching() throws Exception { | |||||
StringResourceCollection collectionTest = new StringResourceCollection(); | |||||
LazyResourceCollectionWrapper lazyCollection = new LazyResourceCollectionWrapper(); | |||||
lazyCollection.add(collectionTest); | |||||
assertTrue(lazyCollection.isCache()); | |||||
Iterator it1 = lazyCollection.iterator(); | |||||
assertOneCreatedIterator(collectionTest); | |||||
Iterator it2 = lazyCollection.iterator(); | |||||
assertOneCreatedIterator(collectionTest); | |||||
StringResourceIterator stringResourceIterator = (StringResourceIterator) collectionTest.createdIterators | |||||
.get(0); | |||||
assertEquals("A resource was loaded without iterating", 1, | |||||
stringResourceIterator.cursor); | |||||
StringResource r = (StringResource) it1.next(); | |||||
assertEquals("r1", r.getValue()); | |||||
assertEquals("Iterating once load more than 1 resource", 2, | |||||
stringResourceIterator.cursor); | |||||
r = (StringResource) it2.next(); | |||||
assertEquals("r1", r.getValue()); | |||||
assertEquals( | |||||
"The second iterator did not lookup in the cache for a resource", | |||||
2, stringResourceIterator.cursor); | |||||
r = (StringResource) it2.next(); | |||||
assertEquals("r2", r.getValue()); | |||||
assertEquals("Iterating twice load more than 2 resources", 3, | |||||
stringResourceIterator.cursor); | |||||
r = (StringResource) it1.next(); | |||||
assertEquals("r2", r.getValue()); | |||||
assertEquals( | |||||
"The first iterator did not lookup in the cache for a resource", | |||||
3, stringResourceIterator.cursor); | |||||
r = (StringResource) it2.next(); | |||||
assertEquals("r3", r.getValue()); | |||||
assertEquals("Iterating 3 times load more than 3 resources", 3, | |||||
stringResourceIterator.cursor); | |||||
r = (StringResource) it1.next(); | |||||
assertEquals("r3", r.getValue()); | |||||
assertEquals( | |||||
"The first iterator did not lookup in the cache for a resource", | |||||
3, stringResourceIterator.cursor); | |||||
try { | |||||
it1.next(); | |||||
fail("NoSuchElementException should have been raised"); | |||||
} catch (NoSuchElementException e) { | |||||
// ok | |||||
} | |||||
try { | |||||
it2.next(); | |||||
fail("NoSuchElementException should have been raised"); | |||||
} catch (NoSuchElementException e) { | |||||
// ok | |||||
} | |||||
} | |||||
} |