/**
*
* Copyright 2003-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.gbean.runtime;
import java.lang.reflect.Method;
import org.apache.geronimo.gbean.DynamicGAttributeInfo;
import org.apache.geronimo.gbean.DynamicGBean;
import org.apache.geronimo.gbean.GAttributeInfo;
import org.apache.geronimo.gbean.InvalidConfigurationException;
import org.apache.geronimo.kernel.ClassLoading;
/**
* @version $Rev$ $Date$
*/
public class GBeanAttribute {
private final GBeanInstance gbeanInstance;
private final String name;
private final Class type;
private final boolean readable;
private final MethodInvoker getInvoker;
private final boolean writable;
private final MethodInvoker setInvoker;
private final boolean isConstructorArg;
private final boolean persistent;
private final boolean manageable;
private Object persistentValue;
/**
* Is this a special attribute like objectName, classLoader or gbeanContext?
* Special attributes are injected at startup just like persistent attrubutes, but are
* otherwise unmodifiable.
*/
private final boolean special;
private final boolean framework;
private final boolean dynamic;
private final GAttributeInfo attributeInfo;
static GBeanAttribute createSpecialAttribute(GBeanAttribute attribute, GBeanInstance gbeanInstance, String name, Class type, Object value) {
return new GBeanAttribute(attribute, gbeanInstance, name, type, value);
}
private GBeanAttribute(GBeanAttribute attribute, GBeanInstance gbeanInstance, String name, Class type, Object value) {
this.special = true;
this.framework = false;
this.dynamic = false;
if (gbeanInstance == null || name == null || type == null) {
throw new IllegalArgumentException("null param(s) supplied");
}
// if we have an attribute verify the gbean instance, name and types match
if (attribute != null) {
assert (gbeanInstance == attribute.gbeanInstance);
assert (name.equals(attribute.name));
if (type != attribute.type) {
throw new InvalidConfigurationException("Special attribute " + name +
" must have the type " + type.getName() + ", but is " +
attribute.type.getName() + ": targetClass=" + gbeanInstance.getType().getName());
}
if (attribute.isPersistent()) {
throw new InvalidConfigurationException("Special attributes must not be persistent:" +
" name=" + name + ", targetClass=" + gbeanInstance.getType().getName());
}
}
this.gbeanInstance = gbeanInstance;
this.name = name;
this.type = type;
// getter
this.getInvoker = null;
this.readable = true;
// setter
if (attribute != null) {
this.setInvoker = attribute.setInvoker;
this.isConstructorArg = attribute.isConstructorArg;
} else {
this.setInvoker = null;
this.isConstructorArg = false;
}
this.writable = false;
// persistence
this.persistent = false;
initializePersistentValue(value);
// not manageable
this.manageable = false;
// create an attribute info for this gbean
if (attribute != null) {
GAttributeInfo attributeInfo = attribute.getAttributeInfo();
this.attributeInfo = new GAttributeInfo(this.name,
this.type.getName(),
this.persistent,
this.manageable,
this.readable,
this.writable,
attributeInfo.getGetterName(),
attributeInfo.getSetterName());
} else {
this.attributeInfo = new GAttributeInfo(this.name,
this.type.getName(),
this.persistent,
this.manageable,
this.readable,
this.writable,
null,
null);
}
}
static GBeanAttribute createFrameworkAttribute(GBeanInstance gbeanInstance, String name, Class type, MethodInvoker getInvoker) {
return new GBeanAttribute(gbeanInstance, name, type, getInvoker, null, false, null, true);
}
static GBeanAttribute createFrameworkAttribute(GBeanInstance gbeanInstance, String name, Class type, MethodInvoker getInvoker, MethodInvoker setInvoker, boolean persistent, Object persistentValue, boolean manageable) {
return new GBeanAttribute(gbeanInstance, name, type, getInvoker, setInvoker, persistent, persistentValue, manageable);
}
private GBeanAttribute(GBeanInstance gbeanInstance, String name, Class type, MethodInvoker getInvoker, MethodInvoker setInvoker, boolean persistent, Object persistentValue, boolean manageable) {
this.special = false;
this.framework = true;
this.dynamic = false;
if (gbeanInstance == null || name == null || type == null) {
throw new IllegalArgumentException("null param(s) supplied");
}
this.gbeanInstance = gbeanInstance;
this.name = name;
this.type = type;
// getter
this.getInvoker = getInvoker;
this.readable = (this.getInvoker != null);
// setter
this.setInvoker = setInvoker;
this.isConstructorArg = false;
this.writable = (this.setInvoker != null);
// persistence
this.persistent = persistent;
initializePersistentValue(persistentValue);
// manageable
this.manageable = manageable;
// create an attribute info for this gbean
attributeInfo = new GAttributeInfo(this.name,
this.type.getName(),
this.persistent,
this.manageable,
this.readable,
this.writable,
null,
null);
}
public GBeanAttribute(GBeanInstance gbeanInstance, GAttributeInfo attributeInfo, boolean isConstructorArg) throws InvalidConfigurationException {
this.special = false;
this.framework = false;
if (gbeanInstance == null || attributeInfo == null) {
throw new IllegalArgumentException("null param(s) supplied");
}
if (!attributeInfo.isReadable() && !attributeInfo.isWritable() && !attributeInfo.isPersistent() && !isConstructorArg) {
throw new InvalidConfigurationException("An attribute must be readable, writable, persistent or a constructor arg: " +
" name=" + attributeInfo.getName() + " targetClass=" + gbeanInstance.getType().getName());
}
this.gbeanInstance = gbeanInstance;
this.attributeInfo = attributeInfo;
this.name = attributeInfo.getName();
this.isConstructorArg = isConstructorArg;
try {
this.type = ClassLoading.loadClass(attributeInfo.getType(), gbeanInstance.getClassLoader());
} catch (ClassNotFoundException e) {
throw new InvalidConfigurationException("Could not load attribute class: " + attributeInfo.getType());
}
this.persistent = attributeInfo.isPersistent();
this.manageable = attributeInfo.isManageable();
readable = attributeInfo.isReadable();
writable = attributeInfo.isWritable();
// If attribute is persistent or not tagged as unreadable, search for a
// getter method
if (attributeInfo instanceof DynamicGAttributeInfo) {
this.dynamic = true;
if (readable) {
getInvoker = new DynamicGetterMethodInvoker(name);
} else {
getInvoker = null;
}
if (writable) {
setInvoker = new DynamicSetterMethodInvoker(name);
} else {
setInvoker = null;
}
} else {
this.dynamic = false;
if (attributeInfo.getGetterName() != null) {
try {
String getterName = attributeInfo.getGetterName();
Method getterMethod = gbeanInstance.getType().getMethod(getterName, null);
if (!getterMethod.getReturnType().equals(type)) {
throw new InvalidConfigurationException("Getter method of wrong type: " + getterMethod.getReturnType() + " expected " +getDescription());
}
getInvoker = new FastMethodInvoker(getterMethod);
} catch (NoSuchMethodException e) {
throw new InvalidConfigurationException("Getter method not found " +getDescription());
}
} else {
getInvoker = null;
}
// If attribute is persistent or not tagged as unwritable, search
// for a setter method
if (attributeInfo.getSetterName() != null) {
try {
String setterName = attributeInfo.getSetterName();
Method setterMethod = gbeanInstance.getType().getMethod(setterName, new Class[] {type});
setInvoker = new FastMethodInvoker(setterMethod);
} catch (NoSuchMethodException e) {
throw new InvalidConfigurationException("Setter method not found " + getDescription());
}
} else {
setInvoker = null;
}
}
initializePersistentValue(null);
}
private void initializePersistentValue(Object value) {
if (persistent || special) {
if (value == null && type.isPrimitive() && isConstructorArg) {
if (type == Boolean.TYPE) {
value = Boolean.FALSE;
} else if (type == Byte.TYPE) {
value = new Byte((byte) 0);
} else if (type == Short.TYPE) {
value = new Short((short) 0);
} else if (type == Integer.TYPE) {
value = new Integer(0);
} else if (type == Long.TYPE) {
value = new Long(0);
} else if (type == Character.TYPE) {
value = new Character((char) 0);
} else if (type == Float.TYPE) {
value = new Float(0);
} else /** if (type == Double.TYPE) */ {
value = new Double(0);
}
}
persistentValue = value;
}
}
public String getName() {
return name;
}
public GAttributeInfo getAttributeInfo() {
return attributeInfo;
}
public boolean isReadable() {
return readable;
}
public boolean isWritable() {
return writable;
}
public Class getType() {
return type;
}
public boolean isFramework() {
return framework;
}
public boolean isDynamic() {
return dynamic;
}
public boolean isPersistent() {
return persistent;
}
public boolean isManageable() {
return manageable;
}
public boolean isSpecial() {
return special;
}
public void inject(Object target) throws Exception {
if ((persistent || special) && !isConstructorArg && writable && persistentValue != null) {
setValue(target, persistentValue);
}
}
public Object getPersistentValue() {
if (!persistent && !special) {
throw new IllegalStateException("Attribute is not persistent " + getDescription());
}
return persistentValue;
}
public void setPersistentValue(Object persistentValue) {
if (!persistent && !special) {
throw new IllegalStateException("Attribute is not persistent " + getDescription());
}
if (persistentValue == null && type.isPrimitive()) {
throw new IllegalArgumentException("Cannot assign null to a primitive attribute. " + getDescription());
}
// @todo actually check type
this.persistentValue = persistentValue;
}
public Object getValue(Object target) throws Exception {
if (!readable) {
if (persistent) {
throw new IllegalStateException("This persistent attribute is not accessible while started. " + getDescription());
} else {
throw new IllegalStateException("This attribute is not readable. " + getDescription());
}
}
if (special) {
return persistentValue;
}
// get the target to invoke
if (target == null && !framework) {
throw new IllegalStateException("GBean does not have a target instance to invoke. " + getDescription());
}
// call the getter
Object value = getInvoker.invoke(target, null);
return value;
}
public void setValue(Object target, Object value) throws Exception {
if (!writable) {
if (persistent) {
throw new IllegalStateException("This persistent attribute is not modifable while running. " + getDescription());
} else {
throw new IllegalStateException("This attribute is not writable. " + getDescription());
}
}
// the value can not be null for primitives
if (value == null && type.isPrimitive()) {
throw new IllegalArgumentException("Cannot assign null to a primitive attribute. " + getDescription());
}
// @todo actually check type
// get the target to invoke
if (target == null && !framework) {
throw new IllegalStateException("GBean does not have a target instance to invoke. " + getDescription());
}
// call the setter
setInvoker.invoke(target, new Object[]{value});
}
public String getDescription() {
return "Attribute Name: " + getName() + ", Type: " + getType() + ", GBeanInstance: " + gbeanInstance.getName();
}
private static final class DynamicGetterMethodInvoker implements MethodInvoker {
private final String name;
public DynamicGetterMethodInvoker(String name) {
this.name = name;
}
public Object invoke(Object target, Object[] arguments) throws Exception {
return ((DynamicGBean) target).getAttribute(name);
}
}
private static final class DynamicSetterMethodInvoker implements MethodInvoker {
private final String name;
public DynamicSetterMethodInvoker(String name) {
this.name = name;
}
public Object invoke(Object target, Object[] arguments) throws Exception {
((DynamicGBean) target).setAttribute(name, arguments[0]);
return null;
}
}
}