diff --git a/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionClient.java b/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionClient.java index 51891fc92..3fa65ebad 100644 --- a/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionClient.java +++ b/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionClient.java @@ -22,7 +22,7 @@ public abstract class ConnectionClient implements IConnectionClient { * org.eclipse.ice.viz.service.connections.IConnectionClient#setConnection * (org.eclipse.ice.viz.service.connections.IConnectionAdapter) */ - public void setConnection(IConnectionAdapter adapter) { + public void setConnectionAdapter(IConnectionAdapter adapter) { if (adapter != this.adapter) { if (this.adapter != null) { this.adapter.unregister(this); diff --git a/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionManager.java b/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionManager.java new file mode 100644 index 000000000..bf950cf1a --- /dev/null +++ b/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/ConnectionManager.java @@ -0,0 +1,263 @@ +package org.eclipse.ice.viz.service.connections; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.ice.datastructures.form.Entry; +import org.eclipse.ice.viz.service.preferences.CustomScopedPreferenceStore; +import org.eclipse.ice.viz.service.preferences.TableComponentPreferenceAdapter; + +/** + * This is an implementation of the {@link IVizService} interface. It is + * specifically designed to handle multiple simultaneous connections--local or + * remote--that are used to render plots. It implements only the required + * methods to manage these connections, and works with {@link ConnectionTable} + * s and {@link ConnectionAdapter}s to help store the connection properties and + * interact with the underlying connections. + * + * @author Jordan Deyton + * + */ + +/** + * A {@code ConnectionManager} maps {@link IConnectionAdapter}s to + * {@link IConnectionClient}s. This class manages the following aspects of the + * connection-client lifecycle: + *
    + *
  • the set of connections, connecting and disconnecting them
  • + *
  • synchronizing the connections with what is specified in the preference + * store
  • + *
  • associating multiple clients with a single connection
  • + *
+ * + * @author Jordan Deyton + * + * @param + * The type of the connection object. + */ +public abstract class ConnectionManager { + + // TODO Implement support for multiple connections rather than a single + // default connection. + + /** + * The table of connection properties. Its content is based on what is in + * the preference store. + */ + private final ConnectionTable table; + + /** + * The default connection adapter. It interfaces with the underlying + * connection utilities. + */ + private IConnectionAdapter adapter; + + /** + * A list of connection clients associated with the default {@link #adapter} + * . + */ + private final List> clients; + + /** + * The default constructor. This should only be called by sub-classes. + */ + protected ConnectionManager() { + + // Initialize the list of created plots. + clients = new ArrayList>(); + + // Initialize the connection manager based on the stored preferences. + table = createConnectionTable(); + TableComponentPreferenceAdapter tableAdapter; + tableAdapter = new TableComponentPreferenceAdapter(); + tableAdapter.toTableComponent( + (CustomScopedPreferenceStore) getPreferenceStore(), table); + + // Create the default adapter based on the current properties. Do not + // connect yet. + updateAdapter(false); + + return; + } + + /** + * Gets the preference store in which the connection properties for all + * adapters are stored. + * + * @return The preference store. This value should not be {@code null}. + */ + protected abstract CustomScopedPreferenceStore getPreferenceStore(); + + /** + * Creates an empty, default {@link #table} of connection preferences. + * + * @return A new table of connection properties. Its content is based on + * what is in the preference store. + */ + protected abstract ConnectionTable createConnectionTable(); + + /** + * Creates a disconnected, default connection {@link #adapter}. + * + * @return A new connection adapter. + */ + protected abstract IConnectionAdapter createConnectionAdapter(); + + /** + * Updates the default adapter based on the current preferences. If there is + * no default connection configured in the preference page, then after this + * call, the {@link #adapter} will be {@code null}. + * + * @param connect + * Whether or not to attempt connecting to the default adapter if + * a change occurred. + */ + private void updateAdapter(boolean connect) { + + // If the default connection exists, load it into an adapter. + String key = getDefaultConnectionKey(); + if (key != null) { + // If the adapter does not exist, create it. + if (adapter == null) { + adapter = createConnectionAdapter(); + + // Notify the plots that the connection has been configured. + for (IConnectionClient client : clients) { + client.setConnectionAdapter(adapter); + } + } + // Set the adapter's properties. If a change occurred and the method + // parameter says we need to attempt a connection, re-establish the + // adapter's connection. + List row = table.getConnection(key); + if (adapter.setConnectionProperties(row) && connect) { + Thread thread = new Thread() { + @Override + public void run() { + // Disconnect, then immediately reconnect. + adapter.disconnect(true); + adapter.connect(false); + } + }; + thread.start(); + } + } + // Otherwise, if the adapter already exists, destroy it.. + else if (adapter != null) { + ConnectionState state = adapter.getState(); + // Disconnect if necessary. + if (state == ConnectionState.Connected) { + adapter.disconnect(false); + } + adapter = null; + + // Notify the plots that the connection has been closed. + for (IConnectionClient client : clients) { + client.setConnectionAdapter(adapter); + } + } + + return; + } + + /** + * This method notifies the manager that the preferences have changed. Any + * connections that have changed should be reset. + */ + protected void preferencesChanged(Map changedKeys, + Set addedKeys, Set removedKeys) { + + // Clear the old connection preferences. + for (int i = 0; i < table.numberOfRows(); i++) { + table.deleteRow(0); + } + + // Update the connection preferences based on the stored preferences. + TableComponentPreferenceAdapter tableAdapter; + tableAdapter = new TableComponentPreferenceAdapter(); + tableAdapter.toTableComponent( + (CustomScopedPreferenceStore) getPreferenceStore(), table); + + // TODO When we have multiple connections, we will need to do the + // following, then send the new connection adapters to the plots. + // Remove all old connections. + // Update all existing connections. + // Add all new connections. + + // Update the default adapter and connect if possible. + updateAdapter(true); + + return; + } + + /** + * Connects to the default {@link #adapter}. This operation does not block + * the caller if the connection needs to be established. + * + * @return True if the connection is established, false otherwise. + */ + public boolean connect() { + return (adapter != null ? adapter.connect(false) : false); + } + + /** + * Disconnects from the default {@link #adapter}. This operation does not + * block the caller if the connection needs to be closed. + * + * @return True if the connection is disconnected, false otherwise. + */ + public boolean disconnect() { + return (adapter != null ? adapter.disconnect(false) : false); + } + + /** + * Adds a new connection client to the default {@link #adapter}. This method + * automatically sets the client's connection adapter. + * + * @param client + * The client to add. + * @return True if the added client was not null and was not already in the + * list, false otherwise (in which case nothing is added). + */ + public boolean addClient(IConnectionClient client) { + boolean added = false; + if (client != null && !clients.contains(client)) { + clients.add(client); + client.setConnectionAdapter(adapter); + added = true; + } + return added; + } + + /** + * Removes a connection client from the default {@link #adapter}. This + * method automatically unsets the client's connection adapter. + * + * @param client + * The client to remove. + * @return True if the added client was not null and was already in the + * list, false otherwise (in which case nothing was removed). + */ + public boolean removeClient(IConnectionClient client) { + boolean removed = clients.remove(client); + if (removed) { + client.setConnectionAdapter(null); + } + return removed; + } + + /** + * Gets the key ("connection ID") associated with the default connection. + * This can be set on the preference page. + * + * @return The key for the default connection, or null if one is not set. + */ + private String getDefaultConnectionKey() { + int id = getPreferenceStore().getInt("defaultConnection"); + List connectionNames = table.getConnectionNames(); + return (id < connectionNames.size() ? connectionNames.get(id) : null); + } + +} diff --git a/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/IConnectionClient.java b/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/IConnectionClient.java index 52d0d78be..5ecc29c04 100644 --- a/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/IConnectionClient.java +++ b/src/org.eclipse.ice.viz.service/src/org/eclipse/ice/viz/service/connections/IConnectionClient.java @@ -27,6 +27,6 @@ public interface IConnectionClient extends IUpdateableListener { * The new connection adapter. If {@code null}, the connection * will be unset and the plot will be cleared. */ - void setConnection(IConnectionAdapter adapter); + void setConnectionAdapter(IConnectionAdapter adapter); }