All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tahomarobotics.maven.plugin.SimulationMojo Maven / Gradle / Ivy

/**
 * Copyright 2018 Tahoma Robotics - http://tahomarobotics.org - Bear Metal 2046 FRC Team
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
 * documentation files (the "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following 
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions 
 * of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 * 
 */
package org.tahomarobotics.maven.plugin;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;

/**
 * This plugin goal simply determines the arguments for running the simulation.  The simulation
 * runs as a java agent since it will modify the loaded class prior to running the Robot.
 *
 */
@Mojo(name = "exec-simulation", requiresDependencyResolution=ResolutionScope.COMPILE_PLUS_RUNTIME)
public class SimulationMojo extends AbstractMojo {

	@Component
	private MavenProject project;
	
	@Component
	private MavenSession session;
	
	@Component
	private RepositorySystem repo;
	
	// java executable path used for running simulation
	@Parameter(defaultValue = "${java.home}\\bin\\java.exe" )
	private String jrePath;
	
	// simulation artifact used for initiating the java-agent
	@Parameter(defaultValue = "bear-simulation")
	private String simulationArtifactId;
	
	// simulation class main
	@Parameter(defaultValue = "org.tahomarobotics.sim.lib.Simulation")
	private String javaMainClass;
	
	@Parameter(defaultValue = "windowsx86-64")
	private String nativeClassifier;

	@Parameter(defaultValue = "target/natives")
	private String nativeUnpackTarget;

	@Parameter(defaultValue = "target/natives/windows/x86-64")
	private String libraryPath;
	
	@Parameter
	private String debugString;
	
	@Parameter(required=true)
	private List models;
	
	private final Set allArtifacts = new LinkedHashSet<>();
	
	private String getSimulationJarPath() {
		
		for (Artifact dependency : allArtifacts) {
			if (dependency.getArtifactId().equals(simulationArtifactId)) {
				return dependency.getFile().getAbsolutePath();
			}
		}
		
		return "not found";
	}
	
	/**
	 * Execute robot with simulation
	 */
	public void execute() throws MojoExecutionException, MojoFailureException {

		// generate class path for all dependencies
		String javaClasspath = getDependencyPath();
		
		// get the path to the simulation jar path used for the java agent argument
		// be sure to quote the path as there might be spaces in path
		String javaVMArgs = "-javaagent:\"" + getSimulationJarPath() + "\"";
		
		// create execution command line
		StringBuffer sb = new StringBuffer();
		sb.append(jrePath).append(" ");
		sb.append(javaVMArgs).append(" ");
		if (debugString != null) {
			sb.append(debugString).append(" ");
		}
		
		// be sure to quote the path as there might be spaces in path
		sb.append("-Djava.library.path=\"").append(libraryPath).append("\" ");
		
		// add simulation models to command line from plugin configuration
		sb.append("-Dsimulation.models=");
		for(String model : models) {
			sb.append(model).append(':');			
		}
		
		// be sure to quote the path as there might be spaces in path
		sb.append(" -classpath \"").append(javaClasspath).append("\" ");
		
		
		sb.append(' ').append(javaMainClass);	
		String cmd = sb.toString();
		
		// log out the command line
		getLog().info(cmd);

		ProcessBuilder builder = new ProcessBuilder().inheritIO();
		builder.command(cmd.split(" "));
		
		try {
			Process process = builder.start();
			int exitCode = process.waitFor();
			if (exitCode != 0) {
				throw new MojoExecutionException("Failed to start simulated robot with a exit code: " + exitCode);
			}
		} catch (IOException | InterruptedException e) {
			throw new MojoExecutionException("Failed to start simulated robot", e);
		}
	}
	
	/**
	 * Create class-path.  This will unpack native archive.
	 *  
	 * @return class-path
	 * @throws MojoExecutionException
	 */
	private String getDependencyPath() throws MojoExecutionException {
		
		StringBuffer sb = new StringBuffer();
		boolean first = true;
		allArtifacts.add(project.getArtifact());
		allArtifacts.addAll(project.getArtifacts());
		for (Artifact dependency : allArtifacts) {
			String classifier = dependency.getClassifier();
			File file = dependency.getFile();
			if (classifier == null) {
				if (!first) {
					sb.append(";");
				}
				first = false;
				sb.append(dependency.getFile().getAbsolutePath());
			
			} else if (classifier.equals(nativeClassifier)) {
				try {
					unpackNatives(file);
				} catch (IOException e) {
					throw new MojoExecutionException("UnpackNatives", e);
				}
			}
		}	
		return sb.toString();
	}

	// unpack any native libraries into a unpack area
	private void unpackNatives(File jarPath) throws IOException {
		
		try (JarFile jar = new JarFile(jarPath)) {

			Enumeration entries = jar.entries();
			
			while (entries.hasMoreElements()) {
			
				JarEntry file = entries.nextElement();

				File f = new File(nativeUnpackTarget, file.getName());

				getLog().info("Copying native - " + file.getName());

				f.getParentFile().mkdirs();

				if (file.isDirectory()) { // if its a directory, create it
					f.mkdir();
					continue;
				}

				try (InputStream is = jar.getInputStream(file); FileOutputStream fos = new FileOutputStream(f)) {
					IOUtils.copy(is, fos);
				}
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy