Repository: geode Updated Branches: refs/heads/feature/GEODE-2594 902cbe79e -> 3592e81c7
Delete LocalProcessController and test Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/3592e81c Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/3592e81c Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/3592e81c Branch: refs/heads/feature/GEODE-2594 Commit: 3592e81c782c51cc94e34df34cc7fc5a64edbb74 Parents: 902cbe7 Author: Kirk Lund <[email protected]> Authored: Wed Mar 8 14:02:24 2017 -0800 Committer: Kirk Lund <[email protected]> Committed: Wed Mar 8 14:02:24 2017 -0800 ---------------------------------------------------------------------- .../process/LocalProcessController.java | 478 ------------------- .../LocalProcessControllerJUnitTest.java | 121 ----- 2 files changed, 599 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/3592e81c/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java b/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java deleted file mode 100755 index efca868..0000000 --- a/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.process; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FilenameFilter; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.util.Properties; -import java.util.Set; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.Query; -import javax.management.QueryExp; -import javax.management.ReflectionException; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import org.apache.geode.internal.util.IOUtils; -import com.sun.tools.attach.AgentInitializationException; -import com.sun.tools.attach.AgentLoadException; -import com.sun.tools.attach.AttachNotSupportedException; -import com.sun.tools.attach.VirtualMachine; - -/** - * Attaches to a local process to control it via JMX. - * - * @since GemFire 7.0 - * @deprecated as of 8.0 please use {@link ControllableProcess} instead - */ -public final class LocalProcessController { - - /** Property name for the JMX local connector address (from sun.management.Agent) */ - private static final String LOCAL_CONNECTOR_ADDRESS_PROP = - "com.sun.management.jmxremote.localConnectorAddress"; - - private final int pid; - - protected JMXConnector jmxc; - protected MBeanServerConnection server; - - /** - * Constructs an instance for controlling a local process. - * - * @param pid process id identifying the process to attach to - * - * @throws IllegalArgumentException if pid is not a positive integer - */ - public LocalProcessController(final int pid) { - if (pid < 1) { - throw new IllegalArgumentException("Invalid pid '" + pid + "' specified"); - } - this.pid = pid; - } - - /** - * Constructs an instance for controlling a local process. - * - * @param pidFile file containing the pid of the process to attach to - * - * @throws FileNotFoundException if the specified file name is not found within the directory - * @throws IOException if unable to read from the specified file - * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer - * @throws NumberFormatException if the pid file does not contain a parsable integer - */ - public LocalProcessController(final File pidFile) throws IOException { - this(readPid(pidFile)); - } - - /** - * Constructs an instance for controlling a local process. - * - * @param directory directory containing a file of name pidFileName - * @param pidFilename name of the file containing the pid of the process to attach to - * - * @throws FileNotFoundException if the specified file name is not found within the directory - * @throws IOException if an I/O error occurs - * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer - * @throws IllegalStateException if dir is not an existing directory - * @throws NumberFormatException if the pid file does not contain a parsable integer - */ - public LocalProcessController(final File directory, final String pidFilename) throws IOException { - this(readPid(directory, pidFilename)); - } - - /** - * Connects to the process and tells it to shut down. - * - * @param namePattern the name pattern of the MBean to use for stopping - * @param pidAttribute the name of the MBean attribute with the process id to compare against - * @param stopMethod the name of the MBean operation to invoke - * @param attributes the names of the MBean attributes to compare with expected values - * @param values the expected values of the specified MBean attributes - * - * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector - * in the process - * @throws IOException if a communication problem occurred when talking to the MBean server - * @throws MBeanInvocationFailedException if failed to invoke stop on the MBean for any reason - * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails - */ - public void stop(final ObjectName namePattern, final String pidAttribute, final String stopMethod, - final String[] attributes, final Object[] values) throws ConnectionFailedException, - IOException, MBeanInvocationFailedException, PidUnavailableException { - invokeOperationOnTargetMBean(namePattern, pidAttribute, stopMethod, attributes, values); - } - - /** - * Connects to the process and acquires its status. - * - * @param namePattern the name pattern of the MBean to use for stopping - * @param pidAttribute the name of the MBean attribute with the process id to compare against - * @param statusMethod the name of the MBean operation to invoke - * @param attributes the names of the MBean attributes to compare with expected values - * @param values the expected values of the specified MBean attributes - * - * @return string describing the status of the process - * - * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector - * in the process - * @throws IOException if a communication problem occurred when talking to the MBean server - * @throws MBeanInvocationFailedException if failed to invoke stop on the MBean for any reason - * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails - */ - public String status(final ObjectName namePattern, final String pidAttribute, - final String statusMethod, final String[] attributes, final Object[] values) - throws ConnectionFailedException, IOException, MBeanInvocationFailedException, - PidUnavailableException { - return invokeOperationOnTargetMBean(namePattern, pidAttribute, statusMethod, attributes, values) - .toString(); - } - - /** - * Connects to the process and use its MBean to stop it. - * - * @param namePattern the name pattern of the MBean to use for stopping - * @param pidAttribute the name of the MBean attribute with the process id to compare against - * @param methodName the name of the MBean operation to invoke - * @param attributes the names of the MBean attributes to compare with expected values - * @param values the expected values of the specified MBean attributes - * - * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector - * in the process - * @throws IOException if a communication problem occurred when talking to the MBean server - * @throws MBeanInvocationFailedException if failed to invoke stop on the MBean for any reason - * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails - */ - private Object invokeOperationOnTargetMBean(final ObjectName namePattern, - final String pidAttribute, final String methodName, final String[] attributes, - final Object[] values) throws ConnectionFailedException, IOException, - MBeanInvocationFailedException, PidUnavailableException { - ObjectName objectName = namePattern; - connect(); - try { - final QueryExp constraint = buildQueryExp(pidAttribute, attributes, values); - final Set<ObjectName> mbeanNames = this.server.queryNames(namePattern, constraint); - - if (mbeanNames.isEmpty()) { - throw new MBeanInvocationFailedException("Failed to find mbean matching '" + namePattern - + "' with attribute '" + pidAttribute + "' of value '" + this.pid + "'"); - } - if (mbeanNames.size() > 1) { - throw new MBeanInvocationFailedException("Found more than one mbean matching '" - + namePattern + "' with attribute '" + pidAttribute + "' of value '" + this.pid + "'"); - } - - objectName = mbeanNames.iterator().next(); - return invoke(objectName, methodName); - } catch (InstanceNotFoundException e) { - throw new MBeanInvocationFailedException( - "Failed to invoke " + methodName + " on " + objectName, e); - } catch (MBeanException e) { - throw new MBeanInvocationFailedException( - "Failed to invoke " + methodName + " on " + objectName, e); - } catch (ReflectionException e) { - throw new MBeanInvocationFailedException( - "Failed to invoke " + methodName + " on " + objectName, e); - } finally { - disconnect(); - } - } - - /** - * Returns the process id (pid) of the process. - * - * @return the process id (pid) of the process - */ - public int getProcessId() { - return this.pid; - } - - /** - * Connects to the JMX agent in the local process. - * - * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector - * in the process - * @throws IOException if the JDK management agent cannot be found and loaded - */ - void connect() throws ConnectionFailedException, IOException { - try { - final JMXServiceURL jmxUrl = getJMXServiceURL(); - this.jmxc = JMXConnectorFactory.connect(jmxUrl); - this.server = this.jmxc.getMBeanServerConnection(); - } catch (AttachNotSupportedException e) { - throw new ConnectionFailedException("Failed to connect to process '" + this.pid + "'", e); - } - } - - /** - * Disconnects from the JMX agent in the local process. - */ - void disconnect() { - this.server = null; - if (this.jmxc != null) { - try { - this.jmxc.close(); - } catch (IOException e) { - // ignore - } - } - this.jmxc = null; - } - - /** - * Ensures that the other process identifies itself by the same pid used by this stopper to - * connect to that process. NOT USED EXCEPT IN TEST. - * - * @return true if the pid matches - * - * @throws IllegalStateException if the other process identifies itself by a different pid - * @throws IOException if a communication problem occurred when accessing the - * MBeanServerConnection - * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails - */ - boolean checkPidMatches() throws IllegalStateException, IOException, PidUnavailableException { - final RuntimeMXBean proxy = ManagementFactory.newPlatformMXBeanProxy(this.server, - ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); - final int remotePid = ProcessUtils.identifyPid(proxy.getName()); - if (remotePid != this.pid) { - throw new IllegalStateException( - "Process has different pid '" + remotePid + "' than expected pid '" + this.pid + "'"); - } else { - return true; - } - } - - /** - * Uses the Attach API to connect to the local process and ensures that it has loaded the JMX - * management agent. The JMXServiceURL identifying the local connector address for the JMX agent - * in the process is returned. - * - * @return the address of the JMX API connector server for connecting to the local process - * - * @throws AttachNotSupportedException if unable to use the Attach API to connect to the process - * @throws IOException if the JDK management agent cannot be found and loaded - */ - private JMXServiceURL getJMXServiceURL() throws AttachNotSupportedException, IOException { - String connectorAddress = null; - final VirtualMachine vm = VirtualMachine.attach(String.valueOf(this.pid)); - try { - Properties agentProps = vm.getAgentProperties(); - connectorAddress = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); - - if (connectorAddress == null) { - // need to load the management-agent and get the address - - final String javaHome = vm.getSystemProperties().getProperty("java.home"); - - // assume java.home is JDK and look in JRE for agent - String managementAgentPath = javaHome + File.separator + "jre" + File.separator + "lib" - + File.separator + "management-agent.jar"; - File managementAgent = new File(managementAgentPath); - if (!managementAgent.exists()) { - // assume java.home is JRE and look in lib for agent - managementAgentPath = - javaHome + File.separator + "lib" + File.separator + "management-agent.jar"; - managementAgent = new File(managementAgentPath); - if (!managementAgent.exists()) { - throw new IOException("JDK management agent not found"); - } - } - - // attempt to load the management agent - managementAgentPath = managementAgent.getCanonicalPath(); - try { - vm.loadAgent(managementAgentPath, "com.sun.management.jmxremote"); - } catch (AgentLoadException e) { - IOException ioe = new IOException(e.getMessage()); - ioe.initCause(e); - throw ioe; - } catch (AgentInitializationException e) { - IOException ioe = new IOException(e.getMessage()); - ioe.initCause(e); - throw ioe; - } - - // get the connector address - agentProps = vm.getAgentProperties(); - connectorAddress = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); - } - } finally { - vm.detach(); - } - - if (connectorAddress == null) { - // should never reach here - throw new IOException("Failed to find address to attach to process"); - } - - return new JMXServiceURL(connectorAddress); - } - - /** - * Builds the QueryExp used to identify the target MBean. - * - * @param pidAttribute the name of the MBean attribute with the process id to compare against - * @param attributes the names of additional MBean attributes to compare with expected values - * @param values the expected values of the specified MBean attributes - * - * @return the main QueryExp for matching the target MBean - */ - private QueryExp buildQueryExp(final String pidAttribute, final String[] attributes, - final Object[] values) { - final QueryExp optionalAttributes = buildOptionalQueryExp(attributes, values); - QueryExp constraint; - if (optionalAttributes != null) { - constraint = - Query.and(optionalAttributes, Query.eq(Query.attr(pidAttribute), Query.value(this.pid))); - } else { - constraint = Query.eq(Query.attr(pidAttribute), Query.value(this.pid)); - } - return constraint; - } - - /** - * Builds an optional QueryExp to aid in matching the correct MBean using additional attributes - * with the specified values. Returns null if no attributes and values were specified during - * construction. - * - * @param attributes the names of additional MBean attributes to compare with expected values - * @param values the expected values of the specified MBean attributes - * - * @return optional QueryExp to aid in matching the correct MBean - */ - private QueryExp buildOptionalQueryExp(final String[] attributes, final Object[] values) { - QueryExp queryExp = null; - for (int i = 0; i < attributes.length; i++) { - if (values[i] instanceof Boolean) { - if (queryExp == null) { - queryExp = Query.eq(Query.attr(attributes[i]), Query.value(((Boolean) values[i]))); - } else { - queryExp = Query.and(queryExp, - Query.eq(Query.attr(attributes[i]), Query.value(((Boolean) values[i])))); - } - } else if (values[i] instanceof Number) { - if (queryExp == null) { - queryExp = Query.eq(Query.attr(attributes[i]), Query.value((Number) values[i])); - } else { - queryExp = Query.and(queryExp, - Query.eq(Query.attr(attributes[i]), Query.value((Number) values[i]))); - } - } else if (values[i] instanceof String) { - if (queryExp == null) { - queryExp = Query.eq(Query.attr(attributes[i]), Query.value((String) values[i])); - } else { - queryExp = Query.and(queryExp, - Query.eq(Query.attr(attributes[i]), Query.value((String) values[i]))); - } - } - } - return queryExp; - } - - /** - * Invokes an operation on the specified MBean. - * - * @param objectName identifies the MBean - * @param method the name of the operation method invoke - * - * @return the result of invoking the operation on the MBean specified or null - * - * @throws InstanceNotFoundException if the specified MBean is not registered in the MBean server - * @throws IOException if a communication problem occurred when talking to the MBean server - * @throws MBeanException if the MBean operation throws an exception - * @throws ReflectionException if the MBean does not have the specified operation - */ - private Object invoke(final ObjectName objectName, final String method) - throws InstanceNotFoundException, IOException, MBeanException, ReflectionException { - return this.server.invoke(objectName, method, new Object[] {}, new String[] {}); - } - - /** - * Reads in the pid from the specified file. - * - * @param pidFile the file containing the pid of the process to stop - * - * @return the process id (pid) contained within the pidFile - * - * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer - * @throws IOException if unable to read from the specified file - * @throws NumberFormatException if the pid file does not contain a parsable integer - */ - private static int readPid(final File pidFile) throws IOException { - BufferedReader fileReader = null; - String pidValue = null; - - try { - fileReader = new BufferedReader(new FileReader(pidFile)); - pidValue = fileReader.readLine(); - - final int pid = Integer.parseInt(pidValue); - - if (pid < 1) { - throw new IllegalArgumentException("Invalid pid '" + pid + "' found in " + pidFile); - } - - return pid; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Invalid pid '" + pidValue + "' found in " + pidFile); - } finally { - IOUtils.close(fileReader); - } - } - - /** - * Reads in the pid from the named file contained within the specified directory. - * - * @param directory directory containing a file of name pidFileName - * @param pidFilename name of the file containing the pid of the process to stop - * - * @return the process id (pid) contained within the pidFile - * - * @throws FileNotFoundException if the specified file name is not found within the directory - * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer - * @throws IllegalStateException if dir is not an existing directory - * @throws IOException if an I/O error occurs - * @throws NumberFormatException if the pid file does not contain a parsable integer - */ - private static int readPid(final File directory, final String pidFilename) throws IOException { - if (!directory.isDirectory() && directory.exists()) { - throw new IllegalArgumentException( - "Argument '" + directory + "' must be an existing directory!"); - } - - final File[] files = directory.listFiles(new FilenameFilter() { - @Override - public boolean accept(File file, String filename) { - return filename.equals(pidFilename); - } - }); - - if (files.length == 0) { - throw new FileNotFoundException( - "Unable to find PID file '" + pidFilename + "' in directory " + directory); - } - - return readPid(files[0]); - } - -} http://git-wip-us.apache.org/repos/asf/geode/blob/3592e81c/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java deleted file mode 100755 index b132647..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.process; - -import static org.junit.Assert.*; - -import java.lang.management.ManagementFactory; -import java.util.Set; - -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanServer; -import javax.management.ObjectInstance; -import javax.management.ObjectName; -import javax.management.Query; -import javax.management.QueryExp; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.TestName; - -import org.apache.geode.internal.process.mbean.Process; -import org.apache.geode.test.junit.categories.UnitTest; - -/** - * Unit tests for LocalProcessController. - * - * @since GemFire 7.0 - */ -@Category(UnitTest.class) -public class LocalProcessControllerJUnitTest { - - private MBeanServer server; - private ObjectName objectName; - private int pid; - - @Rule - public TestName testName = new TestName(); - - @Before - public void setUp() throws Exception { - pid = ProcessUtils.identifyPid(); - final Process process = new Process(pid, true); - - this.objectName = ObjectName - .getInstance(getClass().getSimpleName() + ":testName=" + testName.getMethodName()); - this.server = ManagementFactory.getPlatformMBeanServer(); - - final ObjectInstance instance = this.server.registerMBean(process, objectName); - assertNotNull(instance); - } - - @After - public void tearDown() throws Exception { - this.server.unregisterMBean(objectName); - } - - @Test - public void testProcessMBean() throws Exception { - // validate basics of the ProcessMBean - Set<ObjectName> mbeanNames = this.server.queryNames(objectName, null); - assertFalse("Zero matching mbeans", mbeanNames.isEmpty()); - assertEquals(1, mbeanNames.size()); - final ObjectName name = mbeanNames.iterator().next(); - - final MBeanInfo info = this.server.getMBeanInfo(name); - - final MBeanOperationInfo[] operInfo = info.getOperations(); - assertEquals(1, operInfo.length); - assertEquals("stop", operInfo[0].getName()); - - final MBeanAttributeInfo[] attrInfo = info.getAttributes(); - assertEquals(2, attrInfo.length); - // The order of these attributes is indeterminate - assertTrue("Pid".equals(attrInfo[0].getName()) || "Process".equals(attrInfo[0].getName())); - assertTrue("Pid".equals(attrInfo[1].getName()) || "Process".equals(attrInfo[1].getName())); - assertNotNull(this.server.getAttribute(name, "Pid")); - assertNotNull(this.server.getAttribute(name, "Process")); - - assertEquals(pid, this.server.getAttribute(name, "Pid")); - assertEquals(true, this.server.getAttribute(name, "Process")); - - // validate query using only Pid attribute - QueryExp constraint = Query.eq(Query.attr("Pid"), Query.value(pid)); - mbeanNames = this.server.queryNames(objectName, constraint); - assertFalse("Zero matching mbeans", mbeanNames.isEmpty()); - - // validate query with wrong Pid finds nothing - constraint = Query.eq(Query.attr("Pid"), Query.value(pid + 1)); - mbeanNames = this.server.queryNames(objectName, constraint); - assertTrue("Found matching mbeans", mbeanNames.isEmpty()); - - // validate query using both attributes - constraint = Query.and(Query.eq(Query.attr("Process"), Query.value(true)), - Query.eq(Query.attr("Pid"), Query.value(pid))); - mbeanNames = this.server.queryNames(objectName, constraint); - assertFalse("Zero matching mbeans", mbeanNames.isEmpty()); - - // validate query with wrong attribute finds nothing - constraint = Query.and(Query.eq(Query.attr("Process"), Query.value(false)), - Query.eq(Query.attr("Pid"), Query.value(pid))); - mbeanNames = this.server.queryNames(objectName, constraint); - assertTrue("Found matching mbeans", mbeanNames.isEmpty()); - } -}
