package org.jboss.seam.ioc.spring; import java.util.List; import org.jboss.seam.ScopeType; import org.springframework.aop.framework.DefaultAopProxyFactory; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.AbstractFactoryBean; /** * Obtains an instance of a Seam Component in the current context given the name * and other optional parameters. If proxy is set to true then return a scoped * proxy of the seam component instance. Use <seam:instance/> to simplify * use of this factory. * * @author youngm */ public class SeamFactoryBean extends AbstractFactoryBean implements InitializingBean { private ScopeType scope; private String name; private Boolean create; private SeamTargetSource targetSource; private Object proxyInstance; private Class type; private boolean proxy = false; /** * Initializes the factory. If proxy=true then initialize the proxy. * * @see org.springframework.beans.factory.config.AbstractFactoryBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { if (name == null) { throw new IllegalArgumentException("name must not be null"); } // If we're creating a proxy then we want this to be a singleton setSingleton(proxy); this.targetSource = new SeamTargetSource(name, scope, create, type); if (proxy) { Class targetClass = targetSource.getTargetClass(); if (targetClass == null) { throw new IllegalStateException("Cannot use 'proxy' for an expression without specifying a type."); } // Not sure if I should allow people to change these proxy // parameters or not. We'll see what issues we get hard coding them. ProxyFactory pf = new ProxyFactory(); pf.setProxyTargetClass(true); pf.setOptimize(true); pf.setExposeProxy(false); pf.setFrozen(true); pf.setAopProxyFactory(new DefaultAopProxyFactory()); pf.setTargetSource(this.targetSource); List<Class> interfaces = targetSource.getSeamInterfaces(); //For some reason the targetClass cannot be an interface if(targetClass.isInterface()) { interfaces.add(targetClass); } pf.setInterfaces(interfaces.toArray(new Class[interfaces.size()])); this.proxyInstance = pf.getProxy(Thread.currentThread().getContextClassLoader()); } super.afterPropertiesSet(); } /** * Return the current instance of a Seam component or the proxy if proxy was * set to true. * * @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance() */ @Override protected Object createInstance() throws Exception { if (proxy) { return proxyInstance; } else { return targetSource.getTarget(); } } /** * Return the type of the component if available. * * @throws IllegalStateException * if the component cannot be found or if seam has not yet been * initialized. * * @see org.springframework.beans.factory.config.AbstractFactoryBean#getObjectType() */ @Override public Class getObjectType() { //Incase spring calls getObjectType without calling afterPropertiesSet() if(targetSource == null) { return null; } return targetSource.getTargetClass(); } /** * The name of the seam component to get an instance of. (required) * * @param name * the name of the component */ public void setName(String name) { this.name = name; } /** * The scope of the seam component (optional) * * @param scope * the scope of the component */ public void setScope(ScopeType scope) { this.scope = scope; } /** * Should the factory create an instance of the component if one doesn't * already exist in this context. If null * * Must always be true for STATELESS components. * * @param create * do we create an instance if needed */ public void setCreate(Boolean create) { this.create = create; } /** * Should the factory wrap the component instance in a proxy so the seam * component can be safely injected into a singleton. * * @param proxy * true to proxy the component */ public void setProxy(boolean proxy) { this.proxy = proxy; } /** * Forces type of a proxy created. Useful when using EL where the type of the * object may not be available at Proxy creation time. * * @param type */ public void setType(Class type) { this.type = type; } }