// // ThingReferenceImpl.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad; import java.util.*; import java.rmi.*; /** ThingReferenceImpl is a local implementation of ThingReference.<P> ThingReferenceImpl is not Serializable and should not be copied between JVMs.<P> */ public class ThingReferenceImpl extends Object implements ThingReference { /** name of scalar type */ String Name; /** Thing object refered to (mutable); ThingReferenceImpl is not Serializable, but mark as transient anyway */ private transient Thing thing; /** ref = this if thing is local ref = a RemoteThingReferenceImpl if thing is remote; ThingReferenceImpl is not Serializable, but mark as transient anyway */ private transient ThingReference ref; /** Tick increments each time thing changes */ private long Tick; /** Vector of ThingChangedLinks; ThingReferenceImpl is not Serializable, but mark as transient anyway */ transient Vector ListenerVector = new Vector(); /** * Constructs from a name for the instance. * * @param name The name for this instance. * @throws VisADException if the name is <code>null</code>. */ public ThingReferenceImpl(String name) throws VisADException { if (name == null) { throw new VisADException("ThingReference: name cannot be null"); } Name = name; Tick = Long.MIN_VALUE + 1; } public Thing getThing() { return thing; } /** * Sets the underlying thing to reference. * * @param t The thing to reference. * @throws RemoteVisADException if the thing is a {@link RemoteThing}. * @throws VisADException if a VisAD failure occurs. * @throws RemoteException if a Java RMI failure occurs. */ public synchronized void setThing(Thing t) throws VisADException, RemoteException { /* WLH 9 July 98 if (t == null) { throw new ReferenceException("ThingReferenceImpl: thing cannot be null"); } */ if (t instanceof RemoteThing) { throw new RemoteVisADException("ThingReferenceImpl.setThing: cannot use " + "RemoteThing"); } if (thing != null) thing.removeReference(ref); ref = this; thing = t; if (t != null) t.addReference(ref); incTick(); } /** method for use by RemoteThingReferenceImpl that adapts this ThingReferenceImpl */ synchronized void adaptedSetThing(RemoteThing t, RemoteThingReference r) throws VisADException, RemoteException { if (thing != null) thing.removeReference(ref); ref = r; thing = t; t.addReference(ref); incTick(); } public long getTick() { return Tick; } /** synchronized because incTick, setThing, and adaptedSetThing share access to thing and ref */ public synchronized long incTick() throws VisADException, RemoteException { // if (getName() != null) DisplayImpl.printStack("incTick " + getName()); Tick += 1; if (Tick == Long.MAX_VALUE) Tick = Long.MIN_VALUE + 1; if (ListenerVector != null) { synchronized (ListenerVector) { /* CTR 26 May 2000 handle remote disconnects more robustly Enumeration listeners = ListenerVector.elements(); while (listeners.hasMoreElements()) { ThingChangedLink listener = (ThingChangedLink) listeners.nextElement(); ThingChangedEvent e = new ThingChangedEvent(listener.getId(), Tick); listener.queueThingChangedEvent(e); } */ int i = 0; while (i < ListenerVector.size()) { ThingChangedLink listener = (ThingChangedLink) ListenerVector.elementAt(i); ThingChangedEvent e = new ThingChangedEvent(listener.getId(), Tick); try { listener.queueThingChangedEvent(e); i++; } catch (ConnectException exc) { // CTR 26 May 2000 remote listener has died; remove it from list ListenerVector.remove(i); } } } } return Tick; } public ThingChangedEvent peekThingChanged(Action a) throws VisADException { if (!(a instanceof ActionImpl)) { throw new RemoteVisADException("ThingReferenceImpl.peekThingChanged:" + " Action must be local"); } if (ListenerVector == null) return null; ThingChangedLink listener = findThingChangedLink(a); if (listener == null) { return null; } return listener.peekThingChangedEvent(); } public ThingChangedEvent acknowledgeThingChanged(Action a) throws VisADException { if (!(a instanceof ActionImpl)) { throw new RemoteVisADException("ThingReferenceImpl.acknowledgeThingChanged:" + " Action must be local"); } if (ListenerVector == null) return null; ThingChangedLink listener = findThingChangedLink(a); if (listener == null) { return null; } return listener.acknowledgeThingChangedEvent(); } public ThingChangedEvent adaptedPeekThingChanged(RemoteAction a) throws VisADException { if (ListenerVector == null) return null; ThingChangedLink listener = findThingChangedLink(a); if (listener == null) { return null; } return listener.peekThingChangedEvent(); } public ThingChangedEvent adaptedAcknowledgeThingChanged(RemoteAction a) throws VisADException { if (ListenerVector == null) return null; ThingChangedLink listener = findThingChangedLink(a); if (listener == null) { return null; } return listener.acknowledgeThingChangedEvent(); } /** find ThingChangedLink with action */ public ThingChangedLink findThingChangedLink(Action a) throws VisADException { if (a == null) { throw new ReferenceException("ThingReferenceImpl.findThingChangedLink: " + "Action cannot be null"); } if (ListenerVector == null) return null; synchronized (ListenerVector) { Enumeration listeners = ListenerVector.elements(); while (listeners.hasMoreElements()) { ThingChangedLink listener = (ThingChangedLink) listeners.nextElement(); if (a.equals(listener.getAction())) return listener; } } return null; } public String getName() { return Name; } /** * Adds a listener for changes in the underlying {@link Thing}. If the * thing changes, then the listener is notified. * * @param listener The listener. * @param id The id of the corresponding {@link ReferenceActionLink}. * @throws RemoteVisADException if the listener isn't an {@link ActionImpl}. * @throws ReferenceException if the listener is already registered. * @throws VisADException if a VisAD failure occurs in a subsystem. */ public void addThingChangedListener(ThingChangedListener listener, long id) throws RemoteVisADException, ReferenceException, VisADException { if (!(listener instanceof ActionImpl)) { throw new RemoteVisADException("ThingReferenceImpl.addThingChanged" + "Listener: Action must be local"); } synchronized (this) { if (ListenerVector == null) ListenerVector = new Vector(); } synchronized(ListenerVector) { if (findThingChangedLink((ActionImpl) listener) != null) { throw new ReferenceException("ThingReferenceImpl.addThingChangedListener:" + " link to Action already exists"); } ListenerVector.addElement(new ThingChangedLink((ActionImpl) listener, id)); } } /** method for use by RemoteThingReferenceImpl that adapts this ThingReferenceImpl */ void adaptedAddThingChangedListener(RemoteAction a, long id) throws VisADException { synchronized (this) { if (ListenerVector == null) ListenerVector = new Vector(); } synchronized(ListenerVector) { if (findThingChangedLink(a) != null) { throw new ReferenceException("ThingReferenceImpl.addThingChangedListener:" + " link to Action already exists"); } ListenerVector.addElement(new ThingChangedLink(a, id)); } } /** ThingChangedListener must be local ActionImpl */ public void removeThingChangedListener(ThingChangedListener a) throws VisADException { if (!(a instanceof ActionImpl)) { throw new RemoteVisADException("ThingReferenceImpl.removeThingChanged" + "Listener: Action must be local"); } if (ListenerVector != null) { synchronized(ListenerVector) { ThingChangedLink listener = findThingChangedLink((ActionImpl) a); if (listener != null) { ListenerVector.removeElement(listener); } } } } /** method for use by RemoteThingReferenceImpl that adapts this ThingReferenceImpl */ void adaptedRemoveThingChangedListener(RemoteAction a) throws VisADException { if (ListenerVector != null) { synchronized(ListenerVector) { ThingChangedLink listener = findThingChangedLink(a); if (listener != null) { ListenerVector.removeElement(listener); } } } } public boolean equals(Object obj) { if (!(obj instanceof ThingReference)) return false; return obj == this; } public String toString() { return "ThingReference " + Name; } }