Source for net.dpml.cli.option.SourceDestArgument

   1: /*
   2:  * Copyright 2003-2005 The Apache Software Foundation
   3:  * Copyright 2005 Stephen McConnell
   4:  *
   5:  * Licensed under the Apache License, Version 2.0 (the "License");
   6:  * you may not use this file except in compliance with the License.
   7:  * You may obtain a copy of the License at
   8:  *
   9:  *     http://www.apache.org/licenses/LICENSE-2.0
  10:  *
  11:  * Unless required by applicable law or agreed to in writing, software
  12:  * distributed under the License is distributed on an "AS IS" BASIS,
  13:  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14:  * See the License for the specific language governing permissions and
  15:  * limitations under the License.
  16:  */
  17: package net.dpml.cli.option;
  18: 
  19: import java.util.ArrayList;
  20: import java.util.Comparator;
  21: import java.util.Iterator;
  22: import java.util.List;
  23: import java.util.Set;
  24: 
  25: import net.dpml.cli.Argument;
  26: import net.dpml.cli.Option;
  27: import net.dpml.cli.OptionException;
  28: import net.dpml.cli.WriteableCommandLine;
  29: import net.dpml.cli.resource.ResourceConstants;
  30: import net.dpml.cli.resource.ResourceHelper;
  31: 
  32: /**
  33:  * An Argument implementation that allows a variable size Argument to precede a
  34:  * fixed size argument.  The canonical example of it's use is in the unix
  35:  * <code>cp</code> command where a number of source can be specified with
  36:  * exactly one destination specfied at the end.
  37:  * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
  38:  * @version @PROJECT-VERSION@
  39:  */
  40: public class SourceDestArgument extends ArgumentImpl
  41: {
  42:     private final Argument m_source;
  43:     private final Argument m_dest;
  44: 
  45:     /**
  46:      * Creates a SourceDestArgument using defaults where possible.
  47:      *
  48:      * @param source the variable size Argument
  49:      * @param dest the fixed size Argument
  50:      */
  51:     public SourceDestArgument(
  52:       final Argument source, final Argument dest )
  53:     {
  54:         this( 
  55:           source, 
  56:           dest, 
  57:           DEFAULT_INITIAL_SEPARATOR, 
  58:           DEFAULT_SUBSEQUENT_SEPARATOR,
  59:           DEFAULT_CONSUME_REMAINING, 
  60:           null );
  61:     }
  62: 
  63:     /**
  64:      * Creates a SourceDestArgument using the specified parameters.
  65:      *
  66:      * @param source the variable size Argument
  67:      * @param dest the fixed size Argument
  68:      * @param initialSeparator the inistial separator to use
  69:      * @param subsequentSeparator the subsequent separator to use
  70:      * @param consumeRemaining the token triggering consume remaining behaviour
  71:      * @param defaultValues the default values for the SourceDestArgument
  72:      */
  73:     public SourceDestArgument(
  74:       final Argument source, final Argument dest, final char initialSeparator,
  75:       final char subsequentSeparator, final String consumeRemaining,
  76:       final List defaultValues )
  77:     {
  78:         super( 
  79:           "SourceDestArgument", null, sum( source.getMinimum(), dest.getMinimum() ),
  80:           sum( source.getMaximum(), dest.getMaximum() ), initialSeparator, 
  81:           subsequentSeparator, null, consumeRemaining, defaultValues, 0 );
  82: 
  83:         m_source = source;
  84:         m_dest = dest;
  85: 
  86:         if( dest.getMinimum() != dest.getMaximum() )
  87:         {
  88:             throw new IllegalArgumentException(
  89:               ResourceHelper.getResourceHelper().getMessage(
  90:                 ResourceConstants.SOURCE_DEST_MUST_ENFORCE_VALUES ) );
  91:         }
  92:     }
  93: 
  94:     private static int sum( final int a, final int b )
  95:     {
  96:         return Math.max( a, Math.max( b, a + b ) );
  97:     }
  98: 
  99:     /**
 100:      * Appends usage information to the specified StringBuffer
 101:      * 
 102:      * @param buffer the buffer to append to
 103:      * @param helpSettings a set of display settings @see DisplaySetting
 104:      * @param comp a comparator used to sort the Options
 105:      */
 106:     public void appendUsage(
 107:       final StringBuffer buffer, final Set helpSettings, final Comparator comp )
 108:     {
 109:         final int length = buffer.length();
 110: 
 111:         m_source.appendUsage( buffer, helpSettings, comp );
 112: 
 113:         if( buffer.length() != length )
 114:         {
 115:             buffer.append( ' ' );
 116:         }
 117: 
 118:         m_dest.appendUsage( buffer, helpSettings, comp );
 119:     }
 120: 
 121:     /**
 122:      * Builds up a list of HelpLineImpl instances to be presented by HelpFormatter.
 123:      * 
 124:      * @see net.dpml.cli.HelpLine
 125:      * @see net.dpml.cli.util.HelpFormatter
 126:      * @param depth the initial indent depth
 127:      * @param helpSettings the HelpSettings that should be applied
 128:      * @param comp a comparator used to sort options when applicable.
 129:      * @return a List of HelpLineImpl objects
 130:      */
 131:     public List helpLines(
 132:       int depth, Set helpSettings, Comparator comp )
 133:     {
 134:         final List helpLines = new ArrayList();
 135:         helpLines.addAll( m_source.helpLines( depth, helpSettings, comp ) );
 136:         helpLines.addAll( m_dest.helpLines( depth, helpSettings, comp ) );
 137:         return helpLines;
 138:     }
 139: 
 140:     /**
 141:      * Checks that the supplied CommandLine is valid with respect to the
 142:      * suppled option.
 143:      * 
 144:      * @param commandLine the CommandLine to check.
 145:      * @param option the option to evaluate
 146:      * @throws OptionException if the CommandLine is not valid.
 147:      */
 148:     public void validate( WriteableCommandLine commandLine, Option option )
 149:       throws OptionException
 150:     {
 151:         final List values = commandLine.getValues( option );
 152: 
 153:         final int limit = values.size() - m_dest.getMinimum();
 154:         int count = 0;
 155: 
 156:         final Iterator i = values.iterator();
 157: 
 158:         while( count++ < limit )
 159:         {
 160:             commandLine.addValue( m_source, i.next() );
 161:         }
 162:         
 163:         while( i.hasNext() )
 164:         {
 165:             commandLine.addValue( m_dest, i.next() );
 166:         }
 167:         
 168:         m_source.validate( commandLine, m_source );
 169:         m_dest.validate( commandLine, m_dest );
 170:     }
 171: 
 172:     /**
 173:      * Indicates whether this Option will be able to process the particular
 174:      * argument.
 175:      * 
 176:      * @param commandLine the CommandLine object to store defaults in
 177:      * @param arg the argument to be tested
 178:      * @return true if the argument can be processed by this Option
 179:      */
 180:     public boolean canProcess(
 181:       final WriteableCommandLine commandLine, final String arg )
 182:     {
 183:         return m_source.canProcess( commandLine, arg ) || m_dest.canProcess( commandLine, arg );
 184:     }
 185: }