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();}
};
}