public Set getAuthorityCodes()

in endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java [332:498]


    public Set<String> getAuthorityCodes(final Class<? extends IdentifiedObject> type) throws FactoryException {
        return new SetOfUnknownSize<String>() {
            /**
             * Returns an iterator over all authority codes.
             * Codes are fetched on-the-fly.
             */
            @Override
            public Iterator<String> iterator() {
                return new AbstractIterator<String>() {
                    /** An iterator over the factories for which to return codes. */
                    private final Iterator<AuthorityFactory> factories = getAllFactories();

                    /** An iterator over the codes of the current factory. */
                    private Iterator<String> codes = Collections.emptyIterator();

                    /** The prefix to prepend before codes, or {@code null} if none. */
                    private String prefix;

                    /** For filtering duplicated codes when there is many versions of the same authority. */
                    private final Set<String> done = new HashSet<>();

                    /** Tests if there is more codes to return. */
                    @Override public boolean hasNext() {
                        while (next == null) {
                            while (!codes.hasNext()) {
                                do {
                                    if (!factories.hasNext()) {
                                        return false;
                                    }
                                    final AuthorityFactory factory = factories.next();
                                    codes = getAuthorityCodes(factory).iterator();
                                    prefix = getCodeSpace(factory);
                                } while (!done.add(prefix));
                            }
                            next = codes.next();
                        }
                        return true;
                    }

                    /** Returns the next element, with namespace inserted before the code if needed. */
                    @Override public String next() {
                        String code = super.next();
                        if (prefix != null && code.indexOf(Constants.DEFAULT_SEPARATOR) < 0) {
                            code = prefix + Constants.DEFAULT_SEPARATOR + code;
                        }
                        return code;
                    }
                };
            }

            /**
             * The cache of values returned by {@link #getAuthorityCodes(AuthorityFactory)}.
             */
            private final Map<AuthorityFactory, Set<String>> cache = new IdentityHashMap<>();

            /**
             * Returns the authority codes for the given factory.
             * This method invokes {@link AuthorityFactory#getAuthorityCodes(Class)}
             * only once per factory and caches the returned {@code Set<String>}.
             */
            final Set<String> getAuthorityCodes(final AuthorityFactory factory) {
                Set<String> codes = cache.get(factory);
                if (codes == null) {
                    try {
                        codes = factory.getAuthorityCodes(type);
                    } catch (FactoryException e) {
                        throw new BackingStoreException(e);
                    }
                    if (cache.put(factory, codes) != null) {
                        throw new ConcurrentModificationException();
                    }
                }
                return codes;
            }

            /**
             * The collection size, or a negative value if we have not yet computed the size.
             * A negative value different than -1 means that we have not counted all elements,
             * but we have determined that the set is not empty.
             */
            private int size = -1;

            /**
             * Returns {@code true} if the {@link #size()} method is cheap.
             */
            @Override
            protected boolean isSizeKnown() {
                return size >= 0;
            }

            /**
             * Returns the number of elements in this set (costly operation).
             */
            @Override
            public int size() {
                if (size < 0) {
                    int n = 0;
                    final Set<String> done = new HashSet<>();
                    for (final Iterator<AuthorityFactory> it = getAllFactories(); it.hasNext();) {
                        final AuthorityFactory factory = it.next();
                        if (done.add(getCodeSpace(factory))) {
                            n += getAuthorityCodes(factory).size();
                        }
                    }
                    size = n;
                }
                return size;
            }

            /**
             * Returns {@code true} if the set does not contain any element.
             * This method is much more efficient than testing {@code size() != 0}
             * since it will stop iteration as soon as an element is found.
             */
            @Override
            public boolean isEmpty() {
                if (size == -1) {
                    for (final Iterator<AuthorityFactory> it = getAllFactories(); it.hasNext();) {
                        if (!getAuthorityCodes(it.next()).isEmpty()) {
                            size = -2;      // Size still unknown, but we know that the set is not empty.
                            return false;
                        }
                    }
                    size = 0;
                }
                return size == 0;
            }

            /**
             * The proxy for the {@code GeodeticAuthorityFactory.getAuthorityCodes(type).contains(String)}.
             * Used by {@link #contains(Object)} for delegating its work to the most appropriate factory.
             */
            private final AuthorityFactoryProxy<Boolean> contains =
                new AuthorityFactoryProxy<Boolean>(Boolean.class, AuthorityFactoryIdentifier.Type.ANY) {
                    @Override Boolean createFromAPI(AuthorityFactory factory, String code) throws FactoryException {
                        try {
                            return getAuthorityCodes(factory).contains(code);
                        } catch (BackingStoreException e) {
                            throw e.unwrapOrRethrow(FactoryException.class);
                        }
                    }
                    @Override AuthorityFactoryProxy<Boolean> specialize(String typeName) {
                        return this;
                    }
                };

            /**
             * Returns {@code true} if the factory contains the given code.
             */
            @Override
            public boolean contains(final Object code) {
                if (code instanceof String) try {
                    return create(contains, (String) code);
                } catch (NoSuchAuthorityCodeException e) {
                    // Ignore - will return false.
                } catch (FactoryException e) {
                    throw new BackingStoreException(e);
                }
                return false;
            }

            /** Declared soon as unsupported operation for preventing a call to {@link #size()}. */
            @Override public boolean removeAll(Collection<?> c) {throw new UnsupportedOperationException();}
            @Override public boolean retainAll(Collection<?> c) {throw new UnsupportedOperationException();}
            @Override public boolean remove   (Object o)        {throw new UnsupportedOperationException();}
        };
    }