changeset 2719:597f67d95197

Remove agent proxy Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-June/023968.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-July/024007.html
author Elliott Baron <ebaron@redhat.com>
date Tue, 11 Jul 2017 17:00:25 -0400
parents 084cba24ae87
children 3beac5ce66b4
files agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java agent/core/pom.xml agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolControl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolTracker.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ManagementAgentAttacher.java agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolTrackerTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/ManagementAgentAttacherTest.java agent/pom.xml agent/proxy/pom.xml agent/proxy/server/pom.xml agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java distribution/pom.xml distribution/scripts/thermostat-agent-proxy
diffstat 25 files changed, 438 insertions(+), 2349 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java	Tue Jul 11 17:00:25 2017 -0400
@@ -48,8 +48,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.agent.dao.AgentInfoDAO;
-import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -66,6 +64,8 @@
 import com.redhat.thermostat.agent.Agent;
 import com.redhat.thermostat.agent.cli.internal.AgentApplication.ConfigurationCreator;
 import com.redhat.thermostat.agent.config.AgentStartupConfiguration;
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.common.ExitStatus;
 import com.redhat.thermostat.common.LaunchException;
@@ -76,7 +76,6 @@
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.testutils.StubBundleContext;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
 
 @RunWith(PowerMockRunner.class)
 public class AgentApplicationTest {
@@ -102,7 +101,6 @@
         context.registerService(AgentInfoDAO.class.getName(), agentInfoDAO, null);
         BackendInfoDAO backendInfoDAO = mock(BackendInfoDAO.class);
         context.registerService(BackendInfoDAO.class.getName(), backendInfoDAO, null);
-        context.registerService(MXBeanConnectionPoolControl.class, mock(MXBeanConnectionPoolControl.class), null);
         writerId = mock(WriterID.class);
 
         exitStatus = mock(ExitStatus.class);
--- a/agent/core/pom.xml	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/pom.xml	Tue Jul 11 17:00:25 2017 -0400
@@ -89,11 +89,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-ipc-server</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-process-handler</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Tue Jul 11 17:00:25 2017 -0400
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.agent;
 
-import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
@@ -55,8 +54,6 @@
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.BackendInformation;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolTracker;
 
 /**
  * Represents the Agent running on a host.
@@ -71,12 +68,9 @@
     private final AgentInfoDAO agentDao;
     private final BackendInfoDAO backendDao;
     private final WriterID writerID;
-    private final MXBeanConnectionPoolTracker poolTracker;
     
-    private MXBeanConnectionPoolControl pool;
     private AgentInformation agentInfo;
     private boolean started = false;
-    
 
     private ActionListener<ThermostatExtensionRegistry.Action> backendRegistryListener =
             new ActionListener<ThermostatExtensionRegistry.Action>()
@@ -126,20 +120,11 @@
     
     public Agent(BackendRegistry registry, AgentStartupConfiguration config,
             AgentInfoDAO agentInfoDao, BackendInfoDAO backendInfoDao, WriterID writerId) {
-        this(registry, config, agentInfoDao, backendInfoDao, writerId, new MXBeanConnectionPoolTracker());
-    }
-    
-    Agent(BackendRegistry registry, AgentStartupConfiguration config,
-            AgentInfoDAO agentInfoDao, BackendInfoDAO backendInfoDao, WriterID writerId,
-            MXBeanConnectionPoolTracker poolTracker) {
         this.backendRegistry = registry;
         this.config = config;
         this.agentDao = agentInfoDao;
         this.backendDao = backendInfoDao;
         this.writerID = writerId;
-        // Need MXBeanConnectionPool without breaking 1.x API
-        this.poolTracker = poolTracker;
-        poolTracker.open();
         
         backendInfos = new ConcurrentHashMap<>();
         
@@ -153,13 +138,7 @@
             agentDao.addAgentInformation(agentInfo);
             
             backendRegistry.start();
-            try {
-                pool = poolTracker.getPoolWithTimeout();
-                pool.start();
-                started = true;
-            } catch (IOException e) {
-                throw new LaunchException("Failed to start JMX services for agent", e);
-            }
+            started = true;
         } else {
             logger.warning("Attempt to start agent when already started.");
         }
@@ -180,7 +159,6 @@
 
     public synchronized void stop() {
         if (started) {
-            
             backendRegistry.stop();
             
             if (config.purge()) {
@@ -189,14 +167,6 @@
                 updateAgentStatusToStopped();
             }
             
-            if (pool.isStarted()) {
-                try {
-                    pool.shutdown();
-                } catch (IOException e) {
-                    logger.log(Level.WARNING, "Failed to cleanly shut down JMX services", e);
-                }
-            }
-            poolTracker.close();
             started = false;
         } else {
             logger.warning("Attempt to stop agent which is not active");
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Tue Jul 11 17:00:25 2017 -0400
@@ -36,12 +36,10 @@
 
 package com.redhat.thermostat.agent.internal;
 
-import java.io.IOException;
+import java.io.File;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.dao.AgentInfoDAO;
-import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -49,29 +47,34 @@
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
 import com.redhat.thermostat.agent.config.AgentConfigsUtils;
-import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
-import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
-import com.redhat.thermostat.common.MultipleServiceTracker.DependencyProvider;
-import com.redhat.thermostat.common.portability.UserNameUtil;
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
-
 public class Activator implements BundleActivator {
     
     private static final Logger logger = LoggingUtils.getLogger(Activator.class);
     
+    private final AgentConfigSetter configSetter;
     private ServiceTracker<CommonPaths, CommonPaths> commonPathsTracker;
-    private MultipleServiceTracker agentIPCTracker;
-    private MXBeanConnectionPoolControl pool;
+    
+    public Activator() {
+        this(new AgentConfigSetter());
+    }
+    
+    Activator(AgentConfigSetter configSetter) {
+        this.configSetter = configSetter;
+    }
 
     @Override
     public void start(final BundleContext context) throws Exception {
+        AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl();
+        context.registerService(AgentInfoDAO.class, agentInfoDAO, null);
+
+        BackendInfoDAO backendInfoDAO = new BackendInfoDAOImpl();
+        context.registerService(BackendInfoDAO.class, backendInfoDAO, null);
 
         // Track common paths separately and register storage credentials quickly
         // We need to do this since otherwise no storage credentials will be
@@ -82,8 +85,7 @@
             public CommonPaths addingService(ServiceReference<CommonPaths> ref) {
                 CommonPaths paths = context.getService(ref);
                 try {
-                    AgentConfigsUtils.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile());
-
+                    configSetter.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile());
                 } catch (InvalidConfigurationException e) {
                     logger.log(Level.SEVERE, "Failed to start agent services", e);
                 }
@@ -101,57 +103,19 @@
             }
         });
         
-        // Track IPC related deps separately from CommonPaths/StorageCredentials
-        Class<?>[] deps = new Class<?>[] { CommonPaths.class, AgentIPCService.class, UserNameUtil.class };
-        agentIPCTracker = new MultipleServiceTracker(context, deps, new Action() {
-            
-            @Override
-            public void dependenciesAvailable(DependencyProvider services) {
-
-                try {
-                    AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl();
-                    context.registerService(AgentInfoDAO.class, agentInfoDAO, null);
-
-                    BackendInfoDAO backendInfoDAO = new BackendInfoDAOImpl();
-                    context.registerService(BackendInfoDAO.class, backendInfoDAO, null);
-
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-
-                AgentIPCService ipcService = services.get(AgentIPCService.class);
-                CommonPaths paths = services.get(CommonPaths.class);
-                UserNameUtil util = services.get(UserNameUtil.class);
-                pool = new MXBeanConnectionPoolImpl(paths.getSystemBinRoot(), util, ipcService);
-                context.registerService(MXBeanConnectionPool.class, pool, null);
-                // Used only internally
-                context.registerService(MXBeanConnectionPoolControl.class, pool, null);
-            }
-
-            @Override
-            public void dependenciesUnavailable() {
-                try {
-                    if (pool != null && pool.isStarted()) {
-                        pool.shutdown();
-                    }
-                } catch (IOException e) {
-                    logger.log(Level.WARNING, "Failed to clean up IPC server", e);
-                }
-            }
-        });
         commonPathsTracker.open();
-        agentIPCTracker.open();
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
         commonPathsTracker.close();
-        agentIPCTracker.close();
     }
-
-    // Testing hook.
-    void setPool(MXBeanConnectionPoolControl pool) {
-        this.pool = pool;
+    
+    // For testing purposes
+    static class AgentConfigSetter {
+        void setConfigFiles(File systemConfigFile, File userConfigFile) {
+            AgentConfigsUtils.setConfigFiles(systemConfigFile, userConfigFile);
+        }
     }
 
 }
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.utils.management.internal;
-
-import java.io.File;
-import java.io.IOException;
-
-import com.redhat.thermostat.common.ExitStatus;
-import com.redhat.thermostat.shared.config.OS;
-
-class AgentProxyClient {
-    
-    private static final String SERVER_NAME = "thermostat-agent-proxy";
-    
-    private final int pid;
-    private final ProcessCreator procCreator;
-    private final File binPath;
-    private final String username;
-    private final File ipcConfigFile;
-    private final String serverName;
-    
-    AgentProxyClient(int pid, String user, File binPath, File ipcConfigFile, String serverName) {
-        this(pid, user, binPath, ipcConfigFile, serverName, new ProcessCreator());
-    }
-    
-    AgentProxyClient(int pid, String user, File binPath, File ipcConfigFile, String serverName, ProcessCreator procCreator) {
-        this.pid = pid;
-        this.binPath = binPath;
-        this.procCreator = procCreator;
-        this.username = user;
-        this.ipcConfigFile = ipcConfigFile;
-        this.serverName = serverName;
-    }
-
-    void runProcess() throws IOException, InterruptedException {
-        // Start the agent proxy
-        String serverPath = binPath + File.separator + SERVER_NAME;
-        String[] args = OS.IS_UNIX
-                ? new String[] { serverPath, String.valueOf(pid), username, ipcConfigFile.getAbsolutePath(), serverName }
-                : new String[] { "cmd", "/C", serverPath+".cmd", String.valueOf(pid), username, ipcConfigFile.getAbsolutePath(), serverName };
-        ProcessBuilder builder = new ProcessBuilder(args);
-        builder.inheritIO();
-        Process proxy = procCreator.startProcess(builder);
-        
-        try {
-            // Wait for process to terminate
-            proxy.waitFor();
-            if (proxy.exitValue() != ExitStatus.EXIT_SUCCESS) {
-                throw new IOException("Agent proxy for " + pid + " exited with non-zero exit code");
-            }
-        } finally {
-            proxy.destroy();
-        }
-    }
-    
-    static class ProcessCreator {
-        Process startProcess(ProcessBuilder builder) throws IOException {
-            return builder.start();
-        }
-    }
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.utils.management.internal;
-
-import com.redhat.thermostat.common.Filter;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Service;
-
-/**
- * Prevents Agent Proxies from being monitored, which would create
- * an infinite chain of agent proxies being created.
- */
-@Component
-@Service(value = AgentProxyFilter.class)
-public class AgentProxyFilter extends Filter<String> {
-    
-    private static final String AGENT_PROXY_CLASS = "com.redhat.thermostat.agent.proxy.server.AgentProxy";
-
-    @Override
-    public boolean matches(String mainClass) {
-        return AGENT_PROXY_CLASS.equals(mainClass);
-    }
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolControl.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.utils.management.internal;
-
-import java.io.IOException;
-
-import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
-
-public interface MXBeanConnectionPoolControl extends MXBeanConnectionPool {
-    
-    void start() throws IOException;
-    
-    boolean isStarted();
-    
-    void shutdown() throws IOException;
-
-}
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Tue Jul 11 17:00:25 2017 -0400
@@ -36,217 +36,53 @@
 
 package com.redhat.thermostat.utils.management.internal;
 
-import java.io.File;
 import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.file.FileSystems;
-import java.nio.file.attribute.UserPrincipal;
-import java.nio.file.attribute.UserPrincipalLookupService;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
 
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
-import com.google.gson.JsonParser;
-import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
-import com.redhat.thermostat.agent.ipc.server.IPCMessage;
-import com.redhat.thermostat.agent.ipc.server.ThermostatIPCCallbacks;
-import com.redhat.thermostat.common.portability.ProcessUserInfo;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory;
-import com.redhat.thermostat.common.portability.linux.ProcDataSource;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+
 import com.redhat.thermostat.agent.utils.management.MXBeanConnection;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionException;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
-import com.redhat.thermostat.common.portability.UserNameUtil;
-
-public class MXBeanConnectionPoolImpl implements MXBeanConnectionPoolControl, ThermostatIPCCallbacks {
 
-    private static final Object CURRENT_ENTRY_LOCK = new Object();
-    private static final String IPC_SERVER_PREFIX = "agent-proxy";
-    static final String JSON_PID = "pid";
-    static final String JSON_JMX_URL = "jmxUrl";
-    
-    // pid -> (usageCount, actualObject)
+@Component
+@Service(value = MXBeanConnectionPool.class)
+public class MXBeanConnectionPoolImpl implements MXBeanConnectionPool {
+
+    // Keys are PIDs of target JVMs
     private final Map<Integer, MXBeanConnectionPoolEntry> pool;
-    private final ConnectorCreator creator;
-    private final File binPath;
-    private final ProcessUserInfoBuilder userInfoBuilder;
-    private final AgentIPCService ipcService;
-    private final FileSystemUtils fsUtils;
-    // Keep track of IPC servers we created
-    private final Set<String> ipcServerNames;
+    private final ManagementAgentHelper helper;
     
-    /**
-     * Current {@link MXBeanConnectionPoolEntry} being created by {@link #acquire(int)} for use
-     * by {@link #messageReceived(IPCMessage)}. 
-     * Since {@link #acquire(int)} is a synchronized method and blocks until
-     * {@link #messageReceived(IPCMessage)} is invoked, only one entry can be processed at a time.
-     * Access/modification must be synchronized using {@link #CURRENT_ENTRY_LOCK}.
-     */
-    private MXBeanConnectionPoolEntry currentNewEntry;
-    private boolean started;
-
-    public MXBeanConnectionPoolImpl(File binPath, UserNameUtil userNameUtil, AgentIPCService ipcService) {
-        this(new ConnectorCreator(), binPath, ProcessUserInfoBuilderFactory.createBuilder(new ProcDataSource(), userNameUtil),
-                ipcService, new FileSystemUtils());
+    public MXBeanConnectionPoolImpl() {
+        this(new ManagementAgentHelper());
     }
 
-    MXBeanConnectionPoolImpl(ConnectorCreator connectorCreator, File binPath, ProcessUserInfoBuilder userInfoBuilder, 
-            AgentIPCService ipcService, FileSystemUtils fsUtils) {
+    MXBeanConnectionPoolImpl(ManagementAgentHelper helper) {
         this.pool = new HashMap<>();
-        this.creator = connectorCreator;
-        this.binPath = binPath;
-        this.userInfoBuilder = userInfoBuilder;
-        this.ipcService = ipcService;
-        this.fsUtils = fsUtils;
-        this.currentNewEntry = null;
-        this.started = false;
-        this.ipcServerNames = new HashSet<>();
+        this.helper = helper;
     }
 
     @Override
-    public synchronized void start() throws IOException {
-        this.started = true;
-    }
-    
-    @Override
-    public synchronized boolean isStarted() {
-        return started;
-    }
-    
-    @Override
-    public synchronized void shutdown() throws IOException {
-        this.started = false;
-        
-        // Delete all IPC servers created by this class
-        Set<String> serverNames = new HashSet<>(ipcServerNames);
-        for (String serverName : serverNames) {
-            deleteServerIfExists(serverName);
-            ipcServerNames.remove(serverName);
-        }
-    }
-
-    private void deleteServerIfExists(String serverName) throws IOException {
-        if (ipcService.serverExists(serverName)) {
-            ipcService.destroyServer(serverName);
-        }
-    }
-    
-    @Override
-    public void messageReceived(IPCMessage message) {
-        synchronized (CURRENT_ENTRY_LOCK) {
-            MXBeanConnectionPoolEntry entry = currentNewEntry;
-            Objects.requireNonNull(entry, "currentNewEntry was null, should never happen");
-            
-            ByteBuffer buf = message.get();
-            CharBuffer charBuf = Charset.forName("UTF-8").decode(buf);
-            String dataString = charBuf.toString();
-            try {
-                // Deserialize JSON data
-                GsonBuilder builder = new GsonBuilder();
-                Gson gson = builder.create();
-                JsonParser parser = new JsonParser();
-                
-                // Get root of JsonObject tree
-                JsonElement parsed = parser.parse(dataString);
-                requireNonNull(parsed, "Received empty JSON data");
-                if (!parsed.isJsonObject()) {
-                    throw new IOException("Malformed data from agent proxy");
-                }
-                JsonObject jsonObj = parsed.getAsJsonObject();
-                
-                int pid = getPidFromJson(gson, jsonObj);
-                // Verify PID is correct
-                if (entry.getPid() != pid) {
-                    throw new IOException("Expected message for PID: " + currentNewEntry.getPid() 
-                        + ", got message for PID: " + pid);
-                }
-
-                String jmxUrl = getJmxUrlFromJson(gson, jsonObj, pid);
-                entry.setJmxUrl(jmxUrl);
-            } catch (JsonParseException | IOException e) {
-                entry.setException(e);
-            }
-        }
-    }
-    
-    private int getPidFromJson(Gson gson, JsonObject json) throws IOException {
-        JsonElement jsonPid = json.get(JSON_PID);
-        requireNonNull(jsonPid, "No PID received from agent proxy");
-        return gson.fromJson(jsonPid, Integer.class);
-    }
-    
-    private String getJmxUrlFromJson(Gson gson, JsonObject json, int pid) throws IOException {
-        JsonElement jsonJmxUrl = json.get(JSON_JMX_URL);
-        requireNonNull(jsonJmxUrl, "No JMX service URL received from agent proxy for PID: " + pid);
-        return gson.fromJson(jsonJmxUrl, String.class);
-    }
-    
-    private void requireNonNull(JsonElement element, String errorMessage) throws IOException {
-        if (element == null || element.isJsonNull()) {
-            throw new IOException(errorMessage);
-        }
-    }
-    
-    @Override
     public synchronized MXBeanConnection acquire(int pid) throws MXBeanConnectionException {
-        checkRunning();
         MXBeanConnectionPoolEntry data = pool.get(pid);
         if (data == null) {
-            MXBeanConnector connector = null;
-            ProcessUserInfo info = userInfoBuilder.build(pid);
-            String username = info.getUsername();
-            if (username == null) {
-                throw new MXBeanConnectionException("Unable to determine owner of " + pid);
-            }
-            // Create an Agent Proxy IPC server for this user if it does not already exist
-            String serverName = IPC_SERVER_PREFIX + "-" + String.valueOf(info.getUid());
+            data = new MXBeanConnectionPoolEntry(pid);
             try {
-                // Check if we created an IPC server for this user already
-                if (!ipcServerNames.contains(serverName)) {
-                    createIPCServer(username, serverName);
-                }
+                // Attach to JVM and retrieve JMX service URL
+                ManagementAgentAttacher attacher = helper.createAttacher(pid);
+                attacher.attach();
+                String jmxUrl = attacher.getConnectorAddress();
                 
-                data = new MXBeanConnectionPoolEntry(pid);
-                // Synchronized to ensure any previous callback has completely finished 
-                // before changing currentNewEntry
-                synchronized (CURRENT_ENTRY_LOCK) {
-                    this.currentNewEntry = data;
-                }
-                // Add this to the map early, so our callback can find it
-                pool.put(pid, data);
-                
-                // Start agent proxy which will send the JMX service URL to the IPC server we created
-                File configFile = ipcService.getConfigurationFile();
-                AgentProxyClient proxy = creator.createAgentProxy(pid, username, binPath, configFile, serverName);
-                proxy.runProcess(); // Process completed when this returns
-                
-                // Block until we get a JMX service URL, or Exception
-                String jmxUrl = data.getJmxUrlOrBlock();
-                connector = creator.createConnector(jmxUrl);
+                // Connect using JMX service URL
+                MXBeanConnector connector = helper.createConnector(jmxUrl);
                 MXBeanConnectionImpl connection = connector.connect();
                 data.setConnection(connection);
+                pool.put(pid, data);
             } catch (IOException e) {
                 pool.remove(pid);
                 throw new MXBeanConnectionException(e);
-            } catch (InterruptedException e) {
-                pool.remove(pid);
-                Thread.currentThread().interrupt();
-                throw new MXBeanConnectionException(e);
-            } finally {
-                // Reset currentNewEntry
-                synchronized (CURRENT_ENTRY_LOCK) {
-                    this.currentNewEntry = null;
-                }
             }
         } else {
             data.incrementUsageCount();
@@ -254,24 +90,8 @@
         return data.getConnection();
     }
 
-    private void createIPCServer(String username, String serverName) throws IOException {
-        // Lookup UserPrincipal using username
-        UserPrincipalLookupService lookup = fsUtils.getUserPrincipalLookupService();
-        UserPrincipal principal = lookup.lookupPrincipalByName(username);
-        deleteServerIfExists(serverName); // Chance of old server left behind
-        ipcService.createServer(serverName, this, principal);
-        ipcServerNames.add(serverName);
-    }
-
-    private void checkRunning() throws MXBeanConnectionException {
-        if (!started) {
-            throw new MXBeanConnectionException(MXBeanConnectionPool.class.getSimpleName() + " service is not running");
-        }
-    }
-
     @Override
     public synchronized void release(int pid, MXBeanConnection toRelease) throws MXBeanConnectionException {
-        checkRunning();
         MXBeanConnectionPoolEntry data = pool.get(pid);
         if (data == null) {
             throw new MXBeanConnectionException("Unknown pid: " + pid);
@@ -295,9 +115,9 @@
         }
     }
     
-    static class ConnectorCreator {
-        AgentProxyClient createAgentProxy(int pid, String user, File binPath, File ipcConfigFile, String serverName) {
-            return new AgentProxyClient(pid, user, binPath, ipcConfigFile, serverName);
+    static class ManagementAgentHelper {
+        ManagementAgentAttacher createAttacher(int pid) {
+            return new ManagementAgentAttacher(pid);
         }
         
         MXBeanConnector createConnector(String jmxUrl) throws IOException {
@@ -306,21 +126,5 @@
         }
     }
     
-    static class FileSystemUtils {
-        UserPrincipalLookupService getUserPrincipalLookupService() {
-            return FileSystems.getDefault().getUserPrincipalLookupService();
-        }
-    }
-    
-    // For testing purposes
-    MXBeanConnectionPoolEntry getPoolEntry(int pid) {
-        return pool.get(pid);
-    }
-    
-    // For testing purposes
-    synchronized Set<String> getIPCServerNames() {
-        return ipcServerNames;
-    }
-    
 }
 
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolTracker.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.utils.management.internal;
-
-import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-import com.redhat.thermostat.agent.Agent;
-import com.redhat.thermostat.common.LaunchException;
-
-public class MXBeanConnectionPoolTracker extends ServiceTracker {
-    
-    private static final long TIMEOUT_MS = 5000L;
-    
-    private final LatchCreator latchCreator;
-    private CountDownLatch latch;
-    private MXBeanConnectionPoolControl pool;
-    
-    
-    public MXBeanConnectionPoolTracker() {
-        this(findBundleContext(), new LatchCreator());
-    }
-
-    MXBeanConnectionPoolTracker(BundleContext context, LatchCreator latchCreator) {
-        super(context, MXBeanConnectionPoolControl.class.getName(), null);
-        this.latchCreator = latchCreator;
-        this.latch = latchCreator.create();
-        this.pool = null;
-    }
-    
-    @Override
-    public synchronized Object addingService(ServiceReference reference) {
-        MXBeanConnectionPoolControl pool = (MXBeanConnectionPoolControl) super.addingService(reference);
-        this.pool = pool;
-        latch.countDown();
-        return pool;
-    }
-    
-    @Override
-    public synchronized void removedService(ServiceReference reference, Object service) {
-        // Reset latch
-        latch = latchCreator.create();
-        pool = null;
-        super.removedService(reference, service);
-    }
-    
-    public synchronized MXBeanConnectionPoolControl getPoolWithTimeout() throws LaunchException {
-        // Wait for pool to become available
-        try {
-            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        }
-        
-        // Throw an exception if pool is still unavailable, or we got the wrong implementation type
-        if (pool == null) {
-            throw new LaunchException("JMX connection service is unavailable");
-        }
-        return pool;
-    }
-
-    // Used only by no-arg constructor
-    private static BundleContext findBundleContext() {
-        Bundle bundle = FrameworkUtil.getBundle(Agent.class);
-        Objects.requireNonNull(bundle, "No bundle associated with class: " + Agent.class.getName());
-        return bundle.getBundleContext();
-    }
-    
-    static class LatchCreator {
-        CountDownLatch create() {
-            return new CountDownLatch(1);
-        }
-    }
-    
-    // For testing purposes only
-    synchronized MXBeanConnectionPoolControl getPool() {
-        return pool;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ManagementAgentAttacher.java	Tue Jul 11 17:00:25 2017 -0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.utils.management.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.sun.tools.attach.AgentInitializationException;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.VirtualMachine;
+
+class ManagementAgentAttacher {
+    
+    private static final Logger logger = LoggingUtils.getLogger(ManagementAgentAttacher.class);
+    private static final String CONNECTOR_ADDRESS_PROPERTY = "com.sun.management.jmxremote.localConnectorAddress";
+    private static final String JCMD_NAME = "jcmd";
+    private static final String JCMD_MANAGEMENT_AGENT_START_LOCAL = "ManagementAgent.start_local";
+
+    private final int pid;
+    private final VirtualMachineUtils vmUtils;
+    
+    private VirtualMachine vm;
+    private boolean attached;
+    private String connectorAddress;
+    
+    ManagementAgentAttacher(int pid) {
+        this(pid, new VirtualMachineUtils());
+    }
+    
+    ManagementAgentAttacher(int pid, VirtualMachineUtils vmUtils) {
+        this.pid = pid;
+        this.vmUtils = vmUtils;
+    }
+
+    void attach() throws IOException {
+        try {
+            vm = vmUtils.attach(String.valueOf(pid));
+            attached = true;
+
+            Properties props = vm.getAgentProperties();
+            connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY);
+            if (connectorAddress == null) {
+                props = vm.getSystemProperties();
+                startManagementAgent(props);
+                logger.fine("Started management agent for vm '" + pid + "'");
+                props = vm.getAgentProperties();
+                connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY);
+            }
+        } catch (IOException | AgentLoadException | AgentInitializationException | AttachNotSupportedException e) {
+            throw new IOException("Failed to load management agent into VM (pid: " + pid + ")", e);
+        }
+    }
+
+    private void startManagementAgent(Properties props) throws IOException,
+                                                               AgentLoadException,
+                                                               AgentInitializationException {
+        String home = props.getProperty("java.home");
+        try {
+            // JDK 7 and up have jcmd with JMX management agent start support.
+            startManagementAgentUsingJcmd(home, pid);
+        } catch (Exception e) {
+            // Fall back to old management-agent.jar behaviour.
+            logger.log(Level.FINE, "Failed to activate JMX agent via jcmd.", e);
+            startManagementAgentUsingJavaAgent(home);
+        }
+    }
+
+    private void startManagementAgentUsingJcmd(String home, int vmPid) throws IOException, InterruptedException {
+        String jcmd = home + File.separator + "bin" + File.separator + JCMD_NAME;
+        File jcmdFile = new File(jcmd);
+        if (!jcmdFile.exists()) {
+            // java.home might be JRE home. Try one level up.
+            File binDir = new File(new File(home).getParentFile(), "bin");
+            jcmd = binDir.getAbsolutePath() + File.separator + JCMD_NAME;
+        }
+        String[] args = new String[] { jcmd,
+                                       Integer.toString(vmPid),
+                                       JCMD_MANAGEMENT_AGENT_START_LOCAL };
+        List<String> jcmdArgs = Arrays.asList(args);
+        logger.fine("Starting JMX management agent via JCMD: " + jcmdArgs);
+        Process process = startProcess(jcmdArgs);
+        int result = process.waitFor();
+        if (result != 0) {
+            throw new IllegalStateException("Failed to execute jcmd. Exit code was: " + result);
+        }
+    }
+
+    // Package private for testing
+    Process startProcess(List<String> jcmdArgs) throws IOException {
+        ProcessBuilder builder = new ProcessBuilder(jcmdArgs);
+        return builder.start();
+    }
+
+    private void startManagementAgentUsingJavaAgent(String home) throws AgentLoadException, AgentInitializationException, IOException {
+        String agent = home + File.separator + "lib" + File.separator + "management-agent.jar";
+        logger.fine("Loading '" + agent + "' into VM (pid: " + pid + ")");
+        vm.loadAgent(agent);
+    }
+
+    boolean isAttached() {
+        return attached;
+    }
+
+    String getConnectorAddress() throws IOException {
+        if (!attached) {
+            throw new IOException("Agent not attached to target VM");
+        }
+        return connectorAddress;
+    }
+
+    void detach() throws IOException {
+        if (attached) {
+            vm.detach();
+            attached = false;
+        }
+    }
+    
+    static class VirtualMachineUtils {
+        VirtualMachine attach(String pid) throws AttachNotSupportedException, IOException {
+            return VirtualMachine.attach(pid);
+        }
+    }
+
+}
+
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Tue Jul 11 17:00:25 2017 -0400
@@ -48,13 +48,13 @@
 
 import java.util.UUID;
 
-import com.redhat.thermostat.agent.dao.AgentInfoDAO;
-import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.agent.config.AgentStartupConfiguration;
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.common.ActionEvent;
@@ -63,8 +63,6 @@
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.BackendInformation;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolTracker;
 
 @SuppressWarnings({ "rawtypes", "unchecked" })
 public class AgentTest {
@@ -75,8 +73,6 @@
 
     private AgentInfoDAO agentInfoDao;
     private BackendInfoDAO backendInfoDao;
-    private MXBeanConnectionPoolImpl pool;
-    private MXBeanConnectionPoolTracker poolTracker;
     
     @Before
     public void setUp() throws Exception {
@@ -95,16 +91,12 @@
         when(backend.isActive()).thenReturn(true);
 
         backendRegistry = mock(BackendRegistry.class);
-        pool = mock(MXBeanConnectionPoolImpl.class);
-        when(pool.isStarted()).thenReturn(true);
-        poolTracker = mock(MXBeanConnectionPoolTracker.class);
-        when(poolTracker.getPoolWithTimeout()).thenReturn(pool);
     }
     
     @SuppressWarnings("unused")
     @Test
     public void testAgentInit() throws Exception {
-        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, null, poolTracker);
+        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, null);
         
         verify(backendRegistry).addActionListener(any(ActionListener.class));
     }
@@ -116,7 +108,7 @@
         UUID uuid = UUID.randomUUID();
         WriterID id = mock(WriterID.class);
         when(id.getWriterID()).thenReturn(uuid.toString());
-        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id, poolTracker);
+        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id);
         
         agent.start();
 
@@ -127,8 +119,6 @@
         verify(agentInfoDao).addAgentInformation(argument.capture());
         assertEquals(123, argument.getValue().getStartTime());
         assertEquals(uuid.toString(), argument.getValue().getAgentId());
-        
-        verify(pool).start();
     }
     
     @Test
@@ -137,7 +127,7 @@
 
         // Start agent.
         WriterID id = mock(WriterID.class);
-        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id, poolTracker);
+        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id);
         verify(backendRegistry).addActionListener(backendListener.capture());
         
         agent.start();
@@ -185,7 +175,7 @@
         UUID uuid = UUID.randomUUID();
         WriterID id = mock(WriterID.class);
         when(id.getWriterID()).thenReturn(uuid.toString());
-        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id, poolTracker);
+        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id);
         agent.start();
         
         // stop agent
@@ -196,8 +186,6 @@
         ArgumentCaptor<AgentInformation> argument = ArgumentCaptor.forClass(AgentInformation.class);        
         verify(agentInfoDao, never()).updateAgentInformation(argument.capture());
         //verify(storage, times(1)).purge(uuid.toString()); TODO
-        
-        verify(pool).shutdown();
     }
    
     @Test
@@ -208,7 +196,7 @@
         when(config.purge()).thenReturn(false);
         
         WriterID id = mock(WriterID.class);
-        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id, poolTracker);
+        Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id);
         agent.start();
         
         // stop agent
@@ -218,8 +206,6 @@
 
         verify(agentInfoDao).updateAgentInformation(isA(AgentInformation.class));
         //verify(storage, times(0)).purge(anyString()); TODO
-        
-        verify(pool).shutdown();
     }
 }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Tue Jul 11 17:00:25 2017 -0400
@@ -37,85 +37,47 @@
 package com.redhat.thermostat.agent.internal;
 
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 import java.io.File;
 
-import com.redhat.thermostat.common.portability.UserNameUtil;
-import org.junit.Before;
 import org.junit.Test;
-import org.osgi.framework.ServiceRegistration;
 
-import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
-import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
+import com.redhat.thermostat.agent.internal.Activator.AgentConfigSetter;
 import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.NativeLibraryResolver;
 import com.redhat.thermostat.testutils.StubBundleContext;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
 
 public class ActivatorTest {
     
-    private StubBundleContext context;
-    private ServiceRegistration ipcReg;
-
-    @Before
-    public void setup() {
-        CommonPaths paths = mock(CommonPaths.class);
-    	when(paths.getSystemNativeLibsRoot()).thenReturn(new File("target"));
-        when(paths.getUserAgentAuthConfigFile()).thenReturn(new File("not.exist.does.not.matter"));
-    	NativeLibraryResolver.setCommonPaths(paths);
-    
-        context = new StubBundleContext();
-        context.registerService(CommonPaths.class.getName(), paths, null);
-
-        // required by MXBeanConnectionPoolImpl
-        UserNameUtil userNameUtil = mock(UserNameUtil.class);
-        context.registerService(UserNameUtil.class.getName(), userNameUtil, null);
-
-        AgentIPCService ipcService = mock(AgentIPCService.class);
-        ipcReg = context.registerService(AgentIPCService.class.getName(), ipcService, null);
-    }
-
     @Test
     public void verifyServiceIsRegistered() throws Exception {
+        StubBundleContext context = new StubBundleContext();
         Activator activator = new Activator();
         activator.start(context);
 
-        assertTrue(context.isServiceRegistered(MXBeanConnectionPool.class.getName(), MXBeanConnectionPoolImpl.class));
-        assertTrue(context.isServiceRegistered(MXBeanConnectionPoolControl.class.getName(), MXBeanConnectionPoolImpl.class));
-    }
-
-    @Test
-    public void verifyPoolShutdown() throws Exception {
-        Activator activator = new Activator();
-        activator.start(context);
-        
-        MXBeanConnectionPoolImpl pool = mock(MXBeanConnectionPoolImpl.class);
-        when(pool.isStarted()).thenReturn(true);
-        activator.setPool(pool);
-
-        // Remove tracked service
-        ipcReg.unregister();
-        
-        verify(pool).shutdown();
+        assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
+        assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
     }
     
     @Test
-    public void verifyPoolShutdownNotStarted() throws Exception {
-        Activator activator = new Activator();
+    public void verifyAgentConfig() throws Exception {
+        StubBundleContext context = new StubBundleContext();
+        
+        CommonPaths paths = mock(CommonPaths.class);
+        File sysPropFile = mock(File.class);
+        when(paths.getSystemAgentConfigurationFile()).thenReturn(sysPropFile);
+        File userPropFile = mock(File.class);
+        when(paths.getUserAgentConfigurationFile()).thenReturn(userPropFile);
+        context.registerService(CommonPaths.class.getName(), paths, null);
+        
+        AgentConfigSetter configSetter = mock(AgentConfigSetter.class);
+        Activator activator = new Activator(configSetter);
         activator.start(context);
         
-        MXBeanConnectionPoolImpl pool = mock(MXBeanConnectionPoolImpl.class);
-        activator.setPool(pool);
+        verify(configSetter).setConfigFiles(sysPropFile, userPropFile);
+    }
 
-        // Remove tracked service
-        ipcReg.unregister();
-        
-        verify(pool, never()).shutdown();
-    }
 }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.utils.management.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.ProcessBuilder.Redirect;
-import java.util.List;
-
-import com.redhat.thermostat.shared.config.OS;
-import com.redhat.thermostat.testutils.TestUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.utils.management.internal.AgentProxyClient.ProcessCreator;
-
-public class AgentProxyClientTest {
-    
-    private static final String SERVER_NAME = "agent-proxy-2000";
-    
-    private AgentProxyClient client;
-    private String user;
-    private File binPath;
-    private File ipcConfigFile;
-    private Process proxy;
-    private ProcessCreator procCreator;
-    
-    @Before
-    public void setup() throws Exception {
-        binPath = new File("/path/to/thermostat/bin");
-        user = "Hello";
-        ipcConfigFile = new File("/path/to/ipc/config");
-        procCreator = mock(ProcessCreator.class);
-        proxy = mock(Process.class);
-        when(procCreator.startProcess(any(ProcessBuilder.class))).thenReturn(proxy);
-        client = new AgentProxyClient(9000, user, binPath, ipcConfigFile, SERVER_NAME, procCreator);
-    }
-    
-    @Test
-    public void testStart() throws Exception {
-        when(proxy.exitValue()).thenReturn(0);
-        client.runProcess();
-        
-        ArgumentCaptor<ProcessBuilder> builderCaptor = ArgumentCaptor.forClass(ProcessBuilder.class);
-        verify(procCreator).startProcess(builderCaptor.capture());
-        ProcessBuilder builder = builderCaptor.getValue();
-        
-        // Check I/O redirection
-        assertEquals(Redirect.INHERIT, builder.redirectInput());
-        assertEquals(Redirect.INHERIT, builder.redirectOutput());
-        assertEquals(Redirect.INHERIT, builder.redirectError());
-        
-        // Check process arguments
-        List<String> args = builder.command();
-        int expectedArgCount = OS.IS_WINDOWS ? 7 : 5; // account for extra "cmd", "/c" args on Windows
-        assertEquals(expectedArgCount, args.size());
-
-        if (OS.IS_WINDOWS) {
-            final String arg2 = TestUtils.convertWinPathToUnixPath(args.get(2));
-            final String arg5 = TestUtils.convertWinPathToUnixPath(args.get(5));
-
-            assertEquals("cmd", args.get(0));
-            assertEquals("/C", args.get(1));
-            assertEquals("/path/to/thermostat/bin/thermostat-agent-proxy.cmd", arg2);
-            assertEquals("9000", args.get(3));
-            assertEquals("Hello", args.get(4));
-            assertEquals("/path/to/ipc/config", arg5);
-            assertEquals(SERVER_NAME, args.get(6));
-        } else {
-            assertEquals("/path/to/thermostat/bin/thermostat-agent-proxy", args.get(0));
-            assertEquals("9000", args.get(1));
-            assertEquals("Hello", args.get(2));
-            assertEquals("/path/to/ipc/config", args.get(3));
-            assertEquals(SERVER_NAME, args.get(4));
-        }
-        
-        // Check cleanup
-        verify(proxy).waitFor();
-        verify(proxy).destroy();
-    }
-    
-    @Test
-    public void testStartBadExit() throws Exception {
-        when(proxy.exitValue()).thenReturn(-1);
-        
-        try {
-            client.runProcess();
-            fail("Expected IOException");
-        } catch (IOException e) {
-            verify(proxy).destroy();
-        }
-    }
-    
-    @Test
-    public void testStartInterrupted() throws Exception {
-        when(proxy.waitFor()).thenThrow(new InterruptedException());
-        
-        try {
-            client.runProcess();
-            fail("Expected InterruptedException");
-        } catch (InterruptedException e) {
-            verify(proxy).destroy();
-        }
-    }
-
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java	Tue Jul 11 17:00:25 2017 -0400
@@ -37,298 +37,61 @@
 package com.redhat.thermostat.utils.management.internal;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import java.io.File;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.file.attribute.UserPrincipal;
-import java.nio.file.attribute.UserPrincipalLookupService;
-
-import com.redhat.thermostat.common.portability.ProcessUserInfo;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
-import com.redhat.thermostat.agent.ipc.server.IPCMessage;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnection;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionException;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl.ConnectorCreator;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl.FileSystemUtils;
+import com.redhat.thermostat.common.portability.ProcessUserInfo;
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
+import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl.ManagementAgentHelper;
 
 public class MXBeanConnectionPoolImplTest {
     
-    private static final String IPC_SERVER_NAME = "agent-proxy-8000";
-
-    private File binDir;
-    private AgentIPCService ipcService;
-    private AgentProxyClient proxy;
+    private static final String JMX_URL = "jmxUrl://hello";
+    
+    private ManagementAgentAttacher attacher;
     private MXBeanConnectionPoolImpl pool;
     private MXBeanConnectionImpl connection;
-    private ConnectorCreator creator;
+    private ManagementAgentHelper helper;
     private MXBeanConnector connector;
-    private File ipcConfigFile;
-    private FileSystemUtils fsUtils;
-    private UserPrincipalLookupService lookup;
-    private UserPrincipal principal;
 
     private ProcessUserInfoBuilder builder;
     
     @Before
     public void setup() throws Exception {
-        binDir = mock(File.class);
-        ipcService = mock(AgentIPCService.class);
         connection = mock(MXBeanConnectionImpl.class);
         connector = mock(MXBeanConnector.class);
-        creator = mock(ConnectorCreator.class);
-        ipcConfigFile = mock(File.class);
-        fsUtils = mock(FileSystemUtils.class);
+        helper = mock(ManagementAgentHelper.class);
 
-        proxy = mock(AgentProxyClient.class);
-        when(creator.createConnector("jmxUrl://hello")).thenReturn(connector);
+        attacher = mock(ManagementAgentAttacher.class);
+        when(attacher.getConnectorAddress()).thenReturn(JMX_URL);
+        when(helper.createAttacher(8000)).thenReturn(attacher);
+        when(helper.createConnector(JMX_URL)).thenReturn(connector);
         when(connector.connect()).thenReturn(connection);
 
         builder = mock(ProcessUserInfoBuilder.class);
         ProcessUserInfo info = new ProcessUserInfo(8000, "Test");
         when(builder.build(8000)).thenReturn(info);
         
-        lookup = mock(UserPrincipalLookupService.class);
-        when(fsUtils.getUserPrincipalLookupService()).thenReturn(lookup);
-        principal = mock(UserPrincipal.class);
-        when(lookup.lookupPrincipalByName("Test")).thenReturn(principal);
-
-        when(ipcService.getConfigurationFile()).thenReturn(ipcConfigFile);
-        pool = new MXBeanConnectionPoolImpl(creator, binDir, builder, ipcService, fsUtils);
-    }
-    
-    @Test
-    public void testStart() throws Exception {
-        assertFalse(pool.isStarted());
-        pool.start();
-        assertTrue(pool.isStarted());
-    }
-    
-    @Test
-    public void testShutdown() throws Exception {
-        pool.start();
-        assertTrue(pool.isStarted());
-        pool.shutdown();
-        assertFalse(pool.isStarted());
-        
-    }
-    
-    @Test
-    public void testShutdownCleanup() throws Exception {
-        pool.getIPCServerNames().add(IPC_SERVER_NAME);
-        pool.shutdown();
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService, never()).destroyServer(IPC_SERVER_NAME);
-        assertTrue(pool.getIPCServerNames().isEmpty());
-    }
-    
-    @Test
-    public void testShutdownCleanupServerExists() throws Exception {
-        pool.getIPCServerNames().add(IPC_SERVER_NAME);
-        when(ipcService.serverExists(IPC_SERVER_NAME)).thenReturn(true);
-        pool.shutdown();
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService).destroyServer(IPC_SERVER_NAME);
-        assertTrue(pool.getIPCServerNames().isEmpty());
-    }
-    
-    @Test
-    public void testShutdownCleanupMultipleServers() throws Exception {
-        pool.getIPCServerNames().add(IPC_SERVER_NAME);
-        pool.getIPCServerNames().add("agent-proxy-1001");
-        
-        when(ipcService.serverExists(IPC_SERVER_NAME)).thenReturn(true);
-        when(ipcService.serverExists("agent-proxy-1001")).thenReturn(true);
-        
-        pool.shutdown();
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService).destroyServer(IPC_SERVER_NAME);
-        verify(ipcService).serverExists("agent-proxy-1001");
-        verify(ipcService).destroyServer("agent-proxy-1001");
-        assertTrue(pool.getIPCServerNames().isEmpty());
+        pool = new MXBeanConnectionPoolImpl(helper);
     }
     
     @Test
     public void testAcquire() throws Exception {
-        final byte[] data = getJsonString(8000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-
-        pool.start();
         MXBeanConnection result = pool.acquire(8000);
         
-        verify(lookup).lookupPrincipalByName("Test");
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService, never()).destroyServer(IPC_SERVER_NAME);
-        verify(ipcService).createServer(IPC_SERVER_NAME, pool, principal);
-        verify(creator).createConnector("jmxUrl://hello");
-
-        assertNotNull(result);
-        assertEquals(result, connection);
-
-        verify(connector).connect();
-    }
-
-    private void invokeCallbacksOnProxyCreation(final byte[] data) {
-        invokeCallbacksOnProxyCreation(data, 8000, "Test", IPC_SERVER_NAME);
-    }
-    
-    private void invokeCallbacksOnProxyCreation(final byte[] data, int pid, String username, String ipcServerName) {
-        when(creator.createAgentProxy(pid, username, binDir, ipcConfigFile, ipcServerName)).thenAnswer(new Answer<AgentProxyClient>() {
-            @Override
-            public AgentProxyClient answer(InvocationOnMock invocation) throws Throwable {
-                // Invoke callback
-                IPCMessage message = mock(IPCMessage.class);
-                when(message.get()).thenReturn(ByteBuffer.wrap(data));
-                pool.messageReceived(message);
-                return proxy;
-            }
-        });
-    }
-    
-    @Test
-    public void testAcquireNoPid() throws Exception {
-        final byte[] data = getJsonString(null, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireBadPid() throws Exception {
-        final byte[] data = getJsonString(9000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireNullPid() throws Exception {
-        final byte[] data = getJsonString(null, "jmxUrl://hello", true);
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireNoJmxUrl() throws Exception {
-        final byte[] data = getJsonString(8000, null);
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireNullJmxUrl() throws Exception {
-        final byte[] data = getJsonString(8000, null, true);
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireBadCast() throws Exception {
-        GsonBuilder gsonBuilder = new GsonBuilder();
-        Gson gson = gsonBuilder.create();
-        JsonObject jsonData = new JsonObject();
-        jsonData.addProperty(MXBeanConnectionPoolImpl.JSON_PID, "this is not an integer");
-        jsonData.addProperty(MXBeanConnectionPoolImpl.JSON_JMX_URL, "jmxUrl://hello");
-        
-        String jsonString = gson.toJson(jsonData);
-        final byte[] data = jsonString.getBytes(Charset.forName("UTF-8"));
-        
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireBadJson() throws Exception {
-        String jsonString = "not a json string";
-        final byte[] data = jsonString.getBytes(Charset.forName("UTF-8"));
-        
-        invokeCallbacksOnProxyCreation(data);
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireNotRunning() throws Exception {
-        try {
-            pool.acquire(8000);
-            fail("Expected MXBeanConnectionException");
-        } catch (MXBeanConnectionException e) {
-            verify(creator, never()).createConnector("jmxUrl://hello");
-            verify(connector, never()).connect();
-        }
-    }
-    
-    @Test
-    public void testAcquireOldServer() throws Exception {
-        final byte[] data = getJsonString(8000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-        when(ipcService.serverExists(IPC_SERVER_NAME)).thenReturn(true);
-        
-        pool.start();
-        MXBeanConnection result = pool.acquire(8000);
-        
-        verify(lookup).lookupPrincipalByName("Test");
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService).destroyServer(IPC_SERVER_NAME);
-        verify(ipcService).createServer(IPC_SERVER_NAME, pool, principal);
-        verify(creator).createConnector("jmxUrl://hello");
+        verify(helper).createAttacher(8000);
+        verify(attacher).attach();
+        verify(attacher).getConnectorAddress();
+        verify(helper).createConnector(JMX_URL);
 
         assertNotNull(result);
         assertEquals(result, connection);
@@ -337,11 +100,7 @@
     }
 
     @Test
-    public void testAcquireTwiceSameUser() throws Exception {
-        byte[] data = getJsonString(8000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-    
-        pool.start();
+    public void testAcquireTwice() throws Exception {
         MXBeanConnection connection1 = pool.acquire(8000);
     
         verify(connector).connect();
@@ -349,10 +108,10 @@
         MXBeanConnection connection2 = pool.acquire(8000);
     
         // Should only be invoked once
-        verify(lookup).lookupPrincipalByName("Test");
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService, never()).destroyServer(IPC_SERVER_NAME);
-        verify(ipcService).createServer(IPC_SERVER_NAME, pool, principal);
+        verify(helper).createAttacher(8000);
+        verify(attacher).attach();
+        verify(attacher).getConnectorAddress();
+        verify(helper).createConnector(JMX_URL);
         
         assertEquals(connection1, connection);
         assertEquals(connection2, connection);
@@ -361,49 +120,7 @@
     }
     
     @Test
-    public void testAcquireTwiceDifferentUser() throws Exception {
-        byte[] data = getJsonString(8000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-        data = getJsonString(8001, "jmxUrl://hello1");
-        invokeCallbacksOnProxyCreation(data, 8001, "Test1", "agent-proxy-1001");
-        
-        ProcessUserInfo info = new ProcessUserInfo(1001, "Test1");
-        when(builder.build(8001)).thenReturn(info);
-        UserPrincipal otherPrincipal = mock(UserPrincipal.class);
-        when(lookup.lookupPrincipalByName("Test1")).thenReturn(otherPrincipal);
-        MXBeanConnector otherConnector = mock(MXBeanConnector.class);
-        when(creator.createConnector("jmxUrl://hello1")).thenReturn(otherConnector);
-        MXBeanConnectionImpl otherConnection = mock(MXBeanConnectionImpl.class);
-        when(otherConnector.connect()).thenReturn(otherConnection);
-    
-        pool.start();
-        MXBeanConnection connection1 = pool.acquire(8000);
-        MXBeanConnection connection2 = pool.acquire(8001);
-        
-        verify(lookup).lookupPrincipalByName("Test");
-        verify(ipcService).serverExists(IPC_SERVER_NAME);
-        verify(ipcService, never()).destroyServer(IPC_SERVER_NAME);
-        verify(ipcService).createServer(IPC_SERVER_NAME, pool, principal);
-        verify(creator).createConnector("jmxUrl://hello");
-        verify(connector).connect();
-        
-        verify(lookup).lookupPrincipalByName("Test1");
-        verify(ipcService).serverExists("agent-proxy-1001");
-        verify(ipcService, never()).destroyServer("agent-proxy-1001");
-        verify(ipcService).createServer("agent-proxy-1001", pool, otherPrincipal);
-        verify(creator).createConnector("jmxUrl://hello1");
-        verify(otherConnector).connect();
-    
-        assertEquals(connection1, connection);
-        assertEquals(connection2, otherConnection);
-    }
-
-    @Test
     public void testRelease() throws Exception {
-        byte[] data = getJsonString(8000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-    
-        pool.start();
         MXBeanConnection result = pool.acquire(8000);
     
         verify(connection, never()).close();
@@ -415,10 +132,6 @@
 
     @Test
     public void testReleaseTwice() throws Exception {
-        byte[] data = getJsonString(8000, "jmxUrl://hello");
-        invokeCallbacksOnProxyCreation(data);
-    
-        pool.start();
         // connection1 == connection1 == actualConnection
         MXBeanConnection connection1 = pool.acquire(8000);
         MXBeanConnection connection2 = pool.acquire(8000);
@@ -437,24 +150,5 @@
         pool.release(8000, connection);
     }
 
-    private byte[] getJsonString(Integer pid, String jmxUrl) {
-        return getJsonString(pid, jmxUrl, false);
-    }
-    
-    private byte[] getJsonString(Integer pid, String jmxUrl, boolean serializeNulls) {
-        GsonBuilder gsonBuilder = new GsonBuilder();
-        if (serializeNulls) {
-            gsonBuilder.serializeNulls();
-        }
-        Gson gson = gsonBuilder.create();
-        JsonObject jsonData = new JsonObject();
-
-        jsonData.addProperty(MXBeanConnectionPoolImpl.JSON_PID, pid);
-        jsonData.addProperty(MXBeanConnectionPoolImpl.JSON_JMX_URL, jmxUrl);
-
-        String jsonString = gson.toJson(jsonData);
-        return jsonString.getBytes(Charset.forName("UTF-8"));
-    }
-
 }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolTrackerTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.utils.management.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.common.LaunchException;
-import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolTracker.LatchCreator;
-
-public class MXBeanConnectionPoolTrackerTest {
-    
-    private MXBeanConnectionPoolTracker tracker;
-    private BundleContext context;
-    private CountDownLatch latch;
-    private LatchCreator latchCreator;
-    private MXBeanConnectionPoolControl pool;
-    private ServiceReference ref;
-    
-    @Before
-    public void setUp() {
-        context = mock(BundleContext.class);
-        latchCreator = mock(LatchCreator.class);
-        latch = mock(CountDownLatch.class);
-        when(latchCreator.create()).thenReturn(latch);
-        tracker = new MXBeanConnectionPoolTracker(context, latchCreator);
-        pool = mock(MXBeanConnectionPoolControl.class);
-        ref = mock(ServiceReference.class);
-    }
-
-    @Test
-    public void testAddingService() {
-        Object result = addService();
-        
-        assertEquals(pool, result);
-        assertEquals(pool, tracker.getPool());
-        verify(latch).countDown();
-    }
-
-    private Object addService() {
-        when(context.getService(ref)).thenReturn(pool);
-        Object result = tracker.addingService(ref);
-        return result;
-    }
-
-    @Test
-    public void testRemovedService() {
-        addService();
-        tracker.removedService(ref, pool);
-        assertNull(tracker.getPool());
-        verify(context).ungetService(ref); // Ensures super called
-        verify(latchCreator, times(2)).create();
-    }
-
-    @Test
-    public void testGetPoolWithTimeout() throws Exception {
-        addService();
-        MXBeanConnectionPoolControl result = tracker.getPoolWithTimeout();
-        assertEquals(pool, result);
-        verify(latch).await(anyLong(), any(TimeUnit.class));
-    }
-    
-    @Test
-    public void testGetPoolWithTimeoutNoPool() throws Exception {
-        try {
-            tracker.getPoolWithTimeout();
-            fail("Expected LaunchException");
-        } catch (LaunchException ignored) {
-            verify(latch).await(anyLong(), any(TimeUnit.class));
-        }
-    }
-    
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/ManagementAgentAttacherTest.java	Tue Jul 11 17:00:25 2017 -0400
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.utils.management.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.utils.management.internal.ManagementAgentAttacher.VirtualMachineUtils;
+import com.sun.tools.attach.VirtualMachine;
+
+public class ManagementAgentAttacherTest {
+    
+    private static final int SUCCESS = 0;
+    private static final int FAILURE = 3;
+    private static final int VM_PID = 0;
+    private static final String PATH_TO_JAVA_HOME = new File("/path/to/java/home").getAbsolutePath();
+    private ManagementAgentAttacher control;
+    private VirtualMachine vm;
+    private VirtualMachineUtils vmUtils;
+    
+    @Before
+    public void setup() throws Exception {
+        vmUtils = mock(VirtualMachineUtils.class);
+        vm = mock(VirtualMachine.class);
+        
+        // Mock VM properties
+        Properties agentProps = mock(Properties.class);
+        when(agentProps.getProperty("com.sun.management.jmxremote.localConnectorAddress"))
+            .thenReturn(null).thenReturn("myJmxUrl");
+        when(vm.getAgentProperties()).thenReturn(agentProps);
+        Properties sysProps = mock(Properties.class);
+        when(sysProps.getProperty("java.home")).thenReturn(PATH_TO_JAVA_HOME);
+        when(vm.getSystemProperties()).thenReturn(sysProps);
+        
+        when(vmUtils.attach(anyString())).thenReturn(vm);
+        control = new ManagementAgentAttacher(VM_PID, vmUtils);
+    }
+    
+    @Test
+    public void testAttachJcmd() throws Exception {
+        final Process process = mock(Process.class);
+        when(process.waitFor()).thenReturn(SUCCESS);
+        @SuppressWarnings("unchecked")
+        final List<String>[] startProcessArgs = new List[1];
+        ManagementAgentAttacher controlUnderTest = new ManagementAgentAttacher(VM_PID, vmUtils) {
+            @Override
+            Process startProcess(List<String> args) {
+                startProcessArgs[0] = args;
+                return process;
+            }
+        };
+        controlUnderTest.attach();
+        List<String> args = startProcessArgs[0];
+        assertNotNull(args);
+        String[] expectedArgs = new String[] {
+                new File("/path/to/java/bin/jcmd").getAbsolutePath(), // Uses the jrePath.getParentFile() path
+                Integer.toString(VM_PID),
+                "ManagementAgent.start_local"
+        };
+        List<String> expectedList = Arrays.asList(expectedArgs);
+        assertEquals(expectedList, args);
+        
+        verify(vmUtils).attach(Integer.toString(VM_PID));
+        verify(vm, times(2)).getAgentProperties();
+        verify(vm).getSystemProperties();
+        verify(vm, times(0)).loadAgent(PATH_TO_JAVA_HOME + File.separator + "lib" + File.separator + "management-agent.jar");
+    }
+    
+    @Test
+    public void testAttachManagementJar() throws Exception {
+        final Process process = mock(Process.class);
+        when(process.waitFor()).thenReturn(FAILURE);
+        ManagementAgentAttacher controlUnderTest = new ManagementAgentAttacher(VM_PID, vmUtils) {
+            @Override
+            Process startProcess(List<String> args) {
+                return process; // pretending jcmd process start fails
+            }
+        };
+        controlUnderTest.attach();
+        
+        verify(vmUtils).attach(Integer.toString(VM_PID));
+        verify(vm, times(2)).getAgentProperties();
+        verify(vm).getSystemProperties();
+        verify(vm).loadAgent(PATH_TO_JAVA_HOME + File.separator + "lib" + File.separator + "management-agent.jar");
+    }
+
+    @Test
+    public void testIsAttached() throws Exception {
+        assertFalse(control.isAttached());
+        control.attach();
+        assertTrue(control.isAttached());
+    }
+    
+    @Test
+    public void testGetAddress() throws Exception {
+        control.attach();
+        String addr = control.getConnectorAddress();
+        assertEquals("myJmxUrl", addr);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testGetAddressNotAttached() throws Exception {
+        control.getConnectorAddress();
+    }
+    
+    @Test
+    public void testDetach() throws Exception {
+        control.attach();
+        control.detach();
+        verify(vm).detach();
+    }
+    
+    @Test
+    public void testDetachNotAttached() throws Exception {
+        control.detach();
+        verify(vm, never()).detach();
+    }
+    
+}
+
--- a/agent/pom.xml	Mon Jul 10 14:49:31 2017 -0400
+++ b/agent/pom.xml	Tue Jul 11 17:00:25 2017 -0400
@@ -62,7 +62,6 @@
     <module>cli</module>
     <module>core</module>
     <module>ipc</module>
-    <module>proxy</module>
   </modules>
 
 </project>
--- a/agent/proxy/pom.xml	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 Red Hat, Inc.
-
- This file is part of Thermostat.
-
- Thermostat is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2, or (at your
- option) any later version.
-
- Thermostat is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Thermostat; see the file COPYING.  If not see
- <http://www.gnu.org/licenses/>.
-
- Linking this code with other modules is making a combined work
- based on this code.  Thus, the terms and conditions of the GNU
- General Public License cover the whole combination.
-
- As a special exception, the copyright holders of this code give
- you permission to link this code with independent modules to
- produce an executable, regardless of the license terms of these
- independent modules, and to copy and distribute the resulting
- executable under terms of your choice, provided that you also
- meet, for each linked independent module, the terms and conditions
- of the license of that module.  An independent module is a module
- which is not derived from or based on this code.  If you modify
- this code, you may extend this exception to your version of the
- library, but you are not obligated to do so.  If you do not wish
- to do so, delete this exception statement from your version.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <groupId>com.redhat.thermostat</groupId>
-    <artifactId>thermostat-agent</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-agent-proxy</artifactId>
-  <packaging>pom</packaging>
-
-  <name>Thermostat Agent Proxy</name>
-
-  <modules>
-    <module>server</module>
-  </modules>
-
-</project>
-
--- a/agent/proxy/server/pom.xml	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 Red Hat, Inc.
-
- This file is part of Thermostat.
-
- Thermostat is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2, or (at your
- option) any later version.
-
- Thermostat is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Thermostat; see the file COPYING.  If not see
- <http://www.gnu.org/licenses/>.
-
- Linking this code with other modules is making a combined work
- based on this code.  Thus, the terms and conditions of the GNU
- General Public License cover the whole combination.
-
- As a special exception, the copyright holders of this code give
- you permission to link this code with independent modules to
- produce an executable, regardless of the license terms of these
- independent modules, and to copy and distribute the resulting
- executable under terms of your choice, provided that you also
- meet, for each linked independent module, the terms and conditions
- of the license of that module.  An independent module is a module
- which is not derived from or based on this code.  If you modify
- this code, you may extend this exception to your version of the
- library, but you are not obligated to do so.  If you do not wish
- to do so, delete this exception statement from your version.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <groupId>com.redhat.thermostat</groupId>
-    <artifactId>thermostat-agent-proxy</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-  
-  <artifactId>thermostat-agent-proxy-server</artifactId>
-  <name>Thermostat Agent Proxy Server</name>
-
-  <build>
-    <pluginManagement>
-      <plugins>
-        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
-        <plugin>
-          <groupId>org.eclipse.m2e</groupId>
-          <artifactId>lifecycle-mapping</artifactId>
-          <configuration>
-            <lifecycleMappingMetadata>
-              <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.codehaus.mojo</groupId>
-                    <artifactId>exec-maven-plugin</artifactId>
-                    <versionRange>[1.2.1,)</versionRange>
-                    <goals>
-                      <goal>exec</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-              </pluginExecutions>
-            </lifecycleMappingMetadata>
-          </configuration>
-        </plugin>
-      </plugins>
-    </pluginManagement>
-  </build>
-
-  <dependencies>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-ipc-client</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-</project>
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.agent.proxy.server;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.redhat.thermostat.agent.ipc.client.ClientIPCService;
-import com.redhat.thermostat.agent.ipc.client.ClientIPCServiceFactory;
-import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.NativeLibraryResolver;
-import com.redhat.thermostat.shared.config.OS;
-import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
-import com.sun.tools.attach.AttachNotSupportedException;
-
-public class AgentProxy {
-    
-    private static final Logger logger = LoggingUtils.getLogger(AgentProxy.class);
-    static final String CONFIG_FILE_PROP = "ipcConfigFile";
-    static final String JSON_PID = "pid";
-    static final String JSON_JMX_URL = "jmxUrl";
-    
-    private static ControlCreator creator = new ControlCreator();
-    private static ClientIPCService ipcService = null;
-    
-    public static void main(String[] args) throws IOException {
-        if (args.length < 2) {
-            usage();
-        }
-
-        // Windows named pipes has some native code - must set paths to find the DLL
-        if (OS.IS_WINDOWS) {
-            NativeLibraryResolver.setCommonPaths(new CommonPathsImpl());
-        }
-
-        // Get IPC configuration file location from system property
-        String configFileStr = System.getProperty(CONFIG_FILE_PROP);
-        if (configFileStr == null) {
-            throw new IOException("Unknown IPC configuration file location");
-        }
-        File configFile = new File(configFileStr);
-        if (ipcService == null) { // Only non-null for testing
-            ipcService = ClientIPCServiceFactory.getIPCService(configFile);
-        }
-        
-        int pid = -1;
-        try {
-            // First argument is pid of target VM
-            pid = Integer.parseInt(args[0]);
-        } catch (NumberFormatException e) {
-            usage();
-        }
-        String ipcServerName = args[1];
-        // Connect to IPC server
-        IPCMessageChannel channel = ipcService.connectToServer(ipcServerName);
-        
-        // Start proxy agent
-        AgentProxyControlImpl agent = creator.create(pid);
-        
-        try {
-            attachToTarget(pid, agent);
-            String connectorAddress = getJMXServiceURL(agent);
-            sendConnectionInfo(channel, pid, connectorAddress);
-        } finally {
-            cleanup(agent, channel, pid);
-        }
-    }
-
-    private static void attachToTarget(int pid, AgentProxyControlImpl agent) throws IOException {
-        try {
-            agent.attach();
-        } catch (AttachNotSupportedException | IOException e) {
-            throw new IOException("Failed to attach to VM (pid: " + pid + ")", e);
-        }
-    }
-    
-    private static String getJMXServiceURL(AgentProxyControlImpl agent) throws IOException {
-        try {
-            return agent.getConnectorAddress();
-        } catch (IOException e) {
-            throw new IOException("Failed to retrieve JMX connection URL", e);
-        }
-    }
-
-    private static void sendConnectionInfo(IPCMessageChannel channel, int pid, String connectorAddress) throws IOException {
-        try {
-            // As JSON, write pid first, followed by JMX service URL
-            GsonBuilder builder = new GsonBuilder();
-            Gson gson = builder.create();
-            JsonObject data = new JsonObject();
-            data.addProperty(JSON_PID, pid);
-            data.addProperty(JSON_JMX_URL, connectorAddress);
-            
-            String jsonData = gson.toJson(data);
-            ByteBuffer buf = ByteBuffer.wrap(jsonData.getBytes("UTF-8"));
-            channel.writeMessage(buf);
-        } catch (IOException e) {
-            throw new IOException("Failed to send JMX connection information to agent", e);
-        }
-    }
-
-    private static void cleanup(AgentProxyControlImpl agent, IPCMessageChannel channel, int pid) {
-        try {
-            channel.close();
-        } catch (IOException e) {
-            logger.log(Level.WARNING, "Failed to close channel with agent for VM (pid: " + pid + ")", e);
-        }
-
-        if (agent.isAttached()) {
-            try {
-                agent.detach();
-            } catch (IOException e) {
-                logger.log(Level.WARNING, "Failed to detach from VM (pid: " + pid + ")", e);
-            }
-        }
-    }
-
-    private static void usage() {
-        throw new RuntimeException("usage: java " + AgentProxy.class.getName() + " <pidOfTargetJvm> <userNameOfJvmOwner>");
-    }
-    
-    static class ControlCreator {
-        AgentProxyControlImpl create(int pid) {
-            return new AgentProxyControlImpl(pid);
-        }
-    }
-    
-    /*
-     * For testing purposes only.
-     */
-    static void setControlCreator(ControlCreator creator) {
-        AgentProxy.creator = creator;
-    }
-    
-    /*
-     * For testing purposes only.
-     */
-    static void setIPCService(ClientIPCService ipcService) {
-        AgentProxy.ipcService = ipcService;
-    }
-    
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.agent.proxy.server;
-
-import java.io.File;
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.sun.tools.attach.AgentInitializationException;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.VirtualMachine;
-
-class AgentProxyControlImpl {
-    
-    private static final Logger logger = LoggingUtils.getLogger(AgentProxyControlImpl.class);
-    private static final String CONNECTOR_ADDRESS_PROPERTY = "com.sun.management.jmxremote.localConnectorAddress";
-    private static final String JCMD_NAME = "jcmd";
-    private static final String JCMD_MANAGEMENT_AGENT_START_LOCAL = "ManagementAgent.start_local";
-
-    private final int pid;
-    private final VirtualMachineUtils vmUtils;
-    
-    private VirtualMachine vm;
-    private boolean attached;
-    private String connectorAddress;
-    
-    AgentProxyControlImpl(int pid) {
-        this(pid, new VirtualMachineUtils());
-    }
-    
-    AgentProxyControlImpl(int pid, VirtualMachineUtils vmUtils) {
-        this.pid = pid;
-        this.vmUtils = vmUtils;
-    }
-
-    void attach() throws AttachNotSupportedException, IOException {
-        vm = vmUtils.attach(String.valueOf(pid));
-        attached = true;
-
-        Properties props = vm.getAgentProperties();
-        connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY);
-        if (connectorAddress == null) {
-            String home = null;
-            String agent = null;
-            try {
-                props = vm.getSystemProperties();
-                startManagementAgent(props);
-                logger.fine("Started management agent for vm '" + pid + "'");
-                props = vm.getAgentProperties();
-                connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY);
-            } catch (IOException | AgentLoadException | AgentInitializationException e) {
-                throw new RemoteException("Failed to load agent ('" + agent + "', from home '" + home + "') into VM (pid: " + pid + ")", e);
-            }
-        }
-    }
-
-    private void startManagementAgent(Properties props) throws IOException,
-                                                               AgentLoadException,
-                                                               AgentInitializationException {
-        String home = props.getProperty("java.home");
-        try {
-            // JDK 7 and up have jcmd with JMX management agent start support.
-            startManagementAgentUsingJcmd(home, pid);
-        } catch (Exception e) {
-            // Fall back to old management-agent.jar behaviour.
-            logger.log(Level.FINE, "Failed to activate JMX agent via jcmd.", e);
-            startManagementAgentUsingJavaAgent(home);
-        }
-    }
-
-    private void startManagementAgentUsingJcmd(String home, int vmPid) throws IOException, InterruptedException {
-        String jcmd = home + File.separator + "bin" + File.separator + JCMD_NAME;
-        File jcmdFile = new File(jcmd);
-        if (!jcmdFile.exists()) {
-            // java.home might be JRE home. Try one level up.
-            File binDir = new File(new File(home).getParentFile(), "bin");
-            jcmd = binDir.getAbsolutePath() + File.separator + JCMD_NAME;
-        }
-        String[] args = new String[] { jcmd,
-                                       Integer.toString(vmPid),
-                                       JCMD_MANAGEMENT_AGENT_START_LOCAL };
-        List<String> jcmdArgs = Arrays.asList(args);
-        logger.fine("Starting JMX management agent via JCMD: " + jcmdArgs);
-        Process process = startProcess(jcmdArgs);
-        int result = process.waitFor();
-        if (result != 0) {
-            throw new IllegalStateException("Failed to execute jcmd. Exit code was: " + result);
-        }
-    }
-
-    // Package private for testing
-    Process startProcess(List<String> jcmdArgs) throws IOException {
-        ProcessBuilder builder = new ProcessBuilder(jcmdArgs);
-        return builder.start();
-    }
-
-    private void startManagementAgentUsingJavaAgent(String home) throws AgentLoadException, AgentInitializationException, IOException {
-        String agent = home + File.separator + "lib" + File.separator + "management-agent.jar";
-        logger.fine("Loading '" + agent + "' into VM (pid: " + pid + ")");
-        vm.loadAgent(agent);
-    }
-
-    boolean isAttached() {
-        return attached;
-    }
-
-    String getConnectorAddress() throws IOException {
-        if (!attached) {
-            throw new IOException("Agent not attached to target VM");
-        }
-        return connectorAddress;
-    }
-
-    void detach() throws IOException {
-        if (attached) {
-            vm.detach();
-            attached = false;
-        }
-    }
-    
-    static class VirtualMachineUtils {
-        VirtualMachine attach(String pid) throws AttachNotSupportedException, IOException {
-            return VirtualMachine.attach(pid);
-        }
-    }
-
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.agent.proxy.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Properties;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.agent.proxy.server.AgentProxyControlImpl.VirtualMachineUtils;
-import com.sun.tools.attach.VirtualMachine;
-
-public class AgentProxyControlImplTest {
-    
-    private static final int SUCCESS = 0;
-    private static final int FAILURE = 3;
-    private static final int VM_PID = 0;
-    private static final String PATH_TO_JAVA_HOME = new File("/path/to/java/home").getAbsolutePath();
-    private AgentProxyControlImpl control;
-    private VirtualMachine vm;
-    private VirtualMachineUtils vmUtils;
-    
-    @Before
-    public void setup() throws Exception {
-        vmUtils = mock(VirtualMachineUtils.class);
-        vm = mock(VirtualMachine.class);
-        
-        // Mock VM properties
-        Properties agentProps = mock(Properties.class);
-        when(agentProps.getProperty("com.sun.management.jmxremote.localConnectorAddress"))
-            .thenReturn(null).thenReturn("myJmxUrl");
-        when(vm.getAgentProperties()).thenReturn(agentProps);
-        Properties sysProps = mock(Properties.class);
-        when(sysProps.getProperty("java.home")).thenReturn(PATH_TO_JAVA_HOME);
-        when(vm.getSystemProperties()).thenReturn(sysProps);
-        
-        when(vmUtils.attach(anyString())).thenReturn(vm);
-        control = new AgentProxyControlImpl(VM_PID, vmUtils);
-    }
-    
-    @Test
-    public void testAttachJcmd() throws Exception {
-        final Process process = mock(Process.class);
-        when(process.waitFor()).thenReturn(SUCCESS);
-        @SuppressWarnings("unchecked")
-        final List<String>[] startProcessArgs = new List[1];
-        AgentProxyControlImpl controlUnderTest = new AgentProxyControlImpl(VM_PID, vmUtils) {
-            @Override
-            Process startProcess(List<String> args) {
-                startProcessArgs[0] = args;
-                return process;
-            }
-        };
-        controlUnderTest.attach();
-        List<String> args = startProcessArgs[0];
-        assertNotNull(args);
-        String[] expectedArgs = new String[] {
-                new File("/path/to/java/bin/jcmd").getAbsolutePath(), // Uses the jrePath.getParentFile() path
-                Integer.toString(VM_PID),
-                "ManagementAgent.start_local"
-        };
-        List<String> expectedList = Arrays.asList(expectedArgs);
-        assertEquals(expectedList, args);
-        
-        verify(vmUtils).attach(Integer.toString(VM_PID));
-        verify(vm, times(2)).getAgentProperties();
-        verify(vm).getSystemProperties();
-        verify(vm, times(0)).loadAgent(PATH_TO_JAVA_HOME + File.separator + "lib" + File.separator + "management-agent.jar");
-    }
-    
-    @Test
-    public void testAttachManagementJar() throws Exception {
-        final Process process = mock(Process.class);
-        when(process.waitFor()).thenReturn(FAILURE);
-        AgentProxyControlImpl controlUnderTest = new AgentProxyControlImpl(VM_PID, vmUtils) {
-            @Override
-            Process startProcess(List<String> args) {
-                return process; // pretending jcmd process start fails
-            }
-        };
-        controlUnderTest.attach();
-        
-        verify(vmUtils).attach(Integer.toString(VM_PID));
-        verify(vm, times(2)).getAgentProperties();
-        verify(vm).getSystemProperties();
-        verify(vm).loadAgent(PATH_TO_JAVA_HOME + File.separator + "lib" + File.separator + "management-agent.jar");
-    }
-
-    @Test
-    public void testIsAttached() throws Exception {
-        assertFalse(control.isAttached());
-        control.attach();
-        assertTrue(control.isAttached());
-    }
-    
-    @Test
-    public void testGetAddress() throws Exception {
-        control.attach();
-        String addr = control.getConnectorAddress();
-        assertEquals("myJmxUrl", addr);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testGetAddressNotAttached() throws Exception {
-        control.getConnectorAddress();
-    }
-    
-    @Test
-    public void testDetach() throws Exception {
-        control.attach();
-        control.detach();
-        verify(vm).detach();
-    }
-    
-    @Test
-    public void testDetachNotAttached() throws Exception {
-        control.detach();
-        verify(vm, never()).detach();
-    }
-    
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.agent.proxy.server;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import com.redhat.thermostat.shared.config.OS;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.redhat.thermostat.agent.ipc.client.ClientIPCService;
-import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel;
-import com.redhat.thermostat.agent.proxy.server.AgentProxy.ControlCreator;
-
-public class AgentProxyTest {
-    
-    private static final String JMX_URL = "service:jmx:rmi://myHost:1099/blah";
-    private static final String IPC_SERVER_NAME = "agent-proxy-8000";
-    private static final String IGNORED_PATH = "/";
-    private static final String THERMOSTAT_HOME_PROP = "THERMOSTAT_HOME";
-    private static final String USER_THERMOSTAT_HOME_PROP = "USER_THERMOSTAT_HOME";
-
-    private AgentProxyControlImpl control;
-    private ClientIPCService ipcService;
-    private IPCMessageChannel channel;
-
-    @Before
-    public void setup() throws Exception {
-        System.setProperty(AgentProxy.CONFIG_FILE_PROP, "/path/to/config/file");
-        ControlCreator creator = mock(ControlCreator.class);
-        control = mock(AgentProxyControlImpl.class);
-        when(control.getConnectorAddress()).thenReturn(JMX_URL);
-        when(control.isAttached()).thenReturn(true);
-        when(creator.create(anyInt())).thenReturn(control);
-        AgentProxy.setControlCreator(creator);
-        
-        ipcService = mock(ClientIPCService.class);
-        channel = mock(IPCMessageChannel.class);
-        when(ipcService.connectToServer(IPC_SERVER_NAME)).thenReturn(channel);
-        AgentProxy.setIPCService(ipcService);
-
-        if (OS.IS_WINDOWS) {
-            // Agent Proxy now uses a native DLL for Windows named pipes on Windows
-            // because of this, CommonPathsImpl attempts to initialize.
-            // CommonPathsImpl has not defaults for these values
-            System.setProperty(THERMOSTAT_HOME_PROP, IGNORED_PATH);
-            System.setProperty(USER_THERMOSTAT_HOME_PROP, IGNORED_PATH);
-        }
-    }
-    
-    @After
-    public void teardown() throws Exception {
-        System.clearProperty(AgentProxy.CONFIG_FILE_PROP);
-        System.clearProperty(THERMOSTAT_HOME_PROP);
-        System.clearProperty(USER_THERMOSTAT_HOME_PROP);
-        AgentProxy.setControlCreator(new ControlCreator());
-        AgentProxy.setIPCService(null);
-    }
-    
-    @Test
-    public void testMainSuccess() throws Exception {
-        // Invoke main with PID of 8000
-        AgentProxy.main(new String[] { "8000", IPC_SERVER_NAME });
-        
-        verify(control).attach();
-        verify(control).getConnectorAddress();
-        
-        // Create a buffer with the expected data
-        GsonBuilder builder = new GsonBuilder();
-        Gson gson = builder.create();
-        JsonObject data = new JsonObject();
-        data.addProperty(AgentProxy.JSON_PID, 8000);
-        data.addProperty(AgentProxy.JSON_JMX_URL, JMX_URL);
-        String jsonData = gson.toJson(data);
-        ByteBuffer jsonBuf = ByteBuffer.wrap(jsonData.getBytes("UTF-8"));
-        
-        verify(channel).writeMessage(eq(jsonBuf));
-        verify(channel).close();
-        verify(control).detach();
-    }
-    
-    @Test
-    public void testMainAttachFails() throws Exception {
-        // Simulate failure binding the login object
-        doThrow(new IOException()).when(control).attach();
-        when(control.isAttached()).thenReturn(false);
-        
-        try {
-            // Invoke main with PID of 0
-            AgentProxy.main(new String[] { "0", IPC_SERVER_NAME });
-            fail("Expected IOException");
-        } catch (IOException e) {
-            // Should only call attach and close channel
-            verify(control).attach();
-            verify(control, never()).getConnectorAddress();
-            
-            verify(channel, never()).writeMessage(any(ByteBuffer.class));
-            verify(channel).close();
-            
-            verify(control, never()).detach();
-        }
-    }
-    
-    @Test
-    public void testMainGetAddressFails() throws Exception {
-        // Simulate failure binding the login object
-        doThrow(new IOException()).when(control).getConnectorAddress();
-        
-        try {
-            // Invoke main with PID of 0
-            AgentProxy.main(new String[] { "0", IPC_SERVER_NAME });
-            fail("Expected IOException");
-        } catch (IOException e) {
-            verify(control).attach();
-            verify(control).getConnectorAddress();
-
-            // Should detach and close channel, but not send URL
-            verify(channel, never()).writeMessage(any(ByteBuffer.class));
-            verify(channel).close();
-            
-            verify(control).detach();
-        }
-    }
-    
-    @Test
-    public void testMainSendAddressFails() throws Exception {
-        // Simulate failure binding the login object
-        doThrow(new IOException()).when(channel).writeMessage(any(ByteBuffer.class));
-        
-        try {
-            // Invoke main with PID of 0
-            AgentProxy.main(new String[] { "0", IPC_SERVER_NAME });
-            fail("Expected IOException");
-        } catch (IOException e) {
-            verify(control).attach();
-            verify(control).getConnectorAddress();
-            
-            // Should still detach and close channel
-            verify(channel).writeMessage(any(ByteBuffer.class));
-            verify(channel).close();
-            
-            verify(control).detach();
-        }
-    }
-    
-    @Test
-    public void testMainDetachFails() throws Exception {
-        // Simulate failure binding the login object
-        doThrow(new IOException()).when(control).detach();
-        
-        // Invoke main with PID of 0
-        AgentProxy.main(new String[] { "0", IPC_SERVER_NAME });
-        
-        // All should be called, should not be fatal
-        verify(control).attach();
-        verify(control).getConnectorAddress();
-
-        verify(channel).writeMessage(any(ByteBuffer.class));
-        verify(channel).close();
-
-        verify(control).detach();
-    }
-    
-    @Test
-    public void testMainCloseFails() throws Exception {
-        // Simulate failure binding the login object
-        doThrow(new IOException()).when(channel).close();
-        
-        // Invoke main with PID of 0
-        AgentProxy.main(new String[] { "0", IPC_SERVER_NAME });
-        
-        // All should be called, should not be fatal
-        verify(control).attach();
-        verify(control).getConnectorAddress();
-
-        verify(channel).writeMessage(any(ByteBuffer.class));
-        verify(channel).close();
-
-        verify(control).detach();
-    }
-
-}
-
--- a/distribution/pom.xml	Mon Jul 10 14:49:31 2017 -0400
+++ b/distribution/pom.xml	Tue Jul 11 17:00:25 2017 -0400
@@ -423,11 +423,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-proxy-server</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-agent-ipc-tcpsocket-server</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/distribution/scripts/thermostat-agent-proxy	Mon Jul 10 14:49:31 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2012-2014 Red Hat, Inc.
-#
-# This file is part of Thermostat.
-#
-# Thermostat is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published
-# by the Free Software Foundation; either version 2, or (at your
-# option) any later version.
-#
-# Thermostat is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Thermostat; see the file COPYING.  If not see
-# <http://www.gnu.org/licenses/>.
-#
-# Linking this code with other modules is making a combined work
-# based on this code.  Thus, the terms and conditions of the GNU
-# General Public License cover the whole combination.
-#
-# As a special exception, the copyright holders of this code give
-# you permission to link this code with independent modules to
-# produce an executable, regardless of the license terms of these
-# independent modules, and to copy and distribute the resulting
-# executable under terms of your choice, provided that you also
-# meet, for each linked independent module, the terms and conditions
-# of the license of that module.  An independent module is a module
-# which is not derived from or based on this code.  If you modify
-# this code, you may extend this exception to your version of the
-# library, but you are not obligated to do so.  If you do not wish
-# to do so, delete this exception statement from your version.
-#
-#####################################################################
-#
-if [ "$#" -lt 4 ]; then
-  echo "usage: $0 <pidOfTargetJvm> <userNameOfJvmOwner> <ipcConfigFile> <ipcServerName>" >&2
-  exit 1
-fi
-TARGET_PID="$1"
-TARGET_USER="$2"
-CONFIG_FILE="$3"
-IPC_SERVER_NAME="$4"
-
-# Source thermostat-ipc-client-common from same directory as this script
-# Defines IPC_CLASSPATH variable with JARs necessary for the IPC service
-. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"/thermostat-ipc-client-common
-
-# Ensure thermostat-ipc-client-common sourced correctly
-if [ -z "${IPC_CLASSPATH}" ]; then
-  echo "Classpath not properly defined for command channel" >&2
-  exit 1
-fi
-
-# Need tools from the JVM
-TOOLS_JAR="${JAVA_HOME}/lib/tools.jar"
-
-# Additional JARs necessary for the agent proxy
-IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-common-core-@project.version@.jar"
-IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-shared-config-@project.version@.jar"
-IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-agent-proxy-server-@project.version@.jar"
-IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/gson-@gson.version@.jar"
-IPC_CLASSPATH="${TOOLS_JAR}:${IPC_CLASSPATH}"
-
-AGENT_PROXY_CLASS="com.redhat.thermostat.agent.proxy.server.AgentProxy"
-
-# Set this to remote debug
-if [ x"$THERMOSTAT_DEBUG" != x ] ; then
-  DEBUG_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=1082"
-fi
-
-# Start server
-if [ $CYGWIN_MODE -eq 1 ]; then
-  CONFIG_FILE_ARG="-DipcConfigFile=`cygpath -w ${CONFIG_FILE}`"
-  # Drop permissions, if root
-  if [ "$(id -u)" -eq 0 ]; then
-    /bin/su -s /bin/bash -c "${JAVA} -cp `cygpath -w -p ${IPC_CLASSPATH}` ${CONFIG_FILE_ARG} ${LOGGING_ARGS} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} ${TARGET_PID} ${IPC_SERVER_NAME}" "${TARGET_USER}"
-  else
-    ${JAVA} -cp `cygpath -w -p ${IPC_CLASSPATH}` "${CONFIG_FILE_ARG}" ${DEBUG_OPTS} ${LOGGING_ARGS} ${AGENT_PROXY_CLASS} "${TARGET_PID}" "${IPC_SERVER_NAME}"
-  fi
-else
-  CONFIG_FILE_ARG="-DipcConfigFile=${CONFIG_FILE}"
-  # Drop permissions, if root
-  if [ "$(id -u)" -eq 0 ]; then
-    /bin/su -s /bin/bash -c "${JAVA} -cp ${IPC_CLASSPATH} ${CONFIG_FILE_ARG} ${LOGGING_ARGS} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} ${TARGET_PID} ${IPC_SERVER_NAME}" "${TARGET_USER}"
-  else
-    ${JAVA} -cp ${IPC_CLASSPATH} "${CONFIG_FILE_ARG}" ${DEBUG_OPTS} ${LOGGING_ARGS} ${AGENT_PROXY_CLASS} "${TARGET_PID}" "${IPC_SERVER_NAME}"
-  fi
-fi