• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
create(final String name, final String usageName, final String [] args)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 
run()58     public abstract void run ();
59 
60     // protected: .............................................................
61 
62 
Command(final String usageToolName, final String [] args)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 
usageArgsMsg()69     protected abstract String usageArgsMsg ();
70 
71     // TODO: is this useful (separate from <init>)?
initialize()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 
getToolName()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 
getOptParser(final ClassLoader loader)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 
processOpt(final IOptsParser.IOpt opt)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 
processCmdPropertyOverrides(final IOptsParser.IOpts parsedopts)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 
processFilePropertyOverrides()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 
usageexit(final IOptsParser parser, final int level, final String msg)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 
exit(final boolean showBuildID, final String msg, final Throwable t, final int rc)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 
getOptionalBooleanOptValue(final IOptsParser.IOpt opt)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 
getListOptValue(final IOptsParser.IOpt opt, final String delimiters, final boolean processAtFiles)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 
usageMsgPrefix(final String toolName)269     protected static String usageMsgPrefix (final String toolName)
270     {
271         return toolNameToCommandName (toolName).concat (" usage: ");
272     }
273 
usageResName(final String toolName)274     protected static String usageResName (final String toolName)
275     {
276         return toolName.replace ('.', '/').concat ("_usage.res");
277     }
278 
toolNameToCommandName(final String toolName)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      */
setPropertyOverride(final String key, final String value)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 // ----------------------------------------------------------------------------