/* * 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 com.googlecode.openbeans; import com.googlecode.openbeans.Encoder; import com.googlecode.openbeans.Expression; import com.googlecode.openbeans.PersistenceDelegate; /** * <code>PersistenceDelegate</code> 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 * <code>PersisteneceDelegate</code> 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) { return null != o1 && null != o2 && 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); Class<?> clazz = oldInstance.getClass(); if (mutatesTo(oldInstance, newInstance)) { initialize(clazz, oldInstance, newInstance, out); } else { out.remove(oldInstance); out.writeExpression(instantiate(oldInstance, out)); newInstance = out.get(oldInstance); if (newInstance != null) { initialize(clazz, oldInstance, newInstance, out); } } } }