![JAR search and dependency download from the Maven repository](/logo.png)
org.glassfish.jersey.server.model.ResourceMethodInvoker Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2011-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.jersey.server.model;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.WriterInterceptor;
import javax.inject.Inject;
import javax.inject.Provider;
import org.glassfish.jersey.internal.util.Producer;
import org.glassfish.jersey.message.internal.ReaderInterceptorExecutor;
import org.glassfish.jersey.message.internal.WriterInterceptorExecutor;
import org.glassfish.jersey.model.NameBound;
import org.glassfish.jersey.process.Inflector;
import org.glassfish.jersey.process.internal.PriorityComparator;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ContainerResponse;
import org.glassfish.jersey.server.internal.process.AsyncContext;
import org.glassfish.jersey.server.internal.process.Endpoint;
import org.glassfish.jersey.server.internal.process.RespondingContext;
import org.glassfish.jersey.server.internal.routing.RoutingContext;
import org.glassfish.jersey.server.spi.internal.ResourceMethodDispatcher;
import org.glassfish.jersey.server.spi.internal.ResourceMethodInvocationHandlerProvider;
import com.google.common.base.Function;
import deprecated.javax.ws.rs.DynamicBinder;
/**
* Server-side request-response {@link Inflector inflector} for invoking methods
* of annotation-based resource classes.
*
* @author Marek Potociar (marek.potociar at oracle.com)
* @author Martin Matula (martin.matula at oracle.com)
*/
public class ResourceMethodInvoker implements Endpoint, ResourceInfo {
private final Provider routingContextProvider;
private final Provider asyncContextProvider;
private final Provider respondingContextProvider;
private final ResourceMethod method;
private final ResourceMethodDispatcher dispatcher;
private final Method resourceMethod;
private final Class> resourceClass;
private final Collection requestFilters = new HashSet();
private final Collection responseFilters = new HashSet();
private final List readerInterceptors;
private final List writerInterceptors;
/**
* Resource method invoker "assisted" injection helper.
*
* The injectable builder API provides means for constructing a properly
* injected {@link ResourceMethodInvoker resource method invoker} instances.
*/
public static class Builder {
@Inject
private Provider routingContextProvider;
@Inject
private Provider asyncContextProvider;
@Inject
private Provider respondingContextProvider;
@Inject
private ResourceMethodDispatcherFactory dispatcherProviderFactory;
@Inject
private ResourceMethodInvocationHandlerFactory invocationHandlerProviderFactory;
/**
* Build a new resource method invoker instance.
*
* @param method resource method model.
* @param nameBoundRequestFilters name bound request filters.
* @param nameBoundResponseFilters name bound response filters.
* @param globalReaderInterceptors global reader interceptors.
* @param globalWriterInterceptors global writer interceptors.
* @param nameBoundReaderInterceptors name-bound reader interceptors.
* @param nameBoundWriterInterceptors name-bound writer interceptors.
* @param dynamicBinders dynamic binders.
* @return new resource method invoker instance.
*/
public ResourceMethodInvoker build(ResourceMethod method,
MultivaluedMap,
ContainerRequestFilter> nameBoundRequestFilters,
MultivaluedMap,
ContainerResponseFilter> nameBoundResponseFilters,
Collection globalReaderInterceptors,
Collection globalWriterInterceptors,
MultivaluedMap,
ReaderInterceptor> nameBoundReaderInterceptors,
MultivaluedMap,
WriterInterceptor> nameBoundWriterInterceptors,
Collection dynamicBinders
) {
return new ResourceMethodInvoker(
routingContextProvider,
asyncContextProvider,
respondingContextProvider,
dispatcherProviderFactory,
invocationHandlerProviderFactory,
method,
nameBoundRequestFilters,
nameBoundResponseFilters,
globalReaderInterceptors,
globalWriterInterceptors,
nameBoundReaderInterceptors,
nameBoundWriterInterceptors,
dynamicBinders);
}
}
private ResourceMethodInvoker(
Provider routingContextProvider,
Provider asyncContextProvider,
Provider respondingContextProvider,
ResourceMethodDispatcher.Provider dispatcherProvider,
ResourceMethodInvocationHandlerProvider invocationHandlerProvider,
ResourceMethod method,
MultivaluedMap, ContainerRequestFilter> nameBoundRequestFilters,
MultivaluedMap, ContainerResponseFilter> nameBoundResponseFilters,
Collection globalReaderInterceptors,
Collection globalWriterInterceptors,
MultivaluedMap, ReaderInterceptor> nameBoundReaderInterceptors,
MultivaluedMap, WriterInterceptor> nameBoundWriterInterceptors,
Collection dynamicBinders) {
this.routingContextProvider = routingContextProvider;
this.asyncContextProvider = asyncContextProvider;
this.respondingContextProvider = respondingContextProvider;
this.method = method;
final Invocable invocable = method.getInvocable();
this.dispatcher = dispatcherProvider.create(invocable, invocationHandlerProvider.create(invocable));
this.resourceMethod = invocable.getHandlingMethod();
this.resourceClass = invocable.getHandler().getHandlerClass();
List _readerInterceptors = new LinkedList();
List _writerInterceptors = new LinkedList();
for (DynamicBinder dynamicBinder : dynamicBinders) {
Object boundProvider = dynamicBinder.getBoundProvider(this);
// TODO: should be based on the type arg. value rather than instanceof?
if (boundProvider instanceof WriterInterceptor) {
_writerInterceptors.add((WriterInterceptor) boundProvider);
}
if (boundProvider instanceof ReaderInterceptor) {
_readerInterceptors.add((ReaderInterceptor) boundProvider);
}
if (boundProvider instanceof ContainerRequestFilter) {
this.requestFilters.add((ContainerRequestFilter) boundProvider);
}
if (boundProvider instanceof ContainerResponseFilter) {
this.responseFilters.add((ContainerResponseFilter) boundProvider);
}
}
_readerInterceptors.addAll(globalReaderInterceptors);
_writerInterceptors.addAll(globalWriterInterceptors);
if (resourceMethod != null) {
addNameBoundFiltersAndInterceptors(
nameBoundRequestFilters, nameBoundResponseFilters, nameBoundReaderInterceptors, nameBoundWriterInterceptors,
this.requestFilters, this.responseFilters, _readerInterceptors, _writerInterceptors,
method);
}
Collections.sort(_readerInterceptors, new PriorityComparator(PriorityComparator.Order.ASCENDING));
Collections.sort(_writerInterceptors, new PriorityComparator(PriorityComparator.Order.ASCENDING));
this.readerInterceptors = Collections.unmodifiableList(_readerInterceptors);
this.writerInterceptors = Collections.unmodifiableList(_writerInterceptors);
}
private void addNameBoundFiltersAndInterceptors(
final MultivaluedMap, ContainerRequestFilter> nameBoundRequestFilters,
final MultivaluedMap, ContainerResponseFilter> nameBoundResponseFilters,
final MultivaluedMap, ReaderInterceptor> nameBoundReaderInterceptors,
final MultivaluedMap, WriterInterceptor> nameBoundWriterInterceptors,
final Collection targetRequestFilters,
final Collection targetResponseFilters,
final Collection targetReaderInterceptors,
final Collection targetWriterInterceptors,
final NameBound target
) {
for (Class extends Annotation> nameBinding : target.getNameBindings()) {
List reqF = nameBoundRequestFilters.get(nameBinding);
if (reqF != null) {
targetRequestFilters.addAll(reqF);
}
List resF = nameBoundResponseFilters.get(nameBinding);
if (resF != null) {
targetResponseFilters.addAll(resF);
}
List _readerInterceptors = nameBoundReaderInterceptors.get(nameBinding);
if (_readerInterceptors != null) {
targetReaderInterceptors.addAll(_readerInterceptors);
}
List _writerInterceptors = nameBoundWriterInterceptors.get(nameBinding);
if (_writerInterceptors != null) {
targetWriterInterceptors.addAll(_writerInterceptors);
}
}
}
@Override
public Method getResourceMethod() {
return resourceMethod;
}
@Override
public Class> getResourceClass() {
return resourceClass;
}
@Override
public ContainerResponse apply(final ContainerRequest requestContext) {
final Object resource = routingContextProvider.get().peekMatchedResource();
requestContext.setProperty(ReaderInterceptorExecutor.INTERCEPTORS, getReaderInterceptors());
requestContext.setProperty(WriterInterceptorExecutor.INTERCEPTORS, getWriterInterceptors());
if (method.isSuspendDeclared() || method.isManagedAsyncDeclared()) {
asyncContextProvider.get().suspend();
}
if (method.isManagedAsyncDeclared()) {
asyncContextProvider.get().invokeManaged(new Producer() {
@Override
public Response call() {
final Response response = invoke(requestContext, resource);
if (method.isSuspendDeclared()) {
// we ignore any response returned from a method that injects AsyncResponse
return null;
}
return response;
}
});
return null; // return null on current thread
} else {
return new ContainerResponse(requestContext, invoke(requestContext, resource));
}
}
private Response invoke(ContainerRequest requestContext, Object resource) {
final Response jaxrsResponse = dispatcher.dispatch(resource, requestContext);
respondingContextProvider.get().push(new Function() {
@Override
public ContainerResponse apply(final ContainerResponse response) {
if (response == null) {
return response;
}
final Invocable invocable = method.getInvocable();
final Annotation[] entityAnn = response.getEntityAnnotations();
final Annotation[] methodAnn = invocable.getHandlingMethod().getDeclaredAnnotations();
if (methodAnn.length > 0) {
if (entityAnn.length == 0) {
response.setEntityAnnotations(methodAnn);
} else {
Annotation[] mergedAnn = Arrays.copyOf(methodAnn, methodAnn.length + entityAnn.length);
System.arraycopy(entityAnn, 0, mergedAnn, methodAnn.length, entityAnn.length);
response.setEntityAnnotations(mergedAnn);
}
}
if (response.hasEntity() && !(response.getEntityType() instanceof ParameterizedType)) {
Type invocableType = invocable.getResponseType();
if (invocableType != null &&
Void.TYPE != invocableType &&
Void.class != invocableType &&
Response.class != invocableType) {
response.setEntityType(invocableType);
}
}
return response;
}
});
return jaxrsResponse;
}
/**
* Get all bound request filters applicable to the {@link #getResourceMethod() resource method}
* wrapped by this invoker.
*
* @return All bound (dynamically or by name) request filters applicable to the {@link #getResourceMethod() resource
* method}.
*/
public Collection getRequestFilters() {
return requestFilters;
}
/**
* Get all bound response filters applicable to the {@link #getResourceMethod() resource method}
* wrapped by this invoker.
*
* @return All bound (dynamically or by name) response filters applicable to the {@link #getResourceMethod() resource
* method}.
*/
public Collection getResponseFilters() {
return responseFilters;
}
/**
* Get all reader interceptors applicable to the {@link #getResourceMethod() resource method}
* wrapped by this invoker.
*
* @return All reader interceptors applicable to the {@link #getResourceMethod() resource method}.
*/
public List getWriterInterceptors() {
return writerInterceptors;
}
/**
* Get all writer interceptors applicable to the {@link #getResourceMethod() resource method}
* wrapped by this invoker.
*
* @return All writer interceptors applicable to the {@link #getResourceMethod() resource method}.
*/
public List getReaderInterceptors() {
return readerInterceptors;
}
@Override
public String toString() {
return method.getInvocable().getHandlingMethod().toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy