FileDocCategorySizeDatePackage
Memento.javaAPI DocExample4646Fri Aug 25 08:31:48 BST 2000com.imaginary.lwp

Memento.java

package com.imaginary.lwp;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;

/**
 * Captures the classic memento pattern for Java. The memento pattern
 * decouples a business object from its state so that systems like
 * the lightweight persistence engine can manage storage and retrieval
 * of an object's state to and from a data store.
 * <BR>
 * Last modified $Date$
 * @version $Revision$
 * @author <A href="mailto:george.reese@dasein.org">George Reese</A>
 */
public class Memento implements Serializable {
    /**
     * The bitmask meaning an attribute should not be saved.
     */
    static public final int NOSAVE =
        (Modifier.FINAL | Modifier.STATIC | Modifier.TRANSIENT);

    /**
     * Determines whether or not a given field should be saved.
     * A field should not be saved if it is final, static, or transient.
     * @param f the field to be tested
     * @return true if the field should be saved
     */
    static public boolean isSaved(Field f) {
        int mod = f.getModifiers();
        
        if( (mod & Memento.NOSAVE) == 0 ) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * The values representing the state of the object behind this
     * memento.
     * @serial
     */
    private HashMap values = new HashMap();

    /**
     * Constructs a new, empty memento.
     */
    public Memento() {
        super();
    }

    /**
     * Constructs a memento representing the state of the specified
     * object.
     * @param ob the object to be represented
     */
    public Memento(Object ob) {
        super();
        {
            Class cls = ob.getClass();
            
            while( !cls.equals(Object.class) ) {
                Field[] attrs = cls.getDeclaredFields();
                HashMap map = new HashMap();
                
                values.put(cls, map);
                for(int i=0; i<attrs.length; i++) {
                    attrs[i].setAccessible(true);
                    if( isSaved(attrs[i]) ) {
                        try {
                            map.put(attrs[i].getName(), attrs[i].get(ob));
                        }
                        catch( IllegalAccessException e ) {
                            throw new SecurityException(e.getMessage());
                        }
                    }
                }
                cls = cls.getSuperclass();
            }
        }
    }

    /**
     * Provides the value for the attribute of the specified class.
     * @param cls the class in which the attribute is declared
     * @param attr the name of the attribute
     * @return the value of the attribute
     */
    public Object get(Class cls, String attr) {
        HashMap map;

        if( !values.containsKey(cls) ) {
            return null;
        }
        map = (HashMap)values.get(cls);
        return map.get(attr);
    }

    /**
     * Maps the values currently in the memento to the object
     * in question.
     * @param ob the object who should be assigned values from the memento
     * @throws java.lang.NoSuchFieldException the object in question does
     * not have a field for one of the memento values
     */
    public void map(Object ob) throws NoSuchFieldException {
        Iterator keys = values.keySet().iterator();

        while( keys.hasNext() ) {
            Class cls = (Class)keys.next();
            HashMap vals = (HashMap)values.get(cls);
            Iterator attrs = vals.keySet().iterator();

            while( attrs.hasNext() ) {
                String attr = (String)attrs.next();
                Object val = vals.get(attr);
                Field f = cls.getDeclaredField(attr);

                f.setAccessible(true);
                try {
                    f.set(ob, val);
                }
                catch( IllegalAccessException e ) {
                    throw new SecurityException(e.getMessage());
                }
            }
        }
    }

    /**
     * Places the specified value into the memento based on the field's
     * declaring class and name.
     * @param cls the class in which the field is declared
     * @param attr the name of the attribute
     * @param val the value being stored
     */
    public void put(Class cls, String attr, Object val) {
        HashMap map;
        
        if( values.containsKey(cls) ) {
            map = (HashMap)values.get(cls);
        }
        else {
            map = new HashMap();
            values.put(cls, map);
        }
        map.put(attr, val);
    }
}