From a383fb607ba8caf1903db426fa5207cbaefb61a2 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 12 May 2017 11:08:41 +0200 Subject: [PATCH] PT ##143653365 + PT ##143653925: simple main class that identifies running boot apps and tries to find the port information --- .../commons/commons-boot-app-cli/.classpath | 26 +++ .../commons/commons-boot-app-cli/.project | 23 +++ .../org.eclipse.core.resources.prefs | 3 + .../.settings/org.eclipse.jdt.core.prefs | 5 + .../.settings/org.eclipse.m2e.core.prefs | 4 + .../commons/commons-boot-app-cli/pom.xml | 37 ++++ .../boot/app/cli/SpringBootAppCLI.java | 164 ++++++++++++++++++ headless-services/commons/pom.xml | 1 + 8 files changed, 263 insertions(+) create mode 100644 headless-services/commons/commons-boot-app-cli/.classpath create mode 100644 headless-services/commons/commons-boot-app-cli/.project create mode 100644 headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.core.resources.prefs create mode 100644 headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.jdt.core.prefs create mode 100644 headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.m2e.core.prefs create mode 100644 headless-services/commons/commons-boot-app-cli/pom.xml create mode 100644 headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppCLI.java diff --git a/headless-services/commons/commons-boot-app-cli/.classpath b/headless-services/commons/commons-boot-app-cli/.classpath new file mode 100644 index 000000000..af1430be1 --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/.classpath @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/headless-services/commons/commons-boot-app-cli/.project b/headless-services/commons/commons-boot-app-cli/.project new file mode 100644 index 000000000..76c6118b5 --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/.project @@ -0,0 +1,23 @@ + + + commons-boot-app-cli + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.core.resources.prefs b/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..e9441bb12 --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding/=UTF-8 diff --git a/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.jdt.core.prefs b/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..714351aec --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.m2e.core.prefs b/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 000000000..f897a7f1c --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/headless-services/commons/commons-boot-app-cli/pom.xml b/headless-services/commons/commons-boot-app-cli/pom.xml new file mode 100644 index 000000000..492755f83 --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/pom.xml @@ -0,0 +1,37 @@ + + 4.0.0 + commons-boot-app-cli + commons-boot-app-cli + Common code related to 'accessing running boot apps in a cli-like style' + + + org.springframework.ide.vscode + commons-parent + 0.0.1-SNAPSHOT + ../pom.xml + + + + + org.json + json + 20160810 + + + + com.fasterxml.jackson.core + jackson-databind + 2.8.8.1 + + + + com.sun + tools + 1.8.0 + system + ${java.home}/../lib/tools.jar + + + + diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppCLI.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppCLI.java new file mode 100644 index 000000000..97ead26c7 --- /dev/null +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppCLI.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2017 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.boot.app.cli; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.json.JSONObject; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; + +/** + * @author Martin Lippert + */ +@SuppressWarnings("restriction") +public class SpringBootAppCLI { + + public static void main(String[] args) throws Exception { + List list = VirtualMachine.list(); + for (VirtualMachineDescriptor vmd : list) { + VirtualMachine vm = VirtualMachine.attach(vmd); + Properties props = vm.getSystemProperties(); + + String classpath = (String) props.get("java.class.path"); + String[] cpElements = getClasspath(classpath); + boolean isSpringBoot = contains(cpElements, "spring-boot"); + boolean isSpringBootActuator = contains(cpElements, "spring-boot-actuator"); + + if (isSpringBoot) { + printBootAppDetails(vmd, vm, isSpringBootActuator); + } + } + } + + private static void printBootAppDetails(VirtualMachineDescriptor vmd, VirtualMachine vm, + boolean isSpringBootActuator) throws IOException { + + System.out.println("Spring Boot App: " + vmd.id()); + System.out.println("Name: " + vmd.displayName()); + System.out.println("Actuators available: " + isSpringBootActuator); + + String jmxConnect = vm.startLocalManagementAgent(); + System.out.println("JMX Connection: " + jmxConnect); + + JMXConnector jmxConnector = null; + try { + JMXServiceURL serviceUrl = new JMXServiceURL(jmxConnect); + jmxConnector = JMXConnectorFactory.connect(serviceUrl, null); + + try { + String port = getPort(jmxConnector); + System.out.println("Runs on port: " + port); + } + catch (InstanceNotFoundException e) { + System.out.println("Port not available"); + } + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + if (jmxConnector != null) jmxConnector.close(); + } + + System.out.println(); + } + + private static boolean contains(String[] cpElements, String element) { + for (String cpElement : cpElements) { + if (cpElement.contains(element)) { + return true; + } + } + return false; + } + + private static String[] getClasspath(String classpath) { + List classpathElements = new ArrayList<>(); + if (classpath != null) { + StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator); + while (tokenizer.hasMoreTokens()) { + String classpathElement = tokenizer.nextToken(); + classpathElements.add(classpathElement); + } + } + return (String[]) classpathElements.toArray(new String[classpathElements.size()]); + } + + private static String getPort(JMXConnector jmxConnector) throws Exception { + MBeanServerConnection connection = jmxConnector.getMBeanServerConnection(); + + String port = getPortViaAdmin(connection); + if (port != null) { + return port; + } + else { + return getPortViaActuator(connection); + } + } + + private static String getPortViaAdmin(MBeanServerConnection connection) throws Exception { + try { + String DEFAULT_OBJECT_NAME = "org.springframework.boot:type=Admin,name=SpringApplication"; + ObjectName objectName = new ObjectName(DEFAULT_OBJECT_NAME); + + Object o = connection.invoke(objectName,"getProperty", new String[] {"local.server.port"}, new String[] {String.class.getName()}); + return o.toString(); + } + catch (InstanceNotFoundException e) { + System.out.println("Admin management bean not available"); + return null; + } + } + + private static String getPortViaActuator(MBeanServerConnection connection) throws Exception { + try { + String environment = getEnvironment(connection); + System.out.println("Environment: " + environment); + + JSONObject env = new JSONObject(environment); + if (env != null) { + JSONObject portsObject = env.getJSONObject("server.ports"); + if (portsObject != null) { + String portValue = portsObject.getString("local.server.port"); + return portValue; + } + } + } + catch (InstanceNotFoundException e) { + System.out.println("Actuator not available: Spring Boot actuators not enabled"); + } + return null; + } + + private static String getEnvironment(MBeanServerConnection connection) throws Exception { + String DEFAULT_OBJECT_NAME = "org.springframework.boot:type=Endpoint,name=environmentEndpoint"; + ObjectName objectName = new ObjectName(DEFAULT_OBJECT_NAME); + + Object result = connection.getAttribute(objectName, "Data"); + return new ObjectMapper().writeValueAsString(result); + } + +} diff --git a/headless-services/commons/pom.xml b/headless-services/commons/pom.xml index bdfce3733..7c35b0a56 100644 --- a/headless-services/commons/pom.xml +++ b/headless-services/commons/pom.xml @@ -19,6 +19,7 @@ commons-cf commons-maven commons-gradle + commons-boot-app-cli