package org.aim.ui.manager; import java.io.File; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.aim.api.exceptions.InstrumentationException; import org.aim.api.exceptions.MeasurementException; import org.aim.api.measurement.dataset.Parameter; import org.aim.api.measurement.utils.RecordCSVWriter; import org.aim.artifacts.instrumentation.InstrumentationClient; import org.aim.description.InstrumentationDescription; import org.aim.ui.Main; import org.aim.ui.interfaces.ConnectionStateListener; import org.aim.ui.view.MainView; import org.aim.ui.view.MainView.ClientSettingsState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * Manages the connection to the SUT. * * @author Marius Oehler * */ public final class ClientManager { private static ClientManager instance; private static final Logger LOGGER = LoggerFactory.getLogger(ClientManager.class); /** * Returns an instance of this class. This object is the only instance * (singleton) of this class. * * @return instance of {@link ClientManager} */ public static ClientManager instance() { if (instance == null) { instance = new ClientManager(); } return instance; } private InstrumentationClient client; private Collection<ConnectionStateListener> csListener; private ClientManager() { csListener = new ArrayList<ConnectionStateListener>(); } /** * Will be invoked when the UI's connect/disconnect button is pressed. */ public void actionButton() { if (client == null) { connect(); } else { disconnect(); } } /** * Adds another {@link ConnectionStateListener}. * * @param listener * - listener to register */ public void addConnectionStateListener(ConnectionStateListener listener) { csListener.add(listener); } /** * Provoke the connection buildup to the specified controller. */ public void connect() { MainView.instance().addLogMessage("Connecting.."); MainView.instance().setClientSettingsState(ClientSettingsState.CONNECTING); final String host = MainView.instance().getInputHost().getSelectedItem().toString(); final String port = MainView.instance().getInputPort().getText(); // validate input if (host.isEmpty()) { MainView.instance().addLogMessage("The host is not specified"); MainView.instance().setClientSettingsState(ClientSettingsState.DEFAULT); } else if (port.isEmpty()) { MainView.instance().addLogMessage("The port is not specified"); MainView.instance().setClientSettingsState(ClientSettingsState.DEFAULT); } else if (!port.matches("^\\d+")) { MainView.instance().addLogMessage("'" + port + "' is not a valid port value.."); MainView.instance().setClientSettingsState(ClientSettingsState.DEFAULT); } else { LOGGER.debug("Connecting to {}:{}", host, port); if (!InstrumentationClient.testConnection(host, port)) { MainView.instance().addLogMessage("Can't establish connection to " + host + ":" + port + ""); LOGGER.debug("Can't establish connection to {}:{}", host, port); MainView.instance().setClientSettingsState(ClientSettingsState.DEFAULT); } else { MainView.instance().addLogMessage("Connection establish to " + host + ":" + port + ""); LOGGER.debug("Client connected to {}:{}", host, port); client = new InstrumentationClient(host, port); MainView.instance().setClientSettingsState(ClientSettingsState.CONNECTED); connected(); } } } private void connected() { for (ConnectionStateListener l : csListener) { l.onConnection(); } } /** * Disconnect the client from the agent. */ private void disconnect() { LOGGER.debug("Disconnecting.."); MainView.instance().setClientSettingsState(ClientSettingsState.DEFAULT); MainView.instance().addLogMessage("Connection reversed"); if (client != null) { client = null; } disconnected(); } private void disconnected() { for (ConnectionStateListener l : csListener) { l.onDisconnection(); } } /** * Downloads the agent's dataset into the specified directory. * * @param targetDirectory * target directory of the file */ public void downloadDataset(final File targetDirectory) { try { final PipedOutputStream outPipe = new PipedOutputStream(); PipedInputStream inPipe = new PipedInputStream(outPipe); Main.getThreadPool().execute(new Runnable() { @Override public void run() { try { client.pipeToOutputStream(outPipe); } catch (MeasurementException e) { e.printStackTrace(); } } }); RecordCSVWriter.getInstance().pipeDataToDatasetFiles(inPipe, targetDirectory.getAbsolutePath(), new HashSet<Parameter>()); } catch (IOException e1) { e1.printStackTrace(); } } /** * Returns the a list of api scopes (classes) which are supported by the * connected agent. * * @return api scopes supported by the connected agent */ public List<String> getApiScopes() { return client.getSupportedExtensions().getApiScopeExtensions(); } /** * Returns the a list of custom scopes (classes) which are supported by the * connected agent. * * @return custom scopes supported by the connected agent */ public List<String> getCustomScopes() { return client.getSupportedExtensions().getCustomScopeExtensions(); } /** * Returns whether monitoring is enabled. * * @return monitoring state */ public boolean isMonitoringEnabled() { return client.isMonitoringEnabled(); } /** * Returns the a list of probes (classes) which are supported by the * connected agent. * * @return probes supported by the connected agent */ public List<String> getProbes() { List<String> probes = new ArrayList<String>(client.getSupportedExtensions().getProbeExtensions()); return probes; } /** * Returns the a list of probes (classes) and the corresponding scopes which * are supported by the connected agent. * * @return probes supported by the connected agent */ public Map<String, Set<String>> getProbeMapping() { Map<String, Set<String>> probeExtensionsMapping = client.getSupportedExtensions().getProbeExtensionsMapping(); return probeExtensionsMapping; } /** * Returns the a list of sampler (classes) which are supported by the * connected agent. * * @return sampler supported by the connected agent */ public List<String> getSampler() { return client.getSupportedExtensions().getSamplerExtensions(); } /** * Returns the a list of scopes (classes) which are supported by the * connected agent. * * @return scopes supported by the connected agent */ public List<String> getScopes() { List<String> scopeExtensions = new ArrayList<String>(); scopeExtensions.addAll(client.getSupportedExtensions().getApiScopeExtensions()); scopeExtensions.addAll(client.getSupportedExtensions().getCustomScopeExtensions()); return scopeExtensions; } /** * Instrument the target system with the given * {@link InstrumentationDescription}. * * @param instrumentationDescription * - description to instrument */ public void instrument(InstrumentationDescription instrumentationDescription) { try { client.instrument(instrumentationDescription); } catch (InstrumentationException e) { throw new RuntimeException(e); } } /** * Returns whether a connection to an agent is established. * * @return true if a connection is established */ public boolean isConnected() { return client != null; } /** * Remove the given {@link ConnectionStateListener}. * * @param listener * - listener to remove */ public void removeConnectionStateListener(ConnectionStateListener listener) { csListener.remove(listener); } /** * Enables the monitoring. */ public void startMonitoring() { try { client.enableMonitoring(); } catch (MeasurementException e) { throw new RuntimeException(e); } } /** * Stops the monitoring. */ public void stopMonitoring() { try { client.disableMonitoring(); } catch (MeasurementException e) { throw new RuntimeException(e); } } /** * Uninstrument the target system. */ public void uninstrument() { try { client.uninstrument(); } catch (InstrumentationException e) { throw new RuntimeException(e); } } }