/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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.as.pojo.service;
import org.jboss.as.pojo.logging.PojoLogger;
import org.jboss.as.pojo.descriptor.BeanMetaDataConfig;
import org.jboss.as.pojo.descriptor.ConstructorConfig;
import org.jboss.as.pojo.descriptor.FactoryConfig;
import org.jboss.as.pojo.descriptor.LifecycleConfig;
import org.jboss.as.pojo.descriptor.PropertyConfig;
import org.jboss.as.pojo.descriptor.ValueConfig;
import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
import org.jboss.modules.Module;
import org.jboss.msc.service.StartException;
import org.jboss.msc.value.ImmediateValue;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Bean utils.
*
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
*/
public final class BeanUtils {
/**
* Instantiate bean.
*
* @param beanConfig the bean metadata config, must not be null
* @param beanInfo the bean info, can be null if enough info
* @param index the reflection index, must not be null
* @param module the current CL module, must not be null
* @return new bean instance
* @throws Throwable for any error
*/
public static Object instantiateBean(BeanMetaDataConfig beanConfig, BeanInfo beanInfo, DeploymentReflectionIndex index, Module module) throws Throwable {
Joinpoint instantiateJoinpoint = null;
ValueConfig[] parameters = new ValueConfig[0];
String[] types = Configurator.NO_PARAMS_TYPES;
ConstructorConfig ctorConfig = beanConfig.getConstructor();
if (ctorConfig != null) {
parameters = ctorConfig.getParameters();
types = Configurator.getTypes(parameters);
String factoryClass = ctorConfig.getFactoryClass();
FactoryConfig factory = ctorConfig.getFactory();
if (factoryClass != null || factory != null) {
String factoryMethod = ctorConfig.getFactoryMethod();
if (factoryMethod == null)
throw PojoLogger.ROOT_LOGGER.missingFactoryMethod(beanConfig);
if (factoryClass != null) {
// static factory
Class<?> factoryClazz = Class.forName(factoryClass, false, module.getClassLoader());
Method method = Configurator.findMethod(index, factoryClazz, factoryMethod, types, true, true, true);
MethodJoinpoint mj = new MethodJoinpoint(method);
mj.setTarget(new ImmediateValue<Object>(null)); // null, since this is static call
mj.setParameters(parameters);
instantiateJoinpoint = mj;
} else if (factory != null) {
ReflectionJoinpoint rj = new ReflectionJoinpoint(factory.getBeanInfo(), factoryMethod, types);
// null type is ok, as this should be plain injection
rj.setTarget(new ImmediateValue<Object>(factory.getValue(null)));
rj.setParameters(parameters);
instantiateJoinpoint = rj;
}
}
}
// plain bean's ctor
if (instantiateJoinpoint == null) {
if (beanInfo == null)
throw new StartException(PojoLogger.ROOT_LOGGER.missingBeanInfo(beanConfig));
Constructor ctor = (types.length == 0) ? beanInfo.getConstructor() : beanInfo.findConstructor(types);
ConstructorJoinpoint constructorJoinpoint = new ConstructorJoinpoint(ctor);
constructorJoinpoint.setParameters(parameters);
instantiateJoinpoint = constructorJoinpoint;
}
return instantiateJoinpoint.dispatch();
}
/**
* Configure bean.
*
* @param beanConfig the bean metadata config, must not be null
* @param beanInfo the bean info, can be null if enough info
* @param module the current CL module, must not be null
* @param bean the bean instance
* @param nullify do we nullify property
* @throws Throwable for any error
*/
public static void configure(BeanMetaDataConfig beanConfig, BeanInfo beanInfo, Module module, Object bean, boolean nullify) throws Throwable {
Set<PropertyConfig> properties = beanConfig.getProperties();
if (properties != null) {
List<PropertyConfig> used = new ArrayList<PropertyConfig>();
for (PropertyConfig pc : properties) {
try {
configure(beanInfo, module, bean, pc, nullify);
used.add(pc);
} catch (Throwable t) {
if (nullify == false) {
for (PropertyConfig upc : used) {
try {
configure(beanInfo, module, bean,upc, true);
} catch (Throwable ignored) {
}
}
throw new StartException(t);
}
}
}
}
}
/**
* Dispatch lifecycle joinpoint.
*
* @param beanInfo the bean info
* @param bean the bean instance
* @param config the lifecycle config
* @param defaultMethod the default method
* @throws Throwable for any error
*/
public static void dispatchLifecycleJoinpoint(BeanInfo beanInfo, Object bean, LifecycleConfig config, String defaultMethod) throws Throwable {
if (config != null && config.isIgnored())
return;
Joinpoint joinpoint = createJoinpoint(beanInfo, bean, config, defaultMethod);
if (joinpoint != null)
joinpoint.dispatch();
}
private static Joinpoint createJoinpoint(BeanInfo beanInfo, Object bean, LifecycleConfig config, String defaultMethod) {
Method method;
ValueConfig[] params = null;
if (config == null) {
try {
method = beanInfo.getMethod(defaultMethod);
} catch (Exception t) {
PojoLogger.ROOT_LOGGER.tracef(t, "Ignoring default %s invocation.", defaultMethod);
return null;
}
} else {
String methodName = config.getMethodName();
if (methodName == null) {
methodName = defaultMethod;
}
ValueConfig[] parameters = config.getParameters();
String[] types = Configurator.getTypes(parameters);
method = beanInfo.findMethod(methodName, types);
params = parameters;
}
MethodJoinpoint joinpoint = new MethodJoinpoint(method);
joinpoint.setTarget(new ImmediateValue<Object>(bean));
joinpoint.setParameters(params);
return joinpoint;
}
private static void configure(BeanInfo beanInfo, Module module, Object bean, PropertyConfig pc, boolean nullify) throws Throwable {
ValueConfig value = pc.getValue();
Class<?> clazz = null;
String type = pc.getType(); // check property
if (type == null)
type = value.getType(); // check value
if (type != null)
clazz = module.getClassLoader().loadClass(type);
Method setter = beanInfo.getSetter(pc.getPropertyName(), clazz);
MethodJoinpoint joinpoint = new MethodJoinpoint(setter);
ValueConfig param = (nullify == false) ? value : null;
joinpoint.setParameters(new ValueConfig[]{param});
joinpoint.setTarget(new ImmediateValue<Object>(bean));
joinpoint.dispatch();
}
}