/* * Copyright 2015-2016 Alexander Mackworth * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.deployment.eggs; import java.io.File; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collections; import java.util.jar.Attributes; import java.util.jar.Manifest; import ccre.deployment.Artifact; import ccre.deployment.Jar; import ccre.log.Logger; /** * The main class invoked inside a CCRE Egg to deploy the Egg. * * @author amackworth */ public class EggHatcher { private final static String banner = " .-~-.\n" + " .' '.\n" + " / \\\n" + " .-~-. : ;\n" + " .' '.| |\n" + " / \\ :\n" + " : ; .-~\"\"~-,/ hatching egg...\n" + " | /` `'.\n" + " : | \\\n" + " \\ | /\n" + " `. .' \\ .'\n" + " jgs `~~~` '-.____.-'\n\n"; /** * Deploys the egg contained by the current Jar, following the deployment * action that was specified when the egg was created. * * @param args the program arguments, which are ignored. * @throws Exception if the egg cannot be hatched. */ public static void main(String[] args) throws Exception { System.out.println(banner); InputStream jarStream = EggHatcher.class.getResourceAsStream("/" + DepEgg.userCodeJarName); File tempFile = File.createTempFile("hatched-egg-", ".jar"); Files.copy(jarStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING); try (Artifact userCode = new Jar(tempFile)) { // Thanks to some OS X/Java weirdness, we have to make sure we're // loading the manifest out of this bundle. We do this by counting // the number of manifest resources in the parent, and indexing past // it. // FIXME: this is hacky af ClassLoader parent = EggHatcher.class.getClassLoader().getParent(); int parentEntries; if (parent != null) { parentEntries = Collections.list(parent.getResources("META-INF/MANIFEST.MF")).size(); } else { parentEntries = Collections.list(ClassLoader.getSystemResources("META-INF/MANIFEST.MF")).size(); } ArrayList<URL> manifests = Collections.list(EggHatcher.class.getClassLoader().getResources("META-INF/MANIFEST.MF")); Manifest manifest = new Manifest(manifests.get(parentEntries).openStream()); Attributes attrs = manifest.getMainAttributes(); String className = attrs.getValue("Hatch-Action"); if (className == null) { Logger.severe("Hatch action not found in manifest!"); return; } try (URLClassLoader classLoader = new URLClassLoader(new URL[] { tempFile.toURI().toURL() })) { Class<?> deploymentClass = classLoader.loadClass(className); Constructor<?> construct = deploymentClass.getDeclaredConstructor(); construct.setAccessible(true); Method deployMethod = deploymentClass.getMethod("deployArtifact", Artifact.class); deployMethod.setAccessible(true); deployMethod.invoke(construct.newInstance(), userCode); } } } }