/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.jaxrs.internal.wrappers.provider; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; import java.util.Collections; import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Providers; import org.restlet.data.MediaType; import org.restlet.ext.jaxrs.internal.core.ThreadLocalizedContext; import org.restlet.ext.jaxrs.internal.exceptions.IllegalBeanSetterTypeException; import org.restlet.ext.jaxrs.internal.exceptions.IllegalFieldTypeException; import org.restlet.ext.jaxrs.internal.exceptions.InjectException; import org.restlet.ext.jaxrs.internal.util.Converter; import org.restlet.ext.jaxrs.internal.util.Util; import org.restlet.ext.jaxrs.internal.wrappers.WrapperUtil; import org.restlet.ext.jaxrs.internal.wrappers.params.ContextInjector; /** * Wraps a JAX-RS provider, see chapter 4 of JAX-RS specification. * * @author Stephan Koops * @see javax.ws.rs.ext.Provider */ abstract class AbstractProviderWrapper implements ProviderWrapper { /** * the mimes this MessageBodyReader consumes. */ private final List<org.restlet.data.MediaType> consumedMimes; private final Class<?> genericMbrType; private final Class<?> genericMbwType; private final List<org.restlet.data.MediaType> producedMimes; /** * Creates a new wrapper for a Provider and initializes the provider. If the * given class is not a provider, an {@link IllegalArgumentException} is * thrown. * * @param jaxRsProviderClass * the JAX-RS provider class. * @throws IllegalArgumentException * if the class is not a valid provider, may not be instantiated * or what ever. * @throws WebApplicationException * @see javax.ws.rs.ext.MessageBodyReader * @see javax.ws.rs.ext.MessageBodyWriter * @see javax.ws.rs.ext.ContextResolver */ AbstractProviderWrapper(Class<?> jaxRsProviderClass) throws IllegalArgumentException, WebApplicationException { final Consumes pm = jaxRsProviderClass.getAnnotation(Consumes.class); if (pm != null) { this.consumedMimes = WrapperUtil.convertToMediaTypes(pm.value()); } else { this.consumedMimes = Collections.singletonList(MediaType.ALL); } final Produces cm = jaxRsProviderClass.getAnnotation(Produces.class); if (cm != null) { this.producedMimes = WrapperUtil.convertToMediaTypes(cm.value()); } else { this.producedMimes = Collections.singletonList(MediaType.ALL); } this.genericMbrType = Util.getGenericClass(jaxRsProviderClass, javax.ws.rs.ext.MessageBodyReader.class); this.genericMbwType = Util.getGenericClass(jaxRsProviderClass, javax.ws.rs.ext.MessageBodyWriter.class); // LATER use Type instead of Class here } @Override public abstract boolean equals(Object otherProvider); /** * @return the JAX-RS provider class name */ public abstract String getClassName(); /** * Returns the list of produced {@link MediaType}s of the wrapped * {@link javax.ws.rs.ext.MessageBodyWriter}. * * @return List of produced {@link MediaType}s. */ public List<MediaType> getConsumedMimes() { return this.consumedMimes; } /** * Returns the list of produced {@link MediaType}s of the wrapped * {@link javax.ws.rs.ext.MessageBodyWriter}. * * @return List of produced {@link MediaType}s. If the entity provider is * not annotated with @ {@link Produces}, '*<!---->/*' is * returned. */ public List<MediaType> getProducedMimes() { return this.producedMimes; } @Override public abstract int hashCode(); // TEST before a call of a message body reader or writer the current state // of the matched resources and URIs must be stored for the current thread. /** * initializes the provider (injection into annotated fields and setters). * * @throws IllegalFieldTypeException * @throws IllegalBeanSetterTypeException * @throws InjectException * @throws InvocationTargetException */ void initProvider(Object jaxRsProvider, ThreadLocalizedContext tlContext, Providers allProviders, ExtensionBackwardMapping extensionBackwardMapping) throws IllegalFieldTypeException, IllegalBeanSetterTypeException, InjectException, InvocationTargetException { final ContextInjector iph = new ContextInjector( jaxRsProvider.getClass(), tlContext, allProviders, extensionBackwardMapping); iph.injectInto(jaxRsProvider, false); } /** * Returns true, if this ProviderWrapper is also a * {@link javax.ws.rs.ext.ContextResolver}, otherwise false. * * @return true, if this ProviderWrapper is also a * {@link javax.ws.rs.ext.ContextResolver}, otherwise false. */ public abstract boolean isContextResolver(); /** * Checks, if this provider represents an {@link ExceptionMapper}. * * @return true, if this provider is an {@link ExceptionMapper}, or false if * not. */ public abstract boolean isExceptionMapper(); /** * Returns true, if this ProviderWrapper is also a * {@link javax.ws.rs.ext.MessageBodyReader}, otherwise false. * * @return true, if this ProviderWrapper is also a * {@link javax.ws.rs.ext.MessageBodyReader}, otherwise false. */ public abstract boolean isReader(); /** * Returns true, if this ProviderWrapper is also a * {@link javax.ws.rs.ext.MessageBodyWriter}, otherwise false. * * @return true, if this ProviderWrapper is also a * {@link javax.ws.rs.ext.MessageBodyWriter}, otherwise false. */ public abstract boolean isWriter(); /** * Checks, if this message body reader supports the given type (by the type * parameter of the {@link javax.ws.rs.ext.MessageBodyWriter}) * * @param entityClass * the type * @param genericType * the generic type * @return true, if this MessageBodyReader supports the given type, false, * if not. * @see MessageBodyReader#supportsRead(Class, Type) */ public boolean supportsRead(Class<?> entityClass, Type genericType) { if (entityClass == null) { return false; } if (genericType == null) { // LATER use Type instead of Class } if (this.genericMbrType == null) { return false; } return this.genericMbrType.isAssignableFrom(entityClass); } /** * Checks, if this MessageBodyReader supports the given MediaType. * * @param mediaType */ public boolean supportsRead(MediaType mediaType) { boolean result = false; for (int i = 0; !result && i < getConsumedMimes().size(); i++) { result = getConsumedMimes().get(i).isCompatible(mediaType) || (mediaType == null); } return result; } /** * Checks, if this message body writer supports the given type (by the type * parameter of the {@link javax.ws.rs.ext.MessageBodyWriter}) * * @param entityClass * the type * @param genericType * the generic type * @return true, if this MessageBodyWriter supports the given type, false, * if not. * @see org.restlet.ext.jaxrs.internal.wrappers.provider.MessageBodyWriter#supportsWrite(java.lang.Class, * java.lang.reflect.Type) */ public boolean supportsWrite(Class<?> entityClass, Type genericType) { if (entityClass == null) { return false; } if (genericType == null) { // LATER use Type instead of Class } if (this.genericMbwType == null) { return false; } final boolean supportsWrite = this.genericMbwType .isAssignableFrom(entityClass); return supportsWrite; } /** * Checks, if the wrapped MessageBodyWriter supports at least one of the * requested {@link MediaType}s. * * @param mediaTypes * the {@link MediaType}s * @return true, if at least one of the requested {@link MediaType}s is * supported, otherwise false. */ public boolean supportsWrite(Iterable<MediaType> mediaTypes) { for (final MediaType produced : getProducedMimes()) { for (final MediaType requested : mediaTypes) { if (requested.isCompatible(produced)) { return true; } } } return false; } public boolean supportsWrite(javax.ws.rs.core.MediaType requested) { return this.supportsWrite(Converter.toRestletMediaType(requested)); } /** * Checks, if the wrapped MessageBodyWriter supports at least one of the * requested {@link MediaType}s. * * @param requested * the requested {@link MediaType}s * @return true, if at least one of the requested {@link MediaType}s is * supported, otherwise false. */ public boolean supportsWrite(MediaType requested) { for (final MediaType produced : getProducedMimes()) { if (requested.isCompatible(produced)) { return true; } } return false; } @Override public final String toString() { return this.getClassName(); } }