Source for net.dpml.cli.option.OptionImpl

   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.Iterator;
  20: import java.util.ListIterator;
  21: import java.util.Set;
  22: 
  23: import net.dpml.cli.DisplaySetting;
  24: import net.dpml.cli.Option;
  25: import net.dpml.cli.WriteableCommandLine;
  26: import net.dpml.cli.resource.ResourceConstants;
  27: import net.dpml.cli.resource.ResourceHelper;
  28: 
  29: /**
  30:  * A base implementation of Option providing limited ground work for further
  31:  * Option implementations.
  32:  * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
  33:  * @version @PROJECT-VERSION@
  34:  */
  35: public abstract class OptionImpl implements Option 
  36: {
  37:     private final int m_id;
  38:     private final boolean m_required;
  39: 
  40:     /**
  41:      * Creates an OptionImpl with the specified id
  42:      * @param id the unique id of this Option
  43:      * @param required true iff this Option must be present
  44:      */
  45:     public OptionImpl( final int id, final boolean required ) 
  46:     {
  47:         m_id = id;
  48:         m_required = required;
  49:     }
  50: 
  51:     /**
  52:      * Indicates whether this Option will be able to process the particular
  53:      * argument. The ListIterator must be restored to the initial state before
  54:      * returning the boolean.
  55:      * 
  56:      * @see #canProcess(WriteableCommandLine,String)
  57:      * @param commandLine the CommandLine object to store defaults in
  58:      * @param arguments the ListIterator over String arguments
  59:      * @return true if the argument can be processed by this Option
  60:      */
  61:     public boolean canProcess( 
  62:       final WriteableCommandLine commandLine, final ListIterator arguments )
  63:     {
  64:         if( arguments.hasNext() )
  65:         {
  66:             final String argument = (String) arguments.next();
  67:             arguments.previous();
  68:             return canProcess( commandLine, argument );
  69:         } 
  70:         else 
  71:         {
  72:             return false;
  73:         }
  74:     }
  75: 
  76:    /**
  77:     * Returns a string representation of the option.
  78:     * @return the string value
  79:     */
  80:     public String toString() 
  81:     {
  82:         final StringBuffer buffer = new StringBuffer();
  83:         appendUsage( buffer, DisplaySetting.ALL, null );
  84:         return buffer.toString();
  85:     }
  86: 
  87:     /**
  88:      * Returns the id of the option.  This can be used in a loop and switch 
  89:      * construct:
  90:      * 
  91:      * <code>
  92:      * for(Option o : cmd.getOptions()){
  93:      *     switch(o.getId()){
  94:      *         case POTENTIAL_OPTION:
  95:      *             ...
  96:      *     }
  97:      * }
  98:      * </code> 
  99:      * 
 100:      * The returned value is not guarenteed to be unique.
 101:      * 
 102:      * @return the id of the option.
 103:      */
 104:     public int getId() 
 105:     {
 106:         return m_id;
 107:     }
 108: 
 109:    /**
 110:     * Evaluate this instance against the supplied instance for equality.
 111:     * @param thatObj the other object
 112:     * @return true if the supplied instance is equal to this instance
 113:     */
 114:     public boolean equals( final Object thatObj )
 115:     {
 116:         if( thatObj instanceof OptionImpl )
 117:         {
 118:             final OptionImpl that = (OptionImpl) thatObj;
 119:             return ( getId() == that.getId() ) 
 120:               && equals( getPreferredName(), that.getPreferredName() ) 
 121:               && equals( getDescription(), that.getDescription() ) 
 122:               && equals( getPrefixes(), that.getPrefixes() ) 
 123:               && equals( getTriggers(), that.getTriggers() );
 124:         }
 125:         else
 126:         {
 127:             return false;
 128:         }
 129:     }
 130: 
 131:     private boolean equals( Object left, Object right )
 132:     {
 133:         if( ( left == null ) && ( right == null ) )
 134:         {
 135:             return true;
 136:         }
 137:         else if( ( left == null ) || ( right == null ) )
 138:         {
 139:             return false;
 140:         } 
 141:         else
 142:         {
 143:             return left.equals( right );
 144:         }
 145:     }
 146: 
 147:    /**
 148:     * Return the hashcode value for this instance.
 149:     * @return the hash value
 150:     */
 151:     public int hashCode()
 152:     {
 153:         int hashCode = getId();
 154:         hashCode = ( hashCode * 37 ) + getPreferredName().hashCode();
 155:         if( getDescription() != null )
 156:         {
 157:             hashCode = ( hashCode * 37 ) + getDescription().hashCode();
 158:         }
 159:         hashCode = ( hashCode * 37 ) + getPrefixes().hashCode();
 160:         hashCode = ( hashCode * 37 ) + getTriggers().hashCode();
 161:         return hashCode;
 162:     }
 163: 
 164:    /**
 165:     * Recursively searches for an option with the supplied trigger.
 166:     *
 167:     * @param trigger the trigger to search for.
 168:     * @return the matching option or null.
 169:     */
 170:     public Option findOption( String trigger )
 171:     {
 172:         if( getTriggers().contains( trigger ) )
 173:         {
 174:             return this;
 175:         } 
 176:         else 
 177:         {
 178:             return null;
 179:         }
 180:     }
 181: 
 182:     /**
 183:      * Indicates whether this option is required to be present.
 184:      * @return true if the CommandLine will be invalid without this Option
 185:      */
 186:     public boolean isRequired() 
 187:     {
 188:         return m_required;
 189:     }
 190: 
 191:     /**
 192:      * Adds defaults to a CommandLine.
 193:      * 
 194:      * Any defaults for this option are applied as well as the defaults for 
 195:      * any contained options
 196:      * 
 197:      * @param commandLine the CommandLine object to store defaults in
 198:      */
 199:     public void defaults( final WriteableCommandLine commandLine ) 
 200:     {
 201:         // nothing to do normally
 202:     }
 203: 
 204:    /**
 205:     * Check prefixes.
 206:     * @param prefixes the prefixes set
 207:     */
 208:     protected void checkPrefixes( final Set prefixes ) 
 209:     {
 210:         // nothing to do if empty prefix list
 211:         if( prefixes.isEmpty() )
 212:         {
 213:             return;
 214:         }
 215: 
 216:         // check preferred name
 217:         checkPrefix( prefixes, getPreferredName() );
 218: 
 219:         // check triggers
 220:         getTriggers();
 221: 
 222:         for( final Iterator i = getTriggers().iterator(); i.hasNext();)
 223:         {
 224:             checkPrefix( prefixes, (String) i.next() );
 225:         }
 226:     }
 227: 
 228:    /**
 229:     * Check prefixes.
 230:     * @param prefixes the prefixes set
 231:     * @param trigger the trigger
 232:     */
 233:     private void checkPrefix( final Set prefixes, final String trigger )
 234:     {
 235:         for( final Iterator i = prefixes.iterator(); i.hasNext();) 
 236:         {
 237:             String prefix = (String) i.next();
 238:             if( trigger.startsWith( prefix ) ) 
 239:             {
 240:                 return;
 241:             }
 242:         }
 243: 
 244:         final ResourceHelper helper = ResourceHelper.getResourceHelper();
 245:         final String message =
 246:           helper.getMessage( 
 247:             ResourceConstants.OPTION_TRIGGER_NEEDS_PREFIX, 
 248:             trigger, 
 249:             prefixes.toString() );
 250:         throw new IllegalArgumentException( message );
 251:     }
 252: }