/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: Element.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.engine;
import com.uwyn.rife.engine.exceptions.ElementMemberFieldUncloneableException;
import com.uwyn.rife.engine.exceptions.EngineException;
import com.uwyn.rife.tools.ObjectUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* This is a convenience abstract class that implements the {@link
* ElementAware} interface and extends the {@link ElementSupport} class.
* <p>There are no mandatory abstract methods to implement and all {@link
* ElementSupport} methods are local.
* <p>Additionally, the {@link #clone} method is implemented to provide as
* good as possible default behaviour for continuations usage.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @version $Revision: 3918 $
* @since 1.0
*/
public abstract class Element extends ElementSupport implements ElementAware, Cloneable
{
public final void noticeElement(ElementSupport element)
{
// an Element is already aware of itself
}
public void processElement()
throws EngineException
{
}
/**
* No-op default constructor that can only be used by extending classes.
*
* @since 1.0
*/
protected Element()
{
}
/**
* Provides default cloning behavior by trying to make deep clones of all
* member variables, correctly handling primitives and collections.
* <p>Cloning is important when this element uses continuations since at
* each continuation step a clone will be made of the element instance to
* be able to still execute older continuations.
*
* @return a clone of this element instance
* @since 1.0
*/
public Object clone()
throws CloneNotSupportedException
{
Element new_element = (Element)super.clone();
// make a clone of all member fields that are references
Field[] fields = this.getClass().getDeclaredFields();
Class type = null;
Object value = null;
Object value_new = null;
for (Field field : fields)
{
field.setAccessible(true);
type = field.getType();
// primitive types don't have to be cloned
if (type != boolean.class &&
type != int.class &&
type != long.class &&
type != float.class &&
type != double.class &&
type != byte.class &&
type != char.class)
{
// don't clone static and final fields
if (Modifier.isStatic(field.getModifiers()) ||
Modifier.isFinal(field.getModifiers()) ||
Modifier.isTransient(field.getModifiers()))
{
continue;
}
// obtain the field's value
try
{
value = field.get(this);
}
catch (Throwable e)
{
throw new ElementMemberFieldUncloneableException(getClass().getName(), field.getName(), e);
}
// null values are skipped
if (null == value)
{
continue;
}
// clone it and set it as the value of this element's clone
try
{
value_new = ObjectUtils.deepClone(value);
}
catch (CloneNotSupportedException e)
{
throw new ElementMemberFieldUncloneableException(getClass().getName(), field.getName(), e);
}
try
{
field.set(new_element, value_new);
}
catch (Throwable e)
{
throw new ElementMemberFieldUncloneableException(getClass().getName(), field.getName(), e);
}
}
}
return new_element;
}
}