/** * Copyright 2007-2008 University Of Southern California * * 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. */ package edu.isi.pegasus.planner.client; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.text.DecimalFormat; import java.text.NumberFormat; import edu.isi.pegasus.common.logging.LogManager; import edu.isi.pegasus.common.logging.LogManagerFactory; import edu.isi.pegasus.common.util.FactoryException; import edu.isi.pegasus.common.util.Version; import edu.isi.pegasus.planner.common.PegasusProperties; import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.util.MissingResourceException; /** * The interface which defines all the methods , any executable should implement. * * @author GAURANG MEHTA * @author KARAN VAHI * @version $Revision$ * */ public abstract class Executable { /** * The default properties file to be picked up for the conf option. */ public static String DEFAULT_PROPERTIES_FILE = "pegasus.properties"; /** * The LogManager object which is used to log all the messages. * */ protected LogManager mLogger ; /** * The object holding all the properties pertaining to Pegasus. */ protected PegasusProperties mProps; /** * It stores the verison of the Griphyn Virtual Data System software. */ protected String mVersion; /** * The error message to be logged. */ protected String mLogMsg; /** * The command line options passed to the executable */ private String[] commandLineOpts; /** * The default constructor. */ public Executable(){ this( null ); } /** * The constructor which ends up initialising the PegasusProperties object. * * @param logger the logger to use. Can be null. */ public Executable( LogManager logger ) { mLogger = logger; } /** * Looks up for the conf property in the arguments passed to the executable * @param opts command line arguments passed to the executable * @param confChar the short option corresponding to the conf property * @return */ protected String lookupConfProperty(String[] opts , char confChar){ LongOpt[] longOptions = new LongOpt[1 ]; longOptions[ 0 ] = new LongOpt( "conf", LongOpt.REQUIRED_ARGUMENT, null,confChar ); Getopt g = new Getopt("Executable", opts, confChar+":", longOptions, false); g.setOpterr(false); String propertyFilePath = null; int option = 0; while ( ( option = g.getopt() ) != -1 ) { if(option == confChar){ propertyFilePath = g.getOptarg(); break; } } if( propertyFilePath == null ){ //PM-1018 if no --conf provided fall back to pegasus.properties //in the current working directory from where command is called propertyFilePath = "." + File.separatorChar + Executable.DEFAULT_PROPERTIES_FILE; } return propertyFilePath; } /** * Initialize the executable object * @param opts the command line argument passed by the user * @param confChar the short option corresponding the conf property. */ protected void initialize(String[] opts , char confChar){ this.commandLineOpts = opts; String propertyFile =lookupConfProperty(getCommandLineOptions(), confChar); mProps = PegasusProperties.getInstance(propertyFile); mVersion = Version.instance().toString(); //setup logging before doing anything with properties try{ setupLogging( mLogger , mProps ); }catch(IOException ioe){ throw new RuntimeException("Unable to initialize the logger " , ioe); } mLogMsg = new String(); sanityCheckOnProperties( ); loadProperties(); } /** * Initialize the executable object * @param opts the command line argument passed to the executable */ protected void initialize(String[] opts) { initialize(opts, 'c'); } /** * Returns an error message that chains all the lower order error messages * that might have been thrown. * * @param e the Exception for which the error message has to be composed. * * @return the error message. */ public static String convertException( Exception e ){ return Executable.convertException( e, LogManager.TRACE_MESSAGE_LEVEL ); } /** * Returns an error message that chains all the lower order error messages * that might have been thrown. * * @param e the Exception for which the error message has to be composed. * @param logLevel the user specified level for the logger * * @return the error message. */ public static String convertException( Exception e , int logLevel ){ StringBuffer message = new StringBuffer(); int i = 0; //check if we want to throw the whole stack trace if( logLevel >= LogManager.INFO_MESSAGE_LEVEL ){ //we want the stack trace to a String Writer. StringWriter sw = new StringWriter(); e.printStackTrace( new PrintWriter( sw ) ); return sw.toString(); } //append all the causes for(Throwable cause = e; cause != null ; cause = cause.getCause()){ if( cause instanceof FactoryException ){ //do the specialized convert for Factory Exceptions message.append(((FactoryException)cause).convertException(i)); break; } message.append("\n [").append( Integer.toString(++i)).append("] "). append(cause.getClass().getName()).append(": "). append(cause.getMessage()); //append just one elment of stack trace for each exception message.append( " at " ).append( cause.getStackTrace()[0] ); } return message.toString(); } /** * Sets up the logging options for this class. Looking at the properties * file, sets up the appropriate writers for output and stderr. * * @param logger the logger to use. Can be null. * @param properties reference of pegasus properties object. */ protected void setupLogging( LogManager logger , PegasusProperties properties ) throws IOException{ if( logger != null ){ mLogger = logger; return; } //setup the logger for the default streams. mLogger = LogManagerFactory.loadSingletonInstance( properties ); mLogger.logEventStart( "event.pegasus.planner", "planner.version", mVersion ); //get the logging value set in properties String value = properties.getProperty("pegasus.log.*"); //use defaults if nothing is set. if( value == null){ mLogger.log("Logging to default streams", LogManager.DEBUG_MESSAGE_LEVEL); return; } else{ //take a backup of the log if required. File f = new File( value ); File dir = f.getParentFile(); String basename = f.getName(); NumberFormat formatter = new DecimalFormat( "000" ); File backupFile = null; //start from 000 onwards and check for existence for( int i = 0; i < 999 ; i++ ){ StringBuffer backup = new StringBuffer(); backup.append( basename ).append( "." ).append( formatter.format(i) ); //check if backup file exists. backupFile = new File( dir, backup.toString() ); if( !backupFile.exists() ){ break; } } //log both output and error messages to value specified mLogger.setWriters(backupFile.getAbsolutePath ()); } } /** * Loads all the properties that would be needed by the Toolkit classes. */ public abstract void loadProperties(); /** * This method is used to print the long version of the command. */ public abstract void printLongVersion(); /** * This is used to print the short version of the command. */ public abstract void printShortVersion(); /** * This function is passed command line arguments. In this function you * generate the valid options and parse the options specified at run time. */ //public abstract void executeCommand(String[] args); /** * Generates an array of valid <code>LongOpt</code> objects which contain * all the valid options to the Executable. */ public abstract LongOpt[] generateValidOptions(); /** * Returns the version of the Griphyn Virtual Data System. */ public String getGVDSVersion() { StringBuffer sb = new StringBuffer(); sb.append( "Pegasus Release Version " ).append(mVersion); return sb.toString(); } /** * Logs messages to the singleton logger. * * @param msg is the message itself. * @param level is the level to generate the log message for. */ public void log( String msg, int level ){ mLogger.log( msg, level ); } /** * Get the value of the environment variable. * * @param envVariable the environment variable whose value you want. * * @return String corresponding to the value of the environment * variable if it is set. * null if the environment variable is not set */ public String getEnvValue(String envVariable) { String value = null; value = System.getProperty(envVariable); return value; } /** * Returns the command line arguments passed to the executable * @return command line arguments passed to the executable */ protected String[] getCommandLineOptions(){ String[] optsClone = new String[commandLineOpts.length]; for(int i =0; i< commandLineOpts.length;i++){ optsClone[i] = commandLineOpts[i]; } return optsClone; } /** * Does a sanity check on the properties to make sure that all the * required properties are loaded. * */ protected void sanityCheckOnProperties() { // check required properties if ( mProps.getProperty( "pegasus.home.bindir" ) == null ) { throw new MissingResourceException( "The pegasus.home.bindir property was not set ", "java.util.Properties", "pegasus.home.bindir" ); } if ( mProps.getProperty( "pegasus.home.schemadir" ) == null ) { throw new MissingResourceException( "The pegasus.home.schemadir property was not set ", "java.util.Properties", "pegasus.home.schemadir" ); } if ( mProps.getProperty( "pegasus.home.sharedstatedir" ) == null ) { throw new MissingResourceException( "The pegasus.home.sharedstatedir property was not set ", "java.util.Properties", "pegasus.home.sharedstatedir" ); } if ( mProps.getProperty( "pegasus.home.sysconfdir" ) == null ) { throw new MissingResourceException( "The pegasus.home.sysconfdir property was not set ", "java.util.Properties", "pegasus.home.sysconfdir" ); } } }