/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.beans.metadata.plugins;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import org.jboss.beans.info.spi.BeanAccessMode;
import org.jboss.beans.metadata.api.model.AutowireType;
import static org.jboss.beans.metadata.plugins.CloneUtil.cloneCollection;
import static org.jboss.beans.metadata.plugins.CloneUtil.cloneObject;
import org.jboss.beans.metadata.spi.AliasMetaData;
import org.jboss.beans.metadata.spi.BeanMetaData;
import org.jboss.beans.metadata.spi.BeanMetaDataFactory;
import org.jboss.beans.metadata.spi.CallbackMetaData;
import org.jboss.beans.metadata.spi.ClassLoaderMetaData;
import org.jboss.beans.metadata.spi.ConstructorMetaData;
import org.jboss.beans.metadata.spi.DemandMetaData;
import org.jboss.beans.metadata.spi.DependencyMetaData;
import org.jboss.beans.metadata.spi.InstallMetaData;
import org.jboss.beans.metadata.spi.LifecycleMetaData;
import org.jboss.beans.metadata.spi.MetaDataVisitor;
import org.jboss.beans.metadata.spi.MetaDataVisitorNode;
import org.jboss.beans.metadata.spi.PropertyMetaData;
import org.jboss.beans.metadata.spi.SupplyMetaData;
import org.jboss.beans.metadata.spi.RelatedClassMetaData;
import org.jboss.dependency.plugins.AbstractDependencyItem;
import org.jboss.dependency.spi.Controller;
import org.jboss.dependency.spi.ControllerContext;
import org.jboss.dependency.spi.ControllerMode;
import org.jboss.dependency.spi.ControllerState;
import org.jboss.dependency.spi.DependencyItem;
import org.jboss.dependency.spi.ErrorHandlingMode;
import org.jboss.kernel.spi.dependency.KernelControllerContext;
import org.jboss.managed.api.annotation.ManagementObject;
import org.jboss.managed.api.annotation.ManagementProperties;
import org.jboss.managed.api.annotation.ManagementProperty;
import org.jboss.reflect.spi.TypeInfo;
import org.jboss.util.JBossObject;
import org.jboss.util.JBossStringBuilder;
/**
* Metadata for a bean.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @author <a href="ales.justin@jboss.com">Ales Justin</a>
* @version $Revision: 81535 $
*/
@ManagementObject(properties = ManagementProperties.EXPLICIT) // TODO - explicitly add props we want to manage
@XmlRootElement(name="bean")
@XmlType(name="beanType", propOrder={"aliasMetaData", "related", "annotations", "classLoader", "constructor", "properties", "create", "start", "stop", "destroy", "depends", "demands", "supplies", "installs", "uninstalls", "installCallbacks", "uninstallCallbacks"})
public class AbstractBeanMetaData extends AbstractFeatureMetaData
implements BeanMetaData, BeanMetaDataFactory, MutableLifecycleHolder, Serializable
{
private static final long serialVersionUID = 4L;
/** The bean fully qualified class name */
protected String bean;
/** The name of this instance */
protected String name;
/** The related */
protected Set<RelatedClassMetaData> related;
/** The aliases */
protected Set<Object> aliases;
/** The alias metadata */
protected Set<AliasMetaData> aliasMetaData;
/** The parent */
protected String parent;
/** Is abstract */
protected boolean isAbstract;
/** Autowire type */
protected AutowireType autowireType;
/** The mode */
protected ControllerMode mode;
/** The error handling mode */
protected ErrorHandlingMode errorHandlingMode;
/** The access mode */
protected BeanAccessMode accessMode;
/** Is contextual injection candidate */
protected boolean autowireCandidate = true;
/** The properties configuration Set<PropertyMetaData> */
private Set<PropertyMetaData> properties;
/** The bean ClassLoader */
protected ClassLoaderMetaData classLoader;
/** The constructor */
protected ConstructorMetaData constructor;
/** The create lifecycle */
protected LifecycleMetaData create;
/** The start lifecycle */
protected LifecycleMetaData start;
/** The stop lifecycle */
protected LifecycleMetaData stop;
/** The destroy lifecycle */
protected LifecycleMetaData destroy;
/** What the bean demands Set<DemandMetaData> */
protected Set<DemandMetaData> demands;
/** What the bean supplies Set<SupplyMetaData> */
protected Set<SupplyMetaData> supplies;
/** What the bean dependencies Set<DependencyMetaData> */
protected Set<DependencyMetaData> depends;
/** The install operations List<InstallMetaData> */
protected List<InstallMetaData> installs;
/** The uninstall operations List<InstallMetaData> */
protected List<InstallMetaData> uninstalls;
/** The install callback List<InstallMetaData> */
protected List<CallbackMetaData> installCallbacks;
/** The uninstall callback List<InstallMetaData> */
protected List<CallbackMetaData> uninstallCallbacks;
/** The context */
protected transient ControllerContext context;
/**
* Create a new bean meta data
*/
public AbstractBeanMetaData()
{
super();
}
/**
* Create a new bean meta data
*
* @param bean the bean class name
*/
public AbstractBeanMetaData(String bean)
{
this.bean = bean;
}
/**
* Create a new bean meta data
*
* @param name the name
* @param bean the bean class name
*/
public AbstractBeanMetaData(String name, String bean)
{
this.name = name;
this.bean = bean;
}
public List<BeanMetaData> getBeans()
{
NestedBeanHandler handler = createNestedBeanHandler();
return handler.checkForNestedBeans();
}
/**
* Create nested bean handler.
* Can be overridden to change generateName policy.
*
* @return nested bean handler
*/
protected NestedBeanHandler createNestedBeanHandler()
{
return new NestedBeanHandler(this);
}
/**
* Get the bean class name.
* @return the fully qualified bean class name.
*/
public String getBean()
{
return bean;
}
/**
* Set the bean class name and flush the object cache.
*
* @param bean The bean class name to set.
*/
@XmlAttribute(name="class")
public void setBean(String bean)
{
this.bean = bean;
flushJBossObjectCache();
}
/**
* Get a property
*
* @param name the name
* @return the property name
*/
public PropertyMetaData getProperty(String name)
{
if (name == null)
throw new IllegalArgumentException("Null name");
if (properties != null && properties.size() > 0)
{
for (PropertyMetaData prop : properties)
{
if (name.equals(prop.getName()))
return prop;
}
}
return null;
}
/**
* Add a property
*
* @param property the property
*/
public void addProperty(PropertyMetaData property)
{
if (property == null)
throw new IllegalArgumentException("Null property");
if (properties == null)
properties = new HashSet<PropertyMetaData>();
properties.add(property);
flushJBossObjectCache();
}
/**
* Set the propertiess.
*
* @param properties Set<PropertyMetaData>
*/
@ManagementProperty(managed=true) // TODO - this ok?
@XmlElement(name="property", type=AbstractPropertyMetaData.class)
public void setProperties(Set<PropertyMetaData> properties)
{
this.properties = properties;
flushJBossObjectCache();
}
public ClassLoaderMetaData getClassLoader()
{
return classLoader;
}
@XmlElement(name="classloader", type=AbstractClassLoaderMetaData.class)
public void setClassLoader(ClassLoaderMetaData classLoader)
{
this.classLoader = classLoader;
}
/**
* Set the constructor
*
* @param constructor the constructor metadata
*/
@XmlElement(name="constructor", type=AbstractConstructorMetaData.class)
public void setConstructor(ConstructorMetaData constructor)
{
this.constructor = constructor;
}
/**
* Set what the bean demands.
*
* @param demands Set<DemandMetaData>
*/
@XmlElement(name="demand", type=AbstractDemandMetaData.class)
public void setDemands(Set<DemandMetaData> demands)
{
this.demands = demands;
flushJBossObjectCache();
}
/**
* Set what the bean supplies.
*
* @param supplies Set<SupplyMetaData>
*/
@XmlElement(name="supply", type=AbstractSupplyMetaData.class)
public void setSupplies(Set<SupplyMetaData> supplies)
{
this.supplies = supplies;
flushJBossObjectCache();
}
/**
* Set what the bean depends.
*
* @param depends Set<DependencyMetaData>
*/
@XmlElement(name="depends", type=AbstractDependencyMetaData.class)
public void setDepends(Set<DependencyMetaData> depends)
{
this.depends = depends;
flushJBossObjectCache();
}
public String getName()
{
return name;
}
/**
* Set the name.
*
* @param name The name to set.
*/
@XmlAttribute
public void setName(String name)
{
this.name = name;
flushJBossObjectCache();
}
public Set<RelatedClassMetaData> getRelated()
{
return related;
}
@XmlElement(name="related-class", type=AbstractRelatedClassMetaData.class)
public void setRelated(Set<RelatedClassMetaData> related)
{
this.related = related;
}
public Set<Object> getAliases()
{
return aliases;
}
@XmlTransient
public void setAliases(Set<Object> aliases)
{
this.aliases = aliases;
}
public Set<AliasMetaData> getAliasMetaData()
{
return aliasMetaData;
}
@XmlElement(name="alias", type=AbstractAliasMetaData.class)
public void setAliasMetaData(Set<AliasMetaData> aliases)
{
this.aliasMetaData = aliases;
}
public String getParent()
{
return parent;
}
/**
* Set the parent.
*
* @param parent the parent name
*/
@XmlAttribute
public void setParent(String parent)
{
this.parent = parent;
}
public boolean isAbstract()
{
return isAbstract;
}
/**
* Set abstract.
*
* @param anAbstract is abstract
*/
@XmlAttribute
public void setAbstract(boolean anAbstract)
{
isAbstract = anAbstract;
}
public AutowireType getAutowireType()
{
return autowireType;
}
/**
* Set autowire type.
*
* @param autowireType the type
*/
@XmlAttribute(name="autowire-type")
public void setAutowireType(AutowireType autowireType)
{
this.autowireType = autowireType;
}
public ControllerMode getMode()
{
return mode;
}
@XmlAttribute
public void setMode(ControllerMode mode)
{
this.mode = mode;
flushJBossObjectCache();
}
public ErrorHandlingMode getErrorHandlingMode()
{
return errorHandlingMode;
}
@XmlAttribute(name="error-handling")
public void setErrorHandlingMode(ErrorHandlingMode errorHandlingMode)
{
this.errorHandlingMode = errorHandlingMode;
}
public BeanAccessMode getAccessMode()
{
return accessMode;
}
@XmlAttribute(name="access-mode")
public void setAccessMode(BeanAccessMode accessMode)
{
this.accessMode = accessMode;
}
public boolean isAutowireCandidate()
{
return autowireCandidate;
}
@XmlAttribute(name="autowire-candidate")
public void setAutowireCandidate(boolean autowireCandidate)
{
this.autowireCandidate = autowireCandidate;
}
public Set<PropertyMetaData> getProperties()
{
return properties;
}
public ConstructorMetaData getConstructor()
{
return constructor;
}
public LifecycleMetaData getCreate()
{
return create;
}
/**
* Set the lifecycle metadata
*
* @param lifecycle the lifecycle metadata
*/
@XmlElement(name="create", type=AbstractLifecycleMetaData.class)
public void setCreate(LifecycleMetaData lifecycle)
{
if (lifecycle != null)
lifecycle.setState(ControllerState.CREATE);
this.create = lifecycle;
}
public LifecycleMetaData getStart()
{
return start;
}
/**
* Set the start metadata
*
* @param lifecycle the lifecycle metadata
*/
@XmlElement(name="start", type=AbstractLifecycleMetaData.class)
public void setStart(LifecycleMetaData lifecycle)
{
if (lifecycle != null)
lifecycle.setState(ControllerState.START);
this.start = lifecycle;
}
public LifecycleMetaData getStop()
{
return stop;
}
/**
* Set the stop metadata
*
* @param lifecycle the lifecycle metadata
*/
@XmlElement(name="stop", type=AbstractLifecycleMetaData.class)
public void setStop(LifecycleMetaData lifecycle)
{
if (lifecycle != null)
lifecycle.setState(ControllerState.START);
this.stop = lifecycle;
}
public LifecycleMetaData getDestroy()
{
return destroy;
}
/**
* Set the destroy metadata
*
* @param lifecycle the lifecycle metadata
*/
@XmlElement(name="destroy", type=AbstractLifecycleMetaData.class)
public void setDestroy(LifecycleMetaData lifecycle)
{
if (lifecycle != null)
lifecycle.setState(ControllerState.CREATE);
this.destroy = lifecycle;
}
public Set<DemandMetaData> getDemands()
{
return demands;
}
public Set<SupplyMetaData> getSupplies()
{
return supplies;
}
public Set<DependencyMetaData> getDepends()
{
return depends;
}
public List<InstallMetaData> getInstalls()
{
return installs;
}
/**
* Set the installs
*
* @param installs List<InstallMetaData>
*/
@XmlElement(name="install", type=AbstractInstallMetaData.class)
public void setInstalls(List<InstallMetaData> installs)
{
this.installs = installs;
flushJBossObjectCache();
}
public List<InstallMetaData> getUninstalls()
{
return uninstalls;
}
/**
* Set the uninstalls
*
* @param uninstalls List<InstallMetaData>
*/
@XmlElement(name="uninstall", type=AbstractInstallMetaData.class)
public void setUninstalls(List<InstallMetaData> uninstalls)
{
this.uninstalls = uninstalls;
flushJBossObjectCache();
}
public List<CallbackMetaData> getInstallCallbacks()
{
return installCallbacks;
}
@XmlElement(name="incallback", type=InstallCallbackMetaData.class)
public void setInstallCallbacks(List<CallbackMetaData> installCallbacks)
{
this.installCallbacks = installCallbacks;
flushJBossObjectCache();
}
public List<CallbackMetaData> getUninstallCallbacks()
{
return uninstallCallbacks;
}
@XmlElement(name="uncallback", type=UninstallCallbackMetaData.class)
public void setUninstallCallbacks(List<CallbackMetaData> uninstallCallbacks)
{
this.uninstallCallbacks = uninstallCallbacks;
flushJBossObjectCache();
}
public void initialVisit(MetaDataVisitor visitor)
{
ConstructorMetaData constructor = getConstructor();
if (getBean() == null)
{
if (isAbstract() == false && getParent() == null)
{
if (constructor == null)
throw new IllegalArgumentException("Bean should have a class attribute or a constructor element.");
if (constructor.getFactoryMethod() == null)
{
if (constructor.getValue() == null)
throw new IllegalArgumentException("Bean should have a class attribute or the constructor element should have either a factoryMethod attribute or embedded value.");
}
else if (constructor.getFactory() == null && constructor.getFactoryClass() == null)
throw new IllegalArgumentException("Bean should have a class attribute or the constructor element should have one of a factoryClass attribute or a factory element, or embedded value.");
}
}
else
{
checkConstructorFactoryClass(constructor);
}
KernelControllerContext ctx = visitor.getControllerContext();
if (ctx.getBeanMetaData() == this)
context = ctx;
boolean isInnerBean = visitor.visitorNodeStack().isEmpty() == false;
if (isInnerBean)
{
Object name = ctx.getName();
Object iDependOn = getUnderlyingValue();
ControllerState whenRequired = visitor.getContextState();
DependencyItem di = new AbstractDependencyItem(name, iDependOn, whenRequired, ControllerState.INSTALLED);
visitor.addDependency(di);
}
if (create != null && create.getMethodName() == null)
create.setMethodName("create");
if (start != null && start.getMethodName() == null)
start.setMethodName("start");
if (stop != null && stop.getMethodName() == null)
stop.setMethodName("stop");
if (destroy != null && destroy.getMethodName() == null)
destroy.setMethodName("destroy");
super.initialVisit(visitor);
}
/**
* Check constructor factory class.
*
* @param constructor the constructor meta data
*/
protected void checkConstructorFactoryClass(ConstructorMetaData constructor)
{
if (constructor == null)
return;
if (constructor.getFactoryMethod() == null)
return;
if (constructor.getFactoryClass() != null)
return;
if (constructor.getValue() != null)
return;
if (constructor.getFactory() != null)
return;
if (constructor instanceof AbstractConstructorMetaData == false)
return;
AbstractConstructorMetaData acmd = AbstractConstructorMetaData.class.cast(constructor);
acmd.setFactoryClass(getBean());
}
protected void addChildren(Set<MetaDataVisitorNode> children)
{
super.addChildren(children);
if (classLoader != null && classLoader.getClassLoader() != this)
children.add(classLoader);
if (constructor != null)
children.add(constructor);
if (properties != null)
children.addAll(properties);
if (create != null)
children.add(create);
if (start != null)
children.add(start);
if (stop != null)
children.add(stop);
if (destroy != null)
children.add(destroy);
if (demands != null)
children.addAll(demands);
if (supplies != null)
children.addAll(supplies);
if (depends != null)
children.addAll(depends);
if (installs != null)
children.addAll(installs);
if (uninstalls != null)
children.addAll(uninstalls);
if (installCallbacks != null)
children.addAll(installCallbacks);
if (uninstallCallbacks != null)
children.addAll(uninstallCallbacks);
if (aliasMetaData != null)
children.addAll(aliasMetaData);
if (related != null)
children.addAll(related);
}
public TypeInfo getType(MetaDataVisitor visitor, MetaDataVisitorNode previous) throws Throwable
{
throw new IllegalArgumentException("Cannot determine inject class type: " + this);
}
public Object getUnderlyingValue()
{
return name;
}
@SuppressWarnings({"unchecked", "deprecation"})
public Object getValue(TypeInfo info, ClassLoader cl) throws Throwable
{
if (context == null)
throw new IllegalStateException("Context has not been set: " + this);
Controller controller = context.getController();
ControllerContext lookup = controller.getInstalledContext(name);
if (lookup == null || lookup.getTarget() == null)
{
// possible call for classloader
if (info == null && classLoader != null && classLoader.getClassLoader() == this)
{
return cl;
}
throw new IllegalArgumentException("Bean not yet installed: " + name);
}
Object target = lookup.getTarget();
// TODO - add progression here as well?
if (info != null && info.getType().isAssignableFrom(target.getClass()) == false)
{
throw new ClassCastException(target + " is not a " + info);
}
return target;
}
public void toString(JBossStringBuilder buffer)
{
buffer.append("name=").append(name);
if (aliases != null)
buffer.append(" aliases=").append(aliases);
buffer.append(" bean=").append(bean);
buffer.append(" properties=");
JBossObject.list(buffer, properties);
if (classLoader != null && classLoader.getClassLoader() != this)
buffer.append(" classLoader=").append(classLoader);
buffer.append(" constructor=").append(constructor);
buffer.append(" autowireCandidate=").append(autowireCandidate);
if (create != null)
buffer.append(" create=").append(create);
if (start != null)
buffer.append(" start=").append(start);
if (stop != null)
buffer.append(" stop=").append(stop);
if (destroy != null)
buffer.append(" destroy=").append(destroy);
if (demands != null)
{
buffer.append(" demands=");
JBossObject.list(buffer, demands);
}
super.toString(buffer);
if (supplies != null)
{
buffer.append(" supplies=");
JBossObject.list(buffer, supplies);
}
if (depends != null)
{
buffer.append(" depends=");
JBossObject.list(buffer, depends);
}
if (installs != null)
{
buffer.append(" installs=");
JBossObject.list(buffer, installs);
}
if (uninstalls != null)
{
buffer.append(" uninstalls=");
JBossObject.list(buffer, uninstalls);
}
if (installCallbacks != null)
{
buffer.append(" installCallbacks=");
JBossObject.list(buffer, installCallbacks);
}
if (uninstallCallbacks != null)
{
buffer.append(" uninstallCallbacks=");
JBossObject.list(buffer, uninstallCallbacks);
}
if (aliasMetaData != null)
{
buffer.append(" aliasMetaData=");
JBossObject.list(buffer, aliasMetaData);
}
if (related != null)
{
buffer.append(" related=");
JBossObject.list(buffer, related);
}
}
public void toShortString(JBossStringBuilder buffer)
{
buffer.append(bean);
buffer.append('/');
buffer.append(name);
}
public AbstractBeanMetaData clone()
{
AbstractBeanMetaData clone = (AbstractBeanMetaData)super.clone();
doClone(clone);
return clone;
}
@SuppressWarnings("unchecked")
protected void doClone(AbstractBeanMetaData clone)
{
super.doClone(clone);
if (aliases != null)
clone.setAliases(new HashSet<Object>(aliases));
clone.setAliasMetaData(cloneCollection(aliasMetaData, HashSet.class, AliasMetaData.class));
clone.setRelated(cloneCollection(related, HashSet.class, RelatedClassMetaData.class));
clone.setClassLoader(cloneObject(classLoader, ClassLoaderMetaData.class));
clone.setConstructor(cloneObject(constructor, ConstructorMetaData.class));
clone.setCreate(cloneObject(create, LifecycleMetaData.class));
clone.setDemands(cloneCollection(demands, HashSet.class, DemandMetaData.class));
clone.setDepends(cloneCollection(depends, HashSet.class, DependencyMetaData.class));
clone.setDestroy(cloneObject(destroy, LifecycleMetaData.class));
clone.setInstallCallbacks(cloneCollection(installCallbacks, ArrayList.class, CallbackMetaData.class));
clone.setInstalls(cloneCollection(installs, ArrayList.class, InstallMetaData.class));
clone.setProperties(cloneCollection(properties, HashSet.class, PropertyMetaData.class));
clone.setStart(cloneObject(start, LifecycleMetaData.class));
clone.setStop(cloneObject(stop, LifecycleMetaData.class));
clone.setSupplies(cloneCollection(supplies, HashSet.class, SupplyMetaData.class));
clone.setUninstallCallbacks(cloneCollection(uninstallCallbacks, ArrayList.class, CallbackMetaData.class));
clone.setUninstalls(cloneCollection(uninstalls, ArrayList.class, InstallMetaData.class));
}
}