package org.jboss.seam.remoting.model;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import org.jboss.seam.remoting.AnnotationsParser;
import org.jboss.seam.remoting.Call;
import org.jboss.seam.remoting.CallContext;
import org.jboss.seam.remoting.util.Strings;
/**
* Manages a model request
*
* @author Shane Bryzak
*/
public class Model implements Serializable
{
private static final long serialVersionUID = 8318288750036758325L;
private BeanManager beanManager;
private String id;
private CallContext callContext;
private Call action;
public class BeanProperty implements Serializable
{
private static final long serialVersionUID = 540993772239615536L;
private Bean<?> bean;
private String propertyName;
private Object value;
public BeanProperty(Bean<?> bean, String propertyName)
{
this.bean = bean;
this.propertyName = propertyName;
}
public Bean<?> getBean()
{
return bean;
}
public void evaluate(CreationalContext<?> ctx)
{
Object instance = beanManager.getReference(bean, bean.getBeanClass(), ctx);
if (propertyName != null)
{
try
{
Field f = bean.getBeanClass().getField(propertyName);
boolean accessible = f.isAccessible();
try
{
f.setAccessible(true);
value = f.get(instance);
}
catch (Exception e)
{
throw new RuntimeException(
"Exception reading model property " + propertyName +
" from bean [" + bean + "]");
}
finally
{
f.setAccessible(accessible);
}
}
catch (NoSuchFieldException ex)
{
// Try the getter method
String methodName = "get" + propertyName.substring(0, 1).toUpperCase() +
propertyName.substring(1);
try
{
Method m = bean.getBeanClass().getMethod(methodName);
value = m.invoke(instance);
}
catch (Exception e)
{
throw new RuntimeException(
"Exception reading model property " + propertyName +
" from bean [" + bean + "]");
}
}
}
else
{
this.value = instance;
}
}
public Object getValue()
{
return value;
}
}
private Map<String, BeanProperty> beanProperties;
public Model(BeanManager beanManager)
{
this.beanManager = beanManager;
id = UUID.randomUUID().toString();
callContext = new CallContext(beanManager);
beanProperties = new HashMap<String, BeanProperty>();
}
/**
* Evaluate each of the model's bean properties, expressions, etc and
* store the values in the BeanProperty map.
*/
public void evaluate()
{
for (String alias : beanProperties.keySet())
{
BeanProperty property = beanProperties.get(alias);
property.evaluate(beanManager.createCreationalContext(property.getBean()));
}
}
public Map<String,BeanProperty> getBeanProperties()
{
return beanProperties;
}
public String getId()
{
return id;
}
public CallContext getCallContext()
{
return callContext;
}
public void addBean(String alias, String beanName, String qualifiers, String propertyName)
{
Set<Bean<?>> beans = beanManager.getBeans(beanName);
if (beans.isEmpty())
{
try
{
Class<?> beanType = Class.forName(beanName);
Annotation[] q = qualifiers != null && !Strings.isEmpty(qualifiers) ?
new AnnotationsParser(beanType, qualifiers, beanManager).getAnnotations() :
Call.EMPTY_ANNOTATIONS;
beans = beanManager.getBeans(beanType, q);
}
catch (ClassNotFoundException ex)
{
throw new IllegalArgumentException("Invalid bean class specified: " + beanName);
}
if (beans.isEmpty())
{
throw new IllegalArgumentException(
"Could not find bean with bean with type/name " + beanName +
", qualifiers [" + qualifiers + "]");
}
}
Bean<?> bean = beans.iterator().next();
beanProperties.put(alias, new BeanProperty(bean, propertyName));
}
public void setAction(Call action)
{
this.action = action;
}
public Call getAction()
{
return action;
}
}