Index: src/org/apache/xml/security/keys/storage/StorageResolver.java =================================================================== --- src/org/apache/xml/security/keys/storage/StorageResolver.java (revision 955619) +++ src/org/apache/xml/security/keys/storage/StorageResolver.java (working copy) @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import org.apache.xml.security.keys.storage.implementations.KeyStoreResolver; import org.apache.xml.security.keys.storage.implementations.SingleCertificateResolver; @@ -116,23 +117,16 @@ /** * Method getIterator * @return the iterator for the resolvers. - * - */ + */ public Iterator getIterator() { - - if (this._iterator == null) { - if (_storageResolvers==null) - _storageResolvers=new ArrayList(); - this._iterator = new StorageResolverIterator(this._storageResolvers.iterator()); - } - - return this._iterator; + return new StorageResolverIterator(this._storageResolvers.iterator()); } /** * Method hasNext * - * @return true if there is more elements. + * @return true if there are more elements. + * @deprecated no way to restart the iteration, use {@link #getIterator() getIterator()} instead */ public boolean hasNext() { @@ -149,6 +143,7 @@ * Method next * * @return the next element + * @deprecated no way to restart the iteration, use {@link #getIterator() getIterator()} instead */ public X509Certificate next() { return (X509Certificate) this._iterator.next(); @@ -156,6 +151,7 @@ /** * Class StorageResolverIterator + * This iterates over all the Certificates found in all the resolvers. * * @author $Author$ * @version $Revision$ @@ -165,23 +161,40 @@ /** Field _resolvers */ Iterator _resolvers = null; + /** Field _currentResolver */ + Iterator _currentResolver = null; + /** - * Constructor FilesystemIterator + * Constructor StorageResolverIterator * * @param resolvers */ public StorageResolverIterator(Iterator resolvers) { this._resolvers = resolvers; + _currentResolver = findNextResolver(); } /** @inheritDoc */ public boolean hasNext() { - return _resolvers.hasNext(); + if (_currentResolver == null) { + return false; + } + + if (_currentResolver.hasNext()) { + return true; + } + + _currentResolver = findNextResolver(); + return (_currentResolver != null); } /** @inheritDoc */ public Object next() { - return _resolvers.next(); + if (hasNext()) { + return _currentResolver.next(); + } + + throw new NoSuchElementException(); } /** @@ -191,5 +204,19 @@ throw new UnsupportedOperationException( "Can't remove keys from KeyStore"); } + + // Find the next storage with at least one element and return its Iterator + private Iterator findNextResolver() { + + while (_resolvers.hasNext()) { + StorageResolverSpi resolverSpi = (StorageResolverSpi)_resolvers.next(); + Iterator iter = resolverSpi.getIterator(); + if (iter.hasNext()) { + return iter; + } + } + + return null; + } } } Index: src/org/apache/xml/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java =================================================================== --- src/org/apache/xml/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java (revision 955619) +++ src/org/apache/xml/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java (working copy) @@ -21,6 +21,7 @@ import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.util.Iterator; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.keys.content.X509Data; @@ -98,9 +99,10 @@ } int noOfISS = x509data.lengthIssuerSerial(); + Iterator storageIterator = storage.getIterator(); - while (storage.hasNext()) { - X509Certificate cert = storage.next(); + while (storageIterator.hasNext()) { + X509Certificate cert = (X509Certificate)storageIterator.next(); XMLX509IssuerSerial certSerial = new XMLX509IssuerSerial(element.getOwnerDocument(), cert); if (log.isDebugEnabled()) { Index: src/org/apache/xml/security/keys/keyresolver/implementations/X509SubjectNameResolver.java =================================================================== --- src/org/apache/xml/security/keys/keyresolver/implementations/X509SubjectNameResolver.java (revision 955619) +++ src/org/apache/xml/security/keys/keyresolver/implementations/X509SubjectNameResolver.java (working copy) @@ -16,12 +16,10 @@ */ package org.apache.xml.security.keys.keyresolver.implementations; - - import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.util.Iterator; - import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.keys.content.x509.XMLX509SubjectName; import org.apache.xml.security.keys.keyresolver.KeyResolverException; @@ -31,7 +29,6 @@ import org.apache.xml.security.utils.XMLUtils; import org.w3c.dom.Element; - /** * * @author $Author$ @@ -119,8 +116,9 @@ BaseURI); } - while (storage.hasNext()) { - X509Certificate cert = storage.next(); + Iterator storageIterator = storage.getIterator(); + while (storageIterator.hasNext()) { + X509Certificate cert = (X509Certificate)storageIterator.next(); XMLX509SubjectName certSN = new XMLX509SubjectName(element.getOwnerDocument(), cert); Index: src/org/apache/xml/security/keys/keyresolver/implementations/X509SKIResolver.java =================================================================== --- src/org/apache/xml/security/keys/keyresolver/implementations/X509SKIResolver.java (revision 955619) +++ src/org/apache/xml/security/keys/keyresolver/implementations/X509SKIResolver.java (working copy) @@ -17,12 +17,10 @@ */ package org.apache.xml.security.keys.keyresolver.implementations; - - import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.util.Iterator; - import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.keys.content.x509.XMLX509SKI; import org.apache.xml.security.keys.keyresolver.KeyResolverException; @@ -32,7 +30,6 @@ import org.apache.xml.security.utils.XMLUtils; import org.w3c.dom.Element; - /** * * @@ -119,8 +116,9 @@ new XMLX509SKI(x509childNodes[i], BaseURI); } - while (storage.hasNext()) { - X509Certificate cert = storage.next(); + Iterator storageIterator = storage.getIterator(); + while (storageIterator.hasNext()) { + X509Certificate cert = (X509Certificate)storageIterator.next(); XMLX509SKI certSKI = new XMLX509SKI(element.getOwnerDocument(), cert); for (int i = 0; i < x509childObject.length; i++) { Index: src_unitTests/org/apache/xml/security/test/keys/storage/StorageResolverTest.java =================================================================== --- src_unitTests/org/apache/xml/security/test/keys/storage/StorageResolverTest.java (revision 0) +++ src_unitTests/org/apache/xml/security/test/keys/storage/StorageResolverTest.java (revision 0) @@ -0,0 +1,126 @@ +/* + * Copyright 2008-2010 The Apache Software Foundation. + * + * Licensed 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.xml.security.test.keys.storage; + +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.apache.xml.security.keys.storage.StorageResolver; + +/** + * KeyStore StorageResolver test. + */ +public class StorageResolverTest extends TestCase { + + private static final String BASEDIR = System.getProperty("basedir"); + private static final String SEP = System.getProperty("file.separator"); + + public StorageResolverTest() { + super("KeyStoreResolverTest"); + } + + public StorageResolverTest(String name) { + super(name); + } + + public static Test suite() { + return new TestSuite(StorageResolverTest.class); + } + + public void testStorageResolver() throws Exception { + + String inputDir = BASEDIR + SEP + "data" + SEP + + "org" + SEP + "apache" + SEP + "xml" + SEP + "security" + SEP + + "samples" + SEP + "input"; + + FileInputStream inStream = new FileInputStream(inputDir + SEP + "keystore.jks"); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(inStream, "xmlsecurity".toCharArray()); + + FileInputStream inStream2 = new FileInputStream(inputDir + SEP + "keystore2.jks"); + KeyStore ks2 = KeyStore.getInstance("JCEKS"); + ks2.load(inStream2, "xmlsecurity".toCharArray()); + + StorageResolver storage = new StorageResolver(ks); + storage.add(ks2); + + // iterate directly on the storage + int count = 0; + while (storage.hasNext()) { + X509Certificate cert = storage.next(); + assertNotNull(cert); + count++; + } + + assertEquals(4, count); + + try { + storage.next(); + fail("Expecting NoSuchElementException"); + } catch (NoSuchElementException e) { + } + + Iterator iter = storage.getIterator(); + checkIterator(iter); + + // check new iterator starts from the beginning + Iterator iter2 = storage.getIterator(); + checkIterator(iter2); + + // check the iterators are independent + // check calling next() without calling hasNext() + iter = storage.getIterator(); + iter2 = storage.getIterator(); + + while (iter.hasNext()) { + X509Certificate cert = (X509Certificate) iter.next(); + X509Certificate cert2 = (X509Certificate) iter2.next(); + if (!cert.equals(cert2)) { + fail("StorageResolver iterators are not independent"); + } + } + assertFalse(iter2.hasNext()); + } + + private void checkIterator(Iterator iter) { + int count = 0; + iter.hasNext(); // hasNext() is idempotent + + while (iter.hasNext()) { + X509Certificate cert = (X509Certificate) iter.next(); + String subjectDN = cert.getSubjectDN().getName(); + count++; + } + + // The iterator skipped over symmetric keys + assertEquals(4, count); + + // Cannot go beyond last element + try { + iter.next(); + fail("Expecting NoSuchElementException"); + } catch (NoSuchElementException e) { + } + } +}