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

org.jclarion.clarion.runtime.OverGlue Maven / Gradle / Ivy

/**
 * Copyright 2010, by Andrew Barnham
 *
 * The contents of this file are subject to
 * GNU Lesser General Public License (LGPL), v.3
 * http://www.gnu.org/licenses/lgpl.txt
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 */
package org.jclarion.clarion.runtime;

import java.lang.ref.WeakReference;
import org.jclarion.clarion.ClarionMemoryChangeListener;
import org.jclarion.clarion.ClarionMemoryModel;
import org.jclarion.clarion.memory.CMem;

/**
 * This class allows an object to call setOver() another object. Changes
 * in one object are propagated to other via their memory models as expressed
 * via ClarionMemoryModel interface
 * 
 * Objects are weakly linked. Once one of the objects becomes unreferencable
 * the Glue dissolves.
 * 
 * @author barney
 *
 */
public class OverGlue implements ClarionMemoryChangeListener
{
    private ClarionMemoryModel left;
    private WeakReference right;
   
    private int leftSize;
    private int rightSize;
    
    private CMem sos;
    
    /** 
     * when set we are already propagating changes. Required to protected against
     * backflow which will again forward flow and create an infinite loop
     */
    private boolean propagatingChanges=false;
    
    public OverGlue(ClarionMemoryModel left,ClarionMemoryModel right) {
        
        if (left==null || right==null) {
            // soft in the head clarion code in BufferedPairsClass does this
            return;
        }

        leftSize=CMemory.size(left);
        rightSize=CMemory.size(right);
        
        this.left=left;
        this.right=new WeakReference(right);
        
        left.addChangeListener(this,true);
        right.addChangeListener(this,false);
    }

    @Override
    public void objectChanged(ClarionMemoryModel model) {

        if (left==null || right==null) return;
        
        if (propagatingChanges) return;
        
        ClarionMemoryModel left;
        ClarionMemoryModel right;
        left=this.left;
        right=this.right.get();
        
        if (left==null || right==null) {
            // we are unglued. Remove listeners on any object still strongly referenced
            destroy();
            return;
        }

        ClarionMemoryModel src=null;
        ClarionMemoryModel dst=null;
        
        int srcSize=0;
        int destSize=0;
        
        // work out propagation direction
        
        if (model==left) {
            src=left;
            dst=right;
            srcSize=leftSize;
            destSize=rightSize;
        }
        if (model==right) {
            src=right;
            dst=left;
            srcSize=rightSize;
            destSize=leftSize;
        }
        
        if (src==null) {
            throw new RuntimeException("OverGlue observer triggered but source of event is not known to us!");
        }
        
        try {
            propagatingChanges=true;
         
            if (sos==null) {
                sos=CMem.create();
            }
            
            sos.reset();

            if (destSize>srcSize) {
                dst.serialize(sos);
                sos.reset();
                src.serialize(sos);
                sos.skipWrite(destSize-srcSize);
            } else {
                src.serialize(sos);
            }
            
            dst.deserialize(sos);
        } finally {
            propagatingChanges=false;
        }
    }

    @Override
    public void finalize()
    {
        destroy();
    }
    
    public void destroy()
    {
        if (this.right!=null) {
            ClarionMemoryModel right=this.right.get();
            if (right!=null) right.removeChangeListener(this);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy