org.glassfish.jersey.server.model.Invocable Maven / Gradle / Ivy
The newest version!
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2011-2013 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.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.ws.rs.core.Request;
import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.internal.util.collection.ClassTypePair;
import org.glassfish.jersey.process.Inflector;
import org.glassfish.jersey.server.spi.internal.ParameterValueHelper;
import org.glassfish.jersey.server.spi.internal.ResourceMethodDispatcher;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
/**
* A common interface for invocable resource components. This includes resource
* methods, sub-resource methods and sub-resource locators bound to a concrete
* handler class and a Java method (either directly or indirectly) declared &
* implemented by the handler class.
*
* Invocable component information is used at runtime by a Java method dispatcher
* when processing requests.
*
* @author Marek Potociar (marek.potociar at oracle.com)
* @see ResourceMethod
* @see ResourceMethodDispatcher
*/
public final class Invocable implements Parameterized, ResourceModelComponent {
/**
* Method instance representing the {@link Inflector#apply(Object)} method.
*/
static final Method APPLY_INFLECTOR_METHOD = initApplyMethod();
private static Method initApplyMethod() {
try {
return Inflector.class.getMethod("apply", Object.class);
} catch (NoSuchMethodException e) {
IncompatibleClassChangeError error = new IncompatibleClassChangeError("Inflector.apply(Object) method not found");
error.initCause(e);
throw error;
}
}
/**
* Create a new resource method invocable model backed by an inflector instance.
*
* @param inflector inflector processing the request method.
*/
public static Invocable create(Inflector inflector) {
return create(MethodHandler.create(inflector), APPLY_INFLECTOR_METHOD, false);
}
/**
* Create a new resource method invocable model backed by an inflector class.
*
* @param inflectorClass inflector syb-type processing the request method.
*/
public static Invocable create(Class extends Inflector> inflectorClass) {
return create(MethodHandler.create(inflectorClass), APPLY_INFLECTOR_METHOD, false);
}
/**
* Create a new resource method invocable model. Parameter values will be
* automatically decoded.
*
* @param handler resource method handler.
* @param handlingMethod handling Java method.
*/
public static Invocable create(MethodHandler handler, Method handlingMethod) {
return create(handler, handlingMethod, false);
}
/**
* Create a new resource method invocable model.
*
* @param handler resource method handler.
* @param handlingMethod handling Java method.
* @param encodedParameters {@code true} if the automatic parameter decoding
* should be disabled, false otherwise.
*/
public static Invocable create(MethodHandler handler, Method handlingMethod, boolean encodedParameters) {
final Method validateMethod = ReflectionHelper
.findOverridingMethodOnClass(handler.getHandlerClass(), handlingMethod);
return create(handler, handlingMethod, validateMethod, encodedParameters);
}
/**
* Create a new resource method invocable model.
*
* @param handler resource method handler.
* @param handlingMethod handling Java method.
* @param validateMethod method used during resource bean validation phase.
* @param encodedParameters {@code true} if the automatic parameter decoding
* should be disabled, false otherwise.
*/
public static Invocable create(MethodHandler handler, Method handlingMethod, Method validateMethod,
boolean encodedParameters) {
return new Invocable(handler, handlingMethod, validateMethod, encodedParameters);
}
private final MethodHandler handler;
private final Method handlingMethod;
private final Method validateMethod;
private final List parameters;
private final Class> rawResponseType;
private final Type responseType;
private Invocable(MethodHandler handler, Method handlingMethod, Method validateMethod, boolean encodedParameters) {
this.handler = handler;
this.handlingMethod = handlingMethod;
this.validateMethod = validateMethod;
final Class> handlerClass = handler.getHandlerClass();
final ClassTypePair ctPair = ReflectionHelper.resolveGenericType(
handlerClass,
handlingMethod.getDeclaringClass(),
handlingMethod.getReturnType(),
handlingMethod.getGenericReturnType());
this.rawResponseType = ctPair.rawClass();
this.responseType = ctPair.type();
this.parameters = Collections.unmodifiableList(Parameter.create(
handlerClass, handlingMethod.getDeclaringClass(), handlingMethod, encodedParameters));
}
/**
* Get the model of the resource method handler that will be used to invoke
* the {@link #getHandlingMethod() handling resource method} on.
*
* @return resource method handler model.
*/
public MethodHandler getHandler() {
return handler;
}
/**
* Getter for the Java method
*
* @return corresponding Java method
*/
public Method getHandlingMethod() {
return handlingMethod;
}
/**
* Getter for the Java method used during resource bean validation phase.
*
* @return corresponding Java method used during resource bean validation phase.
*/
public Method getValidateMethod() {
return validateMethod;
}
/**
* Get the resource method generic response type information.
*
* The returned value provides the Type information that contains additional
* generic declaration information for generic Java class types.
*
*
* @return resource method generic response type information.
*/
public Type getResponseType() {
return responseType;
}
/**
* Get the resource method raw response type.
*
* The returned value provides information about the raw Java class.
*
*
* @return resource method raw response type information.
*/
public Class> getRawResponseType() {
return rawResponseType;
}
/**
* Check if the invocable represents an {@link Inflector#apply(Object) inflector
* processing method}.
*
* @return {@code true}, if this invocable represents an inflector invocation,
* {@code false} otherwise.
*/
public boolean isInflector() {
// Method.equals(...) does not perform the identity check (in Java SE 6)
return APPLY_INFLECTOR_METHOD == handlingMethod || APPLY_INFLECTOR_METHOD.equals(handlingMethod);
}
/**
* Returns list of {@link org.glassfish.jersey.server.spi.internal.ValueFactoryProvider value providers} which provides
* values for parameters of this Invocable returned by {@link #getParameters()}. Value providers are ordered in the same
* order as parameters.
*
*
* @param locator HK2 service locator.
* @return Set of value providers for this Invocable.
*/
public List> getValueProviders(ServiceLocator locator) {
return ParameterValueHelper.createValueProviders(locator, this);
}
@Override
public boolean requiresEntity() {
for (Parameter p : getParameters()) {
if (Parameter.Source.ENTITY == p.getSource()) {
return true;
}
}
return false;
}
@Override
public List getParameters() {
return parameters;
}
@Override
public void accept(ResourceModelVisitor visitor) {
visitor.visitInvocable(this);
}
@Override
public List extends ResourceModelComponent> getComponents() {
return Arrays.asList(handler);
}
@Override
public String toString() {
return "Invocable{" +
"handler=" + handler +
", handlingMethod=" + handlingMethod +
", parameters=" + parameters +
", responseType=" + responseType + '}';
}
}