All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.firebirdsql.gds.ng.wire.ProtocolCollection Maven / Gradle / Ivy

There is a newer version: 6.0.0-beta-1
Show newest version
/*
 * Firebird Open Source JDBC Driver
 *
 * Distributable under LGPL license.
 * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * LGPL License for more details.
 *
 * This file was created by members of the firebird development team.
 * All individual contributions remain the Copyright (C) of those
 * individuals.  Contributors to this file are either listed here or
 * can be obtained from a source control history command.
 *
 * All rights reserved.
 */
package org.firebirdsql.gds.ng.wire;

import org.firebirdsql.logging.Logger;
import org.firebirdsql.logging.LoggerFactory;

import java.util.*;

import static java.lang.String.format;

/**
 * Collection of protocols for a connect request.
 * 

* In general use {@link ProtocolCollection#getDefaultCollection()} to retrieve * the default collection. *

* * @author Mark Rotteveel * @since 3.0 */ public final class ProtocolCollection implements Iterable { private static final Logger log = LoggerFactory.getLogger(ProtocolCollection.class); private final Map descriptorMap; private static final ProtocolCollection DEFAULT_COLLECTION; static { // Load protocol implementation information final Set supportedProtocols = new HashSet<>(); final Collection classLoaders = classLoadersForLoading(); for (ClassLoader classLoader : classLoaders) { final ServiceLoader descriptors = ServiceLoader.load(ProtocolDescriptor.class, classLoader); // We can't use foreach here, because the descriptors are lazily loaded, which might trigger a ServiceConfigurationError Iterator descriptorIterator = descriptors.iterator(); int retry = 0; while (retry < 2) { try { while (descriptorIterator.hasNext()) { try { ProtocolDescriptor protocol = descriptorIterator.next(); supportedProtocols.add(protocol); } catch (Exception | ServiceConfigurationError e) { log.errorDebug("Could not load protocol descriptor (skipping)", e); } } break; } catch (ServiceConfigurationError e) { log.error("Error finding next ProtocolDescriptor", e); retry++; } } } if (supportedProtocols.isEmpty()) { for (ClassLoader classLoader : classLoaders) { supportedProtocols.addAll(loadProtocolsFallback(classLoader)); } } DEFAULT_COLLECTION = create(supportedProtocols.toArray(new ProtocolDescriptor[0])); } /** * List of class loaders to use for loading the {@link ProtocolDescriptor} implementations. * * @return Collection of {@link ClassLoader} instances */ private static List classLoadersForLoading() { final List classLoaders = new ArrayList<>(2); final ClassLoader classLoader = ProtocolDescriptor.class.getClassLoader(); if (classLoader != null) { classLoaders.add(classLoader); } else { classLoaders.add(ClassLoader.getSystemClassLoader()); } final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null && !classLoaders.contains(contextClassLoader)) { classLoaders.add(contextClassLoader); } return classLoaders; } /** * Loads the protocols from a hardcoded list of class names. *

* This method is intended as a fallback in case the plugins could not be discovered from the * {@code META-INF/services/org.firebirdsql.gds.ng.wire.ProtocolDescriptor} file(s). See also * issue JDBC-325 *

* * @param classLoader Class loader to use for loading * @return List of protocol descriptors */ private static List loadProtocolsFallback(ClassLoader classLoader) { String[] protocolClasses = { "org.firebirdsql.gds.ng.wire.version10.Version10Descriptor", "org.firebirdsql.gds.ng.wire.version11.Version11Descriptor", "org.firebirdsql.gds.ng.wire.version12.Version12Descriptor", "org.firebirdsql.gds.ng.wire.version13.Version13Descriptor", "org.firebirdsql.gds.ng.wire.version15.Version15Descriptor", "org.firebirdsql.gds.ng.wire.version16.Version16Descriptor", "org.firebirdsql.gds.ng.wire.version18.Version18Descriptor", }; final List protocols = new ArrayList<>(protocolClasses.length); for (String className : protocolClasses) { try { Class clazz = classLoader.loadClass(className); ProtocolDescriptor protocol = (ProtocolDescriptor) clazz.getDeclaredConstructor().newInstance(); protocols.add(protocol); } catch (Exception e) { log.warnDebug(format("Unable to load protocol %s in loadProtocolsFallback; skipping", className), e); } } return protocols; } private ProtocolCollection(Map protocolDescriptors) { // Note: we are not making a defensive copy as the Map should never leak outside this implementation this.descriptorMap = Collections.unmodifiableMap(protocolDescriptors); } @Override public Iterator iterator() { return descriptorMap.values().iterator(); } /** * @param protocolVersion * Version of the protocol * @return ProtocolDescriptor for the specified version, or null if the * version is not in this ProtocolCollection */ public ProtocolDescriptor getProtocolDescriptor(int protocolVersion) { return descriptorMap.get(protocolVersion); } /** * @return The protocol count */ public int getProtocolCount() { return descriptorMap.size(); } /** * Get a list with the protocol versions in this collection. *

* The returned List is created fresh on every call. Changes to * the list have no effect on this object. *

* * @return Protocol version numbers */ public List getProtocolVersions() { List versions = new ArrayList<>(); for (ProtocolDescriptor descriptor : this) { versions.add(descriptor.getVersion()); } return versions; } /** * Creates a ProtocolCollection with the specified ProtocolDescriptors. *

* If descriptors contains multiple implementations with the * same value for {@link ProtocolDescriptor#getVersion()}, then the first * implementation with the highest value for * {@link ProtocolDescriptor#getWeight()} will be loaded into the * collection. *

* * @param descriptors * Vararg parameter with ProtocolDescriptors * @return ProtocolCollection */ public static ProtocolCollection create(ProtocolDescriptor... descriptors) { Map descriptorMap = new HashMap<>(); for (ProtocolDescriptor descriptor : descriptors) { ProtocolDescriptor existingDescriptor = descriptorMap.get(descriptor.getVersion()); if (existingDescriptor == null || descriptor.getWeight() > existingDescriptor.getWeight()) { descriptorMap.put(descriptor.getVersion(), descriptor); } } return new ProtocolCollection(descriptorMap); } /** * Returns the default ProtocolCollection. *

* The default ProtocolCollection is created when this class is loaded by * the classloader. *

*

* This implementation uses the {@link ServiceLoader} to load the default * collection based on all {@link ProtocolDescriptor} implementations found * using all the * /META-INF/services/org.firebirdsql.gds.ng.wire.ProtocolDescriptor * in the classpath. If multiple implementations with the same value for * {@link ProtocolDescriptor#getVersion()} are found, then the first * implementation with the highest value for * {@link ProtocolDescriptor#getWeight()} will be loaded into the default * collection. *

* * @return The default ProtocolCollection * @see ProtocolCollection#create(ProtocolDescriptor...) */ public static ProtocolCollection getDefaultCollection() { return DEFAULT_COLLECTION; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy