package edu.columbia.cs.psl.phosphor.plugin; import edu.columbia.cs.psl.phosphor.driver.DeletingFileVisitor; import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil; import edu.columbia.cs.psl.phosphor.driver.Instrumentation; import edu.columbia.cs.psl.phosphor.driver.Instrumenter; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import java.io.*; import java.nio.file.Files; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Properties; /** * Creates an instrumented Java installation (i.e., Java Development Kit or Java Runtime Environment). *
* If {@link InstrumentMojo#outputDirectory} does not exists, a new instrumented Java installation is created. * If {@link InstrumentMojo#outputDirectory} exists and is not a Java installation previously created by * this plugin, this plugin will throw a {@link MojoExecutionException}. * If {@link InstrumentMojo#outputDirectory} exists and is a Java installation previously created by this plugin, * this plugin checks whether the Java installation needs to be recreated. * If the {@link InstrumentMojo#forceCreation} is {@code false} and the existing Java installation was created from * the same {@link InstrumentMojo#javaHome uninstrumented Java installation} using the same * {@link InstrumentMojo#instrumentationType} and {@link InstrumentMojo#options}, then the Java installation does * not need to be recreated and the plugin terminates. * Otherwise, this plugin will delete the existing Java installation and any * {@link InstrumentMojo#linkedCaches linked files or directories}. * Then, this plugin will create a new instrumented Java installation. *
* The instrumented Java installation is created by instrumenting the Java installation located in the directory
* {@link InstrumentMojo#javaHome} or the Java installation used to run the Maven process if
* {@link InstrumentMojo#javaHome} was not specified.
* An instance of the specified {@link InstrumentMojo#instrumentationType instrumentation class} is created and
* configured using the specified {@link InstrumentMojo#options}.
* This instance determines the type of instrumentation applied.
*
* @see Instrumentation
*/
@Mojo(name = "instrument", defaultPhase = LifecyclePhase.PROCESS_TEST_RESOURCES)
public class InstrumentMojo extends AbstractMojo {
/**
* Directory where the Java installation to be instrumented is located.
* If not specified, then the Java installation used to run the Maven process will be used.
*/
@Parameter(property = "phosphor.javaHome")
private File javaHome = new File(System.getProperty("java.home"));
/**
* Directory to which the instrumented Java installation should be written.
*/
@Parameter(property = "phosphor.outputDirectory", defaultValue = "${project.build.directory}/phosphor/java/")
private File outputDirectory;
/**
* List of directories and files that should be deleted if an existing instrumented Java installation is deleted.
* These can be used to specify caches of dynamically instrumented classes.
*/
@Parameter(property = "phosphor.linkedCaches")
private List
* Non-null.
*/
private final File optionsFile;
/**
* File used to store the checksum for the class path of the instrumentation used to instrument a
* location.
*
* Non-null.
*/
private final File checksumFile;
/**
* File used to store the path of the source location instrumented and the fully qualified name of the
* implementation of {@link Instrumentation} used to instrument a location.
*/
private final File infoFile;
public MatchInfo(File directory) {
File parent = new File(directory, "phosphor-instrument-match");
this.optionsFile = new File(parent, "options.properties");
this.checksumFile = new File(parent, "class-path.md5");
this.infoFile = new File(parent, "info.txt");
}
public boolean exists() {
return optionsFile.isFile() && checksumFile.isFile() && infoFile.isFile();
}
private boolean check(byte[] checksum, String info, Properties options) throws MojoExecutionException {
try (FileReader reader = new FileReader(optionsFile)) {
Properties foundOptions = new Properties();
foundOptions.load(reader);
return foundOptions.equals(options)
&& Arrays.equals(checksum, InstrumentUtil.readAllBytes(checksumFile))
&& new String(InstrumentUtil.readAllBytes(infoFile)).equals(info);
} catch (IOException e) {
throw new MojoExecutionException("Failed to read match info", e);
}
}
public void write(byte[] checksum, String info, Properties options) throws MojoExecutionException {
try {
InstrumentUtil.ensureDirectory(optionsFile.getParentFile());
Files.write(checksumFile.toPath(), checksum);
Files.write(infoFile.toPath(), info.getBytes());
try (FileWriter writer = new FileWriter(optionsFile)) {
options.store(writer, null);
}
} catch (IOException e) {
throw new MojoExecutionException("Failed to write match info", e);
}
}
}
}