< prev index next >

jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java

Print this page

        

*** 25,41 **** package javax.management.remote; import com.sun.jmx.mbeanserver.Util; import java.io.IOException; import java.net.MalformedURLException; import java.util.Collections; import java.util.HashMap; import java.util.Map; - import java.util.Iterator; import java.util.ServiceLoader; import java.util.StringTokenizer; import java.security.AccessController; import java.security.PrivilegedAction; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; --- 25,45 ---- package javax.management.remote; import com.sun.jmx.mbeanserver.Util; import java.io.IOException; + import java.io.UncheckedIOException; + import java.lang.reflect.Module; import java.net.MalformedURLException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.ServiceLoader; + import java.util.ServiceLoader.Provider; import java.util.StringTokenizer; + import java.util.function.Predicate; + import java.util.stream.Stream; import java.security.AccessController; import java.security.PrivilegedAction; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp;
*** 330,358 **** targetInterface, loader); IOException exception = null; if (provider == null) { // Loader is null when context class loader is set to null // and no loader has been provided in map. // com.sun.jmx.remote.util.Service class extracted from j2se // provider search algorithm doesn't handle well null classloader. if (loader != null) { try { ! JMXConnector connection = ! getConnectorAsService(loader, providerURL, envcopy); ! if (connection != null) ! return connection; } catch (JMXProviderException e) { throw e; } catch (IOException e) { exception = e; } } ! provider = getProvider(protocol, PROTOCOL_PROVIDER_DEFAULT_PACKAGE, JMXConnectorFactory.class.getClassLoader(), ! providerClassName, targetInterface); } if (provider == null) { MalformedURLException e = new MalformedURLException("Unsupported protocol: " + protocol); --- 334,369 ---- targetInterface, loader); IOException exception = null; if (provider == null) { + Predicate<Provider<?>> systemProvider = + JMXConnectorFactory::isSystemProvider; // Loader is null when context class loader is set to null // and no loader has been provided in map. // com.sun.jmx.remote.util.Service class extracted from j2se // provider search algorithm doesn't handle well null classloader. + JMXConnector connection = null; if (loader != null) { try { ! connection = getConnectorAsService(loader, ! providerURL, ! envcopy, ! systemProvider.negate()); ! if (connection != null) return connection; } catch (JMXProviderException e) { throw e; } catch (IOException e) { exception = e; } } ! connection = getConnectorAsService( JMXConnectorFactory.class.getClassLoader(), ! providerURL, ! Collections.unmodifiableMap(envcopy), ! systemProvider); ! if (connection != null) return connection; } if (provider == null) { MalformedURLException e = new MalformedURLException("Unsupported protocol: " + protocol);
*** 435,451 **** } return instance; } - static <T> Iterator<T> getProviderIterator(final Class<T> providerClass, - final ClassLoader loader) { - ServiceLoader<T> serviceLoader = - ServiceLoader.load(providerClass, loader); - return serviceLoader.iterator(); - } - private static ClassLoader wrap(final ClassLoader parent) { return parent != null ? AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { @Override public ClassLoader run() { return new ClassLoader(parent) { --- 446,455 ----
*** 457,482 **** }; } }) : null; } private static JMXConnector getConnectorAsService(ClassLoader loader, JMXServiceURL url, ! Map<String, ?> map) throws IOException { ! Iterator<JMXConnectorProvider> providers = ! getProviderIterator(JMXConnectorProvider.class, loader); ! JMXConnector connection; ! IOException exception = null; ! while (providers.hasNext()) { ! JMXConnectorProvider provider = providers.next(); try { ! connection = provider.newJMXConnector(url, map); ! return connection; } catch (JMXProviderException e) { ! throw e; } catch (Exception e) { if (logger.traceOn()) logger.trace("getConnectorAsService", "URL[" + url + "] Service provider exception: " + e); --- 461,616 ---- }; } }) : null; } + /** + * Checks whether the given provider is our system provider for + * the RMI connector. + * If providers for additional protocols are added in the future + * then the name of their modules may need to be added here. + * System providers will be loaded only if no other provider is found. + * @param provider the provider to test. + * @return true if this provider is a default system provider. + */ + static boolean isSystemProvider(Provider<?> provider) { + Module providerModule = provider.type().getModule(); + return providerModule.isNamed() + && providerModule.getName().equals("java.management.rmi"); + } + + /** + * Creates a JMXConnector from the first JMXConnectorProvider service + * supporting the given url that can be loaded from the given loader. + * <p> + * Parses the list of JMXConnectorProvider services that can be loaded + * from the given loader, only retaining those that satisfy the given filter. + * Then for each provider, attempts to create a new JMXConnector. + * The first JMXConnector successfully created is returned. + * <p> + * The filter predicate is usually used to either exclude system providers + * or only retain system providers (see isSystemProvider(...) above). + * + * @param loader The ClassLoader to use when looking up an implementation + * of the service. If null, then only installed services will be + * considered. + * + * @param url The JMXServiceURL of the connector for which a provider is + * requested. + * + * @param filter A filter used to exclude or return provider + * implementations. Typically the filter will either exclude + * system services (system default implementations) or only + * retain those. + * This can allow to first look for custom implementations (e.g. + * deployed on the CLASSPATH with META-INF/services) and + * then only default to system implementations. + * + * @throws IOException if no connector could not be instantiated, and + * at least one provider threw an exception that wasn't a + * {@code MalformedURLException} or a {@code JMProviderException}. + * + * @throws JMXProviderException if a provider for the protocol in + * <code>url</code> was found, but couldn't create the connector + * some reason. + * + * @return an instance of JMXConnector if a provider was found from + * which one could be instantiated, {@code null} otherwise. + */ private static JMXConnector getConnectorAsService(ClassLoader loader, JMXServiceURL url, ! Map<String, ?> map, ! Predicate<Provider<?>> filter) throws IOException { ! final ConnectorFactory<JMXConnectorProvider, JMXConnector> factory = ! (p) -> p.newJMXConnector(url, map); ! return getConnectorAsService(JMXConnectorProvider.class, loader, url, ! filter, factory); ! } ! ! ! /** ! * A factory function that can create a connector from a provider. ! * The pair (P,C) will be either one of: ! * a. (JMXConnectorProvider, JMXConnector) or ! * b. (JMXConnectorServerProvider, JMXConnectorServer) ! */ ! @FunctionalInterface ! static interface ConnectorFactory<P,C> { ! public C apply(P provider) throws Exception; ! } ! ! /** ! * An instance of ProviderFinder is used to traverse a ! * {@code Stream<Provider<P>>} and find the first implementation of P ! * that supports creating a connector C from the given JMXServiceURL. ! * <p> ! * The pair (P,C) will be either one of: <br> ! * a. (JMXConnectorProvider, JMXConnector) or <br> ! * b. (JMXConnectorServerProvider, JMXConnectorServer) ! * <p> ! * The first connector successfully created while traversing the stream ! * is stored in the ProviderFinder instance. After that, the ! * ProviderFinder::test method, if called, will always return false, skipping ! * the remaining providers. ! * <p> ! * An instance of ProviderFinder is always expected to be used in conjunction ! * with Stream::findFirst, so that the stream traversal is stopped as soon ! * as a matching provider is found. ! * <p> ! * At the end of the stream traversal, the ProviderFinder::get method can be ! * used to obtain the connector instance (an instance of C) that was created. ! * If no connector could be created, and an exception was encountered while ! * traversing the stream and attempting to create the connector, then that ! * exception will be thrown by ProviderFinder::get, wrapped, if needed, ! * inside an IOException. ! * <p> ! * If any JMXProviderException is encountered while traversing the stream and ! * attempting to create the connector, that exception will be wrapped in an ! * UncheckedIOException and thrown immediately within the stream, thus ! * interrupting the traversal. ! * <p> ! * If no matching provider was found (no provider found or attempting ! * factory.apply always returned null or threw a MalformedURLException, ! * indicating the provider didn't support the protocol asked for by ! * the JMXServiceURL), then ProviderFinder::get will simply return null. ! */ ! private static final class ProviderFinder<P,C> implements Predicate<Provider<P>> { ! ! final ConnectorFactory<P,C> factory; ! final JMXServiceURL url; ! private IOException exception = null; ! private C connection = null; ! ! ProviderFinder(ConnectorFactory<P,C> factory, JMXServiceURL url) { ! this.factory = factory; ! this.url = url; ! } ! ! /** ! * Returns {@code true} for the first provider {@code sp} that can ! * be used to obtain an instance of {@code C} from the given ! * {@code factory}. ! * ! * @param sp a candidate provider for instantiating {@code C}. ! * ! * @throws UncheckedIOException if {@code sp} throws a ! * JMXProviderException. The JMXProviderException is set as the ! * root cause. ! * ! * @return {@code true} for the first provider {@code sp} for which ! * {@code C} could be instantiated, {@code false} otherwise. ! */ ! public boolean test(Provider<P> sp) { ! if (connection == null) { ! P provider = sp.get(); try { ! connection = factory.apply(provider); ! return connection != null; } catch (JMXProviderException e) { ! throw new UncheckedIOException(e); } catch (Exception e) { if (logger.traceOn()) logger.trace("getConnectorAsService", "URL[" + url + "] Service provider exception: " + e);
*** 488,504 **** exception = EnvHelp.initCause( new IOException(e.getMessage()), e); } } } - continue; } } ! if (exception == null) ! return null; ! else ! throw exception; } static <T> T getProvider(String protocol, String pkgs, ClassLoader loader, --- 622,729 ---- exception = EnvHelp.initCause( new IOException(e.getMessage()), e); } } } } } ! return false; ! } ! ! /** ! * Returns an instance of {@code C} if a provider was found from ! * which {@code C} could be instantiated. ! * ! * @throws IOException if {@code C} could not be instantiated, and ! * at least one provider threw an exception that wasn't a ! * {@code MalformedURLException} or a {@code JMProviderException}. ! * ! * @return an instance of {@code C} if a provider was found from ! * which {@code C} could be instantiated, {@code null} otherwise. ! */ ! C get() throws IOException { ! if (connection != null) return connection; ! else if (exception != null) throw exception; ! else return null; ! } ! } ! ! /** ! * Creates a connector from a provider loaded from the ServiceLoader. ! * <p> ! * The pair (P,C) will be either one of: <br> ! * a. (JMXConnectorProvider, JMXConnector) or <br> ! * b. (JMXConnectorServerProvider, JMXConnectorServer) ! * ! * @param providerClass The service type for which an implementation ! * should be looked up from the {@code ServiceLoader}. This will ! * be either {@code JMXConnectorProvider.class} or ! * {@code JMXConnectorServerProvider.class} ! * ! * @param loader The ClassLoader to use when looking up an implementation ! * of the service. If null, then only installed services will be ! * considered. ! * ! * @param url The JMXServiceURL of the connector for which a provider is ! * requested. ! * ! * @param filter A filter used to exclude or return provider ! * implementations. Typically the filter will either exclude ! * system services (system default implementations) or only ! * retain those. ! * This can allow to first look for custom implementations (e.g. ! * deployed on the CLASSPATH with META-INF/services) and ! * then only default to system implementations. ! * ! * @param factory A functional factory that can attempt to create an ! * instance of connector {@code C} from a provider {@code P}. ! * Typically, this is a simple wrapper over {@code ! * JMXConnectorProvider::newJMXConnector} or {@code ! * JMXConnectorProviderServer::newJMXConnectorServer}. ! * ! * @throws IOException if {@code C} could not be instantiated, and ! * at least one provider {@code P} threw an exception that wasn't a ! * {@code MalformedURLException} or a {@code JMProviderException}. ! * ! * @throws JMXProviderException if a provider {@code P} for the protocol in ! * <code>url</code> was found, but couldn't create the connector ! * {@code C} for some reason. ! * ! * @return an instance of {@code C} if a provider {@code P} was found from ! * which one could be instantiated, {@code null} otherwise. ! */ ! static <P,C> C getConnectorAsService(Class<P> providerClass, ! ClassLoader loader, ! JMXServiceURL url, ! Predicate<Provider<?>> filter, ! ConnectorFactory<P,C> factory) ! throws IOException { ! ! // sanity check ! if (JMXConnectorProvider.class != providerClass ! && JMXConnectorServerProvider.class != providerClass) { ! // should never happen ! throw new InternalError("Unsupported service interface: " ! + providerClass.getName()); ! } ! ! ServiceLoader<P> serviceLoader = loader == null ! ? ServiceLoader.loadInstalled(providerClass) ! : ServiceLoader.load(providerClass, loader); ! Stream<Provider<P>> stream = serviceLoader.stream().filter(filter); ! ProviderFinder<P,C> finder = new ProviderFinder<>(factory, url); ! ! try { ! stream.filter(finder).findFirst(); ! return finder.get(); ! } catch (UncheckedIOException e) { ! if (e.getCause() instanceof JMXProviderException) { ! throw (JMXProviderException) e.getCause(); ! } else { ! throw e; ! } ! } } static <T> T getProvider(String protocol, String pkgs, ClassLoader loader,
< prev index next >