// // Copyright (C) 2009 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.tool; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.Properties; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPFShell; import gov.nasa.jpf.util.JPFSiteUtils; /** * This class is a wrapper for loading JPF or a JPFShell through a classloader * that got initialized from a Config object (i.e. 'native_classpath'). * * This is the main-class entry in the executable RunJPF.jar, which does not * require any JPF specific classpath settings, provided the site.properties * is configured correctly * * NOTE this class is not allowed to use any types that would require * loading JPF classes during class resolution - this would result in * NoClassDefFoundErrors if the respective class is not in RunJPF.jar */ public class RunJPF extends Run { public static final int HELP = 0x1; public static final int SHOW = 0x2; public static final int LOG = 0x4; public static final int BUILD_INFO = 0x8; public static final int ADD_PROJECT = 0x10; public static final int VERSION = 0x20; public static final int DELAY_START = 0x40; public static final int DELAY_EXIT = 0x80; static final String JPF_CLASSNAME = "gov.nasa.jpf.JPF"; static void delay (String msg) { System.out.println(msg); try { System.in.read(); } catch (IOException iox) { // we don't care } } public static void main (String[] args) { try { int options = getOptions(args); if (args.length == 0 || isOptionEnabled(HELP, options)) { showUsage(); return; } if (isOptionEnabled(ADD_PROJECT, options)){ addProject(args); return; } if (isOptionEnabled(DELAY_START, options)) { delay("press any key to start"); } if (isOptionEnabled(LOG, options)) { Config.enableLogging(true); } Config conf = new Config(args); if (isOptionEnabled(SHOW, options)) { conf.printEntries(); } ClassLoader cl = conf.initClassLoader(RunJPF.class.getClassLoader()); if (isOptionEnabled(VERSION, options)) { showVersion(cl); } if (isOptionEnabled(BUILD_INFO, options)) { showBuild(cl); } // using JPFShell is Ok since it is just a simple non-derived interface // note this uses a <init>(Config) ctor in the shell class if there is one, i.e. there is no need for a separate // start(Config,..) or re-loading the config itself JPFShell shell = conf.getInstance("shell", JPFShell.class); if (shell != null) { shell.start( removeConfigArgs(args)); // responsible for exception handling itself } else { // we have to load JPF explicitly through the URLClassLoader, and // call its start() via reflection - interfaces would only work if // we instantiate a JPF object here, which would force us to duplicate all // the logging and event handling that preceedes JPF instantiation Class<?> jpfCls = cl.loadClass(JPF_CLASSNAME); if (!call( jpfCls, "start", new Object[] {conf,args})){ error("cannot find 'public static start(Config,String[])' in " + JPF_CLASSNAME); } } if (isOptionEnabled(DELAY_EXIT, options)) { delay("press any key to exit"); } } catch (NoClassDefFoundError ncfx){ ncfx.printStackTrace(); } catch (ClassNotFoundException cnfx){ error("cannot find " + JPF_CLASSNAME); } catch (InvocationTargetException ix){ // should already be handled by JPF ix.getCause().printStackTrace(); } } public static int getOptions (String[] args){ int mask = 0; if (args != null){ for (int i = 0; i < args.length; i++) { String a = args[i]; if ("-help".equals(a)){ args[i] = null; mask |= HELP; } else if ("-show".equals(a)) { args[i] = null; mask |= SHOW; } else if ("-log".equals(a)){ args[i] = null; mask |= LOG; } else if ("-buildinfo".equals(a)){ args[i] = null; mask |= BUILD_INFO; } else if ("-addproject".equals(a)){ args[i] = null; mask |= ADD_PROJECT; } else if ("-delay-start".equals(a)) { args[i] = null; mask |= DELAY_START; } else if ("-delay-exit".equals(a)) { args[i] = null; mask |= DELAY_EXIT; } else if ("-version".equals(a)){ args[i] = null; mask |= VERSION; } } } return mask; } public static boolean isOptionEnabled (int option, int mask){ return ((mask & option) != 0); } public static void showUsage() { System.out.println("Usage: \"java [<vm-option>..] -jar ...RunJPF.jar [<jpf-option>..] [<app> [<app-arg>..]]"); System.out.println(" <jpf-option> : -help : print usage information and exit"); System.out.println(" | -version : print JPF version information"); System.out.println(" | -buildinfo : print build and runtime information"); System.out.println(" | -addproject [init] [<pathname>] : add project to site properties and exit"); System.out.println(" | -log : print configuration initialization steps"); System.out.println(" | -show : print configuration dictionary contents"); System.out.println(" | +<key>=<value> : add or override key/value pair to config dictionary"); System.out.println(" <app> : *.jpf application properties file pathname | fully qualified application class name"); System.out.println(" <app-arg> : arguments passed into main() method of application class"); } public static void addProject(String[] args){ boolean init = false; int i=0; String sitePathName = null; // check if the first non-null arg is 'init', which means this project // should be added to the 'extensions' list for(; i<args.length; i++){ if (args[i] != null){ if ("init".equals(args[i])){ init = true; continue; } else { sitePathName = args[i]; } break; } } File siteProps = (sitePathName == null) ? JPFSiteUtils.getStandardSiteProperties() : new File(sitePathName); if (siteProps == null) { siteProps = new File(JPFSiteUtils.getGlobalSitePropertiesPath()); } File curDir = new File( System.getProperty("user.dir")); String pid = JPFSiteUtils.getCurrentProjectId(); if (pid == null){ error("current dir not a valid JPF project: " + curDir); } if ("jpf-core".equals(pid)){ // jpf-core always needs to be in the extensions list init = true; } if (JPFSiteUtils.addProject( siteProps, pid, curDir, init)){ System.out.println("added project '" + pid + "' to site properties at: " + siteProps); } else { error("failed to add project: '" + pid + "' to site properties at: " + siteProps); } } public static void showVersion (ClassLoader cl){ try { InputStream is = cl.getResourceAsStream("gov/nasa/jpf/.version"); if (is != null){ System.out.print("JPF version: "); int len = is.available(); byte[] data = new byte[len]; is.read(data); is.close(); String version = new String(data); System.out.println(version); } else { System.out.println("no JPF version information available"); } } catch (Throwable t){ System.err.println("error reading version information: " + t.getMessage()); } } // print out the build.properties settings public static void showBuild(ClassLoader cl) { try { InputStream is = cl.getResourceAsStream("gov/nasa/jpf/build.properties"); if (is != null){ System.out.println("JPF build information:"); Properties buildProperties = new Properties(); buildProperties.load(is); for (Map.Entry<Object, Object> e : buildProperties.entrySet()) { System.out.print('\t'); System.out.print(e.getKey()); System.out.print(" = "); System.out.println(e.getValue()); } is.close(); } else { System.out.println("no JPF build information available"); } } catch (Throwable t){ System.err.println("error reading build information: " + t.getMessage()); } } }