1/*
2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.provider.certpath;
27
28import java.security.InvalidAlgorithmParameterException;
29import java.security.cert.Certificate;
30import java.security.cert.CRL;
31import java.util.Collection;
32import java.util.ConcurrentModificationException;
33import java.util.HashSet;
34import java.security.cert.CertSelector;
35import java.security.cert.CertStore;
36import java.security.cert.CertStoreException;
37import java.security.cert.CertStoreParameters;
38import java.security.cert.CollectionCertStoreParameters;
39import java.security.cert.CRLSelector;
40import java.security.cert.CertStoreSpi;
41
42/**
43 * A <code>CertStore</code> that retrieves <code>Certificates</code> and
44 * <code>CRL</code>s from a <code>Collection</code>.
45 * <p>
46 * Before calling the {@link #engineGetCertificates engineGetCertificates} or
47 * {@link #engineGetCRLs engineGetCRLs} methods, the
48 * {@link #CollectionCertStore(CertStoreParameters)
49 * CollectionCertStore(CertStoreParameters)} constructor is called to
50 * create the <code>CertStore</code> and establish the
51 * <code>Collection</code> from which <code>Certificate</code>s and
52 * <code>CRL</code>s will be retrieved. If the specified
53 * <code>Collection</code> contains an object that is not a
54 * <code>Certificate</code> or <code>CRL</code>, that object will be
55 * ignored.
56 * <p>
57 * <b>Concurrent Access</b>
58 * <p>
59 * As described in the javadoc for <code>CertStoreSpi</code>, the
60 * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
61 * must be thread-safe. That is, multiple threads may concurrently
62 * invoke these methods on a single <code>CollectionCertStore</code>
63 * object (or more than one) with no ill effects.
64 * <p>
65 * This is achieved by requiring that the <code>Collection</code> passed to
66 * the {@link #CollectionCertStore(CertStoreParameters)
67 * CollectionCertStore(CertStoreParameters)} constructor (via the
68 * <code>CollectionCertStoreParameters</code> object) must have fail-fast
69 * iterators. Simultaneous modifications to the <code>Collection</code> can thus be
70 * detected and certificate or CRL retrieval can be retried. The fact that
71 * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
72 * essential.
73 *
74 * @see java.security.cert.CertStore
75 *
76 * @since       1.4
77 * @author      Steve Hanna
78 */
79public class CollectionCertStore extends CertStoreSpi {
80
81    private Collection<?> coll;
82
83    /**
84     * Creates a <code>CertStore</code> with the specified parameters.
85     * For this class, the parameters object must be an instance of
86     * <code>CollectionCertStoreParameters</code>. The <code>Collection</code>
87     * included in the <code>CollectionCertStoreParameters</code> object
88     * must be thread-safe.
89     *
90     * @param params the algorithm parameters
91     * @exception InvalidAlgorithmParameterException if params is not an
92     *   instance of <code>CollectionCertStoreParameters</code>
93     */
94    public CollectionCertStore(CertStoreParameters params)
95        throws InvalidAlgorithmParameterException
96    {
97        super(params);
98        if (!(params instanceof CollectionCertStoreParameters))
99            throw new InvalidAlgorithmParameterException(
100                "parameters must be CollectionCertStoreParameters");
101        coll = ((CollectionCertStoreParameters) params).getCollection();
102    }
103
104    /**
105     * Returns a <code>Collection</code> of <code>Certificate</code>s that
106     * match the specified selector. If no <code>Certificate</code>s
107     * match the selector, an empty <code>Collection</code> will be returned.
108     *
109     * @param selector a <code>CertSelector</code> used to select which
110     *  <code>Certificate</code>s should be returned. Specify <code>null</code>
111     *  to return all <code>Certificate</code>s.
112     * @return a <code>Collection</code> of <code>Certificate</code>s that
113     *         match the specified selector
114     * @throws CertStoreException if an exception occurs
115     */
116    @Override
117    public Collection<Certificate> engineGetCertificates
118            (CertSelector selector) throws CertStoreException {
119        if (coll == null) {
120            throw new CertStoreException("Collection is null");
121        }
122        // Tolerate a few ConcurrentModificationExceptions
123        for (int c = 0; c < 10; c++) {
124            try {
125                HashSet<Certificate> result = new HashSet<>();
126                if (selector != null) {
127                    for (Object o : coll) {
128                        if ((o instanceof Certificate) &&
129                            selector.match((Certificate) o))
130                            result.add((Certificate)o);
131                    }
132                } else {
133                    for (Object o : coll) {
134                        if (o instanceof Certificate)
135                            result.add((Certificate)o);
136                    }
137                }
138                return(result);
139            } catch (ConcurrentModificationException e) { }
140        }
141        throw new ConcurrentModificationException("Too many "
142            + "ConcurrentModificationExceptions");
143    }
144
145    /**
146     * Returns a <code>Collection</code> of <code>CRL</code>s that
147     * match the specified selector. If no <code>CRL</code>s
148     * match the selector, an empty <code>Collection</code> will be returned.
149     *
150     * @param selector a <code>CRLSelector</code> used to select which
151     *  <code>CRL</code>s should be returned. Specify <code>null</code>
152     *  to return all <code>CRL</code>s.
153     * @return a <code>Collection</code> of <code>CRL</code>s that
154     *         match the specified selector
155     * @throws CertStoreException if an exception occurs
156     */
157    @Override
158    public Collection<CRL> engineGetCRLs(CRLSelector selector)
159        throws CertStoreException
160    {
161        if (coll == null)
162            throw new CertStoreException("Collection is null");
163
164        // Tolerate a few ConcurrentModificationExceptions
165        for (int c = 0; c < 10; c++) {
166            try {
167                HashSet<CRL> result = new HashSet<>();
168                if (selector != null) {
169                    for (Object o : coll) {
170                        if ((o instanceof CRL) && selector.match((CRL) o))
171                            result.add((CRL)o);
172                    }
173                } else {
174                    for (Object o : coll) {
175                        if (o instanceof CRL)
176                            result.add((CRL)o);
177                    }
178                }
179                return result;
180            } catch (ConcurrentModificationException e) { }
181        }
182        throw new ConcurrentModificationException("Too many "
183            + "ConcurrentModificationExceptions");
184    }
185}
186