/** * 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.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Providers; import org.restlet.data.CharacterSet; import org.restlet.data.MediaType; import org.restlet.engine.util.SystemUtils; import org.restlet.ext.jaxrs.internal.core.CallContext; import org.restlet.ext.jaxrs.internal.core.ThreadLocalizedContext; import org.restlet.ext.jaxrs.internal.exceptions.IllegalTypeException; import org.restlet.ext.jaxrs.internal.exceptions.InjectException; import org.restlet.ext.jaxrs.internal.util.Converter; import org.restlet.ext.jaxrs.internal.util.Util; /** * @author Stephan * */ public class SingletonProvider extends AbstractProviderWrapper implements MessageBodyReader, MessageBodyWriter, ContextResolver { /** * the {@link ContextResolver}, if this providers is a * {@link ContextResolver} */ private final javax.ws.rs.ext.ContextResolver<?> contextResolver; private final javax.ws.rs.ext.ExceptionMapper<? extends Throwable> excMapper; private final Object jaxRsProvider; /** * The JAX-RS {@link javax.ws.rs.ext.MessageBodyReader} this wrapper * represent. */ private final javax.ws.rs.ext.MessageBodyReader<?> reader; private final javax.ws.rs.ext.MessageBodyWriter<Object> writer; /** * Creates a new wrapper for a ProviderWrapper and initializes the provider. * If the given class is not a provider, an {@link IllegalArgumentException} * is thrown. * * @param jaxRsProvider * the JAX-RS provider class. * @param objectFactory * The object factory is responsible for the provider * instantiation, if given. * @param allResolvers * all available {@link ContextResolver}s. >>>>>>> .r3440 * @param logger * the logger to use. * @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 */ /** * @param jaxRsProvider * @param logger * needed, if the provider implements no provider interface * @throws IllegalArgumentException * @throws WebApplicationException */ @SuppressWarnings("unchecked") public SingletonProvider(Object jaxRsProvider, Logger logger) throws IllegalArgumentException, WebApplicationException { super((jaxRsProvider == null) ? null : jaxRsProvider.getClass()); if (jaxRsProvider == null) { throw new IllegalArgumentException( "The JAX-RS provider class must not be null"); } this.jaxRsProvider = jaxRsProvider; boolean isProvider = false; if (jaxRsProvider instanceof javax.ws.rs.ext.MessageBodyWriter) { this.writer = (javax.ws.rs.ext.MessageBodyWriter<Object>) jaxRsProvider; isProvider = true; } else { this.writer = null; } if (jaxRsProvider instanceof javax.ws.rs.ext.MessageBodyReader) { this.reader = (javax.ws.rs.ext.MessageBodyReader<?>) jaxRsProvider; isProvider = true; } else { this.reader = null; } if (jaxRsProvider instanceof javax.ws.rs.ext.ExceptionMapper) { this.excMapper = (javax.ws.rs.ext.ExceptionMapper<? extends Throwable>) jaxRsProvider; isProvider = true; } else { this.excMapper = null; } if (jaxRsProvider instanceof javax.ws.rs.ext.ContextResolver) { this.contextResolver = (javax.ws.rs.ext.ContextResolver<?>) jaxRsProvider; isProvider = true; } else { this.contextResolver = null; } if (!isProvider) { logger.config("The provider " + jaxRsProvider.getClass() + " is neither a MessageBodyWriter nor a MessageBodyReader nor a ContextResolver nor an ExceptionMapper"); } } @Override public final boolean equals(Object otherProvider) { if (this == otherProvider) { return true; } if (!(otherProvider instanceof SingletonProvider)) { return false; } return this.jaxRsProvider.getClass().equals( ((SingletonProvider) otherProvider).getClass()); } /** * @return the JAX-RS provider class name */ @Override public String getClassName() { return jaxRsProvider.getClass().getName(); } /** * @return the contextResolver */ public javax.ws.rs.ext.ContextResolver<?> getContextResolver() { return this.contextResolver; } /** * Returns the {@link ExceptionMapper}, or null, if this provider is not an * {@link ExceptionMapper}. * * @return the {@link ExceptionMapper}, or null, if this provider is not an * {@link ExceptionMapper}. */ public javax.ws.rs.ext.ExceptionMapper<? extends Throwable> getExcMapper() { return this.excMapper; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.ProviderWrapper#getExcMapperType() */ public Class<?> getExcMapperType() { return Util.getGenericClass(jaxRsProvider.getClass(), ExceptionMapper.class); } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.ProviderWrapper#getInitializedCtxResolver() */ public ContextResolver getInitializedCtxResolver() { return this; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.ProviderWrapper#getInitializedExcMapper() */ public ExceptionMapper<? extends Throwable> getInitializedExcMapper() { return excMapper; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.ProviderWrapper#getInitializedReader() */ public MessageBodyReader getInitializedReader() { return this; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.ProviderWrapper#getInitializedWriter() */ public MessageBodyWriter getInitializedWriter() { return this; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.MessageBodyReader#getJaxRsReader() */ public javax.ws.rs.ext.MessageBodyReader<?> getJaxRsReader() { return this.reader; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.MessageBodyWriter#getJaxRsWriter() */ public javax.ws.rs.ext.MessageBodyWriter<Object> getJaxRsWriter() { return this.writer; } /** * @see org.restlet.ext.jaxrs.internal.wrappers.provider.MessageBodyWriter#getSize(java.lang.Object, * Class, Type, Annotation[], MediaType) */ public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return this.writer.getSize(t, type, genericType, annotations, Converter.toJaxRsMediaType(mediaType)); } @Override public final int hashCode() { return SystemUtils.hashCode(this.jaxRsProvider); } /** * Injects the supported dependencies into this provider and calls the * method annotated with @{@link PostConstruct}. * * @param tlContext * The thread local wrapped {@link CallContext} * @param allProviders * all providers. * @param extensionBackwardMapping * the extension backward mapping * @throws InjectException * @throws InvocationTargetException * if a bean setter throws an exception * @throws IllegalTypeException * if the given class is not valid to be annotated with @ * {@link Context}. * @see ProviderWrapper#initAtAppStartUp(ThreadLocalizedContext, Providers, * ExtensionBackwardMapping) */ public void initAtAppStartUp(ThreadLocalizedContext tlContext, Providers allProviders, ExtensionBackwardMapping extensionBackwardMapping) throws InjectException, InvocationTargetException, IllegalTypeException { initProvider(this.jaxRsProvider, tlContext, allProviders, extensionBackwardMapping); } /** * 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. */ @Override public final boolean isContextResolver() { return this.contextResolver != null; } /** * Checks, if this provider represents an {@link ExceptionMapper}. * * @return true, if this provider is an {@link ExceptionMapper}, or false if * not. */ @Override public final boolean isExceptionMapper() { return this.excMapper != null; } /** * Checks, if this MessageBodyReader could read the given type. * * @param type * @param genericType * @param annotations * @return true, if the wrapped message body reader supports reading for the * given class with the given parameters. * @see javax.ws.rs.ext.MessageBodyReader#isReadable(Class, Type, * Annotation[]) */ public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, javax.ws.rs.core.MediaType mediaType) { try { return this.getJaxRsReader().isReadable(type, genericType, annotations, mediaType); } catch (NullPointerException e) { if (genericType == null || annotations == null) { // interpreted as not readable for the given combination return false; } throw e; } catch (IllegalArgumentException e) { if (genericType == null || annotations == null) { // interpreted as not readable for the given combination return false; } throw e; } } /** * 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. */ @Override public final boolean isReader() { return this.reader != null; } /** * Checks, if the given class could be written by this MessageBodyWriter. * * @param type * @param genericType * @param annotations * @return true, if the wrapped message writer reader supports writing for * the given class with the given parameters. * @see javax.ws.rs.ext.MessageBodyWriter#isWriteable(Class) */ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, javax.ws.rs.core.MediaType mediaType) { try { return this.getJaxRsWriter().isWriteable(type, genericType, annotations, mediaType); } catch (NullPointerException e) { if (genericType == null || annotations == null) { // interpreted as not writable for the given combination return false; } throw e; } catch (IllegalArgumentException e) { if (genericType == null || annotations == null) { // interpreted as not writable for the given combination return false; } throw e; } } /** * 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. */ @Override public final boolean isWriter() { return this.writer != null; } /** * * @param type * @param genericType * The generic {@link Type} to convert to. * @param annotations * the annotations of the artifact to convert to * @param mediaType * @param httpHeaders * @param entityStream * @return the read object * @throws IOException * @see javax.ws.rs.ext.MessageBodyReader#readFrom(Class, Type, * javax.ws.rs.core.MediaType, Annotation[], MultivaluedMap, * InputStream) */ @SuppressWarnings({ "unchecked", "rawtypes" }) public Object readFrom(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, CharacterSet characterSet, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, InvocationTargetException { try { return this.getJaxRsReader().readFrom((Class) type, genericType, annotations, Converter.toJaxRsMediaType(mediaType), httpHeaders, entityStream); } catch (Throwable t) { if (t instanceof IOException) throw (IOException) t; if (t instanceof WebApplicationException) throw (WebApplicationException) t; throw new InvocationTargetException(t); } } /** * Write a type to an HTTP response. The response header map is mutable but * any changes must be made before writing to the output stream since the * headers will be flushed prior to writing the response body. * * @param genericType * The generic {@link Type} to convert to. * @param annotations * the annotations of the artifact to convert to * @param mediaType * the media type of the HTTP entity. * @param httpHeaders * a mutable map of the HTTP response headers. * @param entityStream * the {@link OutputStream} for the HTTP entity. * @param object * the object to write. * * @throws java.io.IOException * if an IO error arises * @see javax.ws.rs.ext.MessageBodyWriter#writeTo(Object, Type, * Annotation[], javax.ws.rs.core.MediaType, MultivaluedMap, * OutputStream) */ public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { this.getJaxRsWriter().writeTo(object, type, genericType, annotations, Converter.toJaxRsMediaType(mediaType), httpHeaders, entityStream); } }