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

org.glassfish.jersey.server.ApplicationHandler Maven / Gradle / Ivy

There is a newer version: 4.0.0-M1
Show newest version
/*
 * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2018 Payara Foundation and/or its affiliates.
 *
 * 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.server;

import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.security.Principal;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import jakarta.ws.rs.HttpMethod;
import jakarta.ws.rs.RuntimeType;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Configuration;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.ext.MessageBodyReader;
import jakarta.ws.rs.ext.MessageBodyWriter;

import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.internal.AutoDiscoverableConfigurator;
import org.glassfish.jersey.internal.BootstrapBag;
import org.glassfish.jersey.internal.BootstrapConfigurator;
import org.glassfish.jersey.internal.ContextResolverFactory;
import org.glassfish.jersey.internal.DynamicFeatureConfigurator;
import org.glassfish.jersey.internal.Errors;
import org.glassfish.jersey.internal.ExceptionMapperFactory;
import org.glassfish.jersey.internal.FeatureConfigurator;
import org.glassfish.jersey.internal.JaxrsProviders;
import org.glassfish.jersey.internal.Version;
import org.glassfish.jersey.internal.inject.Binder;
import org.glassfish.jersey.internal.inject.Bindings;
import org.glassfish.jersey.internal.inject.CompositeBinder;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.inject.Injections;
import org.glassfish.jersey.internal.inject.InstanceBinding;
import org.glassfish.jersey.internal.inject.Providers;
import org.glassfish.jersey.message.MessageBodyWorkers;
import org.glassfish.jersey.message.internal.MessageBodyFactory;
import org.glassfish.jersey.message.internal.MessagingBinders;
import org.glassfish.jersey.message.internal.NullOutputStream;
import org.glassfish.jersey.model.internal.ComponentBag;
import org.glassfish.jersey.model.internal.ManagedObjectsFinalizer;
import org.glassfish.jersey.model.internal.RankedComparator;
import org.glassfish.jersey.model.internal.RankedProvider;
import org.glassfish.jersey.process.internal.ChainableStage;
import org.glassfish.jersey.process.internal.RequestScope;
import org.glassfish.jersey.process.internal.Stage;
import org.glassfish.jersey.process.internal.Stages;
import org.glassfish.jersey.server.internal.JerseyRequestTimeoutHandler;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import org.glassfish.jersey.server.internal.ProcessingProviders;
import org.glassfish.jersey.internal.inject.ParamConverterConfigurator;
import org.glassfish.jersey.server.internal.inject.ParamExtractorConfigurator;
import org.glassfish.jersey.server.internal.inject.ValueParamProviderConfigurator;
import org.glassfish.jersey.server.internal.monitoring.ApplicationEventImpl;
import org.glassfish.jersey.server.internal.monitoring.CompositeApplicationEventListener;
import org.glassfish.jersey.server.internal.monitoring.MonitoringContainerListener;
import org.glassfish.jersey.server.internal.process.ReferencesInitializer;
import org.glassfish.jersey.server.internal.process.RequestProcessingConfigurator;
import org.glassfish.jersey.server.internal.process.RequestProcessingContext;
import org.glassfish.jersey.server.internal.process.RequestProcessingContextReference;
import org.glassfish.jersey.server.internal.routing.Routing;
import org.glassfish.jersey.server.model.ComponentModelValidator;
import org.glassfish.jersey.server.model.ModelProcessor;
import org.glassfish.jersey.server.model.ModelValidationException;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.internal.ModelErrors;
import org.glassfish.jersey.server.model.internal.ResourceMethodInvokerConfigurator;
import org.glassfish.jersey.server.monitoring.ApplicationEvent;
import org.glassfish.jersey.server.monitoring.ApplicationEventListener;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.ContainerLifecycleListener;
import org.glassfish.jersey.server.spi.ContainerResponseWriter;

/**
 * Jersey server-side application handler.
 * 

* Container implementations use the {@code ApplicationHandler} API to process requests * by invoking the {@link #handle(ContainerRequest) handle(request)} * method on a configured application handler instance. *

*

* {@code ApplicationHandler} provides two implementations of {@link jakarta.ws.rs.core.Configuration config} that can be injected * into the application classes. The first is {@link ResourceConfig resource config} which implements {@code Configuration} * itself and is configured by the user. The resource config is not modified by this application handler so the future reloads of * the application is not disrupted by providers found on a classpath. This config can * be injected only as {@code ResourceConfig} or {@code Application}. The second one can be injected into the * {@code Configuration} parameters / fields and contains info about all the properties / provider classes / provider instances * from the resource config and also about all the providers found during processing classes registered under * {@link ServerProperties server properties}. After the application handler is initialized both configurations are marked as * read-only. *

*

* Application handler instance also acts as an aggregate {@link ContainerLifecycleListener} instance * for the associated application. It aggregates all the registered container lifecycle listeners * under a single, umbrella listener, represented by this application handler instance, that delegates all container lifecycle * listener method calls to all the registered listeners. Jersey {@link Container containers} are expected to invoke * the container lifecycle methods directly on the active {@code ApplicationHandler} instance. The application handler will then * make sure to delegate the lifecycle listener calls further to all the container lifecycle listeners registered within the * application. Additionally, invoking the {@link ContainerLifecycleListener#onShutdown(Container)} method on this application * handler instance will release all the resources associated with the underlying application instance as well as close the * application-specific {@link InjectionManager injection manager}. *

* * @author Pavel Bucek * @author Jakub Podlesak * @author Marek Potociar * @author Libor Kramolis * @see ResourceConfig * @see jakarta.ws.rs.core.Configuration * @see org.glassfish.jersey.server.spi.ContainerProvider */ public final class ApplicationHandler implements ContainerLifecycleListener { private static final Logger LOGGER = Logger.getLogger(ApplicationHandler.class.getName()); /** * Default dummy security context. */ private static final SecurityContext DEFAULT_SECURITY_CONTEXT = new SecurityContext() { @Override public boolean isUserInRole(final String role) { return false; } @Override public boolean isSecure() { return false; } @Override public Principal getUserPrincipal() { return null; } @Override public String getAuthenticationScheme() { return null; } }; /** * Configurator which initializes and register {@link ApplicationHandler} and {@link Configuration} instances into * {@link InjectionManager} and {@link BootstrapBag}. * * @author Petr Bouda */ private class RuntimeConfigConfigurator implements BootstrapConfigurator { @Override public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) { ServerBootstrapBag serverBag = (ServerBootstrapBag) bootstrapBag; serverBag.setApplicationHandler(ApplicationHandler.this); serverBag.setConfiguration(ResourceConfig.createRuntimeConfig(serverBag.getApplication())); // TODO: Do we really need these three bindings in DI provider? What JAX-RS specification says? InstanceBinding handlerBinding = Bindings.service(ApplicationHandler.this) .to(ApplicationHandler.class); InstanceBinding configBinding = Bindings.service(serverBag.getRuntimeConfig()) .to(Configuration.class) .to(ServerConfig.class); injectionManager.register(handlerBinding); injectionManager.register(configBinding); } } private Application application; private ResourceConfig runtimeConfig; private ServerRuntime runtime; private Iterable containerLifecycleListeners; private InjectionManager injectionManager; private MessageBodyWorkers msgBodyWorkers; private ManagedObjectsFinalizer managedObjectsFinalizer; /** * Create a new Jersey application handler using a default configuration. */ public ApplicationHandler() { this(new Application()); } /** * Create a new Jersey server-side application handler configured by a * {@link Application JAX-RS Application (sub-)class}. * * @param jaxrsApplicationClass JAX-RS {@code Application} (sub-)class that will be * instantiated and used to configure the new Jersey * application handler. */ public ApplicationHandler(final Class jaxrsApplicationClass) { this(jaxrsApplicationClass, null); } /** * Create a new Jersey server-side application handler configured by a * {@link Application JAX-RS Application (sub-)class}. * * @param applicationClass JAX-RS {@code Application} (sub-)class that will be * instantiated and used to configure the new Jersey * application handler. * @param customBinder additional custom bindings used to configure the application's. */ public ApplicationHandler(final Class applicationClass, final Binder customBinder) { initialize(new ApplicationConfigurator(applicationClass), Injections.createInjectionManager(), customBinder); } /** * Create a new Jersey server-side application handler configured by an instance * of a {@link Application JAX-RS Application sub-class}. * * @param application an instance of a JAX-RS {@code Application} (sub-)class that * will be used to configure the new Jersey application handler. */ public ApplicationHandler(final Application application) { this(application, null, null); } /** * Create a new Jersey server-side application handler configured by an instance * of a {@link ResourceConfig} and a custom {@link Binder}. * * @param application an instance of a JAX-RS {@code Application} (sub-)class that * will be used to configure the new Jersey application handler. * @param customBinder additional custom bindings used to configure the application's. */ public ApplicationHandler(final Application application, final Binder customBinder) { this(application, customBinder, null); } /** * Create a new Jersey server-side application handler configured by an instance * of a {@link ResourceConfig}, custom {@link Binder} and a parent used by {@link InjectionManager}. * * @param application an instance of a JAX-RS {@code Application} (sub-)class that * will be used to configure the new Jersey application handler. * @param customBinder additional custom bindings used during {@link InjectionManager} creation. * @param parentManager parent used in {@link InjectionManager} for a specific DI provider. */ public ApplicationHandler(final Application application, final Binder customBinder, final Object parentManager) { initialize(new ApplicationConfigurator(application), Injections.createInjectionManager(parentManager), customBinder); } private void initialize(ApplicationConfigurator applicationConfigurator, InjectionManager injectionManager, Binder customBinder) { LOGGER.config(LocalizationMessages.INIT_MSG(Version.getBuildId())); this.injectionManager = injectionManager; this.injectionManager.register(CompositeBinder.wrap(new ServerBinder(), customBinder)); this.managedObjectsFinalizer = new ManagedObjectsFinalizer(injectionManager); ServerBootstrapBag bootstrapBag = new ServerBootstrapBag(); bootstrapBag.setManagedObjectsFinalizer(managedObjectsFinalizer); List bootstrapConfigurators = Arrays.asList( new RequestProcessingConfigurator(), new RequestScope.RequestScopeConfigurator(), new ParamConverterConfigurator(), new ParamExtractorConfigurator(), new ValueParamProviderConfigurator(), new JerseyResourceContextConfigurator(), new ComponentProviderConfigurator(), new JaxrsProviders.ProvidersConfigurator(), applicationConfigurator, new RuntimeConfigConfigurator(), new ContextResolverFactory.ContextResolversConfigurator(), new MessageBodyFactory.MessageBodyWorkersConfigurator(), new ExceptionMapperFactory.ExceptionMappersConfigurator(), new ResourceMethodInvokerConfigurator(), new ProcessingProvidersConfigurator(), new ContainerProviderConfigurator(RuntimeType.SERVER), new AutoDiscoverableConfigurator(RuntimeType.SERVER), new DynamicFeatureConfigurator(), new FeatureConfigurator(RuntimeType.SERVER)); bootstrapConfigurators.forEach(configurator -> configurator.init(injectionManager, bootstrapBag)); this.runtime = Errors.processWithException( () -> initialize(injectionManager, bootstrapConfigurators, bootstrapBag)); this.containerLifecycleListeners = Providers.getAllProviders(injectionManager, ContainerLifecycleListener.class); } /** * Assumes the configuration field is initialized with a valid ResourceConfig. */ private ServerRuntime initialize(InjectionManager injectionManager, List bootstrapConfigurators, ServerBootstrapBag bootstrapBag) { this.application = bootstrapBag.getApplication(); this.runtimeConfig = bootstrapBag.getRuntimeConfig(); // Register the binders which are dependent on "Application.properties()" injectionManager.register(new MessagingBinders.MessageBodyProviders(application.getProperties(), RuntimeType.SERVER)); // Lock original ResourceConfig. if (application instanceof ResourceConfig) { ((ResourceConfig) application).lock(); } CompositeApplicationEventListener compositeListener = null; Errors.mark(); // mark begin of validation phase try { // TODO: Create as a configurator? / The same code in ClientConfig. // AutoDiscoverable. if (!CommonProperties.getValue(runtimeConfig.getProperties(), RuntimeType.SERVER, CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, Boolean.FALSE, Boolean.class)) { runtimeConfig.configureAutoDiscoverableProviders(injectionManager, bootstrapBag.getAutoDiscoverables()); } else { runtimeConfig.configureForcedAutoDiscoverableProviders(injectionManager); } // Configure binders and features. runtimeConfig.configureMetaProviders(injectionManager, bootstrapBag.getManagedObjectsFinalizer()); ResourceBagConfigurator resourceBagConfigurator = new ResourceBagConfigurator(); resourceBagConfigurator.init(injectionManager, bootstrapBag); runtimeConfig.lock(); ExternalRequestScopeConfigurator externalRequestScopeConfigurator = new ExternalRequestScopeConfigurator(); externalRequestScopeConfigurator.init(injectionManager, bootstrapBag); ModelProcessorConfigurator modelProcessorConfigurator = new ModelProcessorConfigurator(); modelProcessorConfigurator.init(injectionManager, bootstrapBag); ResourceModelConfigurator resourceModelConfigurator = new ResourceModelConfigurator(); resourceModelConfigurator.init(injectionManager, bootstrapBag); ServerExecutorProvidersConfigurator executorProvidersConfigurator = new ServerExecutorProvidersConfigurator(); executorProvidersConfigurator.init(injectionManager, bootstrapBag); injectionManager.completeRegistration(); bootstrapConfigurators.forEach(configurator -> configurator.postInit(injectionManager, bootstrapBag)); resourceModelConfigurator.postInit(injectionManager, bootstrapBag); Iterable appEventListeners = Providers.getAllProviders(injectionManager, ApplicationEventListener.class, new RankedComparator<>()); if (appEventListeners.iterator().hasNext()) { ResourceBag resourceBag = bootstrapBag.getResourceBag(); compositeListener = new CompositeApplicationEventListener(appEventListeners); compositeListener.onEvent(new ApplicationEventImpl(ApplicationEvent.Type.INITIALIZATION_START, this.runtimeConfig, runtimeConfig.getComponentBag().getRegistrations(), resourceBag.classes, resourceBag.instances, null)); } if (!disableValidation()) { ComponentModelValidator validator = new ComponentModelValidator( bootstrapBag.getValueParamProviders(), bootstrapBag.getMessageBodyWorkers()); validator.validate(bootstrapBag.getResourceModel()); } if (Errors.fatalIssuesFound() && !ignoreValidationError()) { throw new ModelValidationException(LocalizationMessages.RESOURCE_MODEL_VALIDATION_FAILED_AT_INIT(), ModelErrors.getErrorsAsResourceModelIssues(true)); } } finally { if (ignoreValidationError()) { Errors.logErrors(true); Errors.reset(); // reset errors to the state before validation phase } else { Errors.unmark(); } } this.msgBodyWorkers = bootstrapBag.getMessageBodyWorkers(); // assembly request processing chain ProcessingProviders processingProviders = bootstrapBag.getProcessingProviders(); final ContainerFilteringStage preMatchRequestFilteringStage = new ContainerFilteringStage( processingProviders.getPreMatchFilters(), processingProviders.getGlobalResponseFilters()); final ChainableStage routingStage = Routing.forModel(bootstrapBag.getResourceModel().getRuntimeResourceModel()) .resourceContext(bootstrapBag.getResourceContext()) .configuration(runtimeConfig) .entityProviders(msgBodyWorkers) .valueSupplierProviders(bootstrapBag.getValueParamProviders()) .modelProcessors(Providers.getAllRankedSortedProviders(injectionManager, ModelProcessor.class)) .createService(serviceType -> Injections.getOrCreate(injectionManager, serviceType)) .processingProviders(processingProviders) .resourceMethodInvokerBuilder(bootstrapBag.getResourceMethodInvokerBuilder()) .buildStage(); /* * Root linear request acceptor. This is the main entry point for the whole request processing. */ final ContainerFilteringStage resourceFilteringStage = new ContainerFilteringStage(processingProviders.getGlobalRequestFilters(), null); final ReferencesInitializer referencesInitializer = new ReferencesInitializer(injectionManager, () -> injectionManager.getInstance(RequestProcessingContextReference.class)); final Stage rootStage = Stages .chain(referencesInitializer) .to(preMatchRequestFilteringStage) .to(routingStage) .to(resourceFilteringStage) .build(Routing.matchedEndpointExtractor()); ServerRuntime serverRuntime = ServerRuntime.createServerRuntime( injectionManager, bootstrapBag, rootStage, compositeListener, processingProviders); // Inject instances. ComponentBag componentBag = runtimeConfig.getComponentBag(); ResourceBag resourceBag = bootstrapBag.getResourceBag(); for (final Object instance : componentBag.getInstances(ComponentBag.excludeMetaProviders(injectionManager))) { injectionManager.inject(instance); } for (final Object instance : resourceBag.instances) { injectionManager.inject(instance); } logApplicationInitConfiguration(injectionManager, resourceBag, processingProviders); if (compositeListener != null) { ApplicationEvent initFinishedEvent = new ApplicationEventImpl( ApplicationEvent.Type.INITIALIZATION_APP_FINISHED, runtimeConfig, componentBag.getRegistrations(), resourceBag.classes, resourceBag.instances, bootstrapBag.getResourceModel()); compositeListener.onEvent(initFinishedEvent); MonitoringContainerListener containerListener = injectionManager.getInstance(MonitoringContainerListener.class); containerListener.init(compositeListener, initFinishedEvent); } return serverRuntime; } private boolean ignoreValidationError() { return ServerProperties.getValue(runtimeConfig.getProperties(), ServerProperties.RESOURCE_VALIDATION_IGNORE_ERRORS, Boolean.FALSE, Boolean.class); } private boolean disableValidation() { return ServerProperties.getValue(runtimeConfig.getProperties(), ServerProperties.RESOURCE_VALIDATION_DISABLE, Boolean.FALSE, Boolean.class); } private static void logApplicationInitConfiguration(final InjectionManager injectionManager, final ResourceBag resourceBag, final ProcessingProviders processingProviders) { if (!LOGGER.isLoggable(Level.CONFIG)) { return; } final StringBuilder sb = new StringBuilder(LocalizationMessages.LOGGING_APPLICATION_INITIALIZED()).append('\n'); final List rootResourceClasses = resourceBag.getRootResources(); if (!rootResourceClasses.isEmpty()) { sb.append(LocalizationMessages.LOGGING_ROOT_RESOURCE_CLASSES()).append(":"); for (final Resource r : rootResourceClasses) { for (final Class clazz : r.getHandlerClasses()) { sb.append('\n').append(" ").append(clazz.getName()); } } } sb.append('\n'); final Set messageBodyReaders; final Set messageBodyWriters; if (LOGGER.isLoggable(Level.FINE)) { Spliterator mbrSpliterator = Providers.getAllProviders(injectionManager, MessageBodyReader.class).spliterator(); messageBodyReaders = StreamSupport.stream(mbrSpliterator, false).collect(Collectors.toSet()); Spliterator mbwSpliterator = Providers.getAllProviders(injectionManager, MessageBodyWriter.class).spliterator(); messageBodyWriters = StreamSupport.stream(mbwSpliterator, false).collect(Collectors.toSet()); } else { messageBodyReaders = Providers.getCustomProviders(injectionManager, MessageBodyReader.class); messageBodyWriters = Providers.getCustomProviders(injectionManager, MessageBodyWriter.class); } printProviders(LocalizationMessages.LOGGING_PRE_MATCH_FILTERS(), processingProviders.getPreMatchFilters(), sb); printProviders(LocalizationMessages.LOGGING_GLOBAL_REQUEST_FILTERS(), processingProviders.getGlobalRequestFilters(), sb); printProviders(LocalizationMessages.LOGGING_GLOBAL_RESPONSE_FILTERS(), processingProviders.getGlobalResponseFilters(), sb); printProviders(LocalizationMessages.LOGGING_GLOBAL_READER_INTERCEPTORS(), processingProviders.getGlobalReaderInterceptors(), sb); printProviders(LocalizationMessages.LOGGING_GLOBAL_WRITER_INTERCEPTORS(), processingProviders.getGlobalWriterInterceptors(), sb); printNameBoundProviders(LocalizationMessages.LOGGING_NAME_BOUND_REQUEST_FILTERS(), processingProviders.getNameBoundRequestFilters(), sb); printNameBoundProviders(LocalizationMessages.LOGGING_NAME_BOUND_RESPONSE_FILTERS(), processingProviders.getNameBoundResponseFilters(), sb); printNameBoundProviders(LocalizationMessages.LOGGING_NAME_BOUND_READER_INTERCEPTORS(), processingProviders.getNameBoundReaderInterceptors(), sb); printNameBoundProviders(LocalizationMessages.LOGGING_NAME_BOUND_WRITER_INTERCEPTORS(), processingProviders.getNameBoundWriterInterceptors(), sb); printProviders(LocalizationMessages.LOGGING_DYNAMIC_FEATURES(), processingProviders.getDynamicFeatures(), sb); printProviders(LocalizationMessages.LOGGING_MESSAGE_BODY_READERS(), messageBodyReaders.stream().map(new WorkersToStringTransform<>()).collect(Collectors.toList()), sb); printProviders(LocalizationMessages.LOGGING_MESSAGE_BODY_WRITERS(), messageBodyWriters.stream().map(new WorkersToStringTransform<>()).collect(Collectors.toList()), sb); LOGGER.log(Level.CONFIG, sb.toString()); } private static class WorkersToStringTransform implements Function { @Override public String apply(final T t) { if (t != null) { return t.getClass().getName(); } return null; } } private static void printNameBoundProviders(final String title, final Map, List>> providers, final StringBuilder sb) { if (!providers.isEmpty()) { sb.append(title).append(":").append('\n'); for (final Map.Entry, List>> entry : providers.entrySet()) { for (final RankedProvider rankedProvider : entry.getValue()) { sb.append(" ") .append(LocalizationMessages.LOGGING_PROVIDER_BOUND(rankedProvider, entry.getKey())) .append('\n'); } } } } private static void printProviders(final String title, final Iterable providers, final StringBuilder sb) { final Iterator iterator = providers.iterator(); boolean first = true; while (iterator.hasNext()) { if (first) { sb.append(title).append(":").append('\n'); first = false; } final T provider = iterator.next(); sb.append(" ").append(provider).append('\n'); } } /** * Invokes a request and returns the {@link Future response future}. * * @param requestContext request data. * @return response future. */ public Future apply(final ContainerRequest requestContext) { return apply(requestContext, new NullOutputStream()); } /** * Invokes a request and returns the {@link Future response future}. * * @param request request data. * @param outputStream response output stream. * @return response future. */ public Future apply(final ContainerRequest request, final OutputStream outputStream) { final FutureResponseWriter responseFuture = new FutureResponseWriter(request.getMethod(), outputStream, runtime.getBackgroundScheduler()); if (request.getSecurityContext() == null) { request.setSecurityContext(DEFAULT_SECURITY_CONTEXT); } request.setWriter(responseFuture); handle(request); return responseFuture; } private static class FutureResponseWriter extends CompletableFuture implements ContainerResponseWriter { private ContainerResponse response = null; private final String requestMethodName; private final OutputStream outputStream; private final JerseyRequestTimeoutHandler requestTimeoutHandler; private FutureResponseWriter(final String requestMethodName, final OutputStream outputStream, final ScheduledExecutorService backgroundScheduler) { this.requestMethodName = requestMethodName; this.outputStream = outputStream; this.requestTimeoutHandler = new JerseyRequestTimeoutHandler(this, backgroundScheduler); } @Override public OutputStream writeResponseStatusAndHeaders(final long contentLength, final ContainerResponse response) { this.response = response; if (contentLength >= 0) { response.getHeaders().putSingle(HttpHeaders.CONTENT_LENGTH, Long.toString(contentLength)); } return outputStream; } @Override public boolean suspend(final long time, final TimeUnit unit, final TimeoutHandler handler) { return requestTimeoutHandler.suspend(time, unit, handler); } @Override public void setSuspendTimeout(final long time, final TimeUnit unit) { requestTimeoutHandler.setSuspendTimeout(time, unit); } @Override public void commit() { final ContainerResponse current = response; if (current != null) { if (HttpMethod.HEAD.equals(requestMethodName) && current.hasEntity()) { // for testing purposes: // need to also strip the object entity as it was stripped when writing to output current.setEntity(null); } requestTimeoutHandler.close(); super.complete(current); } } @Override public void failure(final Throwable error) { requestTimeoutHandler.close(); super.completeExceptionally(error); } @Override public boolean enableResponseBuffering() { return true; } } /** * The main request/response processing entry point for Jersey container implementations. *

* The method invokes the request processing of the provided * {@link ContainerRequest container request context} and uses the * {@link ContainerResponseWriter container response writer} to suspend & resume the processing * as well as write the response back to the container. *

*

* The the {@link SecurityContext security context} stored in the container request context * is bound as an injectable instance in the scope of the processed request context. * Also, any {@link org.glassfish.jersey.server.spi.RequestScopedInitializer custom scope injections} * are initialized in the current request scope. *

* * @param request container request context of the current request. */ public void handle(final ContainerRequest request) { request.setWorkers(msgBodyWorkers); runtime.process(request); } /** * Returns {@link InjectionManager} relevant to current application. * * @return {@link InjectionManager} instance. * @since 2.26 */ public InjectionManager getInjectionManager() { return injectionManager; } /** * Get the application configuration. * * @return application configuration. */ public ResourceConfig getConfiguration() { return runtimeConfig; } // Aggregate container lifecycle listener implementation @Override public void onStartup(final Container container) { for (final ContainerLifecycleListener listener : containerLifecycleListeners) { listener.onStartup(container); } } @Override public void onReload(final Container container) { for (final ContainerLifecycleListener listener : containerLifecycleListeners) { listener.onReload(container); } } @Override public void onShutdown(final Container container) { try { for (final ContainerLifecycleListener listener : containerLifecycleListeners) { listener.onShutdown(container); } } finally { try { // Call @PreDestroy method on Application. injectionManager.preDestroy(ResourceConfig.unwrapApplication(application)); } finally { // Shutdown ServiceLocator. // Takes care of the injected executors & schedulers shut-down too. managedObjectsFinalizer.preDestroy(); injectionManager.shutdown(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy