/* * BasicTreeClient.java * * Created on May 11, 2003, 6:46 PM */ package hep.aida.ref.remote.basic; import hep.aida.dev.IDevMutableStore; import hep.aida.ref.remote.basic.interfaces.AidaConnectionException; import hep.aida.ref.remote.basic.interfaces.AidaTreeClient; import hep.aida.ref.remote.basic.interfaces.AidaTreeServant; import hep.aida.ref.remote.basic.interfaces.AidaTreeServer; import hep.aida.ref.remote.basic.interfaces.UpdateEvent; /** * This is Basic implementation of AidaTreeClient that support both "Duplex" * and "non-Duplex" modes of communication with the AIDA Tree server. * * In "Duplex" mode AidaTreeServant call stateChanged() method to notify * BasicTreeClient about updates/changes in the server-side AIDA tree. * * In "non-Duplex" mode BasicTreeClient runs as a separate thread and * periodically calls updates() method of AidaTreeServant to get information * about updates/changes in the server-side AIDA tree. * * BasicTreeClient also implements IMutableStore, so it can be used as a * Store for any IDevTree. * * @author serbo */ public class BasicTreeClient implements AidaTreeClient, Runnable { protected AidaTreeServer server; protected AidaTreeServant servant; protected IDevMutableStore store; protected UpdatableQueue queue; protected boolean duplex; protected boolean isConnected; protected long updateInterval; protected boolean keepUpdating; protected String clientID; private AidaTreeServer testServer; // Used for local tests only /** * Creates a new instance of BasicTreeClient. * Duplex is default to "true". If AidaTreeServer does not support * Duplex mode, try to connect in non-Duplex. */ public BasicTreeClient() { this(null, true); } public BasicTreeClient(IDevMutableStore store) { this(store, true); } public BasicTreeClient(IDevMutableStore store, boolean duplex) { init(); this.store = store; this.duplex = duplex; this.keepUpdating = !duplex; queue = new UpdatableQueue(); } /** * This constructor is used for local tests only. */ BasicTreeClient(IDevMutableStore store, boolean duplex, AidaTreeServer server) { init(); this.store = store; this.duplex = duplex; this.keepUpdating = !duplex; this.testServer = server; } // Service methods protected void init() { server = null; servant = null; isConnected = false; updateInterval = 2000; clientID = "AidaTreeClient"; } /** * Retrieves reference to the AidaTreeServer. Should be overwritten by * subclasses. */ protected AidaTreeServer getServer() { return testServer; } /** * Set time interval (in milliseconds) for AidaTreeClient to check for updates. * Relevant only for non-Duplex Mode, as in Duplex Mode updates are "pushed" * into AidaTreeClient by AidaTreeServer calling "stateChanged()" method. * Default value: updateInterval=2000 milliseconds. */ public synchronized void setUpdateTime(long updateInterval) { this.updateInterval = updateInterval; } /** * Set duplex mode. Default is "true". */ public synchronized void setDuplex(boolean duplex) { if (isConnected) { System.out.println("WARNING: Client is connected, can not change DUPLEX settings. "+ "Please disconnect first"); return; } this.duplex = duplex; this.keepUpdating = !duplex; } /** * Retrieves Duplex AidaTreeServant from the AidaTreeServer. */ protected void connectDuplex() throws AidaConnectionException { servant = server.connectDuplex(this); if (servant == null) { throw new AidaConnectionException("Can not retrieve non-Duplex AidaTreeServant from: "+server.treeName()); } isConnected = true; } /** * Retrieves non-Duplex AidaTreeServant from the AidaTreeServer. */ protected void connectNonDuplex() throws AidaConnectionException { servant = server.connectNonDuplex(clientID); if (servant == null) { throw new AidaConnectionException("Can not retrieve non-Duplex AidaTreeServant from: "+server.treeName()); } //if (!clientID.equals(newClientID)) clientID = newClientID; new Thread(this).start(); // Start asking servant for updates. isConnected = true; } // AidaTreeClient methods public String[] listObjectNames(String path) throws IllegalArgumentException { if (!isConnected) { System.out.println("WARNING: Client is not connected."); return null; } String[] names = servant.listObjectNames(path); return names; } public String[] listObjectTypes(String path) throws IllegalArgumentException { if (!isConnected) { System.out.println("WARNING: Client is not connected."); return null; } String[] types = servant.listObjectTypes(path); return types; } public Object find(String path) throws IllegalArgumentException { if (!isConnected) { System.out.println("WARNING: Client is not connected."); return null; } Object obj = servant.find(path); return obj; } /** * In this implementation stateChanged(UpdateEvent[] events) method simply * schedules updates in the UpdatableQueue. Later queue invokes stateChanged(UpdateEvent event) * method on a separate thread to process updates. */ public void stateChanged(UpdateEvent[] events) { if (events != null && events.length > 0) { for (int i=0; i<events.length; i++) { queue.schedule(store, events[i]); } } } public boolean isConnected() { return isConnected; } public boolean connect() throws AidaConnectionException { if (isConnected) { String name = "null"; if (server != null) name = server.treeName(); System.out.println("WARNING: Already connected to AidaTreeServer: "+ name); return false; } queue = new UpdatableQueue(); server = getServer(); System.out.println("Connecting: duplex="+duplex); if (server == null) throw new AidaConnectionException("Can not get reference to AidaTreeServer."); try { if (duplex) { boolean supportsDuplex = server.supportDuplexMode(); if (!supportsDuplex) { System.out.println("Warning: AidaTreeServer \""+server.treeName()+ "\" does not support DUPLEX mode. \nWill try to connect using non-DUPLEX mode."); duplex = false; keepUpdating = !duplex; connectNonDuplex(); } else { connectDuplex(); } } else { connectNonDuplex(); } } catch (AidaConnectionException ae) { throw ae; } catch (Exception e) { String name = "null"; if (server != null) name = server.treeName(); throw new AidaConnectionException("Can not connect to AidaTreeServer: "+name, e); } return true; } public boolean disconnect() { System.out.print("\nBasicTreeClient.disconnect: for Client="+clientID+" ... "); queue.close(); queue = null; if (!isConnected) { keepUpdating = false; server = null; servant = null; return true; } boolean status = true; keepUpdating = false; if (server != null) { if (duplex) status = server.disconnectDuplex(this); else status = server.disconnectNonDuplex(clientID); } server = null; servant = null; System.out.print(" Done.\n"); return status; } // Runnable methods public void run() { while (keepUpdating) { if (isConnected) { UpdateEvent[] events = servant.updates(); //System.out.println("BasicTreeClient.run: GOT "+events.length+" events."); if (events != null && events.length > 0) stateChanged(events); } try { Thread.sleep(updateInterval); } catch (InterruptedException ie) { System.out.println("AidaTreeClient non-DUPLEX Update Thread InterruptedException."); ie.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } } } // Do some simple tests here public static void main(String[] args) { } }