All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javaa.beans.PersistenceDelegate Maven / Gradle / Ivy

/* 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 javaa.beans;

import javaa.beans.Encoder;
import javaa.beans.Expression;
import javaa.beans.PersistenceDelegate;

/**
 * PersistenceDelegate instances write received bean objects to
 * encoders in the form of expressions and statements, which can be evaluated or
 * executed to reconstruct the recorded bean objects in a new environment during
 * decoding. Expressions are usually used to instantiate bean objects in the new
 * environment, and statements are used to initialize their properties if
 * necessary. As a result, the reconstructed bean objects become equivalent to
 * the original recorded ones in terms of their public states.
 * 
 */
public abstract class PersistenceDelegate {

    /**
     * Default constructor.
     */
    public PersistenceDelegate() {
        // empty
    }

    /**
     * Produces a series of expressions and statements for the initialization of
     * a bean object's properties. The default implementation simply invokes the
     * initialization provided by the super class's
     * PersisteneceDelegate instance.
     * 
     * @param type
     *            the type of the bean
     * @param oldInstance
     *            the original bean object to be recorded
     * @param newInstance
     *            the simmulating new bean object to be initialized
     * @param enc
     *            the encoder to write the outputs to
     */
    protected void initialize(Class type, Object oldInstance,
            Object newInstance, Encoder enc) {
        Class c = type.getSuperclass();
        if (null != c) {
            PersistenceDelegate pd = enc.getPersistenceDelegate(c);
            pd.initialize(c, oldInstance, newInstance, enc);
        }
    }

    /**
     * Constructs an expression for instantiating an object of the same type as
     * the old instance. Any exceptions occured during this process could be
     * reported to the exception listener registered in the given encoder.
     * 
     * @param oldInstance
     *            the old instance
     * @param enc
     *            the encoder that wants to record the old instance
     * @return an expression for instantiating an object of the same type as the
     *         old instance
     */
    protected abstract Expression instantiate(Object oldInstance, Encoder enc);

    /**
     * Determines whether one object mutates to the other object. One object is
     * considered able to mutate to another object if they are indistinguishable
     * in terms of behaviors of all public APIs. The default implementation here
     * is to return true only if the two objects are instances of the same
     * class.
     * 
     * @param o1
     *            one object
     * @param o2
     *            the other object
     * @return true if second object mutates to the first object, otherwise
     *         false
     */
    protected boolean mutatesTo(Object o1, Object o2) {
        if (null == o1 || null == o2 ) {
            return false;
        }
        return o1.getClass() == o2.getClass();
    }

    /**
     * Writes a bean object to the given encoder. First it is checked whether
     * the simulating new object can be mutated to the old instance. If yes, it
     * is initialized to produce a series of expressions and statements that can
     * be used to restore the old instance. Otherwise, remove the new object in
     * the simulating new environment and writes an expression that can
     * instantiate a new instance of the same type as the old one to the given
     * encoder.
     * 
     * @param oldInstance
     *            the old instance to be written
     * @param out
     *            the encoder that the old instance will be written to
     */
    public void writeObject(Object oldInstance, Encoder out) {
        Object newInstance = out.get(oldInstance);
        if (mutatesTo(oldInstance, newInstance)) {
            initialize(oldInstance.getClass(), oldInstance, newInstance, out);
        } else {
            out.remove(oldInstance);
            Expression exp = instantiate(oldInstance, out);
            out.writeExpression(exp);
            newInstance = out.get(oldInstance);
            
            if (newInstance != null) {
                initialize(oldInstance.getClass(), oldInstance,
                           newInstance, out);
            }
        }
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy