Home | History | Annotate | Download | only in emma
      1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
      2  *
      3  * This program and the accompanying materials are made available under
      4  * the terms of the Common Public License v1.0 which accompanies this distribution,
      5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
      6  *
      7  * $Id: Command.java,v 1.1.1.1.2.1 2004/07/16 23:32:03 vlad_r Exp $
      8  */
      9 package com.vladium.emma;
     10 
     11 import java.io.File;
     12 import java.io.IOException;
     13 import java.io.PrintWriter;
     14 import java.util.Properties;
     15 
     16 import com.vladium.logging.ILogLevels;
     17 import com.vladium.util.IConstants;
     18 import com.vladium.util.Property;
     19 import com.vladium.util.Strings;
     20 import com.vladium.util.XProperties;
     21 import com.vladium.util.args.IOptsParser;
     22 import com.vladium.emma.data.mergeCommand;
     23 import com.vladium.emma.instr.instrCommand;
     24 import com.vladium.emma.report.reportCommand;
     25 
     26 // ----------------------------------------------------------------------------
     27 /**
     28  * @author Vlad Roubtsov, (C) 2003
     29  */
     30 public
     31 abstract class Command
     32 {
     33     // public: ................................................................
     34 
     35 
     36     public static Command create (final String name, final String usageName, final String [] args)
     37     {
     38         final Command tool;
     39 
     40         // TODO: dynamic load here?
     41 
     42         if ("run".equals (name))
     43             tool = new runCommand (usageName, args);
     44         else if ("instr".equals (name))
     45             tool = new instrCommand (usageName, args);
     46         else if ("report".equals (name))
     47             tool = new reportCommand (usageName, args);
     48         else if ("merge".equals (name))
     49             tool = new mergeCommand (usageName, args);
     50         else
     51             throw new IllegalArgumentException ("unknown command: [" + name + "]");
     52 
     53         tool.initialize ();
     54 
     55         return tool;
     56     }
     57 
     58     public abstract void run ();
     59 
     60     // protected: .............................................................
     61 
     62 
     63     protected Command (final String usageToolName, final String [] args)
     64     {
     65         m_usageToolName = usageToolName;
     66         m_args = args != null ? (String []) args.clone () : IConstants.EMPTY_STRING_ARRAY;
     67     }
     68 
     69     protected abstract String usageArgsMsg ();
     70 
     71     // TODO: is this useful (separate from <init>)?
     72     protected void initialize ()
     73     {
     74         m_exit = false;
     75 
     76         if (m_out != null) try { m_out.flush (); } catch (Throwable ignore) {}
     77         m_out = new PrintWriter (System.out, true);
     78     }
     79 
     80     protected final String getToolName ()
     81     {
     82         // TODO: embed build number etc
     83         final String clsName = getClass ().getName ();
     84 
     85         return clsName.substring (0, clsName.length () - 7);
     86     }
     87 
     88     protected final IOptsParser getOptParser (final ClassLoader loader)
     89     {
     90         return IOptsParser.Factory.create (usageResName (getToolName ()), loader,
     91             usageMsgPrefix (m_usageToolName), USAGE_OPT_NAMES);
     92     }
     93 
     94     protected final boolean processOpt (final IOptsParser.IOpt opt)
     95     {
     96         final String on = opt.getCanonicalName ();
     97 
     98         if ("exit".equals (on)) // 'exit' should always be first in this else-if chain
     99         {
    100             m_exit = getOptionalBooleanOptValue (opt);
    101             return true;
    102         }
    103         else if ("p".equals (on))
    104         {
    105             m_propertyFile = new File (opt.getFirstValue ());
    106             return true;
    107         }
    108         else if ("verbose".equals (on))
    109         {
    110             setPropertyOverride (AppLoggers.PROPERTY_VERBOSITY_LEVEL, ILogLevels.VERBOSE_STRING);
    111             return true;
    112         }
    113         else if ("quiet".equals (on))
    114         {
    115             setPropertyOverride (AppLoggers.PROPERTY_VERBOSITY_LEVEL, ILogLevels.WARNING_STRING);
    116             return true;
    117         }
    118         else if ("silent".equals (on))
    119         {
    120             setPropertyOverride (AppLoggers.PROPERTY_VERBOSITY_LEVEL, ILogLevels.SEVERE_STRING);
    121             return true;
    122         }
    123         else if ("debug".equals (on))
    124         {
    125             if (opt.getValueCount () == 0)
    126                 setPropertyOverride (AppLoggers.PROPERTY_VERBOSITY_LEVEL, ILogLevels.TRACE1_STRING);
    127             else
    128                 setPropertyOverride (AppLoggers.PROPERTY_VERBOSITY_LEVEL, opt.getFirstValue ());
    129 
    130             return true;
    131         }
    132         else if ("debugcls".equals (on))
    133         {
    134             setPropertyOverride (AppLoggers.PROPERTY_VERBOSITY_FILTER, Strings.toListForm (Strings.merge (opt.getValues (), COMMA_DELIMITERS, true), ','));
    135             return true;
    136         }
    137 
    138         return false;
    139     }
    140 
    141     protected final void processCmdPropertyOverrides (final IOptsParser.IOpts parsedopts)
    142     {
    143         final IOptsParser.IOpt [] popts = parsedopts.getOpts (EMMAProperties.GENERIC_PROPERTY_OVERRIDE_PREFIX);
    144         if ((popts != null) && (popts.length != 0))
    145         {
    146             final Properties cmdOverrides = new XProperties ();
    147 
    148             for (int o = 0; o < popts.length; ++ o)
    149             {
    150                 final IOptsParser.IOpt opt = popts [o];
    151                 final String on = opt.getName ().substring (opt.getPatternPrefix ().length ());
    152 
    153                 // TODO: support mergeable prefixed opts?
    154 
    155                 cmdOverrides.setProperty (on, opt.getFirstValue ());
    156             }
    157 
    158             // command line user overrides are have highest precedence:
    159             m_propertyOverrides = Property.combine (cmdOverrides, m_propertyOverrides);
    160         }
    161     }
    162 
    163     protected final boolean processFilePropertyOverrides ()
    164     {
    165         if (m_propertyFile != null)
    166         {
    167             final Properties fileOverrides;
    168 
    169             try
    170             {
    171                 fileOverrides = Property.getPropertiesFromFile (m_propertyFile);
    172             }
    173             catch (IOException ioe)
    174             {
    175                 exit (true, "property override file [" + m_propertyFile.getAbsolutePath () + "] could not be read", ioe, RC_USAGE);
    176                 return false;
    177             }
    178 
    179             // props file overrides have second highest precendence:
    180             m_propertyOverrides = Property.combine (m_propertyOverrides, fileOverrides);
    181         }
    182 
    183         return true;
    184     }
    185 
    186     protected final void usageexit (final IOptsParser parser, final int level, final String msg)
    187     {
    188         if (msg != null)
    189         {
    190             m_out.print (usageMsgPrefix (m_usageToolName));
    191             m_out.println (msg);
    192         }
    193 
    194         if (parser != null)
    195         {
    196             m_out.println ();
    197             m_out.print (usageMsgPrefix (m_usageToolName));
    198             m_out.println (toolNameToCommandName (m_usageToolName) + " " + usageArgsMsg () + ",");
    199             m_out.println ("  where options include:");
    200             m_out.println ();
    201             parser.usage (m_out, level, STDOUT_WIDTH);
    202         }
    203 
    204         m_out.println ();
    205         exit (true, null, null, RC_USAGE);
    206     }
    207 
    208     protected final void exit (final boolean showBuildID, final String msg, final Throwable t, final int rc)
    209         throws EMMARuntimeException
    210     {
    211         if (showBuildID)
    212         {
    213             m_out.println (IAppConstants.APP_USAGE_BUILD_ID);
    214         }
    215 
    216         if (msg != null)
    217         {
    218             m_out.print (toolNameToCommandName (m_usageToolName) + ": "); m_out.println (msg);
    219         }
    220 
    221         if (rc != RC_OK)
    222         {
    223             // error exit:
    224 
    225             //if ((showBuildID) || (msg != null)) m_out.println ();
    226 
    227             if (m_exit)
    228             {
    229                 if (t != null) t.printStackTrace (m_out);
    230                 System.exit (rc);
    231             }
    232             else
    233             {
    234                 if (t instanceof EMMARuntimeException)
    235                     throw (EMMARuntimeException) t;
    236                 else if (t != null)
    237                     throw msg != null ? new EMMARuntimeException (msg, t) : new EMMARuntimeException ("unexpected failure: ", t);
    238             }
    239         }
    240         else
    241         {
    242             // normal exit: 't' is ignored
    243 
    244             if (m_exit)
    245             {
    246                 System.exit (0);
    247             }
    248         }
    249     }
    250 
    251     protected static boolean getOptionalBooleanOptValue (final IOptsParser.IOpt opt)
    252     {
    253         if (opt.getValueCount () == 0)
    254             return true;
    255         else
    256         {
    257             final String v = opt.getFirstValue ().toLowerCase ();
    258 
    259             return Property.toBoolean (v);
    260         }
    261     }
    262 
    263     protected static String [] getListOptValue (final IOptsParser.IOpt opt, final String delimiters, final boolean processAtFiles)
    264         throws IOException
    265     {
    266         return Strings.mergeAT (opt.getValues (), delimiters, processAtFiles);
    267     }
    268 
    269     protected static String usageMsgPrefix (final String toolName)
    270     {
    271         return toolNameToCommandName (toolName).concat (" usage: ");
    272     }
    273 
    274     protected static String usageResName (final String toolName)
    275     {
    276         return toolName.replace ('.', '/').concat ("_usage.res");
    277     }
    278 
    279     protected static String toolNameToCommandName (final String toolName)
    280     {
    281         final int lastDot = toolName.lastIndexOf ('.');
    282 
    283         return lastDot > 0 ? toolName.substring (lastDot + 1) : toolName;
    284     }
    285 
    286 
    287     protected final String m_usageToolName;
    288     protected final String [] m_args;
    289 
    290     protected File m_propertyFile;
    291     protected Properties m_propertyOverrides;
    292     protected boolean m_exit;
    293     protected PrintWriter m_out; // this is set independently from Logger by design
    294 
    295     protected static final String COMMA_DELIMITERS    = "," + Strings.WHITE_SPACE;
    296     protected static final String PATH_DELIMITERS     = ",".concat (File.pathSeparator);
    297 
    298     protected static final String [] USAGE_OPT_NAMES = new String [] {"h", "help"};
    299     protected static final int STDOUT_WIDTH = 80;
    300 
    301     // return codes used with System.exit():
    302     protected static final int RC_OK          = 0;
    303     protected static final int RC_USAGE       = 1;
    304     protected static final int RC_UNEXPECTED  = 2;
    305 
    306     // package: ...............................................................
    307 
    308     // private: ...............................................................
    309 
    310 
    311     /*
    312      * Lazily instantiates m_propertyOverrides if necessary.
    313      */
    314     private void setPropertyOverride (final String key, final String value)
    315     {
    316         Properties propertyOverrides = m_propertyOverrides;
    317         if (propertyOverrides == null)
    318         {
    319             m_propertyOverrides = propertyOverrides = new XProperties ();
    320         }
    321 
    322         propertyOverrides.setProperty (key, value);
    323     }
    324 
    325 } // end of class
    326 // ----------------------------------------------------------------------------