Package jsynoptic.plugins.java3d

Source Code of jsynoptic.plugins.java3d.DataAnimator$State

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2007, by :
*     Corporate:
*         EADS Astrium
*     Individual:
*         Claude Cazenave
*
* $Id: DataAnimator.java,v 1.7 2008/11/06 18:11:21 cazenave Exp $
*
* Changes
* -------
* 19 janv. 08  : Initial public release
*
*/
package jsynoptic.plugins.java3d;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

import javax.media.j3d.Locale;
import javax.media.j3d.SceneGraphObject;

import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceListener;
import simtools.data.DataSourcePool;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;

import com.sun.j3d.utils.scenegraph.io.SceneGraphStateProvider;
import com.sun.j3d.utils.scenegraph.io.retained.Controller;
import com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData;
import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;

/**
*/
public abstract class DataAnimator extends Animator implements SceneGraphStateProvider, DirtyNode{

    private Class<? extends Data> _dataClass;

    private int _dataClassParam;
   
    protected Data _data;

    protected Universe _universe;
   
    /**
     * Create a SceneGraphData linked with a SceneGraphObject
     */
    public DataAnimator() {
        this(null,-1);
    }
   
    /**
     * Create a SceneGraphData linked with a SceneGraphObject
     */
    public DataAnimator(Class<? extends Data> dataClass, int dataClassParam) {
        _dataClass=dataClass;
        _dataClassParam=dataClassParam;
        createData();
        if(_data!=null){
            _data._references=_references;
            _data._animator=this;
        }
        _universe=null;
    }


    public SceneGraphObject getCapableObject(SceneGraphObject o){
        return getData().getCapableObject(o);
    }
   
    public Data getData(){
        return _data;
    }
   
    public boolean isCompatibleWith(Animator an){
        if(!super.isCompatibleWith(an)){
            return false;
        }
        if(!_data.getClass().equals(((DataAnimator)an).getData().getClass())){
            return false;
        }
        return _dataClassParam==((DataAnimator)an)._dataClassParam;
    }
   
    private void createData() {
        if(_dataClass==null){
            return;
        }
        try {
            if(_dataClassParam>=0){
                Constructor<? extends Data> ctor=_dataClass.getConstructor(int.class);
                _data=ctor.newInstance(_dataClassParam);

            }
            else{
                _data=_dataClass.newInstance();
            }
        } catch (InstantiationException e1) {
            e1.printStackTrace();
            throw new RuntimeException("Invalid Data class : "+_dataClass.getName(),e1);
        } catch (IllegalAccessException e1) {
            throw new RuntimeException("Invalid Data class : "+_dataClass.getName(),e1);
        } catch (SecurityException e) {
            throw new RuntimeException("Invalid Data class : "+_dataClass.getName(),e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Invalid Data class : "+_dataClass.getName(),e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Invalid Data class : "+_dataClass.getName(),e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Invalid Data class : "+_dataClass.getName(),e);
        }
    }
   
    public void setDirty(){
        if(_universe==null){
            Locale c=getLocale();
            if(c!=null){
                _universe=(Universe)c.getVirtualUniverse();
                _universe.addDirtyNode(this);
                _data.setDelegateListener(_universe);
            }
        }
        else{
            _universe.addDirtyNode(this);
        }
    }
   
    @Override
    public Class<? extends SceneGraphObjectState> getStateClass() {
        return State.class;
    }

    protected static class SourceHolder {
        public DataSource _ds;

        public long _index;

        public SourceHolder(DataSource ds) {
            this._ds = ds;
            try {
                _index = ds.getLastIndex();
            } catch (UnsupportedOperation e) {
                try {
                    _index = ds.computeLastIndex();
                } catch (UnsupportedOperation e1) {
                    _index = -1;
                }
            }
        }
    }

    public static abstract class Data implements DataSourceListener, EndNotificationListener, Cloneable, Serializable {
        static final long serialVersionUID = -6024176491980593280L;
       
        protected transient SourceHolder[] _sources;
        private transient ArrayList<GraphObjectReference> _references;
       
        /** @see setDelegateListener */
        protected transient EndNotificationListener _delegateListener;

        protected transient DataAnimator _animator;
       
        public Data() {
            _sources = null;
            // lazy creation
            _delegateListener = this;
            _references=null;
            _animator=null;
        }
       
        public SceneGraphObject getCapableObject(SceneGraphObject o){
            return o;
        }
       
        public abstract void set(Values v);
       
        public abstract Values get();
       
        public ArrayList<GraphObjectReference> getReferences(){
            return _references;
        }
       
        /**
         * @return Returns the delegateListener.
         */
        public EndNotificationListener getDelegateListener() {
            return _delegateListener;
        }

        /**
         * Setting a delegate end notification listener is quite important to avoid duplicate events.
         * If the same object listens to multiple SceneGraphData, it will be notified only once.
         * The data themselves are of course listeners for the data source they manage.
         * They are also the default end notificationlistener when there is no delegation
         * 
         * @param delegateListener The delegateListener to set.
         */
        public void setDelegateListener(EndNotificationListener delegateListener) {
            if (this._delegateListener == delegateListener)
                return; // no change
            // unregister old listener
            if (_sources != null) {
                for (int i = 0; i < _sources.length; ++i)
                    if ((_sources[i] != null) && (_sources[i]._ds != null))
                        _sources[i]._ds.removeEndNotificationListener(this._delegateListener);
            }
            this._delegateListener = delegateListener;
            // register new one
            if (_sources != null) {
                for (int i = 0; i < _sources.length; ++i)
                    if ((_sources[i] != null) && (_sources[i]._ds != null))
                        _sources[i]._ds.addEndNotificationListener(delegateListener);
            }
        }

        public void removeSceneGraphData() {
            // unregister old listener
            if (_sources != null) {
                for (int i = 0; i < _sources.length; ++i)
                    if ((_sources[i] != null) && (_sources[i]._ds != null)) {
                        _sources[i]._ds.removeEndNotificationListener(this._delegateListener);
                        _sources[i]._ds.removeListener(this);
                        _sources[i] = null;
                    }
            }
        }

        /**
         * Get number of fields for this data
         */
        public int length() {
            if (_sources == null) {
                return 0;
            }
            return _sources.length;
        }

        /**
         * Get data source
         * @param index = field number 0..length-1
         */
        public DataSource getDataSource(int index) {
            if (_sources[index] == null)
                return null;
            return _sources[index]._ds;
        }

        /**
         * Get data sources
         */
        public DataSource[] getDataSources() {
            if(_sources==null){
                return new DataSource[0];
            }
            DataSource[] res=new DataSource[_sources.length];
            int i=0;
            for(SourceHolder sh : _sources){
                if(sh != null){
                    res[i]=sh._ds;
                }
                else{
                    res[i]=null;
                }
                i++;
            }
            return res;
        }

        /**
         * Set data source
         * @param index = field number 0..length-1
         * @param d new value for the DataSource
         */
        public void setDataSource(int index, DataSource d) {
            if (d == null) {
                if (_sources[index] != null) {
                    _sources[index]._ds.removeEndNotificationListener(_delegateListener);
                    _sources[index]._ds.removeListener(this);
                    _sources[index] = null;
                }
            } else {
                if (_sources[index] == null)
                    _sources[index] = new SourceHolder(d);
                else {
                    _sources[index]._ds.removeEndNotificationListener(_delegateListener);
                    _sources[index]._ds.removeListener(this);
                    _sources[index]._ds = d;
                }
                _sources[index]._ds.addEndNotificationListener(_delegateListener);
                _sources[index]._ds.addListener(this);
            }
        }

        public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
            if (_sources == null)
                return;
            // It is possible to optimize this by storing which data source has changed and for which
            // index, then update in only one loop at notification end.
            // But, this would require to store the data source that changed and the index
            // => is dynamic object management really faster than a few loops ?
            // => could be determined arbitrarily by how many elements are present in the array
            // Is all this worth the bother?
            for (int i = 0; i < _sources.length; ++i)
                if ((_sources[i] != null) && (ds.equals(_sources[i]._ds)))
                    _sources[i]._index = lastIndex;
           
            if (_animator!=null) _animator.setDirty();

        }

        public void DataSourceReplaced(DataSource oldData, DataSource newData) {
            if (_sources == null)
                return;
            for (int i = 0; i < _sources.length; ++i)
                if (_sources[i] != null && _sources[i]._ds == oldData) {
                    _sources[i]._ds = newData;
                    _sources[i]._ds.addEndNotificationListener(_delegateListener);
                    _sources[i]._ds.addListener(this);
                }
        }

        public void DataSourceInfoChanged(DataSource ds, DataInfo newInfo) {
        }

        public void DataSourceOrderChanged(DataSource ds, int newOrder) {
        }

        public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
        }

        public void DataSourceValueRangeChanged(DataSource ds) {
        }

        public void notificationEnd(Object referer) {
        }

        public Object clone() throws CloneNotSupportedException {
            Data res = (Data) super.clone();
            if (_delegateListener == this)
                res._delegateListener = res;
            if (_sources != null) {
                res._sources = new SourceHolder[_sources.length];
                System.arraycopy(_sources, 0, res._sources, 0, _sources.length);
                for (int i = 0; i < _sources.length; ++i)
                    if ((_sources[i] != null) && (_sources[i]._ds != null)) {
                        // delegate listener may be the same in the clone, but need to add ref count
                        _sources[i]._ds.addEndNotificationListener(res._delegateListener);
                        _sources[i]._ds.addListener(res);
                    }
            } else {
                res._sources = null;
            }
            return res;
        }

        /**
         * Inverse operation from clone()
         * Update this data from the content of another one
         */
        public void updateFrom(Data dataCopy) {
            if (_sources != null) {
                // cleanup listeners
                for (int i = 0; i < _sources.length; ++i) {
                    if ((_sources[i] != null) && (_sources[i]._ds != null)) {
                        _sources[i]._ds.removeListener(this);
                        _sources[i]._ds.removeEndNotificationListener(_delegateListener);
                    }
                }
            }
            if (dataCopy._sources != null) {
                _sources = new SourceHolder[dataCopy._sources.length];
                System.arraycopy(dataCopy._sources, 0, _sources, 0, _sources.length);
            } else {
                _sources = null;
            }
            if (dataCopy._delegateListener == dataCopy)
                _delegateListener = this;
            else
                _delegateListener = dataCopy._delegateListener;
            // re-register listeners on the new sources
            if (_sources != null) {
                for (int i = 0; i < _sources.length; ++i) {
                    if ((_sources[i] != null) && (_sources[i]._ds != null)) {
                        _sources[i]._ds.addListener(this);
                        _sources[i]._ds.addEndNotificationListener(_delegateListener);
                    }
                }
            }
        }

        /**
         * Cleanup anything that could possibly help the garbage collector.
         * Ref counted listeners may be a good start...
         */
        public void dispose() {
            if (_sources != null) {
                // cleanup listeners
                for (int i = 0; i < _sources.length; ++i) {
                    if ((_sources[i] != null) && (_sources[i]._ds != null)) {
                        _sources[i]._ds.removeListener(this);
                        _sources[i]._ds.removeEndNotificationListener(_delegateListener);
                    }
                    _sources[i] = null; // release object
                }
            }
            _sources = null; // release object
        }

        private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
            out.defaultWriteObject();
            if (_sources == null)
                out.writeBoolean(false);
            else {
                out.writeBoolean(true);
                out.writeInt(_sources.length);
                for (int i = 0; i < _sources.length; i++)
                    if (_sources[i] != null) {
                        out.writeBoolean(true);
                        DataSourcePool.global.writeDataSource(out, _sources[i]._ds);
                    } else
                        out.writeBoolean(false);
            }
        }

        private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException,
                java.io.IOException {
            in.defaultReadObject();
            _delegateListener = this;
            if (in.readBoolean()) {
                int size = in.readInt();
                _sources = new SourceHolder[size];
                for (int i = 0; i < _sources.length; ++i) {
                    if (in.readBoolean()) {
                        _sources[i] = new SourceHolder(DataSourcePool.global.readDataSource(in));
                        _sources[i]._ds.addEndNotificationListener(_delegateListener);
                        _sources[i]._ds.addListener(this);
                    }
                }
            } else
                _sources = null;
        }   
    }
   
    public static class State extends Animator.State {
       
        public State(SymbolTableData symbol, Controller control) {
            super(symbol, control);
        }

        public void writeObject(DataOutput out) throws IOException {
            super.writeObject(out);
            DataAnimator an=(DataAnimator)node;
           
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            ObjectOutputStream objOut = new ObjectOutputStream( bout );
           
            objOut.writeObject( an._data );
            objOut.writeInt( an._dataClassParam );
            objOut.flush();
            bout.close();
           
            byte[] bytes = bout.toByteArray();
            out.writeInt( bytes.length );
            if (bytes.length!=0)
                out.write( bytes );
        }

        public void readObject(DataInput in) throws IOException {
            super.readObject(in);
            DataAnimator an=(DataAnimator)node;
           
            int size = in.readInt();
           
            if (size<=0) {
                throw new IOException("Missing data serialization");
            }
            byte[] bytes = new byte[size];
            in.readFully( bytes );
            ByteArrayInputStream bin = new ByteArrayInputStream( bytes );
            ObjectInputStream objIn = new ObjectInputStream( bin );

            try {
                Object o = objIn.readObject();
                if(o instanceof Data){
                    an._data=(Data)o;
                    an._data._references=an._references;
                    an._data._animator=an;
                    an._dataClass=an._data.getClass();
                    an._dataClassParam=objIn.readInt();
                }
                else{
                    throw new IOException("Missing data serialization : invalid class="+o.getClass().getName());
                }
            } catch( ClassNotFoundException e ) {
                throw new IOException("Missing data serialization ",e);
            }
            finally{
                objIn.close();
            }
        }
    }
}
TOP

Related Classes of jsynoptic.plugins.java3d.DataAnimator$State

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.