com.sun.jersey.server.impl.application.WebApplicationImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jersey-bundle Show documentation
Show all versions of jersey-bundle Show documentation
A bundle containing code of all jar-based modules that provide
JAX-RS and Jersey-related features. Such a bundle is *only intended* for
developers that do not use Maven's dependency system.
The bundle does not include code for contributes, tests and samples.
/*
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. 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 https://jersey.dev.java.net/CDDL+GPL.html
* or jersey/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 jersey/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [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 com.sun.jersey.server.impl.application;
import com.sun.jersey.server.impl.container.filter.FilterFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.ExceptionMapper;
import com.sun.jersey.api.NotFoundException;
import com.sun.jersey.api.container.ContainerException;
import com.sun.jersey.api.container.MappableContainerException;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.api.core.HttpResponseContext;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.api.core.ResourceContext;
import com.sun.jersey.api.model.AbstractResource;
import com.sun.jersey.api.model.ResourceModelIssue;
import com.sun.jersey.api.core.ExtendedUriInfo;
import com.sun.jersey.api.uri.UriTemplate;
import com.sun.jersey.core.spi.component.ComponentInjector;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProvider;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProviderFactory;
import com.sun.jersey.core.spi.component.ioc.IoCProviderFactory;
import com.sun.jersey.core.spi.component.ProviderFactory;
import com.sun.jersey.core.spi.component.ProviderServices;
import com.sun.jersey.impl.ImplMessages;
import com.sun.jersey.server.impl.ThreadLocalHttpContext;
import com.sun.jersey.server.impl.model.ResourceClass;
import com.sun.jersey.server.impl.model.RulesMap;
import com.sun.jersey.server.impl.model.parameter.CookieParamInjectableProvider;
import com.sun.jersey.server.impl.model.parameter.HeaderParamInjectableProvider;
import com.sun.jersey.server.impl.model.parameter.HttpContextInjectableProvider;
import com.sun.jersey.server.impl.model.parameter.MatrixParamInjectableProvider;
import com.sun.jersey.server.impl.model.parameter.PathParamInjectableProvider;
import com.sun.jersey.server.impl.model.parameter.QueryParamInjectableProvider;
import com.sun.jersey.server.impl.modelapi.annotation.IntrospectionModeller;
import com.sun.jersey.server.impl.modelapi.validation.BasicValidator;
import com.sun.jersey.server.impl.template.TemplateFactory;
import com.sun.jersey.server.impl.uri.PathPattern;
import com.sun.jersey.server.impl.uri.PathTemplate;
import com.sun.jersey.server.impl.uri.rules.ResourceClassRule;
import com.sun.jersey.server.impl.uri.rules.ResourceObjectRule;
import com.sun.jersey.server.impl.uri.rules.RightHandPathRule;
import com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule;
import com.sun.jersey.server.impl.wadl.WadlFactory;
import com.sun.jersey.server.impl.wadl.WadlResource;
import com.sun.jersey.server.impl.inject.ServerInjectableProviderContext;
import com.sun.jersey.server.impl.inject.ServerInjectableProviderFactory;
import com.sun.jersey.spi.MessageBodyWorkers;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
import com.sun.jersey.spi.container.ContainerResponseWriter;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.core.spi.factory.ContextResolverFactory;
import com.sun.jersey.core.spi.factory.MessageBodyFactory;
import com.sun.jersey.server.impl.component.IoCResourceFactory;
import com.sun.jersey.server.impl.component.ResourceFactory;
import com.sun.jersey.spi.inject.Inject;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.sun.jersey.spi.inject.SingletonTypeInjectableProvider;
import com.sun.jersey.spi.inject.InjectableProviderContext;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProcessor;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProcessorFactory;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProcessorFactoryInitializer;
import com.sun.jersey.core.util.FeaturesAndProperties;
import com.sun.jersey.server.impl.model.parameter.multivalued.MultivaluedParameterExtractorFactory;
import com.sun.jersey.server.impl.model.parameter.multivalued.MultivaluedParameterExtractorProvider;
import com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderFactory;
import com.sun.jersey.server.impl.resource.PerRequestFactory;
import com.sun.jersey.server.spi.component.ResourceComponentInjector;
import com.sun.jersey.spi.StringReaderWorkers;
import com.sun.jersey.spi.template.TemplateContext;
import com.sun.jersey.spi.uri.rules.UriRule;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Providers;
/**
* A Web application that contains a set of resources, each referenced by
* an absolute URI template.
*
* @author [email protected]
*/
public final class WebApplicationImpl implements WebApplication {
private static final Logger LOGGER = Logger.getLogger(WebApplicationImpl.class.getName());
private final Map abstractResourceMap =
new HashMap();
private final ConcurrentMap metaClassMap =
new ConcurrentHashMap();
private final ThreadLocalHttpContext context;
private final CloseableServiceFactory closeableFactory;
private boolean initiated;
private ResourceConfig resourceConfig;
private RootResourceClassesRule rootsRule;
private ServerInjectableProviderFactory injectableFactory;
private ProviderFactory cpFactory;
private ResourceFactory rcpFactory;
private IoCComponentProviderFactory provider;
private List providerFactories;
private MessageBodyFactory bodyFactory;
private StringReaderFactory stringReaderFactory;
private TemplateContext templateContext;
private ExceptionMapperFactory exceptionFactory;
private ResourceMethodDispatcherFactory dispatcherFactory;
private ResourceContext resourceContext;
private FilterFactory filterFactory;
private WadlFactory wadlFactory;
public WebApplicationImpl() {
this.context = new ThreadLocalHttpContext();
InvocationHandler requestHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(context.getRequest(), args);
}
};
InvocationHandler uriInfoHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(context.getUriInfo(), args);
}
};
// Create injectable provider factory
this.injectableFactory = new ServerInjectableProviderFactory();
injectableFactory.add(new ContextInjectableProvider(
InjectableProviderContext.class, injectableFactory));
injectableFactory.add(new ContextInjectableProvider(
ServerInjectableProviderContext.class, injectableFactory));
// Add proxied injectables
final Map m = new HashMap();
m.put(HttpContext.class, context);
m.put(HttpHeaders.class, createProxy(HttpHeaders.class, requestHandler));
m.put(UriInfo.class, createProxy(UriInfo.class, uriInfoHandler));
m.put(ExtendedUriInfo.class, createProxy(ExtendedUriInfo.class, uriInfoHandler));
m.put(Request.class, createProxy(Request.class, requestHandler));
m.put(SecurityContext.class, createProxy(SecurityContext.class, requestHandler));
injectableFactory.add(new InjectableProvider() {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext ic, Context a, Type c) {
final Object o = m.get(c);
if (o != null) {
return new Injectable() {
public Object getValue() {
return o;
}
};
} else
return null;
}
});
injectableFactory.add(new InjectableProvider() {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext ic, Context a, Type c) {
if (c instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)c;
if (pt.getRawType() == Injectable.class) {
if (pt.getActualTypeArguments().length == 1) {
final Injectable> i = injectableFactory.getInjectable(
a.annotationType(),
ic,
a,
pt.getActualTypeArguments()[0],
ComponentScope.PERREQUEST_UNDEFINED_SINGLETON);
return new Injectable() {
public Injectable getValue() {
return i;
}
};
}
}
}
return null;
}
});
closeableFactory = new CloseableServiceFactory(context);
injectableFactory.add(closeableFactory);
}
private class ComponentProcessorImpl implements IoCComponentProcessor {
private final ResourceComponentInjector rci;
ComponentProcessorImpl(ComponentScope s, AbstractResource resource) {
this.rci = new ResourceComponentInjector(injectableFactory, s, resource);
}
public void preConstruct() {
}
public void postConstruct(Object o) {
rci.inject(context.get(), o);
}
}
private class ComponentProcessorFactoryImpl implements IoCComponentProcessorFactory {
private final ConcurrentMap componentProcessorMap =
new ConcurrentHashMap();
public IoCComponentProcessor get(Class c, ComponentScope scope) {
IoCComponentProcessor cp = componentProcessorMap.get(c);
if (cp != null) {
return cp;
}
synchronized (metaClassMap) {
cp = componentProcessorMap.get(c);
if (cp != null) {
return cp;
}
cp = new ComponentProcessorImpl(scope, getAbstractResource(c));
componentProcessorMap.put(c, cp);
}
return cp;
}
}
@Override
public WebApplication clone() {
WebApplicationImpl wa = new WebApplicationImpl();
wa.initiate(resourceConfig, provider);
return wa;
}
public ResourceClass getResourceClass(Class c) {
assert c != null;
// Try the non-blocking read, the most common opertaion
ResourceClass rc = metaClassMap.get(c);
if (rc != null) {
return rc;
}
// ResourceClass is not present use a synchronized block
// to ensure that only one ResourceClass instance is created
// and put to the map
synchronized (metaClassMap) {
// One or more threads may have been blocking on the synchronized
// block, re-check the map
rc = metaClassMap.get(c);
if (rc != null) {
return rc;
}
rc = newResourceClass(getAbstractResource(c));
metaClassMap.put(c, rc);
rc.init(rcpFactory);
}
return rc;
}
private ResourceClass getResourceClass(AbstractResource ar) {
ResourceClass rc = newResourceClass(ar);
metaClassMap.put(ar.getResourceClass(), rc);
rc.init(rcpFactory);
return rc;
}
private ResourceClass newResourceClass(final AbstractResource ar) {
assert null != ar;
BasicValidator validator = new BasicValidator();
validator.validate(ar);
boolean fatalIssueFound = false;
for (ResourceModelIssue issue : validator.getIssueList()) {
if (issue.isFatal()) {
fatalIssueFound = true;
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.severe(issue.getMessage());
}
} else {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning(issue.getMessage());
}
}
} // eof model validation
if (fatalIssueFound) {
LOGGER.severe(ImplMessages.FATAL_ISSUES_FOUND_AT_RES_CLASS(ar.getResourceClass().getName()));
throw new ContainerException(ImplMessages.FATAL_ISSUES_FOUND_AT_RES_CLASS(ar.getResourceClass().getName()));
}
return new ResourceClass(
resourceConfig,
dispatcherFactory,
injectableFactory,
filterFactory,
wadlFactory,
ar);
}
private AbstractResource getAbstractResource(Object o) {
return getAbstractResource(o.getClass());
}
private AbstractResource getAbstractResource(Class c) {
AbstractResource ar = abstractResourceMap.get(c);
if (ar == null) {
ar = IntrospectionModeller.createResource(c);
abstractResourceMap.put(c, ar);
}
return ar;
}
private static class ContextInjectableProvider extends
SingletonTypeInjectableProvider {
ContextInjectableProvider(Type type, T instance) {
super(type, instance);
}
}
public boolean isInitiated () {
return initiated;
}
public void initiate(ResourceConfig resourceConfig) {
initiate(resourceConfig, null);
}
public void initiate(ResourceConfig resourceConfig, IoCComponentProviderFactory _provider) {
if (resourceConfig == null) {
throw new IllegalArgumentException("ResourceConfig instance MUST NOT be null");
}
if (initiated) {
throw new ContainerException(ImplMessages.WEB_APP_ALREADY_INITIATED());
}
this.initiated = true;
// Validate the resource config
resourceConfig.validate();
// Check the resource configuration
this.resourceConfig = resourceConfig;
this.provider = _provider;
this.providerFactories = new ArrayList(2);
for (Object o : resourceConfig.getProviderSingletons()) {
if (o instanceof IoCComponentProviderFactory) {
providerFactories.add((IoCComponentProviderFactory)o);
}
}
if (_provider != null)
providerFactories.add(_provider);
for (IoCComponentProviderFactory f : providerFactories) {
IoCComponentProcessorFactory cpf = null;
if (f instanceof IoCComponentProcessorFactoryInitializer) {
if (cpf == null) {
cpf = new ComponentProcessorFactoryImpl();
}
IoCComponentProcessorFactoryInitializer i = (IoCComponentProcessorFactoryInitializer)f;
i.init(cpf);
}
}
// Set up the component provider factory to be
// used with non-resource class components
this.cpFactory = (providerFactories.isEmpty())
? new ProviderFactory(injectableFactory)
: new IoCProviderFactory(injectableFactory, providerFactories);
// Set up the resource component provider factory
this.rcpFactory = (providerFactories.isEmpty())
? new ResourceFactory(this.resourceConfig, this.injectableFactory)
: new IoCResourceFactory(this.resourceConfig, this.injectableFactory, providerFactories);
this.resourceContext = new ResourceContext() {
public T getResource(Class c) {
final ResourceClass rc = getResourceClass(c);
if (rc == null) {
LOGGER.severe("No resource class found for class " + c.getName());
throw new ContainerException("No resource class found for class " + c.getName());
}
final Object instance = rc.rcProvider.getInstance(context);
return instance != null ? c.cast(instance) : null;
}
};
ProviderServices providerServices = new ProviderServices(
this.injectableFactory,
this.cpFactory,
resourceConfig.getProviderClasses(),
resourceConfig.getProviderSingletons());
// Add injectable provider for @Inject
injectableFactory.add(
new InjectableProvider() {
public ComponentScope getScope() {
return ComponentScope.Undefined;
}
@SuppressWarnings("unchecked")
public Injectable