| /* |
| * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package org.glassfish.jersey.client; |
| |
| import java.lang.reflect.Method; |
| import java.security.AccessController; |
| import java.util.Map; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.ScheduledExecutorService; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import org.glassfish.jersey.internal.BootstrapBag; |
| import org.glassfish.jersey.internal.inject.Bindings; |
| import org.glassfish.jersey.internal.inject.InjectionManager; |
| import org.glassfish.jersey.internal.inject.InstanceBinding; |
| import org.glassfish.jersey.internal.util.ReflectionHelper; |
| import org.glassfish.jersey.internal.util.collection.Value; |
| import org.glassfish.jersey.internal.util.collection.Values; |
| import org.glassfish.jersey.model.internal.ComponentBag; |
| import org.glassfish.jersey.model.internal.ManagedObjectsFinalizer; |
| import org.glassfish.jersey.process.internal.AbstractExecutorProvidersConfigurator; |
| import org.glassfish.jersey.spi.ExecutorServiceProvider; |
| import org.glassfish.jersey.spi.ScheduledExecutorServiceProvider; |
| |
| /** |
| * Configurator which initializes and register {@link ExecutorServiceProvider} and |
| * {@link ScheduledExecutorServiceProvider}. |
| * |
| * @author Petr Bouda |
| */ |
| class ClientExecutorProvidersConfigurator extends AbstractExecutorProvidersConfigurator { |
| |
| private static final Logger LOGGER = Logger.getLogger(ClientExecutorProvidersConfigurator.class.getName()); |
| private static final ExecutorService MANAGED_EXECUTOR_SERVICE = lookupManagedExecutorService(); |
| |
| private final ComponentBag componentBag; |
| private final JerseyClient client; |
| private final ExecutorService customExecutorService; |
| private final ScheduledExecutorService customScheduledExecutorService; |
| |
| ClientExecutorProvidersConfigurator(ComponentBag componentBag, JerseyClient client, |
| ExecutorService customExecutorService, |
| ScheduledExecutorService customScheduledExecutorService) { |
| this.componentBag = componentBag; |
| this.client = client; |
| this.customExecutorService = customExecutorService; |
| this.customScheduledExecutorService = customScheduledExecutorService; |
| } |
| |
| @Override |
| public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) { |
| Map<String, Object> runtimeProperties = bootstrapBag.getConfiguration().getProperties(); |
| |
| ExecutorServiceProvider defaultAsyncExecutorProvider; |
| ScheduledExecutorServiceProvider defaultScheduledExecutorProvider; |
| |
| final ExecutorService clientExecutorService = client.getExecutorService() == null |
| // custom executor service can be also set via managed client config class, in that case, it ends up in the |
| // customExecutorService field (similar for scheduled version) |
| ? customExecutorService |
| : client.getExecutorService(); |
| |
| // if there is a users provided executor service, use it |
| if (clientExecutorService != null) { |
| defaultAsyncExecutorProvider = new ClientExecutorServiceProvider(clientExecutorService); |
| // otherwise, check for ClientProperties.ASYNC_THREADPOOL_SIZE - if that is set, Jersey will create the |
| // ExecutorService to be used. If not and running on Java EE container, ManagedExecutorService will be used. |
| // Final fallback is DefaultClientAsyncExecutorProvider with defined default. |
| } else { |
| // Default async request executors support |
| Integer asyncThreadPoolSize = ClientProperties |
| .getValue(runtimeProperties, ClientProperties.ASYNC_THREADPOOL_SIZE, Integer.class); |
| |
| if (asyncThreadPoolSize != null) { |
| // TODO: Do we need to register DEFAULT Executor and ScheduledExecutor to InjectionManager? |
| asyncThreadPoolSize = (asyncThreadPoolSize < 0) ? 0 : asyncThreadPoolSize; |
| InstanceBinding<Integer> asyncThreadPoolSizeBinding = Bindings |
| .service(asyncThreadPoolSize) |
| .named("ClientAsyncThreadPoolSize"); |
| injectionManager.register(asyncThreadPoolSizeBinding); |
| |
| defaultAsyncExecutorProvider = new DefaultClientAsyncExecutorProvider(asyncThreadPoolSize); |
| } else { |
| if (MANAGED_EXECUTOR_SERVICE != null) { |
| defaultAsyncExecutorProvider = new ClientExecutorServiceProvider(MANAGED_EXECUTOR_SERVICE); |
| } else { |
| defaultAsyncExecutorProvider = new DefaultClientAsyncExecutorProvider(0); |
| } |
| } |
| } |
| |
| InstanceBinding<ExecutorServiceProvider> executorBinding = Bindings |
| .service(defaultAsyncExecutorProvider) |
| .to(ExecutorServiceProvider.class); |
| |
| injectionManager.register(executorBinding); |
| |
| final ScheduledExecutorService clientScheduledExecutorService = client.getScheduledExecutorService() == null |
| // scheduled executor service set from {@link ClientConfig}. |
| ? customScheduledExecutorService |
| : client.getScheduledExecutorService(); |
| |
| if (clientScheduledExecutorService != null) { |
| defaultScheduledExecutorProvider = |
| new ClientScheduledExecutorServiceProvider(Values.of(clientScheduledExecutorService)); |
| } else { |
| ScheduledExecutorService scheduledExecutorService = lookupManagedScheduledExecutorService(); |
| defaultScheduledExecutorProvider = |
| scheduledExecutorService == null |
| // default client background scheduler disposes the executor service when client is closed. |
| // we don't need to do that for user provided (via ClientBuilder) or managed executor service. |
| ? new DefaultClientBackgroundSchedulerProvider() |
| : new ClientScheduledExecutorServiceProvider(Values.of(scheduledExecutorService)); |
| } |
| |
| InstanceBinding<ScheduledExecutorServiceProvider> schedulerBinding = Bindings |
| .service(defaultScheduledExecutorProvider) |
| .to(ScheduledExecutorServiceProvider.class); |
| injectionManager.register(schedulerBinding); |
| |
| registerExecutors(injectionManager, componentBag, defaultAsyncExecutorProvider, |
| defaultScheduledExecutorProvider, bootstrapBag.getManagedObjectsFinalizer()); |
| } |
| |
| private static ExecutorService lookupManagedExecutorService() { |
| // Get the default ManagedExecutorService, if available |
| try { |
| // Android and some other environments don't have InitialContext class available. |
| final Class<?> aClass = |
| AccessController.doPrivileged(ReflectionHelper.classForNamePA("javax.naming.InitialContext")); |
| |
| final Object initialContext = aClass.newInstance(); |
| |
| final Method lookupMethod = aClass.getMethod("lookup", String.class); |
| return (ExecutorService) lookupMethod.invoke(initialContext, "java:comp/DefaultManagedExecutorService"); |
| } catch (Exception e) { |
| // ignore |
| if (LOGGER.isLoggable(Level.FINE)) { |
| LOGGER.log(Level.FINE, e.getMessage(), e); |
| } |
| } catch (LinkageError error) { |
| // ignore - JDK8 compact2 profile - http://openjdk.java.net/jeps/161 |
| } |
| |
| return null; |
| } |
| |
| private ScheduledExecutorService lookupManagedScheduledExecutorService() { |
| try { |
| // Android and some other environments don't have InitialContext class available. |
| final Class<?> aClass = |
| AccessController.doPrivileged(ReflectionHelper.classForNamePA("javax.naming.InitialContext")); |
| final Object initialContext = aClass.newInstance(); |
| |
| final Method lookupMethod = aClass.getMethod("lookup", String.class); |
| return (ScheduledExecutorService) lookupMethod |
| .invoke(initialContext, "java:comp/DefaultManagedScheduledExecutorService"); |
| } catch (Exception e) { |
| // ignore |
| if (LOGGER.isLoggable(Level.FINE)) { |
| LOGGER.log(Level.FINE, e.getMessage(), e); |
| } |
| } catch (LinkageError error) { |
| // ignore - JDK8 compact2 profile - http://openjdk.java.net/jeps/161 |
| } |
| |
| return null; |
| } |
| |
| @ClientAsyncExecutor |
| public static class ClientExecutorServiceProvider implements ExecutorServiceProvider { |
| |
| private final ExecutorService executorService; |
| |
| ClientExecutorServiceProvider(ExecutorService executorService) { |
| this.executorService = executorService; |
| } |
| |
| @Override |
| public ExecutorService getExecutorService() { |
| return executorService; |
| } |
| |
| @Override |
| public void dispose(ExecutorService executorService) { |
| |
| } |
| } |
| |
| @ClientBackgroundScheduler |
| public static class ClientScheduledExecutorServiceProvider implements ScheduledExecutorServiceProvider { |
| |
| private final Value<ScheduledExecutorService> executorService; |
| |
| ClientScheduledExecutorServiceProvider(Value<ScheduledExecutorService> executorService) { |
| this.executorService = executorService; |
| } |
| |
| @Override |
| public ScheduledExecutorService getExecutorService() { |
| return executorService.get(); |
| } |
| |
| @Override |
| public void dispose(ExecutorService executorService) { |
| |
| } |
| } |
| } |