package textbender.a.u.transfer; // Copyright 2007, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Textbender Software"), to deal in the Textbender Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Textbender Software, and to permit persons to whom the Textbender Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Textbender Software. THE TEXTBENDER SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TEXTBENDER SOFTWARE OR THE USE OR OTHER DEALINGS IN THE TEXTBENDER SOFTWARE. import java.beans.*; import java.rmi.*; import java.rmi.server.*; import textbender.a.r.desk.*; import textbender.g.beans.*; import textbender.g.hold.*; import textbender.g.lang.*; import textbender.g.util.logging.*; /** Client-side paired-regions transfer hub. Local implementation * of paired-regions transfer service, wrapping a remote server reference. * Its purpose is to speed the dispatch of each remote event * by relaying it to multiple local listeners. */ public @ThreadSafe final class PRTransferCHub extends UnicastRemoteObject implements PropertyChangeListenerR, PropertyChangeListenerX.Registry, PRTransfer { /** Constructs a PRTransferCHub. * * @param hostServiceRegistry registry reference to use * @param spool for internal holds. When unwound, this instance * will become disabled, and will release its internal holds. * * @throws RemoteException if creation fails * in communication with desk daemon */ public PRTransferCHub( final HostServiceRegistry hostServiceRegistry, final Spool spool ) throws RemoteException { server = hostServiceRegistry.getService( PRTransfer.Server.class ); server.addPropertyChangeListener( PRTransferCHub.this ); spool.add( new Hold() { public @ThreadSafe void release() { try{ server.disabledPropertyChangeListener( PRTransferCHub.this ); } catch( RemoteException x ) { LoggerX.i(getClass()).warning( x.toString() ); }} }); transferand = server.getTransferand(); // fire up } // ------------------------------------------------------------------------------------ /** Registry for events (e) * of {@linkplain #setTransferand(Transferand) local origin} only. * Each e is actually a property-set event, rather than a property-change; * e.getOldValue() will be an unknown (a string message, in fact). */ public PropertyChangeListenerX.Registry localOriginRegistry() { return localOriginRegistry; } private final LocalOriginRegistry localOriginRegistry = new LocalOriginRegistry(); /** Returns a remote reference to the desk daemon's paired-regions transfer server. */ public PRTransfer.Server server() { return server; } private final PRTransfer.Server server; // - P - R - T r a n s f e r ---------------------------------------------------------- /** Returns the object loaded for transfer, according to * the latest event received from the {@linkplain #server() server}. */ public Transferand getTransferand() { return transferand; }; // private transient Transferand transferand; private volatile Transferand transferand; /** Calls {@linkplain #server() server}.setTransferand(newTransferand). * Before doing so, it notifies * all {@linkplain #localOriginRegistry() local-origin listeners}. */ public @ThreadSafe void setTransferand( Transferand newTransferand ) throws RemoteException { // System.out.println( "PRTCH newTransferand=" + newTransferand ); localOriginRegistry.propertyChangeSupport.firePropertyChange ( "transferand", "old value, unknown", newTransferand ); server.setTransferand( newTransferand ); } // - P r o p e r t y - C h a n g e - L i s t e n e r - R ------------------------------ public void propertyChange( PropertyChangeEvent e ) { // Remote server dispatches e synchronously (being RMI), // so local set/dispatch below is effectively atomic. transferand = (Transferand)e.getNewValue(); // System.out.println( "PRTCH e.getNewValue()=" + transferand ); propertyChangeSupport.firePropertyChange( e ); } // - P r o p e r t y - C h a n g e - L i s t e n e r - X . R e g i s t r y ------------ /** Registers a listener to receive property change events. * The actual and {@linkplain java.util.EventObject#getSource() formal source} * of all events will be the {@linkplain #server() server}. */ public void addPropertyChangeListener( PropertyChangeListener listener ) { propertyChangeSupport.addPropertyChangeListener( listener ); } public void removePropertyChangeListener( PropertyChangeListener listener ) { propertyChangeSupport.removePropertyChangeListener( listener ); } //// P r i v a t e /////////////////////////////////////////////////////////////////////// private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( PRTransferCHub.this ); // ==================================================================================== private static final class LocalOriginRegistry implements PropertyChangeListenerX.Registry { final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( LocalOriginRegistry.this ); // - P r o p e r t y - C h a n g e - L i s t e n e r - X . R e g i s t r y ------------ public void addPropertyChangeListener( PropertyChangeListener listener ) { propertyChangeSupport.addPropertyChangeListener( listener ); } public void removePropertyChangeListener( PropertyChangeListener listener ) { propertyChangeSupport.removePropertyChangeListener( listener ); } } }