001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 */ 017package org.apache.commons.cli2.commandline; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.Iterator; 023import java.util.List; 024import java.util.Map; 025import java.util.Properties; 026import java.util.Set; 027 028import org.apache.commons.cli2.Argument; 029import org.apache.commons.cli2.Option; 030import org.apache.commons.cli2.WriteableCommandLine; 031import org.apache.commons.cli2.option.PropertyOption; 032import org.apache.commons.cli2.resource.ResourceConstants; 033import org.apache.commons.cli2.resource.ResourceHelper; 034 035/** 036 * A WriteableCommandLine implementation allowing Options to write their 037 * processed information to a CommandLine. 038 */ 039public class WriteableCommandLineImpl 040 extends CommandLineImpl implements WriteableCommandLine { 041 private final Map optionToProperties = new HashMap(); 042// private final Properties properties = new Properties(); 043 private final List options = new ArrayList(); 044 private final Map nameToOption = new HashMap(); 045 private final Map values = new HashMap(); 046 private final Map switches = new HashMap(); 047 private final Map defaultValues = new HashMap(); 048 private final Map defaultSwitches = new HashMap(); 049 private final List normalised; 050 private final Set prefixes; 051 private Option currentOption; 052 private String checkForOption; 053 054 /** 055 * Creates a new WriteableCommandLineImpl rooted on the specified Option, to 056 * hold the parsed arguments. 057 * 058 * @param rootOption the CommandLine's root Option 059 * @param arguments the arguments this CommandLine represents 060 */ 061 public WriteableCommandLineImpl(final Option rootOption, 062 final List arguments) { 063 this.prefixes = rootOption.getPrefixes(); 064 this.normalised = arguments; 065 setCurrentOption(rootOption); 066 } 067 068 public Option getCurrentOption() { 069 return currentOption; 070 } 071 072 public void setCurrentOption(Option currentOption) { 073 this.currentOption = currentOption; 074 } 075 076 public void addOption(Option option) { 077 options.add(option); 078 nameToOption.put(option.getPreferredName(), option); 079 080 for (Iterator i = option.getTriggers().iterator(); i.hasNext();) { 081 nameToOption.put(i.next(), option); 082 } 083 084 // ensure that all parent options are also added 085 Option parent = option.getParent(); 086 while (parent != null && !options.contains(parent)) { 087 options.add(parent); 088 parent = parent.getParent(); 089 } 090 } 091 092 public void addValue(final Option option, 093 final Object value) { 094 if (option instanceof Argument) { 095 addOption(option); 096 } 097 098 List valueList = (List) values.get(option); 099 100 if (valueList == null) { 101 valueList = new ArrayList(); 102 values.put(option, valueList); 103 } 104 105 valueList.add(value); 106 } 107 108 public void addSwitch(final Option option, 109 final boolean value) { 110 addOption(option); 111 112 if (switches.containsKey(option)) { 113 throw new IllegalStateException(ResourceHelper.getResourceHelper().getMessage(ResourceConstants.SWITCH_ALREADY_SET)); 114 } else { 115 switches.put(option, value ? Boolean.TRUE : Boolean.FALSE); 116 } 117 } 118 119 public boolean hasOption(final Option option) { 120 final boolean present = options.contains(option); 121 122 return present; 123 } 124 125 public Option getOption(final String trigger) { 126 return (Option) nameToOption.get(trigger); 127 } 128 129 public List getValues(final Option option, 130 List defaultValues) { 131 // initialize the return list 132 List valueList = (List) values.get(option); 133 134 // grab the correct default values 135 if (defaultValues == null || defaultValues.isEmpty()) { 136 defaultValues = (List) this.defaultValues.get(option); 137 } 138 139 // augment the list with the default values 140 if (defaultValues != null && !defaultValues.isEmpty()) { 141 if (valueList == null || valueList.isEmpty()) { 142 valueList = defaultValues; 143 } else { 144 // if there are more default values as specified, add them to 145 // the list. 146 if (defaultValues.size() > valueList.size()) { 147 // copy the list first 148 valueList = new ArrayList(valueList); 149 for (int i=valueList.size(); i<defaultValues.size(); i++) { 150 valueList.add(defaultValues.get(i)); 151 } 152 } 153 } 154 } 155 156 return valueList == null ? Collections.EMPTY_LIST : valueList; 157 } 158 159 public List getUndefaultedValues(Option option) { 160 // First grab the command line values 161 List valueList = (List) values.get(option); 162 163 // Finally use an empty list 164 if (valueList == null) { 165 valueList = Collections.EMPTY_LIST; 166 } 167 168 return valueList; 169 } 170 171 public Boolean getSwitch(final Option option, 172 final Boolean defaultValue) { 173 // First grab the command line values 174 Boolean bool = (Boolean) switches.get(option); 175 176 // Secondly try the defaults supplied to the method 177 if (bool == null) { 178 bool = defaultValue; 179 } 180 181 // Thirdly try the option's default values 182 if (bool == null) { 183 bool = (Boolean) this.defaultSwitches.get(option); 184 } 185 186 return bool; 187 } 188 189 public String getProperty(final String property) { 190 return getProperty(new PropertyOption(), property); 191 } 192 193 public void addProperty(final Option option, 194 final String property, 195 final String value) { 196 Properties properties = (Properties) optionToProperties.get(option); 197 if (properties == null) { 198 properties = new Properties(); 199 optionToProperties.put(option, properties); 200 } 201 properties.setProperty(property, value); 202 } 203 204 public void addProperty(final String property, final String value) { 205 addProperty(new PropertyOption(), property, value); 206 } 207 208 public String getProperty(final Option option, 209 final String property, 210 final String defaultValue) { 211 Properties properties = (Properties) optionToProperties.get(option); 212 if (properties == null) { 213 return defaultValue; 214 } 215 return properties.getProperty(property, defaultValue); 216 } 217 218 public Set getProperties(final Option option) { 219 Properties properties = (Properties) optionToProperties.get(option); 220 if (properties == null) { 221 return Collections.EMPTY_SET; 222 } 223 return Collections.unmodifiableSet(properties.keySet()); 224 } 225 226 public Set getProperties() { 227 return getProperties(new PropertyOption()); 228 } 229 230 /** 231 * Tests whether the passed in trigger looks like an option. This 232 * implementation first checks whether the passed in string starts with a 233 * prefix that indicates an option. If this is the case, it is also checked 234 * whether an option of this name is known for the current option. (This can 235 * lead to reentrant invocations of this method, so care has to be taken 236 * about this.) 237 * 238 * @param trigger the command line element to test 239 * @return a flag whether this element seems to be an option 240 */ 241 public boolean looksLikeOption(final String trigger) 242 { 243 if (checkForOption != null) 244 { 245 // this is a reentrant call 246 return !checkForOption.equals(trigger); 247 } 248 249 checkForOption = trigger; 250 try 251 { 252 for (final Iterator i = prefixes.iterator(); i.hasNext();) 253 { 254 final String prefix = (String) i.next(); 255 256 if (trigger.startsWith(prefix)) 257 { 258 if (getCurrentOption().canProcess(this, trigger) 259 || getCurrentOption().findOption(trigger) != null) 260 { 261 return true; 262 } 263 } 264 } 265 266 return false; 267 } 268 finally 269 { 270 checkForOption = null; 271 } 272 } 273 274 public String toString() { 275 final StringBuffer buffer = new StringBuffer(); 276 277 // need to add group header 278 for (final Iterator i = normalised.iterator(); i.hasNext();) { 279 final String arg = (String) i.next(); 280 281 if (arg.indexOf(' ') >= 0) { 282 buffer.append("\"").append(arg).append("\""); 283 } else { 284 buffer.append(arg); 285 } 286 287 if (i.hasNext()) { 288 buffer.append(' '); 289 } 290 } 291 292 return buffer.toString(); 293 } 294 295 public List getOptions() { 296 return Collections.unmodifiableList(options); 297 } 298 299 public Set getOptionTriggers() { 300 return Collections.unmodifiableSet(nameToOption.keySet()); 301 } 302 303 public void setDefaultValues(final Option option, 304 final List defaults) { 305 if (defaults == null) { 306 defaultValues.remove(option); 307 } else { 308 defaultValues.put(option, defaults); 309 } 310 } 311 312 public void setDefaultSwitch(final Option option, 313 final Boolean defaultSwitch) { 314 if (defaultSwitch == null) { 315 defaultSwitches.remove(option); 316 } else { 317 defaultSwitches.put(option, defaultSwitch); 318 } 319 } 320 321 public List getNormalised() { 322 return Collections.unmodifiableList(normalised); 323 } 324}