001 /* 002 * Copyright 2003-2005 The Apache Software Foundation 003 * Copyright 2005 Stephen McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package net.dpml.cli.option; 018 019 import java.util.ArrayList; 020 import java.util.Collections; 021 import java.util.Comparator; 022 import java.util.HashSet; 023 import java.util.Iterator; 024 import java.util.List; 025 import java.util.ListIterator; 026 import java.util.Set; 027 028 import net.dpml.cli.Argument; 029 import net.dpml.cli.DisplaySetting; 030 import net.dpml.cli.Group; 031 import net.dpml.cli.OptionException; 032 import net.dpml.cli.WriteableCommandLine; 033 import net.dpml.cli.resource.ResourceConstants; 034 import net.dpml.cli.resource.ResourceHelper; 035 036 /** 037 * Represents a cvs "update" style command line option. 038 * 039 * Like all Parents, Commands can have child options and can be part of 040 * Arguments. 041 * 042 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 043 * @version 1.0.0 044 */ 045 public class Command extends ParentImpl 046 { 047 /** The display name for the command */ 048 private final String m_preferredName; 049 050 /** The aliases for this command */ 051 private final Set m_aliases; 052 053 /** All the names for this command */ 054 private final Set m_triggers; 055 056 /** 057 * Creates a new Command instance. 058 * 059 * @param preferredName the name normally used to refer to the Command 060 * @param description a description of the Command 061 * @param aliases alternative names for the Command 062 * @param required true if the Command is required 063 * @param argument an Argument that the command takes 064 * @param children the Group of child options for this Command 065 * @param id a unique id for the Command 066 * @see ParentImpl#ParentImpl(Argument, Group, String, int, boolean) 067 */ 068 public Command( 069 final String preferredName, final String description, final Set aliases, 070 final boolean required, final Argument argument, final Group children, final int id ) 071 { 072 super( argument, children, description, id, required ); 073 074 // check the preferred name is valid 075 if( ( preferredName == null ) || ( preferredName.length() < 1 ) ) 076 { 077 throw new IllegalArgumentException( 078 ResourceHelper.getResourceHelper().getMessage( 079 ResourceConstants.COMMAND_PREFERRED_NAME_TOO_SHORT ) ); 080 } 081 082 m_preferredName = preferredName; 083 084 // gracefully and defensively handle aliases 085 086 if( null == aliases ) 087 { 088 m_aliases = Collections.EMPTY_SET; 089 } 090 else 091 { 092 m_aliases = Collections.unmodifiableSet( new HashSet( aliases ) ); 093 } 094 095 // populate the triggers Set 096 final Set newTriggers = new HashSet(); 097 newTriggers.add( preferredName ); 098 newTriggers.addAll( m_aliases ); 099 m_triggers = Collections.unmodifiableSet( newTriggers ); 100 } 101 102 /** 103 * Process the parent. 104 * @param commandLine the commandline 105 * @param arguments an iterator of arguments 106 * @exception OptionException if an error occurs 107 */ 108 public void processParent( 109 final WriteableCommandLine commandLine, final ListIterator arguments ) 110 throws OptionException 111 { 112 // grab the argument to process 113 final String arg = (String) arguments.next(); 114 115 // if we can process it 116 if( canProcess( commandLine, arg ) ) 117 { 118 // then note the option 119 commandLine.addOption( this ); 120 121 // normalise the argument list 122 arguments.set( m_preferredName ); 123 } 124 else 125 { 126 throw new OptionException( 127 this, 128 ResourceConstants.UNEXPECTED_TOKEN, 129 arg ); 130 } 131 } 132 133 /** 134 * Identifies the argument prefixes that should trigger this option. This 135 * is used to decide which of many Options should be tried when processing 136 * a given argument string. 137 * 138 * The returned Set must not be null. 139 * 140 * @return The set of triggers for this Option 141 */ 142 public Set getTriggers() 143 { 144 return m_triggers; 145 } 146 147 /** 148 * Checks that the supplied CommandLine is valid with respect to this 149 * option. 150 * 151 * @param commandLine the CommandLine to check. 152 * @throws OptionException if the CommandLine is not valid. 153 */ 154 public void validate( WriteableCommandLine commandLine ) throws OptionException 155 { 156 if( isRequired() && !commandLine.hasOption( this ) ) 157 { 158 throw new OptionException( 159 this, 160 ResourceConstants.OPTION_MISSING_REQUIRED, 161 getPreferredName() ); 162 } 163 super.validate( commandLine ); 164 } 165 166 /** 167 * Appends usage information to the specified StringBuffer 168 * 169 * @param buffer the buffer to append to 170 * @param helpSettings a set of display settings @see DisplaySetting 171 * @param comp a comparator used to sort the Options 172 */ 173 public void appendUsage( 174 final StringBuffer buffer, final Set helpSettings, final Comparator comp ) 175 { 176 // do we display optionality 177 final boolean optional = 178 !isRequired() && helpSettings.contains( DisplaySetting.DISPLAY_OPTIONAL ); 179 final boolean displayAliases = 180 helpSettings.contains( DisplaySetting.DISPLAY_ALIASES ); 181 182 if( optional ) 183 { 184 buffer.append( '[' ); 185 } 186 187 buffer.append( m_preferredName ); 188 189 if( displayAliases && !m_aliases.isEmpty() ) 190 { 191 buffer.append( " (" ); 192 final List list = new ArrayList( m_aliases ); 193 Collections.sort( list ); 194 for( final Iterator i = list.iterator(); i.hasNext();) 195 { 196 final String alias = (String) i.next(); 197 buffer.append( alias ); 198 if( i.hasNext() ) 199 { 200 buffer.append( ',' ); 201 } 202 } 203 buffer.append( ')' ); 204 } 205 206 super.appendUsage( buffer, helpSettings, comp ); 207 if( optional ) 208 { 209 buffer.append( ']' ); 210 } 211 } 212 213 /** 214 * The preferred name of an option is used for generating help and usage 215 * information. 216 * 217 * @return The preferred name of the option 218 */ 219 public String getPreferredName() 220 { 221 return m_preferredName; 222 } 223 }