001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: Element.java 3777 2007-06-07 13:56:36Z gbevin $
007: */
008: package com.uwyn.rife.engine;
009:
010: import com.uwyn.rife.engine.exceptions.ElementMemberFieldUncloneableException;
011: import com.uwyn.rife.engine.exceptions.EngineException;
012: import com.uwyn.rife.tools.ObjectUtils;
013: import java.lang.reflect.Field;
014: import java.lang.reflect.Modifier;
015:
016: /**
017: * This is a convenience abstract class that implements the {@link
018: * ElementAware} interface and extends the {@link ElementSupport} class.
019: * <p>There are no mandatory abstract methods to implement and all {@link
020: * ElementSupport} methods are local.
021: * <p>Additionally, the {@link #clone} method is implemented to provide as
022: * good as possible default behaviour for continuations usage.
023: *
024: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
025: * @version $Revision: 3777 $
026: * @since 1.0
027: */
028: public abstract class Element extends ElementSupport implements
029: ElementAware, Cloneable {
030: public final void noticeElement(ElementSupport element) {
031: // an Element is already aware of itself
032: }
033:
034: public void processElement() throws EngineException {
035: }
036:
037: /**
038: * No-op default constructor that can only be used by extending classes.
039: *
040: * @since 1.0
041: */
042: protected Element() {
043: }
044:
045: /**
046: * Provides default cloning behavior by trying to make deep clones of all
047: * member variables, correctly handling primitives and collections.
048: * <p>Cloning is important when this element uses continuations since at
049: * each continuation step a clone will be made of the element instance to
050: * be able to still execute older continuations.
051: *
052: * @return a clone of this element instance
053: * @since 1.0
054: */
055: public Object clone() throws CloneNotSupportedException {
056: Element new_element = (Element) super .clone();
057:
058: // make a clone of all member fields that are references
059: Field[] fields = this .getClass().getDeclaredFields();
060: Class type = null;
061: Object value = null;
062: Object value_new = null;
063: for (Field field : fields) {
064: field.setAccessible(true);
065: type = field.getType();
066:
067: // primitive types don't have to be cloned
068: if (type != boolean.class && type != int.class
069: && type != long.class && type != float.class
070: && type != double.class && type != byte.class
071: && type != char.class) {
072: // don't clone static and final fields
073: if (Modifier.isStatic(field.getModifiers())
074: || Modifier.isFinal(field.getModifiers())
075: || Modifier.isTransient(field.getModifiers())) {
076: continue;
077: }
078:
079: // obtain the field's value
080: try {
081: value = field.get(this );
082: } catch (Throwable e) {
083: throw new ElementMemberFieldUncloneableException(
084: getClass().getName(), field.getName(), e);
085: }
086:
087: // null values are skipped
088: if (null == value) {
089: continue;
090: }
091:
092: // clone it and set it as the value of this element's clone
093: try {
094: value_new = ObjectUtils.deepClone(value);
095: } catch (CloneNotSupportedException e) {
096: throw new ElementMemberFieldUncloneableException(
097: getClass().getName(), field.getName(), e);
098: }
099:
100: try {
101: field.set(new_element, value_new);
102: } catch (Throwable e) {
103: throw new ElementMemberFieldUncloneableException(
104: getClass().getName(), field.getName(), e);
105: }
106: }
107: }
108:
109: return new_element;
110: }
111: }
|