You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by si...@apache.org on 2009/03/03 17:18:07 UTC
svn commit: r749642 - in
/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans:
BeanData.java BeanHandler.java BeansAspect.aj BeansHandlerAspect.aj
MagmaBean.java MagmaBeanSupport.java PropertyInfo.java
Author: simoneg
Date: Tue Mar 3 16:18:06 2009
New Revision: 749642
URL: http://svn.apache.org/viewvc?rev=749642&view=rev
Log:
LABS-285 : javadocs for foundation-beans
Modified:
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanHandler.java
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansAspect.aj
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansHandlerAspect.aj
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBean.java
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBeanSupport.java
labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java Tue Mar 3 16:18:06 2009
@@ -30,10 +30,25 @@
import org.apache.commons.beanutils.PropertyUtils;
+/**
+ * Holds informations about a bean. The bean is inspected only once, and various components
+ * can participate adding fields to this class or to {@link PropertyInfo} and intercepting the
+ * {@link PropertyInfo#init(PropertyDescriptor, Class)} method to provide parsing.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
public class BeanData {
+ /**
+ * Cached {@link BeanData} for already inspected bean classes.
+ */
private static Map<Class,BeanData> data = new HashMap<Class, BeanData>();
+ /**
+ * Retrieves a {@link BeanData} for a given bean, either cached or by parsing.
+ * @param clazz the class of the bean.
+ * @return a {@link BeanData} for the class.
+ */
public static BeanData getFor(Class clazz) {
BeanData ret = data.get(clazz);
if (ret == null) {
@@ -43,10 +58,20 @@
return ret;
}
+ /**
+ * The class this {@link BeanData} holds informations for.
+ */
private Class beanClass = null;
+ /**
+ * Properties of the class.
+ */
private Map<String, PropertyInfo> properties = new HashMap<String, PropertyInfo>();
+ /**
+ * Builds a new {@link BeanData} for the given class, performing inspection.
+ * @param clazz the class to inspect.
+ */
private BeanData(Class clazz) {
this.beanClass = clazz;
BeanInfo beanInfo = null;
@@ -63,18 +88,35 @@
}
}
+ /**
+ * Fetches names of properties in the bean class.
+ * @return names of properties
+ */
public Set<String> getPropertyNames() {
return Collections.unmodifiableSet(properties.keySet());
}
+ /**
+ * Fetches a single property.
+ * @param name the name of the property to fetch.
+ * @return a {@link PropertyInfo} describing the required property, or null if not found.
+ */
public PropertyInfo getProperty(String name) {
return properties.get(name);
}
+ /**
+ * @return the class this {@link BeanData} holds informations for.
+ */
public Class getBeanClass() {
return this.beanClass;
}
+ /**
+ * Searches for the property on which given method operates.
+ * @param method the method, a getter or setter.
+ * @return the {@link PropertyInfo} describing the property the method works on, or null if not found.
+ */
public PropertyInfo findProperty(Method method) {
String name = method.getName();
if (name.startsWith("set") || name.startsWith("get")) {
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanHandler.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanHandler.java?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanHandler.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanHandler.java Tue Mar 3 16:18:06 2009
@@ -27,21 +27,61 @@
import org.apache.commons.beanutils.PropertyUtils;
+/**
+ * Offers a "transactional" abstraction to a bean instance getters and setters.
+ *
+ * Using an handler to populate or read a bean offers the advantage of offering a
+ * hook point for other components to participate in the process, for example adding
+ * validations.
+ *
+ * Also, this is the good place to add utility methods to perform operations on data, like
+ * conversion or formatting.
+ *
+ * Having a "transactional" approach gives the opportunity to validate all the fields or to
+ * make sure all conversions occurrs correctly before writing any value to the bean, reducing
+ * the possibility of stale data.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
public class BeanHandler {
+ /**
+ * The bean we are working on.
+ */
private MagmaBeanSupport bean;
+
+ /**
+ * The {@link BeanData} of the bean.
+ */
private BeanData data;
+ /**
+ * Temporary storage for bean values.
+ */
private Map<String, Object> values = new HashMap<String, Object>();
+
+ /**
+ * Holds which values has been changed, to avoid calling setters on those unchanged properties.
+ */
private Set<String> changed = new HashSet<String>();
-
+ /**
+ * Builds a handler for the given bean.
+ * @param bean The bean to operate on.
+ */
public BeanHandler(MagmaBeanSupport bean) {
this.bean = bean;
this.data = bean.beanData();
rollback();
}
+ /**
+ * Sets a value on the bean, the {@link BeanData} is used to check that the property exist, it is writable and the value
+ * is of correct type. Value is stored on the temporary area, will be effectively transferred to the bean when
+ * {@link #commit()} is called, or removed when {@link #rollback()} is called.
+ * @param field The name of the property to set.
+ * @param value The value to set.
+ */
public void setValue(String field, Object value) {
PropertyInfo property = data.getProperty(field);
if (property == null) throw new MagmaException("Cannot find a proprty named {0} in class {1}", field, bean.getClass().getName());
@@ -55,6 +95,13 @@
changed.add(field);
}
+ /**
+ * Gets a value from the bean, the {@link BeanData} is used to check that the property exist and it is readable. Value
+ * is taken from the temporary area, where it has been fetched by {@link #rollback()} and eventually modified by
+ * {@link #setValue(String, Object)} or by other methods contributed by other components.
+ * @param field the name of the property to get.
+ * @return the value of the property.
+ */
public Object getValue(String field) {
PropertyInfo property = data.getProperty(field);
if (property == null) throw new MagmaException("Cannot find a proprty named {0} in class {1}", field, bean.getClass().getName());
@@ -62,6 +109,10 @@
return values.get(field);
}
+ /**
+ * Load from the bean (calling getters) all the applicable properties, and places them in the temporary area, eventually
+ * overwriting values placed there by {@link #setValue(String, Object)}.
+ */
public void rollback() {
this.values.clear();
this.changed.clear();
@@ -80,6 +131,11 @@
}
}
+ /**
+ * Saves on the bean (calling setters) all the properties modified using {@link #setValue(String, Object)} (or equivalent
+ * methods contributed by other components). This method is the perfect hook to perform validations or other preprocessing
+ * of values.
+ */
public void commit() {
for (Iterator<String> iterator = changed.iterator(); iterator.hasNext();) {
String name = iterator.next();
@@ -95,6 +151,11 @@
}
}
+ /**
+ * Notifies this {@link BeanHandler} that a property has changed on the bean. An aspect provide interception of
+ * setters to notify existing handlers.
+ * @param property
+ */
public void updated(PropertyInfo property) {
if (property.isReadable()) {
String name = property.getName();
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansAspect.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansAspect.aj?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansAspect.aj (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansAspect.aj Tue Mar 3 16:18:06 2009
@@ -16,7 +16,15 @@
*/
package org.apache.magma.beans;
-
+/**
+ * Injects the {@link MagmaBeanSupport} interface on beans recognized by Magma. Currently
+ * that means beans annotated with {@link MagmaBean} or classes contained in a package
+ * that contains "domain" in its name.
+ *
+ * Also provides a default implementation for the two methods of {@link MagmaBeanSupport}.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
public aspect BeansAspect {
declare parents: (*..domain..*) implements MagmaBeanSupport;
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansHandlerAspect.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansHandlerAspect.aj?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansHandlerAspect.aj (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeansHandlerAspect.aj Tue Mar 3 16:18:06 2009
@@ -19,15 +19,33 @@
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
+import org.apache.magma.basics.startup.Cycle;
import org.apache.magma.basics.startup.CycleThreadLocal;
import org.aspectj.lang.reflect.MethodSignature;
+/**
+ * Manages {@link BeanHandler}s on bean instances, so that each thread has a single
+ * handler if working on the same bean, and old handlers are cleaned up when the
+ * {@link Cycle} ends.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
public aspect BeansHandlerAspect perthis(calledHandler(MagmaBeanSupport)) {
+ /**
+ * A {@link CycleThreadHandler} holding (as SoftRerence) handlers on a bean.
+ */
private CycleThreadLocal<SoftReference<BeanHandler>> tl = new CycleThreadLocal<SoftReference<BeanHandler>>();
+ /**
+ * The call of the method {@link MagmaBeanSupport#handler()}.
+ * @param bean the bean the method was called on.
+ */
pointcut calledHandler(MagmaBeanSupport bean) : execution(public BeanHandler MagmaBeanSupport+.handler()) && this(bean);
+ /**
+ * Returns the existing handler or a new one.
+ */
Object around(MagmaBeanSupport bean) : calledHandler(bean) {
SoftReference<BeanHandler> reference = tl.get();
if (reference != null) {
@@ -41,8 +59,15 @@
return handler;
}
+ /**
+ * Intercepts calls to a setter on a managed bean, to notify handlers.
+ * @param bean
+ */
pointcut calledSetter(MagmaBeanSupport bean) : execution(public void MagmaBeanSupport+.set*(..)) && !cflow(execution(* BeanHandler+.commit()) || execution(* BeanHandler+.rollback())) && this(bean);
+ /**
+ * Notifies handlers that a property on the bean has changed.
+ */
after(MagmaBeanSupport bean) returning : calledSetter(bean) {
if (((MethodSignature)thisJoinPointStaticPart.getSignature()).getMethod().isSynthetic()) return;
Method method = ((MethodSignature)thisJoinPointStaticPart.getSignature()).getMethod();
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBean.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBean.java?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBean.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBean.java Tue Mar 3 16:18:06 2009
@@ -22,6 +22,11 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Marker annotation for beans that should be handled using {@link BeanData} and {@link BeanHandler}.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBeanSupport.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBeanSupport.java?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBeanSupport.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/MagmaBeanSupport.java Tue Mar 3 16:18:06 2009
@@ -16,11 +16,23 @@
*/
package org.apache.magma.beans;
-import java.util.HashMap;
-import java.util.Map;
+/**
+ * Interface inferred on bean managed using {@link BeanData} and {@link BeanHandler}.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
public interface MagmaBeanSupport {
+ /**
+ * Retrieves the {@link BeanData} instance for this class.
+ * @return BeanData for this class.
+ */
public BeanData beanData();
+
+ /**
+ * Retrieves the {@link BeanHandler} instance for this class.
+ * @return BeanHandler for this class.
+ */
public BeanHandler handler();
}
Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java?rev=749642&r1=749641&r2=749642&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java Tue Mar 3 16:18:06 2009
@@ -21,42 +21,110 @@
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import org.apache.magma.basics.utils.GenericClass;
import org.apache.magma.basics.utils.GenericClass.MethodDef;
+/**
+ * Holds informations about a property of a bean.
+ *
+ * Other components can parse more annotation of meta informations intercepting the
+ * {@link #init(PropertyDescriptor, Class)} method, to populate additional fields on this
+ * class. This is how, for example, validation and conversion works.
+ *
+ * @author Simone Gianni <si...@apache.org>
+ */
public class PropertyInfo implements Cloneable {
+ /**
+ * Name of the property.
+ */
private String name;
+
+ /**
+ * Type of the property
+ */
private Class type;
+
+ /**
+ * Class of the bean this property is found on
+ */
private Class beanClass;
+
+ /**
+ * Whether the property is readable
+ */
private boolean readable;
+
+ /**
+ * Whether the property is writable
+ */
private boolean writeable;
+ /**
+ * Whether the property represents a collection (this includes {@link List}, {@link Set} and arrays, but not maps or tables).
+ */
private boolean isCollection;
+
+ /**
+ * The type of elements contained in the collection (could be Object if it's not possible to deduce it)
+ */
private Class collectionClass;
- private int maxStringSize = -1;
+ /**
+ * If content of this property is rendered as a string, the maximum size of this string.
+ */
+ private int maxStringSize = -1;
+ /**
+ * @return true if this property is readable from the bean, false otherwise
+ */
public boolean isReadable() {
return readable;
}
+ /**
+ * @param readable true if this property is readable from the bean, false otherwise
+ */
public void setReadable(boolean readable) {
this.readable = readable;
}
+
+ /**
+ * @return true if this property is writable to the bean, false otherwise
+ */
public boolean isWriteable() {
return writeable;
}
+ /**
+ * @param writeable true if this property is writable to the bean, false otherwise
+ */
public void setWriteable(boolean writeable) {
this.writeable = writeable;
}
+
+ /**
+ * @return the name of the property.
+ */
public String getName() {
return name;
}
+
+ /**
+ * @return the type of the property.
+ */
public Class getType() {
return type;
}
+ /**
+ * Initializes this class, parsing the {@link PropertyDescriptor} and eventually annotations found on the getter or setter methods.
+ *
+ * This is the method to hook to when implementing additional parsing, like validation and conversion does.
+ *
+ * @param descriptor the {@link PropertyDescriptor} of the property.
+ * @param beanClass the class of the bean containing the property.
+ */
public void init(PropertyDescriptor descriptor, Class beanClass) {
this.beanClass = beanClass;
this.name = descriptor.getName();
@@ -75,6 +143,9 @@
this.writeable = descriptor.getWriteMethod() != null;
}
+ /**
+ * Clones this {@link PropertyInfo}
+ */
public PropertyInfo clone() {
try {
return (PropertyInfo) super.clone();
@@ -82,39 +153,92 @@
return null;
}
}
+
+ /**
+ * @return Whether the property represents a collection (this includes {@link List}, {@link Set} and arrays, but not maps or tables).
+ */
public boolean isCollection() {
return isCollection;
}
+
+ /**
+ * @param isCollection Wether the property represents a collection.
+ */
public void setCollection(boolean isCollection) {
this.isCollection = isCollection;
}
+
+ /**
+ * @return The type of elements contained in the collection (could be Object if it's not possible to deduce it)
+ */
public Class getCollectionClass() {
return collectionClass;
}
+
+ /**
+ * @param collectionClass The type of elements contained in the collection (could be Object if it's not possible to deduce it)
+ */
public void setCollectionClass(Class collectionClass) {
this.collectionClass = collectionClass;
}
+
+ /**
+ * @return Class of the bean this property is found on
+ */
public Class getBeanClass() {
return beanClass;
}
+
+ /**
+ * @param beanClass Class of the bean this property is found on
+ */
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
+ /**
+ * @return If content of this property is rendered as a string, the maximum size of this string.
+ */
public int getMaximumStringSize() {
return this.maxStringSize;
}
+
+ /**
+ * @param size If content of this property is rendered as a string, the maximum size of this string.
+ */
public void setMaximumStringSize(int size) {
this.maxStringSize = size;
}
+
+ /**
+ * Alters the string size, only reducing it.
+ * @param size the proposed maximum size, or -1 to leave it unaltered.
+ */
public void alterMaximumStringSize(int size) {
if (size == -1) return;
if (this.maxStringSize == -1 || this.maxStringSize > size) this.maxStringSize = size;
}
-
+
+ /**
+ * Converts the given value to a machine parsable string, considering the value coming from the property represented by this instance.
+ *
+ * This means that other components may alter the way the value is converted, as conversion does.
+ *
+ * @param value The value to convert to string.
+ * @return the string machine parsable representation of value.
+ */
public String toString(Object value) {
return value == null ? "" : value.toString();
}
+
+ /**
+ * Converts the given value to a human friendly string, considering the value coming from the property represented by this instance.
+ *
+ * This means that other components may alter the way the value is converted, as formatters and i18n do.
+ *
+ * @param value The value to convert to string.
+ * @return the string human friendly representation of value.
+ */
public String toUser(Object value) {
return toString(value);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org