1:
17: package ;
18:
19: import ;
20: import ;
21: import ;
22: import ;
23: import ;
24: import ;
25: import ;
26: import ;
27: import ;
28: import ;
29: import ;
30: import ;
31:
32: import ;
33: import ;
34: import ;
35: import ;
36: import ;
37: import ;
38: import ;
39: import ;
40:
41:
46: public class GroupImpl extends OptionImpl implements Group
47: {
48: private final String m_name;
49: private final String m_description;
50: private final List m_options;
51: private final int m_minimum;
52: private final int m_maximum;
53: private final List m_anonymous;
54: private final SortedMap m_optionMap;
55: private final Set m_prefixes;
56:
57:
66: public GroupImpl(
67: final List options, final String name, final String description,
68: final int minimum, final int maximum )
69: {
70: super( 0, false );
71:
72: m_name = name;
73: m_description = description;
74: m_minimum = minimum;
75: m_maximum = maximum;
76:
77:
78:
79: m_options = Collections.unmodifiableList( options );
80:
81:
82: final List newAnonymous = new ArrayList();
83:
84:
85: final SortedMap newOptionMap = new TreeMap( ReverseStringComparator.getInstance() );
86:
87:
88: final Set newPrefixes = new HashSet();
89:
90:
91: for( final Iterator i = options.iterator(); i.hasNext();)
92: {
93: final Option option = (Option) i.next();
94: if( option instanceof Argument )
95: {
96: i.remove();
97: newAnonymous.add( option );
98: }
99: else
100: {
101: final Set triggers = option.getTriggers();
102: for( Iterator j = triggers.iterator(); j.hasNext();)
103: {
104: newOptionMap.put( j.next(), option );
105: }
106:
107: newPrefixes.addAll( option.getPrefixes() );
108: }
109: }
110:
111: m_anonymous = Collections.unmodifiableList( newAnonymous );
112: m_optionMap = Collections.unmodifiableSortedMap( newOptionMap );
113: m_prefixes = Collections.unmodifiableSet( newPrefixes );
114: }
115:
116:
124: public boolean canProcess(
125: final WriteableCommandLine commandLine, final String arg )
126: {
127: if( arg == null )
128: {
129: return false;
130: }
131:
132:
133: if( m_optionMap.containsKey( arg ) )
134: {
135: return true;
136: }
137:
138:
139: final Map tailMap = m_optionMap.tailMap( arg );
140:
141:
142: for( final Iterator iter = tailMap.values().iterator(); iter.hasNext();)
143: {
144: final Option option = (Option) iter.next();
145: if( option.canProcess( commandLine, arg ) )
146: {
147: return true;
148: }
149: }
150:
151: if( commandLine.looksLikeOption( arg ) )
152: {
153: return false;
154: }
155:
156:
157: if( m_anonymous.size() > 0 )
158: {
159: return true;
160: }
161:
162: return false;
163: }
164:
165:
175: public Set getPrefixes()
176: {
177: return m_prefixes;
178: }
179:
180:
189: public Set getTriggers()
190: {
191: return m_optionMap.keySet();
192: }
193:
194:
206: public void process(
207: final WriteableCommandLine commandLine, final ListIterator arguments )
208: throws OptionException
209: {
210: String previous = null;
211:
212:
213: while( arguments.hasNext() )
214: {
215:
216: final String arg = (String) arguments.next();
217:
218:
219: if( arg == previous )
220: {
221:
222: arguments.previous();
223: break;
224: }
225:
226:
227: previous = arg;
228:
229: final Option opt = (Option) m_optionMap.get( arg );
230:
231:
232: if( opt != null )
233: {
234: arguments.previous();
235: opt.process( commandLine, arguments );
236: }
237:
238: else
239: {
240:
241:
242: if( commandLine.looksLikeOption( arg ) )
243: {
244:
245: final Collection values = m_optionMap.tailMap( arg ).values();
246: boolean foundMemberOption = false;
247: for( Iterator i = values.iterator(); i.hasNext() && !foundMemberOption;)
248: {
249: final Option option = (Option) i.next();
250: if( option.canProcess( commandLine, arg ) )
251: {
252: foundMemberOption = true;
253: arguments.previous();
254: option.process( commandLine, arguments );
255: }
256: }
257:
258:
259: if( !foundMemberOption )
260: {
261: arguments.previous();
262: return;
263: }
264:
265: }
266:
267: else
268: {
269:
270: arguments.previous();
271:
272:
273:
274: if( m_anonymous.isEmpty() )
275: {
276: break;
277: }
278:
279:
280:
281: for( final Iterator i = m_anonymous.iterator(); i.hasNext();)
282: {
283: final Argument argument = (Argument) i.next();
284: if( argument.canProcess( commandLine, arguments ) )
285: {
286: argument.process( commandLine, arguments );
287: }
288: }
289: }
290: }
291: }
292: }
293:
294:
301: public void validate( final WriteableCommandLine commandLine ) throws OptionException
302: {
303:
304: int present = 0;
305:
306:
307: Option unexpected = null;
308:
309: for( final Iterator i = m_options.iterator(); i.hasNext();)
310: {
311: final Option option = (Option) i.next();
312:
313:
314: if( option.isRequired() )
315: {
316: option.validate( commandLine );
317: }
318:
319: if( option instanceof Group )
320: {
321: option.validate( commandLine );
322: }
323:
324:
325: if( commandLine.hasOption( option ) )
326: {
327: if( ++present > m_maximum )
328: {
329: unexpected = option;
330: break;
331: }
332: option.validate( commandLine );
333: }
334: }
335:
336:
337: if( unexpected != null )
338: {
339: throw new OptionException(
340: this,
341: ResourceConstants.UNEXPECTED_TOKEN,
342: unexpected.getPreferredName() );
343: }
344:
345:
346: if( present < m_minimum )
347: {
348: throw new OptionException(
349: this,
350: ResourceConstants.MISSING_OPTION );
351: }
352:
353:
354: for( final Iterator i = m_anonymous.iterator(); i.hasNext();)
355: {
356: final Option option = (Option) i.next();
357: option.validate( commandLine );
358: }
359: }
360:
361:
367: public String getPreferredName()
368: {
369: return m_name;
370: }
371:
372:
379: public String getDescription()
380: {
381: return m_description;
382: }
383:
384:
391: public void appendUsage(
392: final StringBuffer buffer, final Set helpSettings, final Comparator comp )
393: {
394: if( getMaximum() == 1 )
395: {
396: appendUsage( buffer, helpSettings, comp, "|" );
397: }
398: else
399: {
400: appendUsage( buffer, helpSettings, comp, " " );
401: }
402: }
403:
404:
412: public void appendUsage(
413: final StringBuffer buffer, final Set helpSettings, final Comparator comp,
414: final String separator )
415: {
416: final Set helpSettingsCopy = new HashSet( helpSettings );
417:
418: final boolean optional =
419: ( m_minimum == 0 )
420: && helpSettingsCopy.contains( DisplaySetting.DISPLAY_OPTIONAL );
421:
422: final boolean expanded =
423: ( m_name == null )
424: || helpSettingsCopy.contains( DisplaySetting.DISPLAY_GROUP_EXPANDED );
425:
426: final boolean named =
427: !expanded
428: || ( ( m_name != null ) && helpSettingsCopy.contains( DisplaySetting.DISPLAY_GROUP_NAME ) );
429:
430: final boolean arguments =
431: helpSettingsCopy.contains( DisplaySetting.DISPLAY_GROUP_ARGUMENT );
432:
433: final boolean outer =
434: helpSettingsCopy.contains( DisplaySetting.DISPLAY_GROUP_OUTER );
435:
436: helpSettingsCopy.remove( DisplaySetting.DISPLAY_GROUP_OUTER );
437:
438: final boolean both = named && expanded;
439:
440: if( optional )
441: {
442: buffer.append( '[' );
443: }
444:
445: if( named )
446: {
447: buffer.append( m_name );
448: }
449:
450: if( both )
451: {
452: buffer.append( " (" );
453: }
454:
455: if( expanded )
456: {
457: final Set childSettings;
458:
459: if( !helpSettingsCopy.contains( DisplaySetting.DISPLAY_GROUP_EXPANDED ) )
460: {
461: childSettings = DisplaySetting.NONE;
462: }
463: else
464: {
465: childSettings = new HashSet( helpSettingsCopy );
466: childSettings.remove( DisplaySetting.DISPLAY_OPTIONAL );
467: }
468:
469:
470: final List list;
471:
472: if( comp == null )
473: {
474:
475: list = m_options;
476: }
477: else
478: {
479:
480: list = new ArrayList( m_options );
481: Collections.sort( list, comp );
482: }
483:
484:
485: for( final Iterator i = list.iterator(); i.hasNext();)
486: {
487: final Option option = (Option) i.next();
488:
489:
490: option.appendUsage( buffer, childSettings, comp );
491:
492:
493: if( i.hasNext() )
494: {
495: buffer.append( separator );
496: }
497: }
498: }
499:
500: if( both )
501: {
502: buffer.append( ')' );
503: }
504:
505: if( optional && outer )
506: {
507: buffer.append( ']' );
508: }
509:
510: if( arguments )
511: {
512: for( final Iterator i = m_anonymous.iterator(); i.hasNext();)
513: {
514: buffer.append( ' ' );
515: final Option option = (Option) i.next();
516: option.appendUsage( buffer, helpSettingsCopy, comp );
517: }
518: }
519:
520: if( optional && !outer )
521: {
522: buffer.append( ']' );
523: }
524: }
525:
526:
536: public List helpLines(
537: final int depth, final Set helpSettings, final Comparator comp )
538: {
539: final List helpLines = new ArrayList();
540:
541: if( helpSettings.contains( DisplaySetting.DISPLAY_GROUP_NAME ) )
542: {
543: final HelpLine helpLine = new HelpLineImpl( this, depth );
544: helpLines.add( helpLine );
545: }
546:
547: if( helpSettings.contains( DisplaySetting.DISPLAY_GROUP_EXPANDED ) )
548: {
549:
550: final List list;
551:
552: if( comp == null )
553: {
554:
555: list = m_options;
556: }
557: else
558: {
559:
560: list = new ArrayList( m_options );
561: Collections.sort( list, comp );
562: }
563:
564:
565: for( final Iterator i = list.iterator(); i.hasNext();)
566: {
567: final Option option = (Option) i.next();
568: helpLines.addAll( option.helpLines( depth + 1, helpSettings, comp ) );
569: }
570: }
571:
572: if( helpSettings.contains( DisplaySetting.DISPLAY_GROUP_ARGUMENT ) )
573: {
574: for( final Iterator i = m_anonymous.iterator(); i.hasNext();)
575: {
576: final Option option = (Option) i.next();
577: helpLines.addAll( option.helpLines( depth + 1, helpSettings, comp ) );
578: }
579: }
580:
581: return helpLines;
582: }
583:
584:
589: public List getOptions()
590: {
591: return m_options;
592: }
593:
594:
598: public List getAnonymous()
599: {
600: return m_anonymous;
601: }
602:
603:
609: public Option findOption( final String trigger )
610: {
611: final Iterator i = getOptions().iterator();
612:
613: while( i.hasNext() )
614: {
615: final Option option = (Option) i.next();
616: final Option found = option.findOption( trigger );
617: if( found != null )
618: {
619: return found;
620: }
621: }
622: return null;
623: }
624:
625:
630: public int getMinimum()
631: {
632: return m_minimum;
633: }
634:
635:
640: public int getMaximum()
641: {
642: return m_maximum;
643: }
644:
645:
654: public boolean isRequired()
655: {
656: return getMinimum() > 0;
657: }
658:
659:
663: public void defaults( final WriteableCommandLine commandLine )
664: {
665: super.defaults( commandLine );
666: for( final Iterator i = m_options.iterator(); i.hasNext();)
667: {
668: final Option option = (Option) i.next();
669: option.defaults( commandLine );
670: }
671:
672: for( final Iterator i = m_anonymous.iterator(); i.hasNext();)
673: {
674: final Option option = (Option) i.next();
675: option.defaults( commandLine );
676: }
677: }
678: }
679:
680:
683: final class ReverseStringComparator implements Comparator
684: {
685: private static final Comparator INSTANCE = new ReverseStringComparator();
686:
687: private ReverseStringComparator()
688: {
689:
690: }
691:
692:
696: public static final Comparator getInstance()
697: {
698: return INSTANCE;
699: }
700:
701:
707: public int compare( final Object o1, final Object o2 )
708: {
709: final String s1 = (String) o1;
710: final String s2 = (String) o2;
711: return -s1.compareTo( s2 );
712: }
713: }