~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/libs/jgdi/src/com/sun/grid/jgdi/util/shell/AnnotatedCommand.java

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*___INFO__MARK_BEGIN__*/
 
2
/*************************************************************************
 
3
 *
 
4
 *  The Contents of this file are made available subject to the terms of
 
5
 *  the Sun Industry Standards Source License Version 1.2
 
6
 *
 
7
 *  Sun Microsystems Inc., March, 2001
 
8
 *
 
9
 *
 
10
 *  Sun Industry Standards Source License Version 1.2
 
11
 *  =================================================
 
12
 *  The contents of this file are subject to the Sun Industry Standards
 
13
 *  Source License Version 1.2 (the "License"); You may not use this file
 
14
 *  except in compliance with the License. You may obtain a copy of the
 
15
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 
16
 *
 
17
 *  Software provided under this License is provided on an "AS IS" basis,
 
18
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 
19
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 
20
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 
21
 *  See the License for the specific provisions governing your rights and
 
22
 *  obligations concerning the Software.
 
23
 *
 
24
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 
25
 *
 
26
 *   Copyright: 2001 by Sun Microsystems, Inc.
 
27
 *
 
28
 *   All Rights Reserved.
 
29
 *
 
30
 ************************************************************************/
 
31
 
 
32
/*___INFO__MARK_END__*/
 
33
package com.sun.grid.jgdi.util.shell;
 
34
 
 
35
import com.sun.grid.jgdi.JGDIException;
 
36
import java.io.PrintWriter;
 
37
import java.lang.annotation.Annotation;
 
38
import java.lang.reflect.Method;
 
39
import java.text.MessageFormat;
 
40
import java.util.ArrayList;
 
41
import java.util.Arrays;
 
42
import java.util.HashMap;
 
43
import java.util.List;
 
44
import java.util.Map;
 
45
import java.util.MissingResourceException;
 
46
import java.util.ResourceBundle;
 
47
import java.util.Set;
 
48
 
 
49
 
 
50
/**
 
51
 *
 
52
 */
 
53
public abstract class AnnotatedCommand extends AbstractCommand {
 
54
    
 
55
    /* Map holding all commands and their respective optionDesriptorMap */
 
56
    private static Map<Class<? extends AbstractCommand>, Map<String, OptionDescriptor>> commandOptionMap = null;
 
57
    /* Map holding all options of selected command and methods that should be invoked for it */
 
58
    private Map<String, OptionDescriptor> optionDescriptorMap = null;
 
59
    /* List of all command options */
 
60
    private List<OptionInfo> optionList = null;
 
61
    /* Map holding OptionInfo (after paring the args) to the option string */
 
62
    private Map<String, OptionInfo> optionInfoMap = null;
 
63
    
 
64
    /* ResourceBundle containging all error messags */
 
65
    private static final ResourceBundle errorMessages = ResourceBundle.getBundle("com.sun.grid.jgdi.util.shell.ErrorMessagesResources");
 
66
 
 
67
    /* Extra argument list for extending commands that support it. Other have to explicitly check and throw error if not-null */
 
68
    private List<List<String>> extraArgs = null;
 
69
    
 
70
    /**
 
71
     * Initialize the option map optionDescriptorMap if not yet created.
 
72
     * Map is created by scanning all OptionMethod annotated functions.
 
73
     * NOTE: Only options in the map will be recognized as implemented
 
74
     */
 
75
    public static void initOptionDescriptorMap(Class<? extends AbstractCommand> cls, PrintWriter out, PrintWriter err) throws Exception {
 
76
        if (commandOptionMap == null) {
 
77
            commandOptionMap = new HashMap<Class<? extends AbstractCommand>, Map<String, OptionDescriptor>>(30);
 
78
        }
 
79
        if (!commandOptionMap.containsKey(cls)) {
 
80
            Map<String, OptionDescriptor> optionDescriptorMap = new HashMap<String, OptionDescriptor>(140);
 
81
            
 
82
            for (Method m : cls.getMethods()) {
 
83
                for (Annotation a : m.getDeclaredAnnotations()) {
 
84
                    if (a instanceof OptionAnnotation) {
 
85
                        OptionAnnotation o = (OptionAnnotation) a;
 
86
                        if (optionDescriptorMap.containsKey(o.value())) {
 
87
                            OptionDescriptor od = optionDescriptorMap.get(o.value());
 
88
                            if (!od.getMethod().getName().equals(m.getName())) {
 
89
                                err.println("WARNING: Attempt to override " +od.getMethod().getDeclaringClass().getName()+"."+od.getMethod().getName() + " by " + cls.getName() + "." + m.getName() + "() for option \""+o.value()+"\"\n");
 
90
                            }
 
91
                        }
 
92
                        //Add method to the optionDescriptorMap
 
93
                        optionDescriptorMap.put(o.value(), new OptionDescriptor(o.value(), o.defaultStringArg(), o.min(), o.extra(), m, out, err));
 
94
                    }
 
95
                }
 
96
            }
 
97
            
 
98
            commandOptionMap.put(cls, optionDescriptorMap);
 
99
        }
 
100
    }
 
101
    
 
102
    /**
 
103
     * Finds option info based on option name.
 
104
     * Use to do a lookahead to see if specific option was in the argument list.
 
105
     * @param option String
 
106
     * @return OptionInfo associated with the option or null does not exist
 
107
     */
 
108
    public OptionInfo getOptionInfo(String option) {
 
109
        if (optionInfoMap.containsKey(option)) {
 
110
            return optionInfoMap.get(option);
 
111
        }
 
112
        return null;
 
113
    }
 
114
    
 
115
    /**
 
116
     * Getter method
 
117
     * @return Map<String, OptionDescriptor>
 
118
     */
 
119
    public Map<String, OptionDescriptor> getOptionDescriptorMap() {
 
120
        if (this.optionDescriptorMap == null) {
 
121
            optionDescriptorMap = commandOptionMap.get(this.getClass());
 
122
        }
 
123
        return optionDescriptorMap;
 
124
    }
 
125
 
 
126
    /**
 
127
     * Gets the extra arguments for the command. Only certail commands actually need it: qrsub, qsub, qalter
 
128
     * @return List<String>
 
129
    */
 
130
    protected List<String> getExtraArguments() {
 
131
        List<String> out = new ArrayList<String>();
 
132
        for (List<String> temp : extraArgs) {
 
133
            for (String arg : temp) {
 
134
                out.add(arg);
 
135
            }
 
136
        }
 
137
        return out;
 
138
    }
 
139
    
 
140
    /**
 
141
     * Gets the original extra arguments (List of List of Stirng) for the command. Only certail commands actually need it: qrsub, qsub, qalter
 
142
     * @return List<List<String>>
 
143
    */
 
144
    protected List<List<String>> getOriginalExtraArguments() {
 
145
        return extraArgs;
 
146
    }
 
147
 
 
148
    /**
 
149
     * Check if there are extra arguments. If command should not support it (not a qrsub, qsub, qalter)
 
150
     * @return boolean
 
151
    */
 
152
    protected boolean hasExtraArguments() {
 
153
        return extraArgs == null || extraArgs.size()==0;
 
154
    }
 
155
    
 
156
    
 
157
    protected void parseOptions(String[] args) throws Exception {
 
158
        optionList = new ArrayList<OptionInfo>();
 
159
        optionInfoMap = new HashMap<String, OptionInfo>();
 
160
        List<List<String>> argList = tokenizeArgs(args);
 
161
        while (!argList.isEmpty()) {
 
162
            //Get option info, token are divided by known option
 
163
            //to option and reladet arguments
 
164
            //The arguments are tested for declared multiplicity
 
165
            OptionInfo info = getOptionInfo(getOptionDescriptorMap(), argList);
 
166
            //If we got extra argument list, we skip it (info is null)
 
167
            if (info != null) {
 
168
                optionList.add(info);
 
169
                optionInfoMap.put(info.getOd().getOption(), info);
 
170
            }
 
171
        }
 
172
    }
 
173
    
 
174
    /**
 
175
     * Parse all arguments and invoke appropriate methods
 
176
     * It calls annotated functions for every recognized option.
 
177
     * @param args command line options
 
178
     * @throws java.lang.Exception an exception during the option call
 
179
     * or some runnable exception, when the options are wrong
 
180
     */
 
181
    protected void parseAndInvokeOptions(String[] args) throws Exception {
 
182
        parseOptions(args);
 
183
        invokeOptions();
 
184
    }
 
185
    
 
186
    /**
 
187
     * Invoke appropriate methods
 
188
     * It calls annotated functions for every recognized option.
 
189
     * @throws java.lang.Exception an exception during the option call
 
190
     * or some runnable exception, when the options are wrong
 
191
     */
 
192
    protected void invokeOptions() throws Exception {
 
193
        for (OptionInfo oi : optionList) {
 
194
            oi.invokeOption(this);
 
195
        }
 
196
    }
 
197
    
 
198
    /**
 
199
     * Parse the ergument array to Array list of separated tokens
 
200
     * The tokens are then divided by known options
 
201
     * @param args command line option
 
202
     * @return List of tokens
 
203
     */
 
204
    protected List<List<String>> tokenizeArgs(String[] args) {
 
205
        List<List<String>> argList = new ArrayList<List<String>>();
 
206
        List<String> tempList = new ArrayList<String>();
 
207
        //Expand args to list of args, 'arg1,arg2 arg3' -> List(List(arg1,arg2),List(arg3)) so we can do magic later on
 
208
        for (String arg : args) {
 
209
            String[] subElems = arg.split("[,]");
 
210
            for (String subElem : subElems) {
 
211
                subElem = subElem.trim();
 
212
                if (subElem.length() > 0) {
 
213
                    tempList.add(subElem);
 
214
                }
 
215
            }
 
216
            argList.add(new ArrayList<String>(tempList));
 
217
            tempList.clear();
 
218
        }
 
219
        return argList;
 
220
    }
 
221
    
 
222
    /**
 
223
     * Lists all known (registered) options for the command
 
224
     */
 
225
    @OptionAnnotation(value = "-list", min=0)
 
226
    public void listOptions(final OptionInfo oi) throws JGDIException {
 
227
        String str = new String();
 
228
        Set<String> set = oi.getMap().keySet();
 
229
        String[] options = oi.getMap().keySet().toArray(new String[set.size()]);
 
230
        Arrays.sort(options);
 
231
        for (String option : options) {
 
232
            out.println(option);
 
233
        }
 
234
        // To avoid the continue of the command
 
235
        throw new AbortException();
 
236
    }
 
237
    
 
238
    /**
 
239
     * Gets option info. Returns correct Option object and all its arguments
 
240
     * Default behavior: 1) Read all mandatory args. Error if not complete
 
241
     *                   2) Read max optional args until end or next option found
 
242
     * Arguments have to be already expanded
 
243
     * @param optMap {@link Map} holding all options for current command.
 
244
     * @param args argument list
 
245
     * @return return the option info structure
 
246
     */
 
247
    //TODO LP: Discuss this enhancement. We now accept "arg1,arg2 arg3,arg4" as 4 valid args
 
248
    private OptionInfo getOptionInfo(final Map<String, OptionDescriptor> optMap, List<List<String>> args) throws JGDIException {
 
249
        //Check we have a map set
 
250
        if (optMap.isEmpty()) {
 
251
            throw new UnsupportedOperationException("Cannot get OptionInfo. Option map is empty!");
 
252
        }
 
253
 
 
254
        List<List<String>> extraArgs = null;
 
255
        List<String> tempArg = args.get(0);
 
256
        String option = tempArg.get(0);
 
257
        String msg;
 
258
        boolean extraArgsValid = this.getClass().getAnnotation(CommandAnnotation.class).hasExtraArgs();
 
259
        
 
260
        //We have unknown option or extra arguments (qconf -ddd x qalter 45)
 
261
        if (!optMap.containsKey(option)) {
 
262
            extraArgs = new ArrayList<List<String>>();
 
263
            //Read all extra argument to the end of the of all args.
 
264
            while (!args.isEmpty()) {
 
265
                extraArgs.add(args.remove(0));
 
266
                //If some is recognized as valid option. First extra arg is InvalidArgument
 
267
                if (!extraArgsValid || optMap.containsKey(option)) {
 
268
                    msg = getErrorMessage("InvalidArgument", extraArgs.get(0).get(0));
 
269
                    int exitCode = getCustomExitCode("InvalidArgument", extraArgs.get(0).get(0));
 
270
                    extraArgs = null;
 
271
                    throw new JGDIException(msg, exitCode);
 
272
                }
 
273
            }
 
274
            //We now store the extraArgs to this command.
 
275
            this.extraArgs = extraArgs;
 
276
            return null;    //null says now you have the extra args so save them
 
277
        }
 
278
        
 
279
        //We take out first arg list
 
280
        tempArg = args.remove(0);
 
281
        //And remove the recognized option
 
282
        tempArg.remove(0);
 
283
        //And we put it back if not empty
 
284
        if (tempArg.size()>0) {
 
285
            args.add(0, tempArg);
 
286
        }
 
287
        OptionDescriptor od = optMap.get(option);
 
288
        List<List<String>> argList = new ArrayList<List<String>>();
 
289
        List<String> tempList = new ArrayList<String>();
 
290
        String arg;
 
291
              
 
292
        if (!od.isWithoutArgs()) {
 
293
            int i = 0;
 
294
            
 
295
            //Try to get all mandatory args
 
296
            while (i < od.getMandatoryArgCount() && args.size() > 0) {
 
297
                tempArg = args.remove(0);
 
298
                tempList.clear();
 
299
                while (tempArg.size() > 0 && i < od.getMandatoryArgCount()) {
 
300
                    arg = tempArg.remove(0);
 
301
                    tempList.add(arg);
 
302
                    i++;
 
303
                }
 
304
                if (tempList.size() > 0) {
 
305
                    argList.add(new ArrayList<String>(tempList));
 
306
                }
 
307
            }
 
308
            //We check we completed the subList (comma separated list) otherwise we mark it for continue
 
309
            boolean appendToLastList = false;
 
310
            if (tempArg.size() > 0) {
 
311
                appendToLastList = true;
 
312
                args.add(0, tempArg);
 
313
            }
 
314
            
 
315
            //Check we have all mandatory args
 
316
            if (i != od.getMandatoryArgCount()) {
 
317
                final String msgType = (i == 0) ? "NoArgument" : "LessArguments";
 
318
                msg = getErrorMessage(msgType, option, argList);
 
319
                int exitCode = getCustomExitCode(msgType, option);
 
320
                throw new JGDIException(msg, exitCode);
 
321
            }
 
322
            
 
323
            //Try to get as many optional args as possible
 
324
            String argVal;
 
325
            boolean exit = false;
 
326
            i = 0;
 
327
            while (!exit && (i < od.getOptionalArgCount() && args.size() > 0)) {
 
328
                tempArg = args.remove(0);
 
329
                tempList.clear();
 
330
                if (appendToLastList) {
 
331
                    appendToLastList = false;
 
332
                    tempList = argList.remove(argList.size() - 1);
 
333
                }
 
334
                for (int j = 0; j<tempArg.size(); j++) {
 
335
                    //We have comma separated list with more elems than required - Error 
 
336
                    if (i >= od.getOptionalArgCount()) {
 
337
                        final String msgType = "MoreArguments";
 
338
                        msg = getErrorMessage(msgType, option, argList);
 
339
                        int exitCode = getCustomExitCode(msgType, option);
 
340
                        throw new JGDIException(msg, exitCode);
 
341
                    }
 
342
                    argVal = tempArg.get(j);
 
343
                    //Not enough args?
 
344
                    if (optMap.containsKey(argVal)) {
 
345
                        if (j == 0) {
 
346
                            //Next recognized option must be the first in the sub list
 
347
                            exit = true;
 
348
                            args.add(0, tempArg);
 
349
                            break;
 
350
                        } else {
 
351
                            //This is an error since option is found in the list 
 
352
                            //qconf -sq a,b c,d,-sh <= -sh is known option so whole command is wrong
 
353
                            //qconf -sq a,g -sh would be accepted
 
354
                            msg = getErrorMessage("InvalidArgument", option, argVal);
 
355
                            int exitCode = getCustomExitCode("InvalidArgument", option);
 
356
                            throw new JGDIException(msg, exitCode);
 
357
                        }
 
358
                    }
 
359
                    tempList.add(argVal);
 
360
                    i++;
 
361
                }
 
362
                //We should always add only complete sub lists.
 
363
                argList.add(new ArrayList<String>(tempList));
 
364
            }
 
365
        }
 
366
        
 
367
        //TODO LP: This should probably never happen - remove?
 
368
        //Check if we have more args than expected
 
369
        if (argList.size() > od.getMaxArgCount()) {
 
370
            msg = "Expected only " + od.getMaxArgCount() + " arguments for " + option + " option. Got " + argList.size() + ".";
 
371
            throw new IllegalArgumentException(msg);
 
372
        }
 
373
        
 
374
        if (argList.size() == 0 && od.getMandatoryArgCount() == 0 && od.getOptionalArgCount() != 0 && od.getDefaultArg().length()> 0) {
 
375
             tempList = new ArrayList<String>();
 
376
             tempList.add(od.getDefaultArg());
 
377
             argList.add(tempList);
 
378
        }
 
379
        
 
380
        boolean hasNoArgs = (od.getMandatoryArgCount() == 0) && (od.getOptionalArgCount() == 0);
 
381
        
 
382
        if (hasNoArgs) {
 
383
            return new OptionInfo(od, optMap);
 
384
        }
 
385
        
 
386
        //TODO: Check we have correct args
 
387
        return new OptionInfo(od, argList, optMap);
 
388
    }
 
389
    
 
390
    /** Hepler method to get the right error message */
 
391
    String getErrorMessage(String msgType, String optionString) {
 
392
        return getErrorMessage(msgType, optionString, new ArrayList<List<String>>());
 
393
    }
 
394
    
 
395
    /** Hepler method to get the right error message */
 
396
    String getErrorMessage(String msgType, String optionString, String arg) {
 
397
        List<List<String>> argList = new ArrayList<List<String>>();
 
398
        List<String> temp = new ArrayList<String>();
 
399
        temp.add(arg);
 
400
        argList.add(temp);
 
401
        return getErrorMessage(msgType, optionString, argList);
 
402
    }
 
403
    
 
404
    /** Hepler method to get the right error message */
 
405
    String getErrorMessage(String msgType, String optionString, List<List<String>> args) {
 
406
        String[] tmp = this.getClass().getName().split("[.]");
 
407
        String cmdName = tmp[tmp.length-1];
 
408
        return getErrorMessage(msgType, cmdName, optionString, args, getUsage());
 
409
    }
 
410
    
 
411
    public static String getDefaultErrorMessage(String cmdName, String msgType, String arg) {
 
412
        List<List<String>> argList = new ArrayList<List<String>>();
 
413
        List<String> temp = new ArrayList<String>();
 
414
        temp.add(arg);
 
415
        argList.add(temp);
 
416
        return getErrorMessage(msgType, cmdName, "", argList, "");
 
417
    }
 
418
    
 
419
    /** Hepler method to get the right error message */
 
420
    private static String getErrorMessage(String msgType, String cmdName, String optionString, List<List<String>> args, String usage) {
 
421
        String cmdString = cmdName.split("Command")[0].toLowerCase();
 
422
        String prefix = msgType+"."+cmdName+".";
 
423
        String argString = "";
 
424
        if (args != null && args.size() > 0) {
 
425
            for (List<String> temp : args) {
 
426
                for (String arg : temp) {
 
427
                    argString += arg + " ";
 
428
                }
 
429
            }
 
430
            argString = argString.substring(0, argString.length()-1);
 
431
        }
 
432
        //TODO LP: Remove the New generic message string
 
433
        String msg = "Missing error messages file!";
 
434
        try { //Try to get option specific message
 
435
            msg = errorMessages.getString(prefix+optionString);
 
436
        } catch (MissingResourceException ex) {
 
437
            try { //Try to get command default message
 
438
                msg = errorMessages.getString(prefix+"default");
 
439
            } catch (MissingResourceException dex) {
 
440
                msg = errorMessages.getString(prefix+"generic");
 
441
            }
 
442
        }
 
443
        return MessageFormat.format(msg, optionString, argString, "Usage: "+cmdString+" -help", usage);
 
444
    }
 
445
    
 
446
    /** Hepler method to get the right exit code for specified error (msgType) */
 
447
    int getCustomExitCode(String msgType, String optionString) {
 
448
        String[] tmp = this.getClass().getName().split("[.]");
 
449
        String cmdName = tmp[tmp.length-1];
 
450
        return getCustomExitCode(msgType, cmdName, optionString);
 
451
    }
 
452
    
 
453
    public static int getCustomExitCode(String msgType, String cmdName, String optionString) {
 
454
        String cmdString = cmdName.split("Command")[0].toLowerCase();
 
455
        String prefix = msgType+"."+cmdName+".";
 
456
        String argString = "";
 
457
        int exitCode = 0;
 
458
        try { //Try to get option specific exitCode for this message type
 
459
            exitCode = Integer.valueOf(errorMessages.getString(prefix+optionString+".exitCode"));
 
460
        } catch (MissingResourceException ex) {
 
461
            try { //Try to get command default message specific exitCode
 
462
            exitCode = Integer.valueOf(errorMessages.getString(prefix+"default.exitCode"));
 
463
            } catch (MissingResourceException dex) {}
 
464
        }
 
465
        return exitCode;
 
466
    }
 
467
}
 
 
b'\\ No newline at end of file'