151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.security.jca;
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.*;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.*;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.Provider.Service;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * List of Providers. Used to represent the provider preferences.
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The system starts out with a ProviderList that only has the classNames
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of the Providers. Providers are loaded on demand only when needed.
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * For compatibility reasons, Providers that could not be loaded are ignored
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and internally presented as the instance EMPTY_PROVIDER. However, those
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * objects cannot be presented to applications. Call the convert() method
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * to force all Providers to be loaded and to obtain a ProviderList with
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * invalid entries removed. All this is handled by the Security class.
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Note that all indices used by this class are 0-based per general Java
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * convention. These must be converted to the 1-based indices used by the
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Security class externally when needed.
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Instances of this class are immutable. This eliminates the need for
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * cloning and synchronization in consumers. The add() and remove() style
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * methods are static in order to avoid confusion about the immutability.
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author  Andreas Sterbenz
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since   1.5
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic final class ProviderList {
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    final static sun.security.util.Debug debug =
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        sun.security.util.Debug.getInstance("jca", "ProviderList");
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final static ProviderConfig[] PC0 = new ProviderConfig[0];
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final static Provider[] P0 = new Provider[0];
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // constant for an ProviderList with no elements
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static final ProviderList EMPTY = new ProviderList(PC0, true);
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // dummy provider object to use during initialization
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // used to avoid explicit null checks in various places
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final Provider EMPTY_PROVIDER =
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        new Provider("##Empty##", 1.0d, "initialization in progress") {
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // override getService() to return null slightly faster
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            public Service getService(String type, String algorithm) {
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return null;
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        };
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // construct a ProviderList from the security properties
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // (static provider configuration in the java.security file)
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static ProviderList fromSecurityProperties() {
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // doPrivileged() because of Security.getProperty()
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return AccessController.doPrivileged(
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        new PrivilegedAction<ProviderList>() {
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            public ProviderList run() {
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return new ProviderList();
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        });
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static ProviderList add(ProviderList providerList, Provider p) {
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return insertAt(providerList, p, -1);
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static ProviderList insertAt(ProviderList providerList, Provider p,
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int position) {
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (providerList.getProvider(p.getName()) != null) {
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return providerList;
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<ProviderConfig> list = new ArrayList<>
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    (Arrays.asList(providerList.configs));
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = list.size();
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((position < 0) || (position > n)) {
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            position = n;
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        list.add(position, new ProviderConfig(p));
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ProviderList(list.toArray(PC0), true);
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static ProviderList remove(ProviderList providerList, String name) {
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // make sure provider exists
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (providerList.getProvider(name) == null) {
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return providerList;
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // copy all except matching to new list
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ProviderConfig[] configs = new ProviderConfig[providerList.size() - 1];
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int j = 0;
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (ProviderConfig config : providerList.configs) {
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (config.getProvider().getName().equals(name) == false) {
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                configs[j++] = config;
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ProviderList(configs, true);
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Create a new ProviderList from the specified Providers.
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // This method is for use by SunJSSE.
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static ProviderList newList(Provider ... providers) {
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ProviderConfig[] configs = new ProviderConfig[providers.length];
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < providers.length; i++) {
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            configs[i] = new ProviderConfig(providers[i]);
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ProviderList(configs, true);
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // configuration of the providers
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final ProviderConfig[] configs;
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // flag indicating whether all configs have been loaded successfully
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private volatile boolean allLoaded;
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // List returned by providers()
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final List<Provider> userList = new AbstractList<Provider>() {
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public int size() {
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return configs.length;
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Provider get(int index) {
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return getProvider(index);
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Create a new ProviderList from an array of configs
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ProviderList(ProviderConfig[] configs, boolean allLoaded) {
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.configs = configs;
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.allLoaded = allLoaded;
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a new ProviderList parsed from the java.security Properties.
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ProviderList() {
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<ProviderConfig> configList = new ArrayList<>();
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 1; true; i++) {
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String entry = Security.getProperty("security.provider." + i);
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (entry == null) {
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            entry = entry.trim();
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (entry.length() == 0) {
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                System.err.println("invalid entry for " +
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                   "security.provider." + i);
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int k = entry.indexOf(' ');
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ProviderConfig config;
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (k == -1) {
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                config = new ProviderConfig(entry);
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String className = entry.substring(0, k);
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String argument = entry.substring(k + 1).trim();
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                config = new ProviderConfig(className, argument);
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Get rid of duplicate providers.
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (configList.contains(config) == false) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                configList.add(config);
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        configs = configList.toArray(PC0);
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (debug != null) {
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            debug.println("provider configuration: " + configList);
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Construct a special ProviderList for JAR verification. It consists
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of the providers specified via jarClassNames, which must be on the
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * bootclasspath and cannot be in signed JAR files. This is to avoid
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * possible recursion and deadlock during verification.
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    ProviderList getJarList(String[] jarClassNames) {
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<ProviderConfig> newConfigs = new ArrayList<>();
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (String className : jarClassNames) {
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ProviderConfig newConfig = new ProviderConfig(className);
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (ProviderConfig config : configs) {
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // if the equivalent object is present in this provider list,
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // use the old object rather than the new object.
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // this ensures that when the provider is loaded in the
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // new thread local list, it will also become available
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // in this provider list
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (config.equals(newConfig)) {
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    newConfig = config;
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            newConfigs.add(newConfig);
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ProviderConfig[] configArray = newConfigs.toArray(PC0);
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ProviderList(configArray, false);
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int size() {
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return configs.length;
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return the Provider at the specified index. Returns EMPTY_PROVIDER
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * if the provider could not be loaded at this time.
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    Provider getProvider(int index) {
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Provider p = configs[index].getProvider();
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (p != null) ? p : EMPTY_PROVIDER;
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return an unmodifiable List of all Providers in this List. The
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * individual Providers are loaded on demand. Elements that could not
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * be initialized are replaced with EMPTY_PROVIDER.
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public List<Provider> providers() {
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return userList;
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ProviderConfig getProviderConfig(String name) {
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int index = getIndex(name);
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (index != -1) ? configs[index] : null;
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // return the Provider with the specified name or null
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Provider getProvider(String name) {
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ProviderConfig config = getProviderConfig(name);
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (config == null) ? null : config.getProvider();
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return the index at which the provider with the specified name is
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * installed or -1 if it is not present in this ProviderList.
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getIndex(String name) {
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < configs.length; i++) {
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Provider p = getProvider(i);
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (p.getName().equals(name)) {
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return i;
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return -1;
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // attempt to load all Providers not already loaded
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int loadAll() {
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (allLoaded) {
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return configs.length;
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (debug != null) {
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            debug.println("Loading all providers");
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new Exception("Call trace").printStackTrace();
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = 0;
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < configs.length; i++) {
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Provider p = configs[i].getProvider();
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (p != null) {
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                n++;
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (n == configs.length) {
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            allLoaded = true;
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return n;
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Try to load all Providers and return the ProviderList. If one or
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * more Providers could not be loaded, a new ProviderList with those
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * entries removed is returned. Otherwise, the method returns this.
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    ProviderList removeInvalid() {
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = loadAll();
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (n == configs.length) {
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return this;
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ProviderConfig[] newConfigs = new ProviderConfig[n];
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0, j = 0; i < configs.length; i++) {
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ProviderConfig config = configs[i];
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (config.isLoaded()) {
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                newConfigs[j++] = config;
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ProviderList(newConfigs, true);
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // return the providers as an array
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Provider[] toArray() {
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return providers().toArray(P0);
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // return a String representation of this ProviderList
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String toString() {
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return Arrays.asList(configs).toString();
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a Service describing an implementation of the specified
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * algorithm from the Provider with the highest precedence that
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * supports that algorithm. Return null if no Provider supports this
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * algorithm.
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Service getService(String type, String name) {
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < configs.length; i++) {
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Provider p = getProvider(i);
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Service s = p.getService(type, name);
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (s != null) {
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return s;
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a List containing all the Services describing implementations
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of the specified algorithms in precedence order. If no implementation
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * exists, this method returns an empty List.
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The elements of this list are determined lazily on demand.
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The List returned is NOT thread safe.
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public List<Service> getServices(String type, String algorithm) {
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ServiceList(type, algorithm);
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * This method exists for compatibility with JCE only. It will be removed
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * once JCE has been changed to use the replacement method.
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @deprecated use getServices(List<ServiceId>) instead
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Deprecated
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public List<Service> getServices(String type, List<String> algorithms) {
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<ServiceId> ids = new ArrayList<>();
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (String alg : algorithms) {
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ids.add(new ServiceId(type, alg));
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return getServices(ids);
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public List<Service> getServices(List<ServiceId> ids) {
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new ServiceList(ids);
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Inner class for a List of Services. Custom List implementation in
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * order to delay Provider initialization and lookup.
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Not thread safe.
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final class ServiceList extends AbstractList<Service> {
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // type and algorithm for simple lookup
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // avoid allocating/traversing the ServiceId list for these lookups
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private final String type;
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private final String algorithm;
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // list of ids for parallel lookup
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // if ids is non-null, type and algorithm are null
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private final List<ServiceId> ids;
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // first service we have found
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // it is stored in a separate variable so that we can avoid
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // allocating the services list if we do not need the second service.
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // this is the case if we don't failover (failovers are typically rare)
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private Service firstService;
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // list of the services we have found so far
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private List<Service> services;
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // index into config[] of the next provider we need to query
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private int providerIndex;
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ServiceList(String type, String algorithm) {
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.type = type;
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.algorithm = algorithm;
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.ids = null;
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ServiceList(List<ServiceId> ids) {
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.type = null;
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.algorithm = null;
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.ids = ids;
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private void addService(Service s) {
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (firstService == null) {
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                firstService = s;
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (services == null) {
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    services = new ArrayList<Service>(4);
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    services.add(firstService);
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                services.add(s);
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private Service tryGet(int index) {
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (true) {
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((index == 0) && (firstService != null)) {
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return firstService;
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else if ((services != null) && (services.size() > index)) {
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return services.get(index);
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (providerIndex >= configs.length) {
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // check all algorithms in this provider before moving on
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                Provider p = getProvider(providerIndex++);
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (type != null) {
43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // simple lookup
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Service s = p.getService(type, algorithm);
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (s != null) {
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        addService(s);
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // parallel lookup
44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    for (ServiceId id : ids) {
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        Service s = p.getService(id.type, id.algorithm);
44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (s != null) {
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            addService(s);
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Service get(int index) {
45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Service s = tryGet(index);
45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (s == null) {
45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IndexOutOfBoundsException();
45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return s;
45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public int size() {
46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int n;
46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (services != null) {
46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                n = services.size();
46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                n = (firstService != null) ? 1 : 0;
46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (tryGet(n) != null) {
46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                n++;
46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return n;
47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // override isEmpty() and iterator() to not call size()
47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // this avoids loading + checking all Providers
47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean isEmpty() {
47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return (tryGet(0) == null);
47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Iterator<Service> iterator() {
48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new Iterator<Service>() {
48251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int index;
48351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                public boolean hasNext() {
48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return tryGet(index) != null;
48651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                public Service next() {
48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Service s = tryGet(index);
49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (s == null) {
49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        throw new NoSuchElementException();
49251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    index++;
49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return s;
49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
49651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                public void remove() {
49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    throw new UnsupportedOperationException();
49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            };
50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
505