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.Collections;
020 import java.util.Comparator;
021 import java.util.List;
022 import java.util.ListIterator;
023 import java.util.Set;
024
025 import net.dpml.cli.DisplaySetting;
026 import net.dpml.cli.HelpLine;
027 import net.dpml.cli.OptionException;
028 import net.dpml.cli.WriteableCommandLine;
029 import net.dpml.cli.resource.ResourceConstants;
030
031 /**
032 * Handles the java style "-Dprop=value" opions
033 * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
034 * @version @PROJECT-VERSION@
035 */
036 public class PropertyOption extends OptionImpl
037 {
038 /**
039 * The default property option name.
040 */
041 public static final String DEFAULT_OPTION_STRING = "-D";
042
043 /**
044 * The default property option description.
045 */
046 public static final String DEFAULT_DESCRIPTION = "Set property values.";
047
048 /**
049 * A default PropertyOption instance
050 */
051 public static final PropertyOption INSTANCE = new PropertyOption();
052
053 private final String m_optionString;
054 private final String m_description;
055 private final Set m_prefixes;
056
057 /**
058 * Creates a new PropertyOption using the default settings of a "-D" trigger
059 * and an id of 'D'
060 */
061 public PropertyOption()
062 {
063 this( DEFAULT_OPTION_STRING, DEFAULT_DESCRIPTION, 'D' );
064 }
065
066 /**
067 * Creates a new PropertyOption using the specified parameters
068 * @param optionString the trigger for the Option
069 * @param description the description of the Option
070 * @param id the id of the Option
071 */
072 public PropertyOption(
073 final String optionString, final String description, final int id )
074 {
075 super( id, false );
076 m_optionString = optionString;
077 m_description = description;
078 m_prefixes = Collections.singleton( optionString );
079 }
080
081 /**
082 * Indicates whether this Option will be able to process the particular
083 * argument.
084 *
085 * @param commandLine the CommandLine object to store defaults in
086 * @param argument the argument to be tested
087 * @return true if the argument can be processed by this Option
088 */
089 public boolean canProcess(
090 final WriteableCommandLine commandLine, final String argument )
091 {
092 return ( argument != null )
093 && argument.startsWith( m_optionString )
094 && ( argument.length() > m_optionString.length() );
095 }
096
097 /**
098 * Identifies the argument prefixes that should be considered options. This
099 * is used to identify whether a given string looks like an option or an
100 * argument value. Typically an option would return the set [--,-] while
101 * switches might offer [-,+].
102 *
103 * The returned Set must not be null.
104 *
105 * @return The set of prefixes for this Option
106 */
107 public Set getPrefixes()
108 {
109 return m_prefixes;
110 }
111
112 /**
113 * Processes String arguments into a CommandLine.
114 *
115 * The iterator will initially point at the first argument to be processed
116 * and at the end of the method should point to the first argument not
117 * processed. This method MUST process at least one argument from the
118 * ListIterator.
119 *
120 * @param commandLine the CommandLine object to store results in
121 * @param arguments the arguments to process
122 * @throws OptionException if any problems occur
123 */
124 public void process(
125 final WriteableCommandLine commandLine, final ListIterator arguments )
126 throws OptionException
127 {
128 final String arg = (String) arguments.next();
129
130 if( !canProcess( commandLine, arg ) )
131 {
132 throw new OptionException(
133 this,
134 ResourceConstants.UNEXPECTED_TOKEN,
135 arg );
136 }
137
138 final int propertyStart = m_optionString.length();
139 final int equalsIndex = arg.indexOf( '=', propertyStart );
140 final String property;
141 final String value;
142
143 if( equalsIndex < 0 )
144 {
145 property = arg.substring( propertyStart );
146 value = "true";
147 }
148 else
149 {
150 property = arg.substring( propertyStart, equalsIndex );
151 value = arg.substring( equalsIndex + 1 );
152 }
153 commandLine.addProperty( property, value );
154 }
155
156 /**
157 * Identifies the argument prefixes that should trigger this option. This
158 * is used to decide which of many Options should be tried when processing
159 * a given argument string.
160 *
161 * The returned Set must not be null.
162 *
163 * @return The set of triggers for this Option
164 */
165 public Set getTriggers()
166 {
167 return Collections.singleton( m_optionString );
168 }
169
170 /**
171 * Checks that the supplied CommandLine is valid with respect to this
172 * option.
173 *
174 * @param commandLine the CommandLine to check.
175 * @throws OptionException if the CommandLine is not valid.
176 */
177 public void validate( WriteableCommandLine commandLine ) throws OptionException
178 {
179 // PropertyOption needs no validation
180 }
181
182 /**
183 * Appends usage information to the specified StringBuffer
184 *
185 * @param buffer the buffer to append to
186 * @param helpSettings a set of display settings @see DisplaySetting
187 * @param comp a comparator used to sort the Options
188 */
189 public void appendUsage(
190 final StringBuffer buffer, final Set helpSettings, final Comparator comp )
191 {
192 final boolean display = helpSettings.contains( DisplaySetting.DISPLAY_PROPERTY_OPTION );
193 final boolean bracketed = helpSettings.contains( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
194
195 if( display )
196 {
197 buffer.append( m_optionString );
198 if( bracketed )
199 {
200 buffer.append( '<' );
201 }
202 buffer.append( "property" );
203 if( bracketed )
204 {
205 buffer.append( '>' );
206 }
207 buffer.append( "=" );
208 if( bracketed )
209 {
210 buffer.append( '<' );
211 }
212 buffer.append( "value" );
213 if( bracketed )
214 {
215 buffer.append( '>' );
216 }
217 }
218 }
219
220 /**
221 * The preferred name of an option is used for generating help and usage
222 * information.
223 *
224 * @return The preferred name of the option
225 */
226 public String getPreferredName()
227 {
228 return m_optionString;
229 }
230
231 /**
232 * Returns a description of the option. This string is used to build help
233 * messages as in the HelpFormatter.
234 *
235 * @see net.dpml.cli.util.HelpFormatter
236 * @return a description of the option.
237 */
238 public String getDescription()
239 {
240 return m_description;
241 }
242
243 /**
244 * Builds up a list of HelpLineImpl instances to be presented by HelpFormatter.
245 *
246 * @see HelpLine
247 * @see net.dpml.cli.util.HelpFormatter
248 * @param depth the initial indent depth
249 * @param helpSettings the HelpSettings that should be applied
250 * @param comp a comparator used to sort options when applicable.
251 * @return a List of HelpLineImpl objects
252 */
253 public List helpLines(
254 final int depth, final Set helpSettings, final Comparator comp )
255 {
256 if( helpSettings.contains( DisplaySetting.DISPLAY_PROPERTY_OPTION ) )
257 {
258 final HelpLine helpLine = new HelpLineImpl( this, depth );
259 return Collections.singletonList( helpLine );
260 }
261 else
262 {
263 return Collections.EMPTY_LIST;
264 }
265 }
266 }