package edu.colostate.vchill.connection; import edu.colostate.vchill.ControlMessage; import edu.colostate.vchill.cache.CacheMainLRU; import edu.colostate.vchill.file.FileConnection; import edu.colostate.vchill.gui.ViewFileBrowser; import edu.colostate.vchill.radar.RealtimeConnection; import javax.security.auth.login.LoginException; import java.io.File; import java.io.IOException; import java.util.*; /** * Control module for VCHILL's data acquisistion backend - controls Socket, Cache and File modules. * No external synchronization is necessary. * * @author Jochen Deyke * @author Alexander Deyke * @author jpont * @version 2009-11-10 */ public class Controller extends Observable { public static final String FILESYSTEM = "Local%20Filesystem"; private final CacheMainLRU cache = new CacheMainLRU(2); //shared cache private final HashMap<String, Connection> connections = new HashMap<String, Connection>(); private final FileConnection filesystem; /** * Sole constructor */ public Controller() { connections.put(FILESYSTEM, this.filesystem = new FileConnection(cache)); try { this.filesystem.connect(); } catch (IOException ioe) { ioe.printStackTrace(); } } public void addFile(final File file) { this.filesystem.addFile(file); ViewFileBrowser.getInstance().getActions().refreshConnections(); } /** * Gets the list of all currently active connections. * Each is identified by a string of the format servername:port * * @return a Collection of String objects containing available servers and ports */ public Collection<String> getConnectionList() { synchronized (this.connections) { String[] connectionStrings = this.connections.keySet().toArray(new String[0]); Arrays.sort(connectionStrings); Vector<String> connectionList = new Vector<String>(); for (String connection : connectionStrings) connectionList.add(connection); return connectionList; } } /** * Gets the list of all available (sub-)directories and files on a given server and port * in a given directory * * @param key ControlMessage containing the directory, server and port (other fields are ignored) * @return a Collection of String objects containing all available directories */ public Collection<String> getDirectory(final ControlMessage key) throws IOException { return this.selectConnection(key).getDirectory(key); } /** * Gets the list of all available sweeps in a given file in a given directory on a given server and port * * @param key ControlMessage containing the file, directory, server and port (other fields are ignored) * @return a Collection of String objects containing all available sweeps */ public Collection<String> getSweepList(final ControlMessage key) throws IOException { return this.selectConnection(key).getSweepList(key); } /** * Alert the backend that we want a certain sweep for display * * @param key ControlMessage containing all types needed */ public void requestSweep(final ControlMessage key, final Set<String> wantedTypes) { this.selectConnection(key).requestSweep(key, wantedTypes); } /** * Indicates whether the sweep has been fully read in yet. * * @param key ControlMessage to indentify server and sweep. */ public boolean isSweepDone(final ControlMessage key) { return this.selectConnection(key).isSweepDone(); } /** * Gets a specific ray * * @param key ControlMessage containing the desired data type, sweep, file, directory, server and port * @return the requested ray (or null if it does not exist) */ public Object getRay(final ControlMessage key, final String type, final int ray) { return this.selectConnection(key).getRay(key, type, ray); } /** * Gets a specific ray. If the ray is not yet available, waits * for the ray to become available or the sweep to be marked complete. * * @param key ControlMessage containing the desired data type, sweep, file, directory, server and port * @return the requested ray (or null if it does not exist) */ public Object getRayWait(final ControlMessage key, final String type, final int ray) { return this.selectConnection(key).getRayWait(key, type, ray); } /** * Gets a specific ray. If the ray is not yet available, waits * for the ray to become available or the sweep to be marked complete. * * @param key ControlMessage containing the desired data type, sweep, file, directory, server and port * @param timeout the maximum number of milliseconds to wait * @return the requested ray (or null if it does not exist) */ public Object getRayWait(final ControlMessage key, final String type, final int ray, final long timeout) { return this.selectConnection(key).getRayWait(key, type, ray, timeout); } /** * Clears all enqueued requests * * @param key ControlMessage containing the server and port of the connection to clear (other fields are ignored) */ public void stop(final ControlMessage key) { this.selectConnection(key).stop(); } /** * Establishes a connection to a specific server and port * * @param key ControlMessage containing the server and port to connect to (other fields are ignored) */ public void connect(final ControlMessage key) throws IOException, LoginException { synchronized (this.connections) { try { this.selectConnection(key).connect(); } catch (IOException ioe) { this.connections.remove(key.getURL()); throw ioe; } if (!isConnected(key)) { this.connections.remove(key.getURL()); throw new LoginException("connect failed"); } this.setChanged(); this.notifyObservers(); ViewFileBrowser.getInstance().getActions().refreshConnections(); } } /** * Disconnects from a specific server and port * * @param key ControlMessage containing the server and port to disconnect from (other fields are ignored) */ public void disconnect(final ControlMessage key) throws IOException { synchronized (this.connections) { if (this.selectConnection(key).disconnect()) { this.connections.remove(key.getURL()); } this.setChanged(); this.notifyObservers(); ViewFileBrowser.getInstance().getActions().refreshConnections(); } } /** * Reconnects to a specific server and port * * @param key ControlMessage containing the server and port to reconnect to (other fields are ignored) */ public void reconnect(final ControlMessage key) throws IOException { synchronized (this.connections) { this.selectConnection(key).reconnect(); this.setChanged(); this.notifyObservers(); ViewFileBrowser.getInstance().getActions().refreshConnections(); } } /** * Checks whether a connection is currently active to a specific server and port * * @param key ControlMessage containing the server and port to disconnect from (other fields are ignored) * @return true if the specified connection is active; false otherwise */ public boolean isConnected(final ControlMessage key) throws IOException { final String url = key.getURL(); Connection conn; synchronized (this.connections) { conn = this.connections.get(url); return conn == null ? false : conn.isConnected(); } } /** * Returns the number of rays currently cached in a particular sweep * * @param key ControlMessage containing the desired data type, sweep, file, directory, server and port */ public int getNumberOfRays(final ControlMessage key, final String type) { return this.cache.getNumberOfRays(key, type); } /** * Selects the connection matching <code>key</code>. * Always returns a valid connection - if it did not previously exist, it is created. * * @param key ControlMessage containing the server and port of the connection to select (other fields are ignored) * @return the selected connection */ private Connection selectConnection(final ControlMessage key) { synchronized (this.connections) { final String url = key.getURL(); Connection conn = this.connections.get(url); if (conn == null) { /* * Username and password don't need to be prompted for if VCHILL * is simply connecting to the other vchill server. */ boolean promptLogin = true; if (url.equals("vchill.chill.colostate.edu:2510")) { if (this.connections.get("vchill.chill.colostate.edu:2513") != null) promptLogin = false; } else if (url.equals("vchill.chill.colostate.edu:2513")) { if (this.connections.get("vchill.chill.colostate.edu:2510") != null) promptLogin = false; } conn = ConnectionFactory.createConnection(key, this.cache, promptLogin); this.connections.put(url, conn); } return conn; } } /** * Creates a connection to a realtime server * * @param url the server:port to connect to */ public void createRealtimeConnection(final String url) throws IOException { synchronized (this.connections) { Connection conn = new RealtimeConnection(url); this.connections.put(url, conn); this.setChanged(); this.notifyObservers(/* Object arg */); ViewFileBrowser.getInstance().getActions().refreshConnections(); } } /** * Empties the shared file/socket connection cache */ public void clearCache() { this.cache.clear(); } }