From 78c39f13752f338494969608ceb8a5abba0b320d Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Fri, 29 Jan 2021 22:40:44 -0500 Subject: [PATCH 01/13] Initial version of java map plugin. --- java-maven-plugin/pom.xml | 23 ++++++++++ .../appland/appmap/RunAppMapAgentMojo.java | 43 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 java-maven-plugin/pom.xml create mode 100644 java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java diff --git a/java-maven-plugin/pom.xml b/java-maven-plugin/pom.xml new file mode 100644 index 00000000..003f0a27 --- /dev/null +++ b/java-maven-plugin/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + com.appland.appmap + java-maven-plugin + maven-plugin + 1.0-SNAPSHOT + java-maven-plugin Maven Mojo + http://maven.apache.org + + + org.apache.maven + maven-plugin-api + 2.0 + + + junit + junit + 3.8.1 + test + + + diff --git a/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java b/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java new file mode 100644 index 00000000..28eb92db --- /dev/null +++ b/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java @@ -0,0 +1,43 @@ +package com.appland.appmap; + +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed 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. + */ + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; + +import java.io.File; + +/** + * Goal which touches a timestamp file. + * + * @goal run-map-agent + * @phase test + */ +public class RunAppMapAgentMojo extends AbstractMojo { + /** + * Location of the file. + * + * @parameter expression="${project.build.directory}" + * @required + */ + private File outputDirectory; + + public void execute() + throws MojoExecutionException { + getLog().info("Look momma no hands!!"); + } +} From 1692b0429c7eabb64e589152afba4c8ae92a0a43 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Sat, 30 Jan 2021 00:50:09 -0500 Subject: [PATCH 02/13] Trying to register a java recorder by code from within the plugin mojo. --- java-maven-plugin/pom.xml | 70 +++++++++++++------ .../appland/appmap/RunAppMapAgentMojo.java | 15 +++- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/java-maven-plugin/pom.xml b/java-maven-plugin/pom.xml index 003f0a27..4bd8e598 100644 --- a/java-maven-plugin/pom.xml +++ b/java-maven-plugin/pom.xml @@ -1,23 +1,49 @@ - - 4.0.0 - com.appland.appmap - java-maven-plugin - maven-plugin - 1.0-SNAPSHOT - java-maven-plugin Maven Mojo - http://maven.apache.org - - - org.apache.maven - maven-plugin-api - 2.0 - - - junit - junit - 3.8.1 - test - - + + 4.0.0 + com.appland.appmap + java-maven-plugin + maven-plugin + 1.0-SNAPSHOT + Appland Java Recorder Maven Plugin + This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. + https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin + + + org.apache.maven + maven-plugin-api + 2.0 + + + junit + junit + 3.8.1 + test + + + + + + + org.apache.maven.plugins + maven-site-plugin + 3.7.1 + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 3.0.0 + + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 2.5.1 + + + diff --git a/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java b/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java index 28eb92db..bee9fbe6 100644 --- a/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java +++ b/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java @@ -18,14 +18,16 @@ import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; +import com.appland.appmap.record.IRecordingSession; +import com.appland.appmap.record.Recorder; import java.io.File; /** - * Goal which touches a timestamp file. + * Goal which register a appmap java recording agent, right before the test execution begins. * * @goal run-map-agent - * @phase test + * @phase test-compile */ public class RunAppMapAgentMojo extends AbstractMojo { /** @@ -38,6 +40,13 @@ public class RunAppMapAgentMojo extends AbstractMojo { public void execute() throws MojoExecutionException { - getLog().info("Look momma no hands!!"); + getLog().info("Initializing AppLand AppMap Java Recorder"); + try { + final IRecordingSession.Metadata metadata = new IRecordingSession.Metadata(); + Recorder.getInstance().start(metadata); + }catch (Exception e) { + getLog().error("Error initializing AppLand AppMap Java Recorder"); + e.printStackTrace(); + } } } From 51c1cb7b221718a93a33ef6ac924ea567aa6b708 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Mon, 1 Feb 2021 17:41:04 -0500 Subject: [PATCH 03/13] Adding the missing agent library so the plugin can fire up the recording process. --- java-maven-plugin/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java-maven-plugin/pom.xml b/java-maven-plugin/pom.xml index 4bd8e598..32152d1a 100644 --- a/java-maven-plugin/pom.xml +++ b/java-maven-plugin/pom.xml @@ -9,6 +9,13 @@ This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin + + com.appland.appmap + java-agent + 0.5.0 + system + C:/Users/msanchez3/.m2/repository/com/appland/appmap/java-agent/0.5.0/java-agent-0.5.0.jar + org.apache.maven maven-plugin-api From a3df52eef8a4a30e6c74dc82ca7ff87e9474542e Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Mon, 1 Feb 2021 20:08:34 -0500 Subject: [PATCH 04/13] First Attempt to add proper test to the maven dependency project. --- java-maven-plugin/pom.xml | 17 +++---- ...Mojo.java => LoadJavaAppMapAgentMojo.java} | 2 +- .../appmap/LoadJavaMapAgentMojoTest.java | 51 +++++++++++++++++++ 3 files changed, 59 insertions(+), 11 deletions(-) rename java-maven-plugin/src/main/java/com/appland/appmap/{RunAppMapAgentMojo.java => LoadJavaAppMapAgentMojo.java} (96%) create mode 100644 java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java diff --git a/java-maven-plugin/pom.xml b/java-maven-plugin/pom.xml index 32152d1a..9e33b0f7 100644 --- a/java-maven-plugin/pom.xml +++ b/java-maven-plugin/pom.xml @@ -24,7 +24,13 @@ junit junit - 3.8.1 + 4.13.1 + test + + + org.apache.commons + commons-lang3 + 3.10 test @@ -44,13 +50,4 @@ - - - - org.apache.maven.plugins - maven-plugin-plugin - 2.5.1 - - - diff --git a/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java b/java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java similarity index 96% rename from java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java rename to java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index bee9fbe6..1f558cd3 100644 --- a/java-maven-plugin/src/main/java/com/appland/appmap/RunAppMapAgentMojo.java +++ b/java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -29,7 +29,7 @@ * @goal run-map-agent * @phase test-compile */ -public class RunAppMapAgentMojo extends AbstractMojo { +public class LoadJavaAppMapAgentMojo extends AbstractMojo { /** * Location of the file. * diff --git a/java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java b/java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java new file mode 100644 index 00000000..e8ca9d78 --- /dev/null +++ b/java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java @@ -0,0 +1,51 @@ +package com.appland.appmap; + +import static org.junit.Assert.assertEquals; + +import com.appland.appmap.output.v1.Event; + +import com.appland.appmap.record.IRecordingSession; +import com.appland.appmap.record.Recorder; +import org.apache.commons.lang3.StringUtils; +import org.junit.Before; +import org.junit.Test; + +public class LoadJavaMapAgentMojoTest { + + @Before + public void before() throws Exception { + final IRecordingSession.Metadata metadata = + new IRecordingSession.Metadata(); + + Recorder.getInstance().start(metadata); + } + + @Test + public void testAllEventsWritten() { + final Recorder recorder = Recorder.getInstance(); + final Long threadId = Thread.currentThread().getId(); + final Event[] events = new Event[] { + new Event(), + new Event(), + new Event(), + }; + + for (int i = 0; i < events.length; i++) { + final Event event = events[i]; + event + .setDefinedClass("SomeClass") + .setMethodId("SomeMethod") + .setStatic(false) + .setLineNumber(315) + .setThreadId(threadId); + + recorder.add(event); + assertEquals(event, recorder.getLastEvent()); + } + + final String appmapJson = recorder.stop(); + final String expectedJson = "\"thread_id\":" + threadId.toString(); + final int numMatches = StringUtils.countMatches(appmapJson, expectedJson); + assertEquals(numMatches, events.length); + } +} From 02e18fdd064e3280f5e85b70fce36462b83b3334 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Tue, 2 Feb 2021 13:56:51 -0500 Subject: [PATCH 05/13] Renaming project artifacts to adhere to tech specs. --- .../pom.xml | 6 ++--- .../appmap/LoadJavaAppMapAgentMojo.java | 22 ++++++++++++++++--- .../appmap/LoadJavaMapAgentMojoTest.java | 0 3 files changed, 22 insertions(+), 6 deletions(-) rename {java-maven-plugin => appmap-java-maven-plugin}/pom.xml (94%) rename {java-maven-plugin => appmap-java-maven-plugin}/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java (79%) rename {java-maven-plugin => appmap-java-maven-plugin}/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java (100%) diff --git a/java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml similarity index 94% rename from java-maven-plugin/pom.xml rename to appmap-java-maven-plugin/pom.xml index 9e33b0f7..ba5b1169 100644 --- a/java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -1,10 +1,10 @@ 4.0.0 - com.appland.appmap - java-maven-plugin + org.appland + appmap-java-maven-plugin maven-plugin - 1.0-SNAPSHOT + 0.5.0 Appland Java Recorder Maven Plugin This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin diff --git a/java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java similarity index 79% rename from java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java rename to appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index 1f558cd3..ad7d740d 100644 --- a/java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -26,18 +26,34 @@ /** * Goal which register a appmap java recording agent, right before the test execution begins. * - * @goal run-map-agent + * @goal prepare-agent * @phase test-compile */ public class LoadJavaAppMapAgentMojo extends AbstractMojo { /** - * Location of the file. + * Directory where reports will be generated. * * @parameter expression="${project.build.directory}" - * @required + * */ private File outputDirectory; + /** + * Configuration file for the java agent @default /appmap.yml. + * + * @parameter expression="${project.build.directory}" + * + */ + private File configFile; + + /** + * Java Agent Debug Option. + * + * @parameter expression="${project.build.directory} + * + */ + private Boolean debug = false; + public void execute() throws MojoExecutionException { getLog().info("Initializing AppLand AppMap Java Recorder"); diff --git a/java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java b/appmap-java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java similarity index 100% rename from java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java rename to appmap-java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java From 909bbce64cab5920e52fa1533a98534f973c64cc Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Tue, 2 Feb 2021 23:41:49 -0500 Subject: [PATCH 06/13] First working version of the AppMap plugin being loaded as per technical spec document demands. --- appmap-java-maven-plugin/pom.xml | 42 ++++- .../appland/appmap/CommandLineSupport.java | 141 ++++++++++++++++ .../appmap/LoadJavaAppMapAgentMojo.java | 158 ++++++++++++++++-- 3 files changed, 328 insertions(+), 13 deletions(-) create mode 100644 appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java diff --git a/appmap-java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml index ba5b1169..6e5384ce 100644 --- a/appmap-java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -4,10 +4,17 @@ org.appland appmap-java-maven-plugin maven-plugin - 0.5.0 + 0.5.0-SNAPSHOT Appland Java Recorder Maven Plugin This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin + + + + + 3.0 + + com.appland.appmap @@ -16,11 +23,41 @@ system C:/Users/msanchez3/.m2/repository/com/appland/appmap/java-agent/0.5.0/java-agent-0.5.0.jar + org.apache.maven maven-plugin-api - 2.0 + ${project.prerequisites.maven} + + org.apache.maven + maven-core + ${project.prerequisites.maven} + + + org.codehaus.plexus + plexus-utils + 3.0.22 + + + org.apache.maven.shared + file-management + 1.2.1 + + + org.apache.maven.reporting + maven-reporting-api + ${project.prerequisites.maven} + + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.4 + + provided + + junit junit @@ -34,6 +71,7 @@ test + diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java new file mode 100644 index 00000000..05ba4296 --- /dev/null +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package com.appland.appmap; + +import java.util.ArrayList; +import java.util.List; + +/** + * Internal utility to parse and create command lines arguments. + */ +final class CommandLineSupport { + + private static final char BLANK = ' '; + private static final char QUOTE = '"'; + private static final char SLASH = '\\'; + + /** + * Quotes a single command line argument if necessary. + * + * @param arg + * command line argument + * @return quoted argument + */ + static String quote(final String arg) { + final StringBuilder escaped = new StringBuilder(); + for (final char c : arg.toCharArray()) { + if (c == QUOTE || c == SLASH) { + escaped.append(SLASH); + } + escaped.append(c); + } + if (arg.indexOf(BLANK) != -1 || arg.indexOf(QUOTE) != -1) { + escaped.insert(0, QUOTE).append(QUOTE); + } + return escaped.toString(); + } + + /** + * Builds a single command line string from the given argument list. + * Arguments are quoted when necessary. + * + * @param args + * command line arguments + * @return combined command line + */ + static String quote(final List args) { + final StringBuilder result = new StringBuilder(); + boolean separate = false; + for (final String arg : args) { + if (separate) { + result.append(BLANK); + } + result.append(quote(arg)); + separate = true; + } + return result.toString(); + } + + /** + * Splits a command line into single arguments and removes quotes if + * present. + * + * @param commandline + * combined command line + * @return list of arguments + */ + static List split(final String commandline) { + if (commandline == null || commandline.length() == 0) { + return new ArrayList(); + } + final List args = new ArrayList(); + final StringBuilder current = new StringBuilder(); + int mode = M_STRIP_WHITESPACE; + int endChar = BLANK; + for (final char c : commandline.toCharArray()) { + switch (mode) { + case M_STRIP_WHITESPACE: + if (!Character.isWhitespace(c)) { + if (c == QUOTE) { + endChar = QUOTE; + } else { + current.append(c); + endChar = BLANK; + } + mode = M_PARSE_ARGUMENT; + } + break; + case M_PARSE_ARGUMENT: + if (c == endChar) { + addArgument(args, current); + mode = M_STRIP_WHITESPACE; + } else if (c == SLASH) { + current.append(SLASH); + mode = M_ESCAPED; + } else { + current.append(c); + } + break; + case M_ESCAPED: + if (c == QUOTE || c == SLASH) { + current.setCharAt(current.length() - 1, c); + } else if (c == endChar) { + addArgument(args, current); + mode = M_STRIP_WHITESPACE; + } else { + current.append(c); + } + mode = M_PARSE_ARGUMENT; + break; + } + } + addArgument(args, current); + return args; + } + + private static void addArgument(final List args, + final StringBuilder current) { + if (current.length() > 0) { + args.add(current.toString()); + current.setLength(0); + } + } + + private static final int M_STRIP_WHITESPACE = 0; + private static final int M_PARSE_ARGUMENT = 1; + private static final int M_ESCAPED = 2; + + private CommandLineSupport() { + // no instances + } +} diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index ad7d740d..14427836 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -16,24 +16,33 @@ * limitations under the License. */ -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; import com.appland.appmap.record.IRecordingSession; import com.appland.appmap.record.Recorder; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; import java.io.File; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import static java.lang.String.format; /** - * Goal which register a appmap java recording agent, right before the test execution begins. + * Goal which adds appmap.jar to JVM execution as javaagent, right before the test execution begins. * * @goal prepare-agent * @phase test-compile */ public class LoadJavaAppMapAgentMojo extends AbstractMojo { /** - * Directory where reports will be generated. + * Directory where reports will be generated. @default /tmp * - * @parameter expression="${project.build.directory}" + * @parameter expression="${project.outputDirectory}" * */ private File outputDirectory; @@ -41,7 +50,7 @@ public class LoadJavaAppMapAgentMojo extends AbstractMojo { /** * Configuration file for the java agent @default /appmap.yml. * - * @parameter expression="${project.build.directory}" + * @parameter expression="${project.configFile}" * */ private File configFile; @@ -49,20 +58,147 @@ public class LoadJavaAppMapAgentMojo extends AbstractMojo { /** * Java Agent Debug Option. * - * @parameter expression="${project.build.directory} + * @parameter expression="${project.debug} + * + */ + private String debug = "disabled"; + + /** + * Java Agent Event Description Size. + * + * @parameter expression="${project.eventValueSize} * */ - private Boolean debug = false; + private Integer eventValueSize = 1024; + + /** + * Maven project. + * @parameter expression="${project} + */ + private MavenProject project; + + /** + * Flag used to suppress execution. + * + * @parameter expression="${project.skip} + */ + private boolean skip; + + /** + * Name of the AppMap Agent artifact. + */ + static final String AGENT_ARTIFACT_NAME = "com.appland.appmap:java-agent"; + + /** + * Map of plugin artifacts. + * @parameter expression="${plugin.artifactMap} + */ + //@Parameter(property = "plugin.artifactMap", required = true, readonly = true) + Map pluginArtifactMap; + + /** + * Allows to specify property which will contains settings for AppMap Agent. + * If not specified, then "argLine" would be used for "jar" packaging and + * "tycho.testArgLine" for "eclipse-test-plugin". + */ + @Parameter(property = "appmap.propertyName") + String propertyName; + + /** + * Name of the property used in maven-surefire-plugin. + */ + static final String SUREFIRE_ARG_LINE = "argLine"; + + /** + * Name of the property used in maven-osgi-test-plugin. + */ + static final String TYCHO_ARG_LINE = "tycho.testArgLine"; + public void execute() throws MojoExecutionException { - getLog().info("Initializing AppLand AppMap Java Recorder"); + getLog().info("Initializing AppLand AppMap Java Recorder >" + project + "< " + skip+ " "+outputDirectory + " "+ configFile + " " + debug + " "+ eventValueSize); try { - final IRecordingSession.Metadata metadata = new IRecordingSession.Metadata(); - Recorder.getInstance().start(metadata); + if (skip) { + getLog().info( + "Skipping AppMap execution because property skip is set."); + skipMojo(); + return; + }else { + final String name = getEffectivePropertyName(); + final Properties projectProperties = getProject().getProperties(); + final String oldValue = projectProperties.getProperty(name); + + final String newValue = prependVMArguments(oldValue, getAgentJarFile()); + getLog().info(name + " set to " + newValue); + projectProperties.setProperty(name, newValue); + } + + }catch (Exception e) { getLog().error("Error initializing AppLand AppMap Java Recorder"); e.printStackTrace(); } } + + /** + * Skips Mojo. + */ + protected void skipMojo() { + } + + /** + * @return Maven project + */ + protected final MavenProject getProject() { + return project; + } + + File getAgentJarFile() { + final Artifact appmapAgentArtifact = pluginArtifactMap.get(AGENT_ARTIFACT_NAME); + return appmapAgentArtifact.getFile(); + } + + String getEffectivePropertyName() { + if (isPropertyNameSpecified()) { + return propertyName; + } + if (isEclipseTestPluginPackaging()) { + return TYCHO_ARG_LINE; + } + return SUREFIRE_ARG_LINE; + } + + boolean isPropertyNameSpecified() { + return propertyName != null && !"".equals(propertyName); + } + + boolean isEclipseTestPluginPackaging() { + return "eclipse-test-plugin".equals(getProject().getPackaging()); + } + + public String prependVMArguments(final String arguments, + final File agentJarFile) { + final List args = CommandLineSupport.split(arguments); + final String plainAgent = format("-javaagent:%s", agentJarFile); + for (final Iterator i = args.iterator(); i.hasNext();) { + if (i.next().startsWith(plainAgent)) { + i.remove(); + } + } + args.add(0, getVMArgument(agentJarFile)); + return CommandLineSupport.quote(args); + } + + /** + * Generate required JVM argument based on current configuration and + * supplied agent jar location. + * + * @param agentJarFile + * location of the AppMap Agent Jar + * @return Argument to pass to create new VM with App Mapping enabled + */ + public String getVMArgument(final File agentJarFile) { + return format("-javaagent:%s=%s", agentJarFile, this); + } } From 95a78b93acfc32a371dad1907a497ad03a5d2e5a Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Wed, 3 Feb 2021 22:10:13 -0500 Subject: [PATCH 07/13] Minor refactor of the working command line version. --- .../com/appland/appmap/AppMapAgentMojo.java | 125 +++++++++++++++ .../appmap/LoadJavaAppMapAgentMojo.java | 147 +----------------- 2 files changed, 132 insertions(+), 140 deletions(-) create mode 100644 appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java new file mode 100644 index 00000000..f96813e1 --- /dev/null +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java @@ -0,0 +1,125 @@ +package com.appland.appmap; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import static java.lang.String.format; + +public abstract class AppMapAgentMojo extends AbstractMojo { + /** + * Name of the AppMap Agent artifact. + */ + static final String AGENT_ARTIFACT_NAME = "com.appland.appmap:java-agent"; + /** + * Name of the property used in maven-surefire-plugin. + */ + static final String SUREFIRE_ARG_LINE = "argLine"; + /** + * Name of the property used in maven-osgi-test-plugin. + */ + static final String TYCHO_ARG_LINE = "tycho.testArgLine"; + /** + * Directory where reports will be generated. @default /tmp + * + * @parameter expression="${project.outputDirectory}" + */ + protected File outputDirectory; + /** + * Configuration file for the java agent @default /appmap.yml. + * + * @parameter expression="${project.configFile}" + */ + protected File configFile; + /** + * Java Agent Debug Option. + * + * @parameter expression="${project.debug} + */ + protected String debug = "disabled"; + /** + * Java Agent Event Description Size. + * + * @parameter expression="${project.eventValueSize} + */ + protected Integer eventValueSize = 1024; + /** + * Maven project. + * + * @parameter expression="${project} + */ + protected MavenProject project; + /** + * Flag used to suppress execution. + * + * @parameter expression="${project.skip} + */ + protected boolean skip; + /** + * Allows to specify property which will contains settings for AppMap Agent. + * If not specified, then "argLine" would be used for "jar" packaging and + * "tycho.testArgLine" for "eclipse-test-plugin". + */ + @Parameter(property = "appmap.propertyName") + String propertyName; + + public abstract void execute() + throws MojoExecutionException; + + protected void skipMojo() { + } + + /** + * @return Maven project + */ + protected final MavenProject getProject() { + return project; + } + + String getEffectivePropertyName() { + if (isPropertyNameSpecified()) { + return propertyName; + } + if (isEclipseTestPluginPackaging()) { + return TYCHO_ARG_LINE; + } + return SUREFIRE_ARG_LINE; + } + + protected boolean isPropertyNameSpecified() { + return propertyName != null && !"".equals(propertyName); + } + + protected boolean isEclipseTestPluginPackaging() { + return "eclipse-test-plugin".equals(getProject().getPackaging()); + } + + protected String prependVMArguments(final String arguments, + final File agentJarFile) { + final List args = CommandLineSupport.split(arguments); + final String plainAgent = format("-javaagent:%s", agentJarFile); + for (final Iterator i = args.iterator(); i.hasNext(); ) { + if (i.next().startsWith(plainAgent)) { + i.remove(); + } + } + args.add(0, getVMArgument(agentJarFile)); + return CommandLineSupport.quote(args); + } + + /** + * Generate required JVM argument based on current configuration and + * supplied agent jar location. + * + * @param agentJarFile location of the AppMap Agent Jar + * @return Argument to pass to create new VM with App Mapping enabled + */ + protected String getVMArgument(final File agentJarFile) { + return format("-javaagent:%s=%s", agentJarFile, this); + } +} diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index 14427836..f94dabcd 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -16,115 +16,39 @@ * limitations under the License. */ -import com.appland.appmap.record.IRecordingSession; -import com.appland.appmap.record.Recorder; import org.apache.maven.artifact.Artifact; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; import java.io.File; -import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Properties; -import static java.lang.String.format; - /** * Goal which adds appmap.jar to JVM execution as javaagent, right before the test execution begins. * * @goal prepare-agent * @phase test-compile */ -public class LoadJavaAppMapAgentMojo extends AbstractMojo { - /** - * Directory where reports will be generated. @default /tmp - * - * @parameter expression="${project.outputDirectory}" - * - */ - private File outputDirectory; - - /** - * Configuration file for the java agent @default /appmap.yml. - * - * @parameter expression="${project.configFile}" - * - */ - private File configFile; - - /** - * Java Agent Debug Option. - * - * @parameter expression="${project.debug} - * - */ - private String debug = "disabled"; - - /** - * Java Agent Event Description Size. - * - * @parameter expression="${project.eventValueSize} - * - */ - private Integer eventValueSize = 1024; - - /** - * Maven project. - * @parameter expression="${project} - */ - private MavenProject project; - - /** - * Flag used to suppress execution. - * - * @parameter expression="${project.skip} - */ - private boolean skip; - - /** - * Name of the AppMap Agent artifact. - */ - static final String AGENT_ARTIFACT_NAME = "com.appland.appmap:java-agent"; +public class LoadJavaAppMapAgentMojo extends AppMapAgentMojo { /** * Map of plugin artifacts. + * * @parameter expression="${plugin.artifactMap} */ - //@Parameter(property = "plugin.artifactMap", required = true, readonly = true) Map pluginArtifactMap; - /** - * Allows to specify property which will contains settings for AppMap Agent. - * If not specified, then "argLine" would be used for "jar" packaging and - * "tycho.testArgLine" for "eclipse-test-plugin". - */ - @Parameter(property = "appmap.propertyName") - String propertyName; - - /** - * Name of the property used in maven-surefire-plugin. - */ - static final String SUREFIRE_ARG_LINE = "argLine"; - - /** - * Name of the property used in maven-osgi-test-plugin. - */ - static final String TYCHO_ARG_LINE = "tycho.testArgLine"; - - + @Override public void execute() throws MojoExecutionException { - getLog().info("Initializing AppLand AppMap Java Recorder >" + project + "< " + skip+ " "+outputDirectory + " "+ configFile + " " + debug + " "+ eventValueSize); + getLog().info("Initializing AppLand AppMap Java Recorder >" + project + "< " + skip + " " + outputDirectory + " " + configFile + " " + debug + " " + eventValueSize); try { if (skip) { getLog().info( "Skipping AppMap execution because property skip is set."); skipMojo(); return; - }else { + } else { final String name = getEffectivePropertyName(); final Properties projectProperties = getProject().getProperties(); final String oldValue = projectProperties.getProperty(name); @@ -133,72 +57,15 @@ public void execute() getLog().info(name + " set to " + newValue); projectProperties.setProperty(name, newValue); } - - - }catch (Exception e) { + } catch (Exception e) { getLog().error("Error initializing AppLand AppMap Java Recorder"); e.printStackTrace(); } } - /** - * Skips Mojo. - */ - protected void skipMojo() { - } - - /** - * @return Maven project - */ - protected final MavenProject getProject() { - return project; - } - - File getAgentJarFile() { + private File getAgentJarFile() { final Artifact appmapAgentArtifact = pluginArtifactMap.get(AGENT_ARTIFACT_NAME); return appmapAgentArtifact.getFile(); } - String getEffectivePropertyName() { - if (isPropertyNameSpecified()) { - return propertyName; - } - if (isEclipseTestPluginPackaging()) { - return TYCHO_ARG_LINE; - } - return SUREFIRE_ARG_LINE; - } - - boolean isPropertyNameSpecified() { - return propertyName != null && !"".equals(propertyName); - } - - boolean isEclipseTestPluginPackaging() { - return "eclipse-test-plugin".equals(getProject().getPackaging()); - } - - public String prependVMArguments(final String arguments, - final File agentJarFile) { - final List args = CommandLineSupport.split(arguments); - final String plainAgent = format("-javaagent:%s", agentJarFile); - for (final Iterator i = args.iterator(); i.hasNext();) { - if (i.next().startsWith(plainAgent)) { - i.remove(); - } - } - args.add(0, getVMArgument(agentJarFile)); - return CommandLineSupport.quote(args); - } - - /** - * Generate required JVM argument based on current configuration and - * supplied agent jar location. - * - * @param agentJarFile - * location of the AppMap Agent Jar - * @return Argument to pass to create new VM with App Mapping enabled - */ - public String getVMArgument(final File agentJarFile) { - return format("-javaagent:%s=%s", agentJarFile, this); - } } From f021384aa4bf4d5da32140b6748178a4a1679816 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Wed, 3 Feb 2021 22:20:43 -0500 Subject: [PATCH 08/13] Minor refactor of the working command line version. --- .../com/appland/appmap/AppMapAgentMojo.java | 31 ++++++++++++++++--- .../appmap/LoadJavaAppMapAgentMojo.java | 20 +----------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java index f96813e1..d26fbace 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java @@ -1,5 +1,6 @@ package com.appland.appmap; +import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Parameter; @@ -8,6 +9,8 @@ import java.io.File; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Properties; import static java.lang.String.format; @@ -68,11 +71,16 @@ public abstract class AppMapAgentMojo extends AbstractMojo { @Parameter(property = "appmap.propertyName") String propertyName; - public abstract void execute() - throws MojoExecutionException; + /** + * Map of plugin artifacts. + * + * @parameter expression="${plugin.artifactMap} + */ + Map pluginArtifactMap; - protected void skipMojo() { - } + public abstract void execute() throws MojoExecutionException; + + protected void skipMojo() { } /** * @return Maven project @@ -122,4 +130,19 @@ protected String prependVMArguments(final String arguments, protected String getVMArgument(final File agentJarFile) { return format("-javaagent:%s=%s", agentJarFile, this); } + + protected void loadAppMapJavaAgent() { + final String name = getEffectivePropertyName(); + final Properties projectProperties = getProject().getProperties(); + final String oldValue = projectProperties.getProperty(name); + + final String newValue = prependVMArguments(oldValue, getAgentJarFile()); + getLog().info(name + " set to " + newValue); + projectProperties.setProperty(name, newValue); + } + + protected File getAgentJarFile() { + final Artifact appmapAgentArtifact = pluginArtifactMap.get(AGENT_ARTIFACT_NAME); + return appmapAgentArtifact.getFile(); + } } diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index f94dabcd..ba01e81a 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -31,13 +31,6 @@ */ public class LoadJavaAppMapAgentMojo extends AppMapAgentMojo { - /** - * Map of plugin artifacts. - * - * @parameter expression="${plugin.artifactMap} - */ - Map pluginArtifactMap; - @Override public void execute() throws MojoExecutionException { @@ -49,13 +42,7 @@ public void execute() skipMojo(); return; } else { - final String name = getEffectivePropertyName(); - final Properties projectProperties = getProject().getProperties(); - final String oldValue = projectProperties.getProperty(name); - - final String newValue = prependVMArguments(oldValue, getAgentJarFile()); - getLog().info(name + " set to " + newValue); - projectProperties.setProperty(name, newValue); + loadAppMapJavaAgent(); } } catch (Exception e) { getLog().error("Error initializing AppLand AppMap Java Recorder"); @@ -63,9 +50,4 @@ public void execute() } } - private File getAgentJarFile() { - final Artifact appmapAgentArtifact = pluginArtifactMap.get(AGENT_ARTIFACT_NAME); - return appmapAgentArtifact.getFile(); - } - } From 4caa606d4a2408aeec2373ce72094b87d4788d77 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Fri, 5 Feb 2021 00:16:16 -0500 Subject: [PATCH 09/13] Maven Plugin for AppMap Java Agent. --- appmap-java-maven-plugin/pom.xml | 29 ++-- .../com/appland/appmap/AppMapAgentMojo.java | 158 +++++------------- .../appland/appmap/CommandLineSupport.java | 141 ---------------- .../appmap/LoadJavaAppMapAgentMojo.java | 35 +--- 4 files changed, 66 insertions(+), 297 deletions(-) delete mode 100644 appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java diff --git a/appmap-java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml index 6e5384ce..e9b1063a 100644 --- a/appmap-java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -9,12 +9,6 @@ This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin - - - - 3.0 - - com.appland.appmap @@ -27,33 +21,32 @@ org.apache.maven maven-plugin-api - ${project.prerequisites.maven} + 3.3.9 org.apache.maven maven-core - ${project.prerequisites.maven} + 3.3.9 org.codehaus.plexus plexus-utils - 3.0.22 + 3.3.0 org.apache.maven.shared file-management - 1.2.1 + 3.0.0 org.apache.maven.reporting maven-reporting-api - ${project.prerequisites.maven} + 3.0 - org.apache.maven.plugin-tools maven-plugin-annotations - 3.4 + 3.6.0 provided @@ -87,5 +80,15 @@ + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java index d26fbace..86693f77 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java @@ -1,5 +1,6 @@ package com.appland.appmap; +import com.appland.shade.org.apache.commons.lang3.StringEscapeUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; @@ -7,142 +8,69 @@ import org.apache.maven.project.MavenProject; import java.io.File; -import java.util.Iterator; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Properties; +import java.util.stream.Collectors; import static java.lang.String.format; public abstract class AppMapAgentMojo extends AbstractMojo { - /** - * Name of the AppMap Agent artifact. - */ - static final String AGENT_ARTIFACT_NAME = "com.appland.appmap:java-agent"; - /** - * Name of the property used in maven-surefire-plugin. - */ + + static final String APPMAP_AGENT_ARTIFACT_NAME = "com.appland.appmap:java-agent"; static final String SUREFIRE_ARG_LINE = "argLine"; - /** - * Name of the property used in maven-osgi-test-plugin. - */ - static final String TYCHO_ARG_LINE = "tycho.testArgLine"; - /** - * Directory where reports will be generated. @default /tmp - * - * @parameter expression="${project.outputDirectory}" - */ - protected File outputDirectory; - /** - * Configuration file for the java agent @default /appmap.yml. - * - * @parameter expression="${project.configFile}" - */ - protected File configFile; - /** - * Java Agent Debug Option. - * - * @parameter expression="${project.debug} - */ - protected String debug = "disabled"; - /** - * Java Agent Event Description Size. - * - * @parameter expression="${project.eventValueSize} - */ - protected Integer eventValueSize = 1024; - /** - * Maven project. - * - * @parameter expression="${project} - */ - protected MavenProject project; - /** - * Flag used to suppress execution. - * - * @parameter expression="${project.skip} - */ - protected boolean skip; - /** - * Allows to specify property which will contains settings for AppMap Agent. - * If not specified, then "argLine" would be used for "jar" packaging and - * "tycho.testArgLine" for "eclipse-test-plugin". - */ - @Parameter(property = "appmap.propertyName") - String propertyName; - - /** - * Map of plugin artifacts. - * - * @parameter expression="${plugin.artifactMap} - */ - Map pluginArtifactMap; - public abstract void execute() throws MojoExecutionException; + @Parameter(property = "skip") + protected boolean skip = false; - protected void skipMojo() { } + @Parameter(property = "project.outputDirectory") + protected File outputDirectory = new File("tmp"); - /** - * @return Maven project - */ - protected final MavenProject getProject() { - return project; - } + @Parameter(property = "project.configFile") + protected File configFile = new File("appmap.yml"); - String getEffectivePropertyName() { - if (isPropertyNameSpecified()) { - return propertyName; - } - if (isEclipseTestPluginPackaging()) { - return TYCHO_ARG_LINE; - } - return SUREFIRE_ARG_LINE; - } + @Parameter(property = "project.debug") + protected String debug = "disabled"; - protected boolean isPropertyNameSpecified() { - return propertyName != null && !"".equals(propertyName); - } + @Parameter(property = "project.eventValueSize") + protected Integer eventValueSize = 1024; + + @Parameter(property = "project") + protected MavenProject project; + + @Parameter(property = "plugin.artifactMap") + protected Map pluginArtifactMap; - protected boolean isEclipseTestPluginPackaging() { - return "eclipse-test-plugin".equals(getProject().getPackaging()); + public abstract void execute() throws MojoExecutionException; + + protected void skipMojo() { } - protected String prependVMArguments(final String arguments, - final File agentJarFile) { - final List args = CommandLineSupport.split(arguments); - final String plainAgent = format("-javaagent:%s", agentJarFile); - for (final Iterator i = args.iterator(); i.hasNext(); ) { - if (i.next().startsWith(plainAgent)) { - i.remove(); - } - } - args.add(0, getVMArgument(agentJarFile)); - return CommandLineSupport.quote(args); + protected void loadAppMapJavaAgent() { + final String newValue = buildArguments(); + setProjectArgLineProperty(newValue); + getLog().info(SUREFIRE_ARG_LINE + + " set to " + StringEscapeUtils.unescapeJava(newValue)); } - /** - * Generate required JVM argument based on current configuration and - * supplied agent jar location. - * - * @param agentJarFile location of the AppMap Agent Jar - * @return Argument to pass to create new VM with App Mapping enabled - */ - protected String getVMArgument(final File agentJarFile) { - return format("-javaagent:%s=%s", agentJarFile, this); + private String buildArguments() { + List args = new ArrayList(); + args.add(StringEscapeUtils.escapeJava( + format("-javaagent:%s=%s", getAppMapAgentJar(), this) + )); + args.add("-Dappmap.debug=" + StringEscapeUtils.escapeJava(debug)); + args.add("-Dappmap.output.directory=" + StringEscapeUtils.escapeJava( format("%s",outputDirectory))); + args.add("-Dappmap.config.file=" + StringEscapeUtils.escapeJava( format("%s",configFile))); + args.add("-Dappmap.event.valueSize=" + eventValueSize); + return args.stream().collect(Collectors.joining(" ")).toString(); } - protected void loadAppMapJavaAgent() { - final String name = getEffectivePropertyName(); - final Properties projectProperties = getProject().getProperties(); - final String oldValue = projectProperties.getProperty(name); - final String newValue = prependVMArguments(oldValue, getAgentJarFile()); - getLog().info(name + " set to " + newValue); - projectProperties.setProperty(name, newValue); + private Object setProjectArgLineProperty(String newValue) { + return project.getProperties().setProperty(SUREFIRE_ARG_LINE, newValue); } - protected File getAgentJarFile() { - final Artifact appmapAgentArtifact = pluginArtifactMap.get(AGENT_ARTIFACT_NAME); - return appmapAgentArtifact.getFile(); + protected File getAppMapAgentJar() { + return pluginArtifactMap.get(APPMAP_AGENT_ARTIFACT_NAME).getFile(); } } diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java deleted file mode 100644 index 05ba4296..00000000 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/CommandLineSupport.java +++ /dev/null @@ -1,141 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors - * This program and the accompanying materials are made available under - * the terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Marc R. Hoffmann - initial API and implementation - * - *******************************************************************************/ -package com.appland.appmap; - -import java.util.ArrayList; -import java.util.List; - -/** - * Internal utility to parse and create command lines arguments. - */ -final class CommandLineSupport { - - private static final char BLANK = ' '; - private static final char QUOTE = '"'; - private static final char SLASH = '\\'; - - /** - * Quotes a single command line argument if necessary. - * - * @param arg - * command line argument - * @return quoted argument - */ - static String quote(final String arg) { - final StringBuilder escaped = new StringBuilder(); - for (final char c : arg.toCharArray()) { - if (c == QUOTE || c == SLASH) { - escaped.append(SLASH); - } - escaped.append(c); - } - if (arg.indexOf(BLANK) != -1 || arg.indexOf(QUOTE) != -1) { - escaped.insert(0, QUOTE).append(QUOTE); - } - return escaped.toString(); - } - - /** - * Builds a single command line string from the given argument list. - * Arguments are quoted when necessary. - * - * @param args - * command line arguments - * @return combined command line - */ - static String quote(final List args) { - final StringBuilder result = new StringBuilder(); - boolean separate = false; - for (final String arg : args) { - if (separate) { - result.append(BLANK); - } - result.append(quote(arg)); - separate = true; - } - return result.toString(); - } - - /** - * Splits a command line into single arguments and removes quotes if - * present. - * - * @param commandline - * combined command line - * @return list of arguments - */ - static List split(final String commandline) { - if (commandline == null || commandline.length() == 0) { - return new ArrayList(); - } - final List args = new ArrayList(); - final StringBuilder current = new StringBuilder(); - int mode = M_STRIP_WHITESPACE; - int endChar = BLANK; - for (final char c : commandline.toCharArray()) { - switch (mode) { - case M_STRIP_WHITESPACE: - if (!Character.isWhitespace(c)) { - if (c == QUOTE) { - endChar = QUOTE; - } else { - current.append(c); - endChar = BLANK; - } - mode = M_PARSE_ARGUMENT; - } - break; - case M_PARSE_ARGUMENT: - if (c == endChar) { - addArgument(args, current); - mode = M_STRIP_WHITESPACE; - } else if (c == SLASH) { - current.append(SLASH); - mode = M_ESCAPED; - } else { - current.append(c); - } - break; - case M_ESCAPED: - if (c == QUOTE || c == SLASH) { - current.setCharAt(current.length() - 1, c); - } else if (c == endChar) { - addArgument(args, current); - mode = M_STRIP_WHITESPACE; - } else { - current.append(c); - } - mode = M_PARSE_ARGUMENT; - break; - } - } - addArgument(args, current); - return args; - } - - private static void addArgument(final List args, - final StringBuilder current) { - if (current.length() > 0) { - args.add(current.toString()); - current.setLength(0); - } - } - - private static final int M_STRIP_WHITESPACE = 0; - private static final int M_PARSE_ARGUMENT = 1; - private static final int M_ESCAPED = 2; - - private CommandLineSupport() { - // no instances - } -} diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index ba01e81a..d291f834 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -1,47 +1,27 @@ package com.appland.appmap; -/* - * Copyright 2001-2005 The Apache Software Foundation. - * - * Licensed 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. - */ -import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; - -import java.io.File; -import java.util.Map; -import java.util.Properties; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; /** - * Goal which adds appmap.jar to JVM execution as javaagent, right before the test execution begins. - * - * @goal prepare-agent - * @phase test-compile + * Goal that adds appmap.jar to JVM execution as javaagent, + * right before the test execution begins. */ +@Mojo(name = "prepare-agent", defaultPhase = LifecyclePhase.TEST_COMPILE) public class LoadJavaAppMapAgentMojo extends AppMapAgentMojo { @Override public void execute() throws MojoExecutionException { - getLog().info("Initializing AppLand AppMap Java Recorder >" + project + "< " + skip + " " + outputDirectory + " " + configFile + " " + debug + " " + eventValueSize); try { if (skip) { - getLog().info( - "Skipping AppMap execution because property skip is set."); + getLog().info("Skipping AppLan AppMap execution because property skip is set."); skipMojo(); return; } else { + getLog().info("Initializing AppLand AppMap Java Recorder." ); loadAppMapJavaAgent(); } } catch (Exception e) { @@ -49,5 +29,4 @@ public void execute() e.printStackTrace(); } } - } From d93311bb6081379ec0d2d3273df15541fec76a38 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Sun, 14 Feb 2021 12:19:22 -0500 Subject: [PATCH 10/13] Added README.md file. Fixed issue with preexistent command line. Minor Refactor. --- appmap-java-maven-plugin/README.md | 67 +++++++++++++++++++ appmap-java-maven-plugin/pom.xml | 6 -- .../com/appland/appmap/AppMapAgentMojo.java | 48 ++++++++++--- .../appmap/LoadJavaAppMapAgentMojo.java | 2 +- 4 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 appmap-java-maven-plugin/README.md diff --git a/appmap-java-maven-plugin/README.md b/appmap-java-maven-plugin/README.md new file mode 100644 index 00000000..6c3a44f3 --- /dev/null +++ b/appmap-java-maven-plugin/README.md @@ -0,0 +1,67 @@ +AppLand AppMap Maven Plugin for Java +-------------------------------- + + +- [Building](#building) +- [Agent Configuration](#agent-configuration) +- [Maven Plugin Configuration](#maven-plugin-config) + - [Plugin Goals](#plugin-goals) + - [Plugin configuration options](#plugin-configuration) + - [Example](#example) + + +# Building +Artifacts will be written to `target/` use `appmap-java-plugin-[VERSION].jar`. as your maven plugin. +```bash +$ mvn clean install +``` + +# Agent Configuration +When you run your program, the agent reads configuration settings from `appmap.yml` by default. + +Please read configuration options from [AppMap Java Agent README.md](../README.md) + +# Maven Plugin Configuration + +## Plugin goals +prepare-agent : adds appmap.jar to JVM execution as javaagent + +## Plugin configuration options +outputD.directory (default: ./target/appmap/) +configF.file (default: ./appmap.yml) +debug (enabled|disabled, default: disabled) +eventV.valueSize (integer, default 1024) +skip(Boolean, default false) + +## Example plugin config in a standard POM.xml file +```xml + + + org.appland + appmap-java-maven-plugin + ${appmap-java.version} + + + appmap.yml + enabled + 1024 + false + + + + + prepare-agent + + + + +``` + + +# Running +To run the java agent with correct plugin configuration you only need to build your project as usual without skipping +the test goal. + +```bash +$ mvn clean install +``` diff --git a/appmap-java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml index e9b1063a..f506860e 100644 --- a/appmap-java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -57,12 +57,6 @@ 4.13.1 test - - org.apache.commons - commons-lang3 - 3.10 - test - diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java index 86693f77..5908e829 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java @@ -8,9 +8,7 @@ import org.apache.maven.project.MavenProject; import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import static java.lang.String.format; @@ -35,12 +33,12 @@ public abstract class AppMapAgentMojo extends AbstractMojo { @Parameter(property = "project.eventValueSize") protected Integer eventValueSize = 1024; - @Parameter(property = "project") - protected MavenProject project; - @Parameter(property = "plugin.artifactMap") protected Map pluginArtifactMap; + @Parameter(property = "project") + private MavenProject project; + public abstract void execute() throws MojoExecutionException; protected void skipMojo() { @@ -53,16 +51,40 @@ protected void loadAppMapJavaAgent() { + " set to " + StringEscapeUtils.unescapeJava(newValue)); } + /** + * This method builds the needed parameter to run the Agent, if previous configuration is found is also attached in + * the SUREFIRE_ARG_LINE, if previous version of the AppMap agent is found is removed and replaced with the version + * of this maven plugin + * + * @return formatted and escaped arguments to run on command line + */ private String buildArguments() { + final String oldConfig = getCurrentArgLinePropertyValue(); + final List oldArgs = Arrays.asList(oldConfig.split(" ")); + removeOldAppMapAgentFromCommandLine(oldArgs); List args = new ArrayList(); + addMvnAppMapCommandLineArgs(args); + args.addAll(oldArgs); + return args.stream().collect(Collectors.joining(" ")); + } + + private void removeOldAppMapAgentFromCommandLine(List oldArgs) { + final String plainAgent = format("-javaagent:%s", getAppMapAgentJar()); + for (final Iterator i = oldArgs.iterator(); i.hasNext(); ) { + if (i.next().startsWith(plainAgent)) { + i.remove(); + } + } + } + + private void addMvnAppMapCommandLineArgs(List args) { args.add(StringEscapeUtils.escapeJava( format("-javaagent:%s=%s", getAppMapAgentJar(), this) )); args.add("-Dappmap.debug=" + StringEscapeUtils.escapeJava(debug)); - args.add("-Dappmap.output.directory=" + StringEscapeUtils.escapeJava( format("%s",outputDirectory))); - args.add("-Dappmap.config.file=" + StringEscapeUtils.escapeJava( format("%s",configFile))); + args.add("-Dappmap.output.directory=" + StringEscapeUtils.escapeJava(format("%s", outputDirectory))); + args.add("-Dappmap.config.file=" + StringEscapeUtils.escapeJava(format("%s", configFile))); args.add("-Dappmap.event.valueSize=" + eventValueSize); - return args.stream().collect(Collectors.joining(" ")).toString(); } @@ -70,7 +92,15 @@ private Object setProjectArgLineProperty(String newValue) { return project.getProperties().setProperty(SUREFIRE_ARG_LINE, newValue); } + private String getCurrentArgLinePropertyValue() { + return project.getProperties().getProperty(SUREFIRE_ARG_LINE); + } + protected File getAppMapAgentJar() { return pluginArtifactMap.get(APPMAP_AGENT_ARTIFACT_NAME).getFile(); } + + public MavenProject getProject() { + return project; + } } diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java index d291f834..2a6e8728 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java @@ -17,7 +17,7 @@ public void execute() throws MojoExecutionException { try { if (skip) { - getLog().info("Skipping AppLan AppMap execution because property skip is set."); + getLog().info("Skipping AppLand AppMap execution because property skip is set."); skipMojo(); return; } else { From aded373c631c296004f4de0fa7b33ebff706385d Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Wed, 24 Feb 2021 22:27:23 -0500 Subject: [PATCH 11/13] Changes as requested in code review. drop the java identifier since it is a maven plugin. --- appmap-java-maven-plugin/README.md | 6 +-- appmap-java-maven-plugin/pom.xml | 8 ++-- .../com/appland/appmap/AppMapAgentMojo.java | 38 +++++++++++++------ 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/appmap-java-maven-plugin/README.md b/appmap-java-maven-plugin/README.md index 6c3a44f3..9d2c9adf 100644 --- a/appmap-java-maven-plugin/README.md +++ b/appmap-java-maven-plugin/README.md @@ -27,10 +27,10 @@ Please read configuration options from [AppMap Java Agent README.md](../README.m prepare-agent : adds appmap.jar to JVM execution as javaagent ## Plugin configuration options -outputD.directory (default: ./target/appmap/) -configF.file (default: ./appmap.yml) +outputDirectory (default: ./target/appmap/) +configFile (default: ./appmap.yml) debug (enabled|disabled, default: disabled) -eventV.valueSize (integer, default 1024) +eventValueSize (integer, default 1024) skip(Boolean, default false) ## Example plugin config in a standard POM.xml file diff --git a/appmap-java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml index f506860e..d9ea210d 100644 --- a/appmap-java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -1,8 +1,8 @@ 4.0.0 - org.appland - appmap-java-maven-plugin + com.appland + appmap-maven-plugin maven-plugin 0.5.0-SNAPSHOT Appland Java Recorder Maven Plugin @@ -11,11 +11,9 @@ - com.appland.appmap + com.appland java-agent 0.5.0 - system - C:/Users/msanchez3/.m2/repository/com/appland/appmap/java-agent/0.5.0/java-agent-0.5.0.jar diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java index 5908e829..979f1630 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java @@ -15,7 +15,7 @@ public abstract class AppMapAgentMojo extends AbstractMojo { - static final String APPMAP_AGENT_ARTIFACT_NAME = "com.appland.appmap:java-agent"; + static final String APPMAP_AGENT_ARTIFACT_NAME = "com.appland:appmap-agent"; static final String SUREFIRE_ARG_LINE = "argLine"; @Parameter(property = "skip") @@ -59,32 +59,46 @@ protected void loadAppMapJavaAgent() { * @return formatted and escaped arguments to run on command line */ private String buildArguments() { - final String oldConfig = getCurrentArgLinePropertyValue(); - final List oldArgs = Arrays.asList(oldConfig.split(" ")); - removeOldAppMapAgentFromCommandLine(oldArgs); List args = new ArrayList(); - addMvnAppMapCommandLineArgs(args); - args.addAll(oldArgs); + final String oldConfig = getCurrentArgLinePropertyValue(); + if (oldConfig != null) { + final List oldArgs = Arrays.asList(oldConfig.split(" ")); + removeOldAppMapAgentFromCommandLine(oldArgs); + args.addAll(oldArgs); + } + addMvnAppMapCommandLineArgsFirst(args); return args.stream().collect(Collectors.joining(" ")); } + /** + * Generate required quotes JVM argument based on current configuration and + * prepends it to the given argument command line. If a agent with the same + * JAR file is already specified this parameter is removed from the existing + * command line, does the same for xbootclasspath command. + */ private void removeOldAppMapAgentFromCommandLine(List oldArgs) { final String plainAgent = format("-javaagent:%s", getAppMapAgentJar()); + final String xbootClasspath = format("-Xbootclasspath/a:%s", getAppMapAgentJar()); for (final Iterator i = oldArgs.iterator(); i.hasNext(); ) { - if (i.next().startsWith(plainAgent)) { + final String oldCommand = i.next(); + if (oldCommand.startsWith(plainAgent) || oldCommand.startsWith(xbootClasspath)) { i.remove(); } } } - private void addMvnAppMapCommandLineArgs(List args) { + private void addMvnAppMapCommandLineArgsFirst(List args) { + args.add(StringEscapeUtils.escapeJava( + format("-Xbootclasspath/a:%s", getAppMapAgentJar(), this) + )); args.add(StringEscapeUtils.escapeJava( format("-javaagent:%s=%s", getAppMapAgentJar(), this) )); - args.add("-Dappmap.debug=" + StringEscapeUtils.escapeJava(debug)); - args.add("-Dappmap.output.directory=" + StringEscapeUtils.escapeJava(format("%s", outputDirectory))); - args.add("-Dappmap.config.file=" + StringEscapeUtils.escapeJava(format("%s", configFile))); - args.add("-Dappmap.event.valueSize=" + eventValueSize); + + args.add(0, "-Dappmap.debug=" + StringEscapeUtils.escapeJava(debug)); + args.add(0, "-Dappmap.output.directory=" + StringEscapeUtils.escapeJava(format("%s", outputDirectory))); + args.add(0, "-Dappmap.config.file=" + StringEscapeUtils.escapeJava(format("%s", configFile))); + args.add(0, "-Dappmap.event.valueSize=" + eventValueSize); } From 1581894f86229676cf3949655f8b34194cabc085 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Wed, 24 Feb 2021 22:44:00 -0500 Subject: [PATCH 12/13] changed as requested during code review PR --- appmap-java-maven-plugin/README.md | 4 ++-- appmap-java-maven-plugin/pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/appmap-java-maven-plugin/README.md b/appmap-java-maven-plugin/README.md index 9d2c9adf..b9f3b8b6 100644 --- a/appmap-java-maven-plugin/README.md +++ b/appmap-java-maven-plugin/README.md @@ -37,8 +37,8 @@ skip(Boolean, default false) ```xml - org.appland - appmap-java-maven-plugin + com.appland + appmap-maven-plugin ${appmap-java.version} diff --git a/appmap-java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml index d9ea210d..92421c76 100644 --- a/appmap-java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -12,7 +12,7 @@ com.appland - java-agent + appmap-agent 0.5.0 From 33849a8322e419ff29cca8c8b1ee477628fd0ea6 Mon Sep 17 00:00:00 2001 From: Marcus Sanchez Date: Thu, 25 Feb 2021 11:06:06 -0500 Subject: [PATCH 13/13] Fixed build issue. removed java 8 dependencies, now the project can be compiled with java 1.7 --- appmap-java-maven-plugin/pom.xml | 66 +++++++------------ .../com/appland/appmap/AppMapAgentMojo.java | 9 ++- 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/appmap-java-maven-plugin/pom.xml b/appmap-java-maven-plugin/pom.xml index 92421c76..751e5921 100644 --- a/appmap-java-maven-plugin/pom.xml +++ b/appmap-java-maven-plugin/pom.xml @@ -6,9 +6,15 @@ maven-plugin 0.5.0-SNAPSHOT Appland Java Recorder Maven Plugin - This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. + This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. + https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin + + UTF-8 + UTF-8 + + com.appland @@ -19,34 +25,17 @@ org.apache.maven maven-plugin-api - 3.3.9 - - - org.apache.maven - maven-core - 3.3.9 - - - org.codehaus.plexus - plexus-utils - 3.3.0 - - - org.apache.maven.shared - file-management - 3.0.0 - - - org.apache.maven.reporting - maven-reporting-api - 3.0 + 3.6.1 org.apache.maven.plugin-tools maven-plugin-annotations 3.6.0 - - provided + + + org.apache.maven + maven-core + 3.5.4 @@ -58,28 +47,23 @@ - - - - org.apache.maven.plugins - maven-site-plugin - 3.7.1 - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 3.0.0 - - - org.apache.maven.plugins - maven-compiler-plugin + maven-plugin-plugin + 3.6.0 - 8 - 8 + + true + + + mojo-descriptor + + descriptor + + + diff --git a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java index 979f1630..dfeeeb30 100644 --- a/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java +++ b/appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java @@ -1,6 +1,6 @@ package com.appland.appmap; -import com.appland.shade.org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringEscapeUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; @@ -9,7 +9,6 @@ import java.io.File; import java.util.*; -import java.util.stream.Collectors; import static java.lang.String.format; @@ -67,7 +66,11 @@ private String buildArguments() { args.addAll(oldArgs); } addMvnAppMapCommandLineArgsFirst(args); - return args.stream().collect(Collectors.joining(" ")); + StringBuilder builder = new StringBuilder(); + for ( String arg : args) { + builder.append(arg).append(" "); + } + return builder.toString(); } /**