Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.cxf.jaxrs.provider.ProviderFactory Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.jaxrs.provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.ws.rs.BindingPriority;
import javax.ws.rs.Produces;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configurable;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.WriterInterceptor;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.ClassHelper;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
import org.apache.cxf.jaxrs.ext.ContextProvider;
import org.apache.cxf.jaxrs.ext.ParameterHandler;
import org.apache.cxf.jaxrs.ext.RequestHandler;
import org.apache.cxf.jaxrs.ext.ResponseHandler;
import org.apache.cxf.jaxrs.impl.HttpHeadersImpl;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.impl.ReaderInterceptorMBR;
import org.apache.cxf.jaxrs.impl.RequestPreprocessor;
import org.apache.cxf.jaxrs.impl.ResourceInfoImpl;
import org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper;
import org.apache.cxf.jaxrs.impl.WriterInterceptorMBW;
import org.apache.cxf.jaxrs.model.BeanParamInfo;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.model.ProviderInfo;
import org.apache.cxf.jaxrs.model.wadl.WadlGenerator;
import org.apache.cxf.jaxrs.utils.AnnotationUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
import org.apache.cxf.jaxrs.utils.JAXRSUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageUtils;
public final class ProviderFactory {
public static final String PROVIDER_SELECTION_PROPERTY_CHANGED = "provider.selection.property.changed";
static final String IGNORE_TYPE_VARIABLES = "org.apache.cxf.jaxrs.providers.ignore.typevars";
private static final Class>[] FILTER_INTERCEPTOR_CLASSES =
new Class>[] {ContainerRequestFilter.class,
ContainerResponseFilter.class,
ReaderInterceptor.class,
WriterInterceptor.class};
private static final String ACTIVE_JAXRS_PROVIDER_KEY = "active.jaxrs.provider";
private static final Logger LOG = LogUtils.getL7dLogger(ProviderFactory.class);
private static final ProviderFactory SHARED_FACTORY = getInstance();
private static final String DEFAULT_FILTER_NAME_BINDING = "org.apache.cxf.filter.binding";
private static final String JAXB_PROVIDER_NAME = "org.apache.cxf.jaxrs.provider.JAXBElementProvider";
private static final String JSON_PROVIDER_NAME = "org.apache.cxf.jaxrs.provider.json.JSONProvider";
private static final String BUS_PROVIDERS_ALL = "org.apache.cxf.jaxrs.bus.providers";
static {
SHARED_FACTORY.setProviders(new BinaryDataProvider(),
new SourceProvider(),
new DataSourceProvider(),
new FormEncodingProvider(),
new PrimitiveTextProvider(),
new MultipartProvider(),
new WebApplicationExceptionMapper(),
new WadlGenerator());
}
private List>> messageReaders =
new ArrayList>>();
private List>> messageWriters =
new ArrayList>>();
private List>> contextResolvers =
new ArrayList>>(1);
private List>> contextProviders =
new ArrayList>>(1);
private Set newParamConverters;
private LegacyParamConverterProvider legacyParamConverter;
private List>> jaxbReaders =
new ArrayList>>();
private List>> jaxbWriters =
new ArrayList>>();
private List> readerInterceptors =
new ArrayList>(1);
private List> writerInterceptors =
new ArrayList>(1);
// Server specific providers
private List>> exceptionMappers =
new ArrayList>>(1);
// RequestHandler & ResponseHandler will have to be deprecated for 2.7.0
private List> requestHandlers =
new ArrayList>(1);
private List> responseHandlers =
new ArrayList>(1);
// ContainerRequestFilter & ContainerResponseFilter are introduced in JAX-RS 2.0
private List> preMatchContainerRequestFilters =
new ArrayList>(1);
//TODO: consider using List as a value type for postmatching filters
private Map> postMatchContainerRequestFilters =
new LinkedHashMap>();
private Map> postMatchContainerResponseFilters =
new LinkedHashMap>();
private RequestPreprocessor requestPreprocessor;
private ProviderInfo application;
private List dynamicFeatures = new LinkedList();
// This may be better be kept at OperationResourceInfo ? Though we may have many methods
// across different resources that use the same BeanParam.
private Map, BeanParamInfo> beanParams = new HashMap, BeanParamInfo>();
// List of injected providers
private Collection> injectedProviders =
new LinkedList>();
//TODO: Client-only providers, consider introducing ClientProviderFactory,
// will make it easier to split the client API into a separate module
private List> clientRequestFilters =
new ArrayList>(1);
private List> clientResponseFilters =
new ArrayList>(1);
private List>> responseExceptionMappers =
new ArrayList>>(1);
private Bus bus;
private ProviderFactory(Bus bus) {
this.bus = bus;
initJaxbProviders();
setBusProviders();
}
public Bus getBus() {
return bus;
}
// Not ideal but in the end seems like the simplest option compared
// to adding default readers/writers to existing messageReaders/Writers
// (due to all sort of conflicts with custom providers) and cloning
// at the request time
private void initJaxbProviders() {
Object jaxbProvider = createProvider(JAXB_PROVIDER_NAME);
if (jaxbProvider != null) {
jaxbReaders.add(new ProviderInfo>((MessageBodyReader>)jaxbProvider, bus));
jaxbWriters.add(new ProviderInfo>((MessageBodyWriter>)jaxbProvider, bus));
}
Object jsonProvider = createProvider(JSON_PROVIDER_NAME);
if (jsonProvider != null) {
jaxbReaders.add(new ProviderInfo>((MessageBodyReader>)jsonProvider, bus));
jaxbWriters.add(new ProviderInfo>((MessageBodyWriter>)jsonProvider, bus));
}
injectContextProxies(jaxbReaders, jaxbWriters);
}
private static Object createProvider(String className) {
try {
return ClassLoaderUtils.loadClass(className, ProviderFactory.class).newInstance();
} catch (Throwable ex) {
String message = "Problem with creating the default provider " + className;
if (ex.getMessage() != null) {
message += ": " + ex.getMessage();
} else {
message += ", exception class : " + ex.getClass().getName();
}
LOG.fine(message);
}
return null;
}
public static ProviderFactory getInstance() {
return new ProviderFactory(BusFactory.getThreadDefaultBus());
}
public static ProviderFactory createInstance(Bus bus) {
return new ProviderFactory(bus);
}
public static ProviderFactory getInstance(Bus bus) {
return (ProviderFactory)bus.getProperty(ProviderFactory.class.getName());
}
public static ProviderFactory getInstance(Message m) {
Endpoint e = m.getExchange().get(Endpoint.class);
return (ProviderFactory)e.get(ProviderFactory.class.getName());
}
public static ProviderFactory getSharedInstance() {
return SHARED_FACTORY;
}
public void addBeanParamInfo(BeanParamInfo bpi) {
beanParams.put(bpi.getResourceClass(), bpi);
}
public BeanParamInfo getBeanParamInfo(Class> beanClass) {
return beanParams.get(beanClass);
}
public ContextResolver createContextResolver(Type contextType,
Message m) {
boolean isRequestor = MessageUtils.isRequestor(m);
Message requestMessage = isRequestor ? m.getExchange().getOutMessage()
: m.getExchange().getInMessage();
HttpHeaders requestHeaders = new HttpHeadersImpl(requestMessage);
MediaType mt = null;
Message responseMessage = isRequestor ? m.getExchange().getInMessage()
: m.getExchange().getOutMessage();
if (responseMessage != null) {
Object ctProperty = responseMessage.get(Message.CONTENT_TYPE);
if (ctProperty == null) {
List accepts = requestHeaders.getAcceptableMediaTypes();
if (accepts.size() > 0) {
mt = accepts.get(0);
}
} else {
mt = JAXRSUtils.toMediaType(ctProperty.toString());
}
} else {
mt = requestHeaders.getMediaType();
}
return createContextResolver(contextType, m,
mt == null ? MediaType.WILDCARD_TYPE : mt);
}
@SuppressWarnings("unchecked")
public ContextResolver createContextResolver(Type contextType,
Message m,
MediaType type) {
Class> contextCls = InjectionUtils.getActualType(contextType);
if (contextCls == null) {
return null;
}
List> candidates = new LinkedList>();
for (ProviderInfo> cr : contextResolvers) {
Type[] types = cr.getProvider().getClass().getGenericInterfaces();
for (Type t : types) {
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)t;
Type[] args = pt.getActualTypeArguments();
if (args.length > 0) {
Class> argCls = InjectionUtils.getActualType(args[0]);
if (argCls != null && argCls.isAssignableFrom(contextCls)) {
List mTypes = JAXRSUtils.getProduceTypes(
cr.getProvider().getClass().getAnnotation(Produces.class));
if (JAXRSUtils.intersectMimeTypes(mTypes, type).size() > 0) {
injectContextValues(cr, m);
candidates.add((ContextResolver)cr.getProvider());
}
}
}
}
}
}
if (candidates.size() == 0) {
return null;
} else if (candidates.size() == 1) {
return candidates.get(0);
} else {
Collections.sort(candidates, new ClassComparator());
return new ContextResolverProxy(candidates);
}
}
@SuppressWarnings("unchecked")
public ContextProvider createContextProvider(Type contextType,
Message m) {
Class> contextCls = InjectionUtils.getActualType(contextType);
if (contextCls == null) {
return null;
}
for (ProviderInfo> cr : contextProviders) {
Type[] types = cr.getProvider().getClass().getGenericInterfaces();
for (Type t : types) {
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)t;
Type[] args = pt.getActualTypeArguments();
if (args.length > 0) {
Class> argCls = InjectionUtils.getActualType(args[0]);
if (argCls != null && argCls.isAssignableFrom(contextCls)) {
return (ContextProvider)cr.getProvider();
}
}
}
}
}
return null;
}
public ExceptionMapper createExceptionMapper(Class> exceptionType,
Message m) {
ExceptionMapper mapper = doCreateExceptionMapper(exceptionType, m);
if (mapper != null || this == SHARED_FACTORY) {
return mapper;
}
return SHARED_FACTORY.createExceptionMapper(exceptionType, m);
}
@SuppressWarnings("unchecked")
private ExceptionMapper doCreateExceptionMapper(
Class> exceptionType, Message m) {
List> candidates = new LinkedList>();
for (ProviderInfo> em : exceptionMappers) {
handleMapper(candidates, em, exceptionType, m, ExceptionMapper.class, true);
}
if (candidates.size() == 0) {
return null;
}
Collections.sort(candidates, new ClassComparator(exceptionType));
return (ExceptionMapper) candidates.get(0);
}
public ParamConverter createParameterHandler(Class paramType, Annotation[] anns) {
if (newParamConverters != null) {
anns = anns != null ? anns : new Annotation[]{};
for (ParamConverterProvider newParamConverter : newParamConverters) {
ParamConverter converter = newParamConverter.getConverter(paramType, paramType, anns);
if (converter != null) {
return converter;
}
}
} else if (legacyParamConverter != null) {
return legacyParamConverter.getConverter(paramType, null, null);
}
return null;
}
@SuppressWarnings("unchecked")
public ResponseExceptionMapper createResponseExceptionMapper(
Message m, Class> paramType) {
List> candidates = new LinkedList>();
for (ProviderInfo> em : responseExceptionMappers) {
handleMapper(candidates, em, paramType, m, ResponseExceptionMapper.class, true);
}
if (candidates.size() == 0) {
return null;
}
Collections.sort(candidates, new ClassComparator(paramType));
return (ResponseExceptionMapper) candidates.get(0);
}
private static void handleMapper(List candidates,
ProviderInfo em,
Class> expectedType,
Message m,
Class> providerClass,
boolean injectContext) {
Class> mapperClass = ClassHelper.getRealClass(em.getProvider());
Type[] types = null;
if (m != null && MessageUtils.isTrue(m.getContextualProperty(IGNORE_TYPE_VARIABLES))) {
types = new Type[]{mapperClass};
} else {
types = getGenericInterfaces(mapperClass, expectedType);
}
for (Type t : types) {
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)t;
Type[] args = pt.getActualTypeArguments();
for (int i = 0; i < args.length; i++) {
Type arg = args[i];
if (arg instanceof TypeVariable) {
TypeVariable> var = (TypeVariable>)arg;
Type[] bounds = var.getBounds();
boolean isResolved = false;
for (int j = 0; j < bounds.length; j++) {
Class> cls = InjectionUtils.getRawType(bounds[j]);
if (cls != null && cls.isAssignableFrom(expectedType)) {
isResolved = true;
break;
}
}
if (!isResolved) {
return;
}
if (injectContext) {
injectContextValues(em, m);
}
candidates.add(em.getProvider());
return;
}
Class> actualClass = InjectionUtils.getRawType(arg);
if (actualClass == null) {
continue;
}
if (expectedType.isArray() && !actualClass.isArray()) {
expectedType = expectedType.getComponentType();
}
if (actualClass.isAssignableFrom(expectedType) || actualClass == Object.class) {
if (injectContext) {
injectContextValues(em, m);
}
candidates.add(em.getProvider());
return;
}
}
} else if (t instanceof Class && providerClass.isAssignableFrom((Class>)t)) {
if (injectContext) {
injectContextValues(em, m);
}
candidates.add(em.getProvider());
}
}
}
public List createMessageBodyReaderInterceptor(Class bodyType,
Type parameterType,
Annotation[] parameterAnnotations,
MediaType mediaType,
Message m) {
MessageBodyReader mr = createMessageBodyReader(bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
if (mr != null) {
ReaderInterceptor mbrReader = new ReaderInterceptorMBR(mr, m.getExchange().getInMessage());
int size = readerInterceptors.size();
List interceptors = null;
if (size > 0) {
interceptors = new ArrayList(size + 1);
for (ProviderInfo p : readerInterceptors) {
InjectionUtils.injectContexts(p.getProvider(), p, m);
interceptors.add(p.getProvider());
}
interceptors.add(mbrReader);
} else {
interceptors = Collections.singletonList(mbrReader);
}
return interceptors;
} else {
return null;
}
}
public List createMessageBodyWriterInterceptor(Class bodyType,
Type parameterType,
Annotation[] parameterAnnotations,
MediaType mediaType,
Message m) {
MessageBodyWriter mw = createMessageBodyWriter(bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
if (mw != null) {
@SuppressWarnings({
"unchecked", "rawtypes"
})
WriterInterceptor mbwWriter = new WriterInterceptorMBW((MessageBodyWriter)mw, m);
int size = writerInterceptors.size();
List interceptors = null;
if (size > 0) {
interceptors = new ArrayList(size + 1);
for (ProviderInfo p : writerInterceptors) {
InjectionUtils.injectContexts(p.getProvider(), p, m);
interceptors.add(p.getProvider());
}
interceptors.add(mbwWriter);
} else {
interceptors = Collections.singletonList(mbwWriter);
}
return interceptors;
} else {
return null;
}
}
public MessageBodyReader createMessageBodyReader(Class bodyType,
Type parameterType,
Annotation[] parameterAnnotations,
MediaType mediaType,
Message m) {
// Try user provided providers
MessageBodyReader mr = chooseMessageReader(messageReaders,
bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
if (mr == null) {
mr = chooseMessageReader(jaxbReaders,
bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
}
if (mr != null || SHARED_FACTORY == this) {
return mr;
}
return SHARED_FACTORY.createMessageBodyReader(bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
}
private boolean isJaxbBasedProvider(Object sharedProvider) {
String clsName = sharedProvider.getClass().getName();
return JAXB_PROVIDER_NAME.equals(clsName) || JSON_PROVIDER_NAME.equals(clsName);
}
public List> getPreMatchContainerRequestFilters() {
return Collections.unmodifiableList(preMatchContainerRequestFilters);
}
public List> getPostMatchContainerRequestFilters(List names) {
return getPostMatchContainerFilters(postMatchContainerRequestFilters,
names);
}
public List> getContainerResponseFilters(List names) {
return getPostMatchContainerFilters(postMatchContainerResponseFilters,
names);
}
public List> getClientRequestFilters() {
return Collections.unmodifiableList(clientRequestFilters);
}
public List> getClientResponseFilters() {
return Collections.unmodifiableList(clientResponseFilters);
}
//TODO: Also sort based on BindingPriority
private static List> getPostMatchContainerFilters(Map> boundFilters,
List names) {
if (boundFilters.isEmpty()) {
return Collections.emptyList();
}
names = names == null ? Collections.emptyList() : names;
MultivaluedMap, String> map =
new MetadataMap, String>();
for (Map.Entry> entry : boundFilters.entrySet()) {
String entryName = entry.getKey().getName();
if (entryName.equals(DEFAULT_FILTER_NAME_BINDING)) {
map.put(entry.getValue(), Collections.emptyList());
} else {
if (entryName.endsWith(":dynamic") && !names.contains(entryName)) {
continue;
}
map.add(entry.getValue(), entryName);
}
}
List> list = new LinkedList>();
for (Map.Entry, List> entry : map.entrySet()) {
if (names.containsAll(entry.getValue())) {
list.add(entry.getKey());
}
}
return list;
}
public List> getRequestHandlers() {
List> handlers = null;
if (requestHandlers.size() == 0) {
handlers = SHARED_FACTORY.requestHandlers;
} else {
handlers = new ArrayList>();
boolean customWADLHandler = false;
for (int i = 0; i < requestHandlers.size(); i++) {
if (requestHandlers.get(i).getProvider() instanceof WadlGenerator) {
customWADLHandler = true;
break;
}
}
if (!customWADLHandler) {
// TODO : this works only because we know we only have a single
// system handler which is a default WADLGenerator, think of a better approach
handlers.addAll(SHARED_FACTORY.requestHandlers);
}
handlers.addAll(requestHandlers);
}
return Collections.unmodifiableList(handlers);
}
public List> getResponseHandlers() {
return Collections.unmodifiableList(responseHandlers);
}
public MessageBodyWriter createMessageBodyWriter(Class bodyType,
Type parameterType,
Annotation[] parameterAnnotations,
MediaType mediaType,
Message m) {
// Try user provided providers
MessageBodyWriter mw = chooseMessageWriter(messageWriters,
bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
if (mw == null) {
mw = chooseMessageWriter(jaxbWriters,
bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
}
if (mw != null || SHARED_FACTORY == this) {
return mw;
}
return SHARED_FACTORY.createMessageBodyWriter(bodyType,
parameterType,
parameterAnnotations,
mediaType,
m);
}
private void setBusProviders() {
List extensions = new LinkedList();
final String alreadySetProp = "bus.providers.set";
if (bus.getProperty(alreadySetProp) == null) {
addBusExtension(extensions,
MessageBodyReader.class,
MessageBodyWriter.class,
ExceptionMapper.class);
if (!extensions.isEmpty()) {
setProviders(extensions.toArray());
bus.setProperty(alreadySetProp, "");
}
}
}
private void addBusExtension(List extensions, Class>... extClasses) {
for (Class> extClass : extClasses) {
Object ext = bus.getProperty(extClass.getName());
if (extClass.isInstance(ext)) {
extensions.add(ext);
}
}
Object allProp = bus.getProperty(BUS_PROVIDERS_ALL);
if (allProp instanceof List) {
@SuppressWarnings("unchecked")
List all = (List)allProp;
extensions.addAll(all);
}
}
//CHECKSTYLE:OFF
private void setProviders(Object... providers) {
List> postMatchRequestFilters =
new LinkedList>();
List> postMatchResponseFilters =
new LinkedList>();
for (Object o : providers) {
if (o == null) {
continue;
}
Class> oClass = ClassHelper.getRealClass(o);
if (MessageBodyReader.class.isAssignableFrom(oClass)) {
messageReaders.add(new ProviderInfo>((MessageBodyReader>)o, bus));
}
if (MessageBodyWriter.class.isAssignableFrom(oClass)) {
messageWriters.add(new ProviderInfo>((MessageBodyWriter>)o, bus));
}
if (ContextResolver.class.isAssignableFrom(oClass)) {
contextResolvers.add(new ProviderInfo>((ContextResolver>)o, bus));
}
if (ContextProvider.class.isAssignableFrom(oClass)) {
contextProviders.add(new ProviderInfo>((ContextProvider>)o, bus));
}
if (RequestHandler.class.isAssignableFrom(oClass)) {
requestHandlers.add(new ProviderInfo((RequestHandler)o, bus));
}
if (ResponseHandler.class.isAssignableFrom(oClass)) {
responseHandlers.add(new ProviderInfo((ResponseHandler)o, bus));
}
if (ContainerRequestFilter.class.isAssignableFrom(oClass)) {
addContainerFilter(postMatchRequestFilters,
new ProviderInfo((ContainerRequestFilter)o, bus),
preMatchContainerRequestFilters);
}
if (ContainerResponseFilter.class.isAssignableFrom(oClass)) {
addContainerFilter(postMatchResponseFilters,
new ProviderInfo((ContainerResponseFilter)o, bus),
null);
}
if (ReaderInterceptor.class.isAssignableFrom(oClass)) {
readerInterceptors.add(
new ProviderInfo((ReaderInterceptor)o, bus));
}
if (WriterInterceptor.class.isAssignableFrom(oClass)) {
writerInterceptors.add(
new ProviderInfo((WriterInterceptor)o, bus));
}
if (DynamicFeature.class.isAssignableFrom(oClass)) {
dynamicFeatures.add((DynamicFeature)o);
}
if (ClientRequestFilter.class.isAssignableFrom(oClass)) {
clientRequestFilters.add(
new ProviderInfo((ClientRequestFilter)o, bus));
}
if (ClientResponseFilter.class.isAssignableFrom(oClass)) {
clientResponseFilters.add(
new ProviderInfo((ClientResponseFilter)o, bus));
}
if (ExceptionMapper.class.isAssignableFrom(oClass)) {
exceptionMappers.add(new ProviderInfo>((ExceptionMapper>)o, bus));
}
if (ResponseExceptionMapper.class.isAssignableFrom(oClass)) {
responseExceptionMappers.add(new ProviderInfo>((ResponseExceptionMapper>)o, bus));
}
if (ParamConverterProvider.class.isAssignableFrom(oClass)) {
if (newParamConverters == null) {
newParamConverters = new LinkedHashSet();
}
newParamConverters.add((ParamConverterProvider)o);
}
if (ParameterHandler.class.isAssignableFrom(oClass)) {
if (legacyParamConverter == null) {
legacyParamConverter = new LegacyParamConverterProvider();
}
legacyParamConverter.add(o, bus);
}
}
sortReaders();
sortWriters();
sortContextResolvers();
Collections.sort(preMatchContainerRequestFilters, new BindingPriorityComparator(true));
mapContainerFilters(postMatchContainerRequestFilters, postMatchRequestFilters, true);
mapContainerFilters(postMatchContainerResponseFilters, postMatchResponseFilters, false);
Collections.sort(readerInterceptors, new BindingPriorityComparator(true));
Collections.sort(writerInterceptors, new BindingPriorityComparator(false));
Collections.sort(clientRequestFilters, new BindingPriorityComparator(true));
Collections.sort(clientResponseFilters, new BindingPriorityComparator(false));
injectContextProxies(messageReaders, messageWriters, contextResolvers,
requestHandlers, responseHandlers, exceptionMappers,
postMatchContainerRequestFilters.values(), preMatchContainerRequestFilters,
postMatchContainerResponseFilters.values(),
responseExceptionMappers, clientRequestFilters, clientResponseFilters,
readerInterceptors, writerInterceptors);
}
//CHECKSTYLE:ON
private static void mapContainerFilters(Map> map,
List> postMatchFilters,
boolean ascending) {
Collections.sort(postMatchFilters, new PostMatchFilterComparator(ascending));
for (ProviderInfo p : postMatchFilters) {
List names = AnnotationUtils.getNameBindings(
p.getProvider().getClass().getAnnotations());
names = names.isEmpty() ? Collections.singletonList(DEFAULT_FILTER_NAME_BINDING) : names;
for (String name : names) {
map.put(new NameKey(name, AnnotationUtils.getBindingPriority(p.getProvider().getClass())),
p);
}
}
}
private static void addContainerFilter(List> postMatchFilters,
ProviderInfo p,
List> preMatchFilters) {
T filter = p.getProvider();
if (preMatchFilters != null && isPrematching(filter.getClass())) {
preMatchFilters.add(p);
} else {
postMatchFilters.add(p);
}
}
private static boolean isPrematching(Class> filterCls) {
return AnnotationUtils.getAnnotation(filterCls.getAnnotations(),
PreMatching.class) != null;
}
static void injectContextValues(ProviderInfo> pi, Message m) {
if (m != null) {
InjectionUtils.injectContexts(pi.getProvider(), pi, m);
}
}
void injectContextProxies(Collection> ... providerLists) {
for (Collection> list : providerLists) {
Collection> l2 = CastUtils.cast(list);
for (ProviderInfo> pi : l2) {
if (ProviderFactory.SHARED_FACTORY == this && isJaxbBasedProvider(pi.getProvider())) {
continue;
}
injectContextProxiesIntoProvider(pi);
}
}
}
void injectContextProxiesIntoProvider(ProviderInfo> pi) {
if (pi.contextsAvailable()) {
InjectionUtils.injectContextProxies(pi, pi.getProvider());
synchronized (injectedProviders) {
injectedProviders.add(pi);
}
}
}
/*
* sorts the available providers according to the media types they declare
* support for. Sorting of media types follows the general rule: x/y < * x < *,
* i.e. a provider that explicitly lists a media types is sorted before a
* provider that lists *. Quality parameter values are also used such that
* x/y;q=1.0 < x/y;q=0.7.
*/
private void sortReaders() {
Collections.sort(messageReaders, new MessageBodyReaderComparator());
}
private void sortWriters() {
Collections.sort(messageWriters, new MessageBodyWriterComparator());
}
private void sortContextResolvers() {
Collections.sort(contextResolvers, new ContextResolverComparator());
}
/**
* Choose the first body reader provider that matches the requestedMimeType
* for a sorted list of Entity providers
* Returns null if none is found.
* @param
* @param messageBodyReaders
* @param type
* @param requestedMimeType
* @return
*/
@SuppressWarnings("unchecked")
private MessageBodyReader chooseMessageReader(List>> readers,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
Message m) {
List> candidates = new LinkedList>();
for (ProviderInfo> ep : readers) {
if (matchesReaderCriterias(ep, type, genericType, annotations, mediaType, m)) {
if (this == SHARED_FACTORY) {
return (MessageBodyReader) ep.getProvider();
}
handleMapper(candidates, ep, type, m, MessageBodyReader.class, false);
}
}
if (candidates.size() == 0) {
return null;
}
Collections.sort(candidates, new ClassComparator());
return (MessageBodyReader) candidates.get(0);
}
private boolean matchesReaderCriterias(ProviderInfo> pi,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
Message m) {
MessageBodyReader> ep = pi.getProvider();
List supportedMediaTypes = JAXRSUtils.getProviderConsumeTypes(ep);
List availableMimeTypes =
JAXRSUtils.intersectMimeTypes(Collections.singletonList(mediaType), supportedMediaTypes, false);
if (availableMimeTypes.size() == 0) {
return false;
}
if (this != SHARED_FACTORY || !isJaxbBasedProvider(ep)) {
injectContextValues(pi, m);
}
return ep.isReadable(type, genericType, annotations, mediaType);
}
/**
* Choose the first body writer provider that matches the requestedMimeType
* for a sorted list of Entity providers
* Returns null if none is found.
* @param
* @param messageBodyWriters
* @param type
* @param requestedMimeType
* @return
*/
@SuppressWarnings("unchecked")
private MessageBodyWriter chooseMessageWriter(List>> writers,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
Message m) {
List> candidates = new LinkedList>();
for (ProviderInfo> ep : writers) {
if (matchesWriterCriterias(ep, type, genericType, annotations, mediaType, m)) {
if (this == SHARED_FACTORY) {
return (MessageBodyWriter) ep.getProvider();
}
handleMapper(candidates, ep, type, m, MessageBodyWriter.class, false);
}
}
if (candidates.size() == 0) {
return null;
}
Collections.sort(candidates, new ClassComparator());
return (MessageBodyWriter) candidates.get(0);
}
private boolean matchesWriterCriterias(ProviderInfo> pi,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
Message m) {
MessageBodyWriter> ep = pi.getProvider();
List supportedMediaTypes = JAXRSUtils.getProviderProduceTypes(ep);
List availableMimeTypes =
JAXRSUtils.intersectMimeTypes(Collections.singletonList(mediaType),
supportedMediaTypes, false);
if (availableMimeTypes.size() == 0) {
return false;
}
if ((this != SHARED_FACTORY || !isJaxbBasedProvider(ep))
&& m.get(ACTIVE_JAXRS_PROVIDER_KEY) != ep) {
injectContextValues(pi, m);
}
return ep.isWriteable(type, genericType, annotations, mediaType);
}
List>> getMessageReaders() {
return Collections.unmodifiableList(messageReaders);
}
List>> getMessageWriters() {
return Collections.unmodifiableList(messageWriters);
}
List>> getContextResolvers() {
return Collections.unmodifiableList(contextResolvers);
}
public void registerUserProvider(Object provider) {
setUserProviders(Collections.singletonList(provider));
}
/**
* Use for injection of entityProviders
* @param entityProviders the entityProviders to set
*/
public void setUserProviders(List> userProviders) {
setProviders(userProviders.toArray());
}
private static class MessageBodyReaderComparator
implements Comparator>> {
public int compare(ProviderInfo> p1,
ProviderInfo> p2) {
MessageBodyReader> e1 = p1.getProvider();
MessageBodyReader> e2 = p2.getProvider();
List types1 = JAXRSUtils.getProviderConsumeTypes(e1);
types1 = JAXRSUtils.sortMediaTypes(types1, null);
List types2 = JAXRSUtils.getProviderConsumeTypes(e2);
types2 = JAXRSUtils.sortMediaTypes(types2, null);
return JAXRSUtils.compareSortedMediaTypes(types1, types2, null);
}
}
private static class MessageBodyWriterComparator
implements Comparator>> {
public int compare(ProviderInfo> p1,
ProviderInfo> p2) {
MessageBodyWriter> e1 = p1.getProvider();
MessageBodyWriter> e2 = p2.getProvider();
List types1 =
JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(e1), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
List types2 =
JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(e2), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
return JAXRSUtils.compareSortedMediaTypes(types1, types2, JAXRSUtils.MEDIA_TYPE_QS_PARAM);
}
}
private static class ContextResolverComparator
implements Comparator>> {
public int compare(ProviderInfo> p1,
ProviderInfo> p2) {
ContextResolver> e1 = p1.getProvider();
ContextResolver> e2 = p2.getProvider();
List types1 =
JAXRSUtils.sortMediaTypes(JAXRSUtils.getProduceTypes(
e1.getClass().getAnnotation(Produces.class)), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
List types2 =
JAXRSUtils.sortMediaTypes(JAXRSUtils.getProduceTypes(
e2.getClass().getAnnotation(Produces.class)), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
return JAXRSUtils.compareSortedMediaTypes(types1, types2, JAXRSUtils.MEDIA_TYPE_QS_PARAM);
}
}
public void setApplicationProvider(ProviderInfo app) {
application = app;
}
public void setRequestPreprocessor(RequestPreprocessor rp) {
this.requestPreprocessor = rp;
}
public RequestPreprocessor getRequestPreprocessor() {
return requestPreprocessor;
}
public void clearExceptionMapperProxies() {
clearProxies(exceptionMappers);
}
public void clearThreadLocalProxies() {
clearProxies(injectedProviders);
if (application != null) {
application.clearThreadLocalProxies();
}
if (this != SHARED_FACTORY) {
SHARED_FACTORY.clearThreadLocalProxies();
}
}
void clearProxies(Collection> ...lists) {
for (Collection> list : lists) {
Collection> l2 = CastUtils.cast(list);
synchronized (l2) {
for (ProviderInfo> pi : l2) {
pi.clearThreadLocalProxies();
}
}
}
}
public void clearProviders() {
messageReaders.clear();
messageWriters.clear();
contextResolvers.clear();
contextProviders.clear();
exceptionMappers.clear();
requestHandlers.clear();
responseHandlers.clear();
postMatchContainerRequestFilters.clear();
postMatchContainerResponseFilters.clear();
preMatchContainerRequestFilters.clear();
if (legacyParamConverter != null) {
legacyParamConverter.clear();
}
responseExceptionMappers.clear();
clientRequestFilters.clear();
clientResponseFilters.clear();
}
public void setBus(Bus bus) {
if (bus == null) {
return;
}
for (ProviderInfo> r : messageReaders) {
injectProviderProperty(r.getProvider(), "setBus", Bus.class, bus);
}
}
public void applyDynamicFeatures(List list) {
if (dynamicFeatures.size() > 0) {
for (ClassResourceInfo cri : list) {
doApplyDynamicFeatures(cri);
}
}
}
private void doApplyDynamicFeatures(ClassResourceInfo cri) {
Set oris = cri.getMethodDispatcher().getOperationResourceInfos();
for (OperationResourceInfo ori : oris) {
for (DynamicFeature feature : dynamicFeatures) {
Configurable methodConfigurable = new MethodConfigurable(ori);
feature.configure(new ResourceInfoImpl(ori), methodConfigurable);
}
}
Collection subs = cri.getSubResources();
for (ClassResourceInfo sub : subs) {
if (sub != cri) {
doApplyDynamicFeatures(sub);
}
}
}
private boolean injectProviderProperty(Object provider, String mName, Class> pClass,
Object pValue) {
try {
Method m = provider.getClass().getMethod(mName, new Class[]{pClass});
m.invoke(provider, new Object[]{pValue});
return true;
} catch (Exception ex) {
// ignore
}
return false;
}
public void setSchemaLocations(List schemas) {
boolean schemasMethodAvailable = false;
for (ProviderInfo> r : messageReaders) {
schemasMethodAvailable =
injectProviderProperty(r.getProvider(), "setSchemaLocations", List.class, schemas);
}
if (!schemasMethodAvailable) {
for (ProviderInfo> r : jaxbReaders) {
injectProviderProperty(r.getProvider(), "setSchemaLocations", List.class, schemas);
}
}
}
public void initProviders(List cris) {
Set set = getReadersWriters();
for (Object o : set) {
Object provider = ((ProviderInfo>)o).getProvider();
if (provider instanceof AbstractConfigurableProvider) {
((AbstractConfigurableProvider)provider).init(cris);
}
}
if (this != SHARED_FACTORY) {
SHARED_FACTORY.initProviders(cris);
}
}
Set getReadersWriters() {
Set set = new HashSet();
set.addAll(messageReaders);
set.addAll(jaxbReaders);
set.addAll(messageWriters);
set.addAll(jaxbWriters);
return set;
}
private static class ClassComparator implements
Comparator {
private Class> expectedCls;
public ClassComparator() {
}
public ClassComparator(Class> expectedCls) {
this.expectedCls = expectedCls;
}
public int compare(Object em1, Object em2) {
return compareClasses(expectedCls, em1, em2);
}
}
protected static int compareClasses(Class> expectedCls, Object o1, Object o2) {
Class> cl1 = ClassHelper.getRealClass(o1);
Class> cl2 = ClassHelper.getRealClass(o2);
Type[] types1 = getGenericInterfaces(cl1, expectedCls);
Type[] types2 = getGenericInterfaces(cl2, expectedCls);
if (types1.length == 0 && types2.length == 0) {
return 0;
} else if (types1.length == 0 && types2.length > 0) {
return 1;
} else if (types1.length > 0 && types2.length == 0) {
return -1;
}
Class> realClass1 = InjectionUtils.getActualType(types1[0]);
Class> realClass2 = InjectionUtils.getActualType(types2[0]);
if (realClass1 == realClass2) {
return 0;
}
if (realClass1.isAssignableFrom(realClass2)) {
// subclass should go first
return 1;
}
return -1;
}
private static Type[] getGenericInterfaces(Class> cls, Class> expectedClass) {
if (Object.class == cls) {
return new Type[]{};
}
if (expectedClass != null) {
Type genericSuperType = cls.getGenericSuperclass();
if (genericSuperType instanceof ParameterizedType) {
Class> actualType = InjectionUtils.getActualType(genericSuperType);
if (actualType != null && actualType.isAssignableFrom(expectedClass)) {
return new Type[]{genericSuperType};
} else if (expectedClass.isAssignableFrom(actualType)) {
return new Type[]{};
}
}
}
Type[] types = cls.getGenericInterfaces();
if (types.length > 0) {
return types;
}
return getGenericInterfaces(cls.getSuperclass(), expectedClass);
}
private static class PostMatchFilterComparator extends BindingPriorityComparator {
public PostMatchFilterComparator(boolean ascending) {
super(ascending);
}
@Override
public int compare(ProviderInfo> p1, ProviderInfo> p2) {
int result = super.compare(p1, p2);
if (result == 0) {
Integer namesSize1 =
AnnotationUtils.getNameBindings(p1.getProvider().getClass().getAnnotations()).size();
Integer namesSize2 =
AnnotationUtils.getNameBindings(p2.getProvider().getClass().getAnnotations()).size();
// if we have two filters with the same binding priority,
// then put a filter with more name bindings upfront
// (this effectively puts name bound filters before global ones)
result = namesSize1.compareTo(namesSize2) * -1;
}
return result;
}
}
private static class BindingPriorityComparator extends AbstactBindingPriorityComparator {
public BindingPriorityComparator(boolean ascending) {
super(ascending);
}
}
private abstract static class AbstactBindingPriorityComparator implements
Comparator> {
private boolean ascending;
protected AbstactBindingPriorityComparator(boolean ascending) {
this.ascending = ascending;
}
public int compare(ProviderInfo> p1, ProviderInfo> p2) {
Integer b1Value = getBindingPriorityValue(p1);
Integer b2Value = getBindingPriorityValue(p2);
int result = b1Value.compareTo(b2Value);
return ascending ? result : result * -1;
}
private int getBindingPriorityValue(ProviderInfo> p) {
return AnnotationUtils.getBindingPriority(p.getProvider().getClass());
}
}
static class ContextResolverProxy implements ContextResolver {
private List> candidates;
public ContextResolverProxy(List> candidates) {
this.candidates = candidates;
}
public T getContext(Class> cls) {
for (ContextResolver resolver : candidates) {
T context = resolver.getContext(cls);
if (context != null) {
return context;
}
}
return null;
}
public List> getResolvers() {
return candidates;
}
}
private static class NameKey {
private String name;
private int bindingPriority;
public NameKey(String name, int priority) {
this.name = name;
this.bindingPriority = priority;
}
public String getName() {
return name;
}
public int getPriority() {
return bindingPriority;
}
}
private class MethodConfigurable implements Configurable {
private OperationResourceInfo ori;
private String nameBinding;
private boolean bindingSet;
public MethodConfigurable(OperationResourceInfo ori) {
this.ori = ori;
nameBinding = DEFAULT_FILTER_NAME_BINDING
+ ori.getClassResourceInfo().getServiceClass().getName()
+ "."
+ ori.getMethodToInvoke().toString()
+ ":dynamic";
}
@Override
public Configurable register(Object provider) {
return register(provider, AnnotationUtils.getBindingPriority(provider.getClass()));
}
@Override
public Configurable register(Object provider, int bindingPriority) {
return doRegister(provider, bindingPriority, FILTER_INTERCEPTOR_CLASSES);
}
@Override
public Configurable register(Object provider, Class super T>... contracts) {
return register(provider, BindingPriority.USER, contracts);
}
@Override
public Configurable register(Object provider, int bindingPriority, Class super T>... contracts) {
return doRegister(provider, bindingPriority, contracts);
}
@Override
public Configurable register(Class> providerClass) {
return register(providerClass, AnnotationUtils.getBindingPriority(providerClass));
}
@Override
public Configurable register(Class> providerClass, int bindingPriority) {
return doRegister(createProvider(providerClass), bindingPriority,
FILTER_INTERCEPTOR_CLASSES);
}
@Override
public Configurable register(Class providerClass, Class super T>... contracts) {
return register(providerClass, BindingPriority.USER, contracts);
}
@Override
public Configurable register(Class providerClass, int bindingPriority,
Class super T>... contracts) {
return doRegister(createProvider(providerClass), bindingPriority, contracts);
}
private Configurable doRegister(Object provider, int bindingPriority, Class>... contracts) {
if (provider instanceof Feature) {
((Feature)provider).configure(this);
return this;
}
boolean setIsNeeded = false;
for (Class> contract : contracts) {
if (contract == ContainerRequestFilter.class && provider instanceof ContainerRequestFilter) {
if (isPrematching(provider.getClass())) {
addToInterceptors(preMatchContainerRequestFilters, provider, bindingPriority, true);
} else {
postMatchContainerRequestFilters =
addToPostMatching(postMatchContainerRequestFilters, provider, bindingPriority, true);
setIsNeeded = true;
}
}
if (contract == ContainerResponseFilter.class && provider instanceof ContainerResponseFilter) {
postMatchContainerResponseFilters =
addToPostMatching(postMatchContainerResponseFilters, provider, bindingPriority, false);
setIsNeeded = true;
}
if (contract == ReaderInterceptor.class && provider instanceof ReaderInterceptor) {
addToInterceptors(readerInterceptors, provider, bindingPriority, true);
}
if (contract == WriterInterceptor.class && provider instanceof WriterInterceptor) {
addToInterceptors(writerInterceptors, provider, bindingPriority, false);
}
}
if (setIsNeeded && !bindingSet) {
ori.addNameBindings(Collections.singletonList(nameBinding));
bindingSet = true;
}
return this;
}
@SuppressWarnings("unchecked")
private void addToInterceptors(List> providers, Object provider,
int priority, boolean asc) {
int size = providers.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
int providerPriority = AnnotationUtils.getBindingPriority(
providers.get(i).getProvider().getClass());
if (asc) {
if (priority < providerPriority || i + 1 == size) {
int index = priority < providerPriority ? i : i + 1;
providers.add(index, (ProviderInfo)newProvider(provider));
break;
}
} else if (priority > providerPriority || i + 1 == size) {
int index = priority > providerPriority ? i : i + 1;
providers.add(index, (ProviderInfo)newProvider(provider));
break;
}
}
} else {
providers.add((ProviderInfo)newProvider(provider));
}
}
private ProviderInfo