Source Code Cross Referenced for CmdLineParser.java in  » Development » args4j » org » kohsuke » args4j » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Development » args4j » org.kohsuke.args4j 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package org.kohsuke.args4j;
002:
003:        import java.io.File;
004:        import java.io.OutputStream;
005:        import java.io.OutputStreamWriter;
006:        import java.io.PrintWriter;
007:        import java.io.Writer;
008:        import java.lang.reflect.Constructor;
009:        import java.lang.reflect.Field;
010:        import java.lang.reflect.InvocationTargetException;
011:        import java.lang.reflect.Method;
012:        import java.util.ArrayList;
013:        import java.util.Collections;
014:        import java.util.Comparator;
015:        import java.util.HashMap;
016:        import java.util.HashSet;
017:        import java.util.List;
018:        import java.util.Map;
019:        import java.util.ResourceBundle;
020:        import java.util.Set;
021:        import java.util.TreeMap;
022:
023:        import org.kohsuke.args4j.spi.BooleanOptionHandler;
024:        import org.kohsuke.args4j.spi.DoubleOptionHandler;
025:        import org.kohsuke.args4j.spi.EnumOptionHandler;
026:        import org.kohsuke.args4j.spi.FileOptionHandler;
027:        import org.kohsuke.args4j.spi.IntOptionHandler;
028:        import org.kohsuke.args4j.spi.OptionHandler;
029:        import org.kohsuke.args4j.spi.Parameters;
030:        import org.kohsuke.args4j.spi.Setter;
031:        import org.kohsuke.args4j.spi.StringOptionHandler;
032:
033:        /**
034:         * Command line argument owner.
035:         *
036:         * <p>
037:         * For a typical usage, see <a href="https://args4j.dev.java.net/source/browse/args4j/args4j/examples/SampleMain.java?view=markup">this example</a>.
038:         *
039:         * @author
040:         *     Kohsuke Kawaguchi (kk@kohsuke.org)
041:         */
042:        public class CmdLineParser {
043:            /**
044:             * Option bean instance.
045:             */
046:            private final Object bean;
047:
048:            /**
049:             * Discovered {@link OptionHandler}s for options.
050:             */
051:            private final List<OptionHandler> options = new ArrayList<OptionHandler>();
052:
053:            /**
054:             * Discovered {@link OptionHandler}s for arguments.
055:             */
056:            private final List<OptionHandler> arguments = new ArrayList<OptionHandler>();
057:
058:            private boolean parsingOptions = true;
059:            private OptionHandler currentOptionHandler = null;
060:
061:            /**
062:             *  The length of a usage line. 
063:             *  If the usage message is longer than this value, the parser
064:             *  wraps the line. Defaults to 80.
065:             */
066:            private int usageWidth = 80;
067:
068:            /**
069:             * Creates a new command line owner that
070:             * parses arguments/options and set them into
071:             * the given object.
072:             *
073:             * @param bean
074:             *      instance of a class annotated by {@link Option} and {@link Argument}.
075:             *      this object will receive values.
076:             *
077:             * @throws IllegalAnnotationError
078:             *      if the option bean class is using args4j annotations incorrectly.
079:             */
080:            public CmdLineParser(Object bean) {
081:                this .bean = bean;
082:
083:                // recursively process all the methods/fields.
084:                for (Class c = bean.getClass(); c != null; c = c
085:                        .getSuperclass()) {
086:                    for (Method m : c.getDeclaredMethods()) {
087:                        Option o = m.getAnnotation(Option.class);
088:                        if (o != null) {
089:                            addOption(new MethodSetter(bean, m), o);
090:                        }
091:                        Argument a = m.getAnnotation(Argument.class);
092:                        if (a != null) {
093:                            addArgument(new MethodSetter(bean, m), a);
094:                        }
095:                    }
096:
097:                    for (Field f : c.getDeclaredFields()) {
098:                        Option o = f.getAnnotation(Option.class);
099:                        if (o != null) {
100:                            addOption(createFieldSetter(f), o);
101:                        }
102:                        Argument a = f.getAnnotation(Argument.class);
103:                        if (a != null) {
104:                            addArgument(createFieldSetter(f), a);
105:                        }
106:                    }
107:                }
108:                for (int i = 0; i < arguments.size(); ++i) {
109:                    if (arguments.get(i) == null) {
110:                        throw new IllegalAnnotationError(
111:                                "No argument annotation for index " + i);
112:                    }
113:                }
114:
115:                // for display purposes, we like the arguments in argument order, but the options in alphabetical order
116:                Collections.sort(options, new Comparator<OptionHandler>() {
117:                    public int compare(OptionHandler o1, OptionHandler o2) {
118:                        return o1.option.toString().compareTo(
119:                                o2.option.toString());
120:                    }
121:                });
122:            }
123:
124:            private Setter createFieldSetter(Field f) {
125:                if (List.class.isAssignableFrom(f.getType()))
126:                    return new MultiValueFieldSetter(bean, f);
127:                //else if(Map.class.isAssignableFrom(f.getType()))
128:                //    return new MapFieldSetter(bean,f);
129:                else
130:                    return new FieldSetter(bean, f);
131:            }
132:
133:            private void addArgument(Setter setter, Argument a) {
134:                OptionHandler h = createOptionHandler(new OptionDef(a, setter
135:                        .isMultiValued()), setter);
136:                int index = a.index();
137:                // make sure the argument will fit in the list
138:                while (index >= arguments.size()) {
139:                    arguments.add(null);
140:                }
141:                if (arguments.get(index) != null) {
142:                    throw new IllegalAnnotationError("Argument with index "
143:                            + index + " is used more than once");
144:                }
145:                arguments.set(index, h);
146:            }
147:
148:            private void addOption(Setter setter, Option o) {
149:                OptionHandler h = createOptionHandler(new NamedOptionDef(o,
150:                        setter.isMultiValued()), setter);
151:                checkOptionNotInMap(o.name());
152:                for (String alias : o.aliases()) {
153:                    checkOptionNotInMap(alias);
154:                }
155:                options.add(h);
156:            }
157:
158:            private void checkOptionNotInMap(String name)
159:                    throws IllegalAnnotationError {
160:                if (findOptionByName(name) != null) {
161:                    throw new IllegalAnnotationError("Option name " + name
162:                            + " is used more than once");
163:                }
164:            }
165:
166:            /**
167:             * Creates an {@link OptionHandler} that handles the given {@link Option} annotation
168:             * and the {@link Setter} instance.
169:             */
170:            protected OptionHandler createOptionHandler(OptionDef o,
171:                    Setter setter) {
172:
173:                Constructor<? extends OptionHandler> handlerType;
174:                Class<? extends OptionHandler> h = o.handler();
175:                if (h == OptionHandler.class) {
176:                    // infer the type
177:
178:                    // enum is the special case
179:                    Class t = setter.getType();
180:                    if (Enum.class.isAssignableFrom(t))
181:                        return new EnumOptionHandler(this , o, setter, t);
182:
183:                    handlerType = handlerClasses.get(t);
184:                    if (handlerType == null)
185:                        throw new IllegalAnnotationError(
186:                                "No OptionHandler is registered to handle " + t);
187:                } else {
188:                    handlerType = getConstructor(h);
189:                }
190:
191:                try {
192:                    return handlerType.newInstance(this , o, setter);
193:                } catch (InstantiationException e) {
194:                    throw new IllegalAnnotationError(e);
195:                } catch (IllegalAccessException e) {
196:                    throw new IllegalAnnotationError(e);
197:                } catch (InvocationTargetException e) {
198:                    throw new IllegalAnnotationError(e);
199:                }
200:            }
201:
202:            /**
203:             * Formats a command line example into a string.
204:             *
205:             * See {@link #printExample(ExampleMode, ResourceBundle)} for more details.
206:             *
207:             * @param mode
208:             *      must not be null.
209:             * @return
210:             *      always non-null.
211:             */
212:            public String printExample(ExampleMode mode) {
213:                return printExample(mode, null);
214:            }
215:
216:            /**
217:             * Formats a command line example into a string.
218:             *
219:             * <p>
220:             * This method produces a string like " -d &lt;dir> -v -b",
221:             * which is useful for printing a command line example, perhaps
222:             * as a part of the usage screen.
223:             *
224:             *
225:             * @param mode
226:             *      One of the {@link ExampleMode} constants. Must not be null.
227:             *      This determines what option should be a part of the returned string.
228:             * @param rb
229:             *      If non-null, meta variables (&lt;dir> in the above example)
230:             *      is treated as a key to this resource bundle, and the associated
231:             *      value is printed. See {@link Option#metaVar()}. This is to support
232:             *      localization.
233:             *
234:             *      Passing <tt>null</tt> would print {@link Option#metaVar()} directly.
235:             * @return
236:             *      always non-null. If there's no option, this method returns
237:             *      just the empty string "". Otherwise, this method returns a
238:             *      string that contains a space at the beginning (but not at the end.)
239:             *      This allows you to do something like:
240:             *
241:             *      <pre>System.err.println("java -jar my.jar"+parser.printExample(REQUIRED)+" arg1 arg2");</pre> 
242:             */
243:            public String printExample(ExampleMode mode, ResourceBundle rb) {
244:                StringBuilder buf = new StringBuilder();
245:
246:                for (OptionHandler h : options) {
247:                    OptionDef option = h.option;
248:                    if (option.usage().length() == 0)
249:                        continue; // ignore
250:                    if (!mode.print(option))
251:                        continue;
252:
253:                    buf.append(' ');
254:                    buf.append(h.getNameAndMeta(rb));
255:                }
256:
257:                return buf.toString();
258:            }
259:
260:            /**
261:             * Prints the list of options and their usages to the screen.
262:             *
263:             * <p>
264:             * This is a convenience method for calling {@code printUsage(new OutputStreamWriter(out),null)}
265:             * so that you can do {@code printUsage(System.err)}.
266:             */
267:            public void printUsage(OutputStream out) {
268:                printUsage(new OutputStreamWriter(out), null);
269:            }
270:
271:            /**
272:             * Prints the list of options and their usages to the screen.
273:             *
274:             * @param rb
275:             *      if this is non-null, {@link Option#usage()} is treated
276:             *      as a key to obtain the actual message from this resource bundle.
277:             */
278:            public void printUsage(Writer out, ResourceBundle rb) {
279:                PrintWriter w = new PrintWriter(out);
280:                // determine the length of the option + metavar first
281:                int len = 0;
282:                for (OptionHandler h : arguments) {
283:                    int curLen = getPrefixLen(h, rb);
284:                    len = Math.max(len, curLen);
285:                }
286:                for (OptionHandler h : options) {
287:                    int curLen = getPrefixLen(h, rb);
288:                    len = Math.max(len, curLen);
289:                }
290:
291:                // then print
292:                for (OptionHandler h : arguments) {
293:                    printOption(w, h, len, rb);
294:                }
295:                for (OptionHandler h : options) {
296:                    printOption(w, h, len, rb);
297:                }
298:
299:                w.flush();
300:            }
301:
302:            private void printOption(PrintWriter w, OptionHandler h, int len,
303:                    ResourceBundle rb) {
304:                int descriptionWidth = usageWidth - len - 4; // 3 for " : " + 1 for left-most SP
305:
306:                String usage = h.option.usage();
307:                if (usage.length() == 0)
308:                    return; // ignore
309:
310:                String nameAndMeta = h.getNameAndMeta(rb);
311:                w.print(' ');
312:                w.print(nameAndMeta);
313:                for (int i = nameAndMeta.length(); i < len; ++i) {
314:                    w.print(' ');
315:                }
316:                w.print(" : ");
317:
318:                if (rb != null)
319:                    usage = rb.getString(usage);
320:
321:                while (usage != null && usage.length() > 0) {
322:                    int idx = usage.indexOf('\n');
323:                    if (idx >= 0 && idx <= descriptionWidth) {
324:                        w.println(usage.substring(0, idx));
325:                        usage = usage.substring(idx + 1);
326:                        if (usage.length() > 0)
327:                            indent(w, len + 4);
328:                        continue;
329:                    }
330:                    if (usage.length() <= descriptionWidth) {
331:                        w.println(usage);
332:                        break;
333:                    }
334:
335:                    w.println(usage.substring(0, descriptionWidth));
336:                    usage = usage.substring(descriptionWidth);
337:                    indent(w, len + 4);
338:                }
339:            }
340:
341:            private int getPrefixLen(OptionHandler h, ResourceBundle rb) {
342:                if (h.option.usage().length() == 0)
343:                    return 0;
344:
345:                return h.getNameAndMeta(rb).length();
346:            }
347:
348:            private void indent(PrintWriter w, int i) {
349:                for (; i > 0; i--)
350:                    w.print(' ');
351:            }
352:
353:            /**
354:             * Essentially a pointer over a {@link String} array.
355:             * Can move forward, can look ahead.
356:             */
357:            private class CmdLineImpl implements  Parameters {
358:                private final String[] args;
359:                private int pos;
360:
361:                CmdLineImpl(String[] args) {
362:                    this .args = args;
363:                    pos = 0;
364:                }
365:
366:                protected boolean hasMore() {
367:                    return pos < args.length;
368:                }
369:
370:                protected String getCurrentToken() {
371:                    return args[pos];
372:                }
373:
374:                private void proceed(int n) {
375:                    pos += n;
376:                }
377:
378:                public String getParameter(int idx) throws CmdLineException {
379:                    if (pos + idx >= args.length)
380:                        throw new CmdLineException(Messages.MISSING_OPERAND
381:                                .format(getOptionName()));
382:                    return args[pos + idx];
383:                }
384:            }
385:
386:            private String getOptionName() {
387:                return currentOptionHandler.option.toString();
388:            }
389:
390:            /**
391:             * Parses the command line arguments and set them to the option bean
392:             * given in the constructor.
393:             * 
394:             * @param args arguments to parse
395:             *
396:             * @throws CmdLineException
397:             *      if there's any error parsing arguments, or if
398:             *      {@link Option#required() required} option was not given.
399:             */
400:            public void parseArgument(final String... args)
401:                    throws CmdLineException {
402:                CmdLineImpl cmdLine = new CmdLineImpl(args);
403:
404:                Set<OptionHandler> present = new HashSet<OptionHandler>();
405:                int argIndex = 0;
406:
407:                while (cmdLine.hasMore()) {
408:                    String arg = cmdLine.getCurrentToken();
409:                    if (isOption(arg)) {
410:                        boolean isKeyValuePair = arg.indexOf('=') != -1;
411:                        // parse this as an option.
412:                        currentOptionHandler = isKeyValuePair ? findOptionHandler(arg)
413:                                : findOptionByName(arg);
414:
415:                        if (currentOptionHandler == null) {
416:                            // TODO: insert dynamic handler processing
417:                            throw new CmdLineException(
418:                                    Messages.UNDEFINED_OPTION.format(arg));
419:                        }
420:
421:                        // known option; skip its name
422:                        cmdLine.proceed(1);
423:                    } else {
424:                        if (argIndex >= arguments.size()) {
425:                            Messages msg = arguments.size() == 0 ? Messages.NO_ARGUMENT_ALLOWED
426:                                    : Messages.TOO_MANY_ARGUMENTS;
427:                            throw new CmdLineException(msg.format(arg));
428:                        }
429:
430:                        // known argument
431:                        currentOptionHandler = arguments.get(argIndex);
432:                        if (!currentOptionHandler.option.isMultiValued())
433:                            argIndex++;
434:                    }
435:                    int diff = currentOptionHandler.parseArguments(cmdLine);
436:                    cmdLine.proceed(diff);
437:                    present.add(currentOptionHandler);
438:                }
439:
440:                // make sure that all mandatory options are present
441:                for (OptionHandler handler : options)
442:                    if (handler.option.required() && !present.contains(handler))
443:                        throw new CmdLineException(
444:                                Messages.REQUIRED_OPTION_MISSING
445:                                        .format(handler.option.toString()));
446:
447:                // make sure that all mandatory arguments are present
448:                for (OptionHandler handler : arguments)
449:                    if (handler.option.required() && !present.contains(handler))
450:                        throw new CmdLineException(
451:                                Messages.REQUIRED_ARGUMENT_MISSING
452:                                        .format(handler.option.toString()));
453:            }
454:
455:            private OptionHandler findOptionHandler(String name) {
456:                OptionHandler handler = findOptionByName(name);
457:                if (handler == null) {
458:                    // Have not found by its name, maybe its a property?
459:                    // Search for parts of the name (=prefix) - most specific first 
460:                    for (int i = name.length(); i > 1; i--) {
461:                        String prefix = name.substring(0, i);
462:                        Map<String, OptionHandler> possibleHandlers = filter(
463:                                options, prefix);
464:                        handler = possibleHandlers.get(prefix);
465:                        if (handler != null)
466:                            return handler;
467:                    }
468:                }
469:                return handler;
470:            }
471:
472:            private OptionHandler findOptionByName(String name) {
473:                for (OptionHandler h : options) {
474:                    NamedOptionDef option = (NamedOptionDef) h.option;
475:                    if (name.equals(option.name())) {
476:                        return h;
477:                    }
478:                    for (String alias : option.aliases()) {
479:                        if (name.equals(alias)) {
480:                            return h;
481:                        }
482:                    }
483:                }
484:                return null;
485:            }
486:
487:            private Map<String, OptionHandler> filter(List<OptionHandler> opt,
488:                    String keyFilter) {
489:                Map<String, OptionHandler> rv = new TreeMap<String, OptionHandler>();
490:                for (OptionHandler h : opt) {
491:                    if (opt.toString().startsWith(keyFilter))
492:                        rv.put(opt.toString(), h);
493:                }
494:                return rv;
495:            }
496:
497:            /**
498:             * Returns true if the given token is an option
499:             * (as opposed to an argument.)
500:             */
501:            protected boolean isOption(String arg) {
502:                return parsingOptions && arg.startsWith("-");
503:            }
504:
505:            /**
506:             * All {@link OptionHandler}s known to the {@link CmdLineParser}.
507:             *
508:             * Constructors of {@link OptionHandler}-derived class keyed by their supported types.
509:             */
510:            private static final Map<Class, Constructor<? extends OptionHandler>> handlerClasses = Collections
511:                    .synchronizedMap(new HashMap<Class, Constructor<? extends OptionHandler>>());
512:
513:            /**
514:             * Registers a user-defined {@link OptionHandler} class with args4j.
515:             *
516:             * <p>
517:             * This method allows users to extend the behavior of args4j by writing
518:             * their own {@link OptionHandler} implementation.
519:             *
520:             * @param valueType
521:             *      The specified handler is used when the field/method annotated by {@link Option}
522:             *      is of this type.
523:             * @param handlerClass
524:             *      This class must have the constructor that has the same signature as
525:             *      {@link OptionHandler#OptionHandler(CmdLineParser, NamedOptionDef, Setter)}.
526:             */
527:            public static void registerHandler(Class valueType,
528:                    Class<? extends OptionHandler> handlerClass) {
529:                if (valueType == null || handlerClass == null)
530:                    throw new IllegalArgumentException();
531:                if (!OptionHandler.class.isAssignableFrom(handlerClass))
532:                    throw new IllegalArgumentException(
533:                            "Not an OptionHandler class");
534:
535:                Constructor<? extends OptionHandler> c = getConstructor(handlerClass);
536:                handlerClasses.put(valueType, c);
537:            }
538:
539:            private static Constructor<? extends OptionHandler> getConstructor(
540:                    Class<? extends OptionHandler> handlerClass) {
541:                try {
542:                    return handlerClass.getConstructor(CmdLineParser.class,
543:                            OptionDef.class, Setter.class);
544:                } catch (NoSuchMethodException e) {
545:                    throw new IllegalArgumentException(handlerClass
546:                            + " does not have the proper constructor");
547:                }
548:            }
549:
550:            static {
551:                registerHandler(Boolean.class, BooleanOptionHandler.class);
552:                registerHandler(boolean.class, BooleanOptionHandler.class);
553:                registerHandler(File.class, FileOptionHandler.class);
554:                registerHandler(Integer.class, IntOptionHandler.class);
555:                registerHandler(int.class, IntOptionHandler.class);
556:                registerHandler(Double.class, DoubleOptionHandler.class);
557:                registerHandler(double.class, DoubleOptionHandler.class);
558:                registerHandler(String.class, StringOptionHandler.class);
559:                // enum is a special case
560:                //registerHandler(Map.class,MapOptionHandler.class);
561:            }
562:
563:            public void setUsageWidth(int usageWidth) {
564:                this .usageWidth = usageWidth;
565:            }
566:
567:            public void stopOptionParsing() {
568:                parsingOptions = false;
569:            }
570:
571:            /**
572:             * Prints a single-line usage to the screen.
573:             *
574:             * <p>
575:             * This is a convenience method for calling {@code printUsage(new OutputStreamWriter(out),null)}
576:             * so that you can do {@code printUsage(System.err)}.
577:             */
578:            public void printSingleLineUsage(OutputStream out) {
579:                printSingleLineUsage(new OutputStreamWriter(out), null);
580:            }
581:
582:            /**
583:             * Prints a single-line usage to the screen.
584:             *
585:             * @param rb
586:             *      if this is non-null, {@link Option#usage()} is treated
587:             *      as a key to obtain the actual message from this resource bundle.
588:             */
589:            public void printSingleLineUsage(Writer w, ResourceBundle rb) {
590:                PrintWriter pw = new PrintWriter(w);
591:                for (OptionHandler h : arguments) {
592:                    printSingleLineOption(pw, h, rb);
593:                }
594:                for (OptionHandler h : options) {
595:                    printSingleLineOption(pw, h, rb);
596:                }
597:                pw.flush();
598:            }
599:
600:            private void printSingleLineOption(PrintWriter pw, OptionHandler h,
601:                    ResourceBundle rb) {
602:                pw.print(' ');
603:                if (!h.option.required())
604:                    pw.print('[');
605:                pw.print(h.getNameAndMeta(rb));
606:                if (h.option.isMultiValued()) {
607:                    pw.print(" ...");
608:                }
609:                if (!h.option.required())
610:                    pw.print(']');
611:            }
612:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.