/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* 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.deployers.plugins.managed;
import java.lang.annotation.Annotation;
import java.util.Set;
import org.jboss.beans.info.spi.BeanInfo;
import org.jboss.beans.info.spi.PropertyInfo;
import org.jboss.beans.metadata.spi.AnnotationMetaData;
import org.jboss.beans.metadata.spi.BeanMetaData;
import org.jboss.beans.metadata.spi.PropertyMetaData;
import org.jboss.beans.metadata.spi.builder.BeanMetaDataBuilder;
import org.jboss.dependency.spi.ControllerContext;
import org.jboss.kernel.plugins.config.Configurator;
import org.jboss.kernel.spi.dependency.KernelController;
import org.jboss.logging.Logger;
import org.jboss.managed.api.Fields;
import org.jboss.managed.api.ManagedProperty;
import org.jboss.managed.api.annotation.ManagementObject;
import org.jboss.managed.api.annotation.ManagementObjectClass;
import org.jboss.managed.spi.factory.InstanceClassFactory;
import org.jboss.metadata.spi.MetaData;
import org.jboss.metatype.api.values.MetaValue;
import org.jboss.metatype.api.values.MetaValueFactory;
import org.jboss.metatype.spi.values.MetaMapper;
import org.jboss.reflect.spi.TypeInfo;
/**
* An InstanceClassFactory for BeanMetaData
*
* @author Scott.Stark@jboss.org
* @version $Revision: 89429 $
*/
public class BeanMetaDataICF
implements InstanceClassFactory<BeanMetaData>
{
private static final Logger log = Logger.getLogger(BeanMetaDataICF.class);
private KernelController controller;
/** The meta value factory */
private MetaValueFactory metaValueFactory = MetaValueFactory.getInstance();
/** */
private InstanceClassFactory delegateICF;
public KernelController getController()
{
return controller;
}
public void setController(KernelController controller)
{
this.controller = controller;
}
public MetaValueFactory getMetaValueFactory()
{
return metaValueFactory;
}
public void setMetaValueFactory(MetaValueFactory metaValueFactory)
{
this.metaValueFactory = metaValueFactory;
}
public InstanceClassFactory getDelegateICF()
{
return delegateICF;
}
public void setDelegateICF(InstanceClassFactory delegateICF)
{
this.delegateICF = delegateICF;
}
public Object locateBean(String beanName)
{
ControllerContext context = getController().getInstalledContext(beanName);
if (context == null)
{
return null;
}
return context.getTarget();
}
public Class<BeanMetaData> getType()
{
return BeanMetaData.class;
}
public Object getComponentName(BeanInfo beanInfo, ManagedProperty property,
BeanMetaData attachment, MetaValue value)
{
return attachment.getName();
}
public Class<?> getManagedObjectClass(BeanMetaData attachment)
throws ClassNotFoundException
{
Class<?> mocClass = null;
// Look for a ManagementObjectClass annotation
Set<AnnotationMetaData> annotations = attachment.getAnnotations();
if(annotations != null)
{
for(AnnotationMetaData amd : annotations)
{
Annotation ann = amd.getAnnotationInstance();
if(ann instanceof ManagementObjectClass)
{
ManagementObjectClass moc = (ManagementObjectClass) ann;
mocClass = moc.code();
log.debug("Saw ManagementObjectClass, "+mocClass+" for bean: "+attachment);
break;
}
}
}
// Find <annotation/> in the beans.xml
// if(annotations != null)
// {
// for(AnnotationMetaData amd : annotations)
// {
// Annotation ann = amd.getAnnotationInstance();
// if(ann instanceof ManagementObject)
// {
// String beanClassName = attachment.getBean();
// ClassLoader loader = getClassLoader(attachment);
// mocClass = loader.loadClass(beanClassName);
// log.debug("Saw ManagementObject, "+mocClass+" for bean: "+attachment);
// break;
// }
// }
// }
// Use the bean from the metadata
if(mocClass == null)
{
String beanClassName = attachment.getBean();
if(beanClassName != null && beanClassName.length() > 0)
{
// TODO: TCL may not be correct
ClassLoader loader = getClassLoader(attachment);
mocClass = loader.loadClass(beanClassName);
// Make sure it has an ManagementObject annotation
ManagementObject moAnn = mocClass.getAnnotation(ManagementObject.class);
if(moAnn == null)
{
// Revert back to the BeanMetaData class
mocClass = attachment.getClass();
}
log.debug("Using bean class:, "+mocClass+" for bean: "+attachment);
}
}
return mocClass;
}
public MetaValue getValue(BeanInfo beanInfo, ManagedProperty property,
MetaData metaData,
BeanMetaData attachment)
{
// Get the property from the bean
// First look to the mapped name
String name = property.getMappedName();
if (name == null)
name = property.getName();
PropertyInfo propertyInfo = property.getField(Fields.PROPERTY_INFO, PropertyInfo.class);
if(propertyInfo == null)
propertyInfo = beanInfo.getProperty(name);
Object bean = locateBean(attachment.getName());
MetaValue mvalue = null;
if(propertyInfo.isReadable() == false)
{
if(log.isTraceEnabled())
log.trace("Skipping get of non-readable property: "+propertyInfo);
return null;
}
try
{
String getterClassName = propertyInfo.getGetter().getDeclaringClass().getName();
if(getterClassName.equals(attachment.getClass().getName()))
{
// use attachment
mvalue = delegateICF.getValue(beanInfo, property, metaData, attachment);
}
else if(bean != null)
{
// use bean (if installed)
mvalue = delegateICF.getValue(beanInfo, property, metaData, bean);
}
else
{
// Try to find the property in the meta data
PropertyMetaData md = null;
if(attachment.getProperties() != null && attachment.getProperties().isEmpty() == false)
{
for(PropertyMetaData bp : attachment.getProperties())
{
if(name.equals(bp.getName()))
{
md = bp;
break;
}
}
if(md != null)
{
// TODO add metaMapping
if(md.getValue() != null)
{
mvalue = metaValueFactory.create(md.getValue().getUnderlyingValue(),
propertyInfo.getType());
}
}
}
}
}
catch(Throwable e)
{
log.debug("Failed to get property value for bean: "+beanInfo.getName()
+", property: "+propertyInfo.getName(), e);
mvalue = metaValueFactory.create(null, propertyInfo.getType());
return mvalue;
}
return mvalue;
}
public void setValue(BeanInfo beanInfo, ManagedProperty property,
BeanMetaData attachment, MetaValue value)
{
ClassLoader prevLoader = SecurityActions.getContextClassLoader();
String beanName = attachment.getName();
// First look to the mapped name
String name = property.getMappedName();
if (name == null)
name = property.getName();
try
{
ClassLoader loader = getClassLoader(attachment);
// Set the mbean class loader as the TCL
SecurityActions.setContextClassLoader(loader);
PropertyInfo propertyInfo = property.getField(Fields.PROPERTY_INFO, PropertyInfo.class);
if(propertyInfo == null)
propertyInfo = beanInfo.getProperty(name);
if(propertyInfo == null)
throw new IllegalArgumentException("No matching property found: " + name + "/" + beanName);
if(propertyInfo.isWritable() == false)
{
if(log.isTraceEnabled())
log.trace("Skipping get of non-writable property: "+propertyInfo);
return;
}
Object plainValue = unwrapValue(property, propertyInfo.getType(), value);
Object bean = locateBean(beanName);
// Only update the bean if installed
if(bean != null)
propertyInfo.set(bean, plainValue);
BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(attachment);
builder.addPropertyMetaData(name, plainValue);
}
catch(Throwable e)
{
throw new IllegalStateException("Failed to set property value: "+name + "/" + beanName, e);
}
finally
{
SecurityActions.setContextClassLoader(prevLoader);
}
}
protected ClassLoader getClassLoader(BeanMetaData bmd)
{
ClassLoader loader = null;
try
{
loader = Configurator.getClassLoader(bmd);
}
catch(Throwable t)
{
log.debug("Failed to load BeanMetaData class loader", t);
}
// Fallback to TCL if there is no
if(loader == null)
loader = SecurityActions.getContextClassLoader();
return loader;
}
private Object unwrapValue(ManagedProperty property, TypeInfo typeInfo, MetaValue value)
{
// Look for a property MetaMapper
MetaMapper<?> metaMapper = property.getTransientAttachment(MetaMapper.class);
if(metaMapper != null)
{
return metaMapper.unwrapMetaValue(value);
}
return metaValueFactory.unwrap(value, typeInfo);
}
}