All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.jersey.spi.spring.container.SpringComponentProviderFactory Maven / Gradle / Ivy

There is a newer version: 1.19.4
Show newest version
/*
 *
 * 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.spi.spring.container;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ClassUtils;

import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.api.spring.Autowire;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
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.IoCInstantiatedComponentProvider;
import com.sun.jersey.core.spi.component.ioc.IoCManagedComponentProvider;
import com.sun.jersey.spi.inject.Inject;
import java.util.HashMap;
import java.util.Map;

/**
 * The Spring-based {@link IoCComponentProviderFactory}.
 * 

* Resource and provider classes can be registered Spring-based beans using * XML-based registration or auto-wire-based registration. * * @author [email protected] */ public class SpringComponentProviderFactory implements IoCComponentProviderFactory { private static final Logger LOGGER = Logger.getLogger(SpringComponentProviderFactory.class.getName()); private final ConfigurableApplicationContext springContext; public SpringComponentProviderFactory(ResourceConfig rc, ConfigurableApplicationContext springContext) { this.springContext = springContext; register(rc, springContext); } private void register(ResourceConfig rc, ConfigurableApplicationContext springContext) { String[] names = BeanFactoryUtils.beanNamesIncludingAncestors(springContext); for (String name : names) { Class type = ClassUtils.getUserClass(springContext.getType(name)); if (ResourceConfig.isProviderClass(type)) { LOGGER.info("Registering Spring bean, " + name + ", of type " + type.getName() + " as a provider class"); rc.getClasses().add(type); } else if (ResourceConfig.isRootResourceClass(type)) { LOGGER.info("Registering Spring bean, " + name + ", of type " + type.getName() + " as a root resource class"); rc.getClasses().add(type); } } } public IoCComponentProvider getComponentProvider(Class c) { return getComponentProvider(null, c); } public IoCComponentProvider getComponentProvider(ComponentContext cc, Class c) { final Autowire autowire = (Autowire) c.getAnnotation(Autowire.class); if (autowire != null) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("Creating resource class " + c.getSimpleName() + " annotated with @" + Autowire.class.getSimpleName() + " as spring bean."); } return new SpringInstantiatedComponentProvider(c, autowire); } final String beanName = getBeanName(cc, c, springContext); if (beanName == null) { return null; } final String scope = findBeanDefinition(beanName).getScope(); return new SpringManagedComponentProvider(getComponentScope(scope), beanName, c); } /** * Fine the bean definition from a given context or from any of the parent * contexts. * * @param beanName the bean name. * @return the bean definition. * @throws NoSuchBeanDefinitionException if the bean definition could not * be found. */ private BeanDefinition findBeanDefinition(String beanName) { ConfigurableApplicationContext current = springContext; BeanDefinition beanDef = null; do { try { return current.getBeanFactory().getBeanDefinition(beanName); } catch (NoSuchBeanDefinitionException e) { final ApplicationContext parent = current.getParent(); if (parent != null && parent instanceof ConfigurableApplicationContext) { current = (ConfigurableApplicationContext) parent; } else { throw e; } } } while (beanDef == null && current != null); return beanDef; } private ComponentScope getComponentScope(String scope) { ComponentScope cs = scopeMap.get(scope); return (cs != null) ? cs : ComponentScope.Undefined; } private final Map scopeMap = createScopeMap(); private Map createScopeMap() { Map m = new HashMap(); m.put(BeanDefinition.SCOPE_SINGLETON, ComponentScope.Singleton); m.put(BeanDefinition.SCOPE_PROTOTYPE, ComponentScope.PerRequest); m.put("request", ComponentScope.PerRequest); return m; } private class SpringInstantiatedComponentProvider implements IoCInstantiatedComponentProvider { private final Class c; private final Autowire a; SpringInstantiatedComponentProvider(Class c, Autowire a) { this.c = c; this.a = a; } public Object getInstance() { return springContext.getBeanFactory().createBean(c, a.mode().getSpringCode(), a.dependencyCheck()); } public Object getInjectableInstance(Object o) { return SpringComponentProviderFactory.getInjectableInstance(o); } } private class SpringManagedComponentProvider implements IoCManagedComponentProvider { private final ComponentScope scope; private final String beanName; private final Class c; SpringManagedComponentProvider(ComponentScope scope, String beanName, Class c) { this.scope = scope; this.beanName = beanName; this.c = c; } public ComponentScope getScope() { return scope; } public Object getInjectableInstance(Object o) { return SpringComponentProviderFactory.getInjectableInstance(o); } public Object getInstance() { return springContext.getBean(beanName, c); } } private static Object getInjectableInstance(Object o) { if (AopUtils.isAopProxy(o)) { final Advised aopResource = (Advised) o; try { return aopResource.getTargetSource().getTarget(); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Could not get target object from proxy.", e); throw new RuntimeException("Could not get target object from proxy.", e); } } else { return o; } } private static String getBeanName(ComponentContext cc, Class c, ApplicationContext springContext) { boolean annotatedWithInject = false; if (cc != null) { final Inject inject = getAnnotation(cc.getAnnotations(), Inject.class); if (inject != null) { annotatedWithInject = true; if (inject.value() != null && !inject.value().equals("")) { return inject.value(); } } } final String names[] = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(springContext, c); if (names.length == 0) { return null; } else if (names.length == 1) { return names[0]; } else { // Check if types of the beans names are assignable // Spring auto-registration for a type A will include the bean // names for classes that extend A boolean inheritedNames = false; String beanName = null; for (String name : names) { Class beanType = ClassUtils.getUserClass(springContext.getType(name)); inheritedNames = c.isAssignableFrom(beanType); if (c == beanType) beanName = name; } if (inheritedNames) { if (beanName != null) return beanName; } final StringBuilder sb = new StringBuilder(); sb.append("There are multiple beans configured in spring for the type "). append(c.getName()).append("."); if (annotatedWithInject) { sb.append("\nYou should specify the name of the preferred bean at @Inject: Inject(\"yourBean\")."); } else { sb.append("\nAnnotation information was not available, the reason might be because you're not using " + "@Inject. You should use @Inject and specifiy the bean name via Inject(\"yourBean\")."); } sb.append("\nAvailable bean names: ").append(toCSV(names)); throw new RuntimeException(sb.toString()); } } private static T getAnnotation(Annotation[] annotations, Class clazz) { if (annotations != null) { for (Annotation annotation : annotations) { if (annotation.annotationType().equals(clazz)) { return clazz.cast(annotation); } } } return null; } private static String toCSV(T[] items) { if (items == null) { return null; } return toCSV(Arrays.asList(items)); } private static String toCSV(Collection items) { return toCSV(items, ", ", null); } private static String toCSV(Collection items, String separator, String delimiter) { if (items == null) { return null; } if (items.isEmpty()) { return ""; } final StringBuilder sb = new StringBuilder(); for (final Iterator iter = items.iterator(); iter.hasNext();) { if (delimiter != null) { sb.append(delimiter); } final I item = iter.next(); sb.append(item); if (delimiter != null) { sb.append(delimiter); } if (iter.hasNext()) { sb.append(separator); } } return sb.toString(); } }