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.option; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.Comparator; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.List; 025import java.util.ListIterator; 026import java.util.Set; 027 028import org.apache.commons.cli2.Argument; 029import org.apache.commons.cli2.DisplaySetting; 030import org.apache.commons.cli2.Group; 031import org.apache.commons.cli2.OptionException; 032import org.apache.commons.cli2.WriteableCommandLine; 033import org.apache.commons.cli2.resource.ResourceConstants; 034 035/** 036 * A Parent implementation representing normal options. 037 */ 038public class DefaultOption 039 extends ParentImpl { 040 /** 041 * The default token used to prefix a short option 042 */ 043 public static final String DEFAULT_SHORT_PREFIX = "-"; 044 045 /** 046 * The default token used to prefix a long option 047 */ 048 public static final String DEFAULT_LONG_PREFIX = "--"; 049 050 /** 051 * The default value for the burstEnabled constructor parameter 052 */ 053 public static final boolean DEFAULT_BURST_ENABLED = true; 054 private final String preferredName; 055 private final Set aliases; 056 private final Set burstAliases; 057 private final Set triggers; 058 private final Set prefixes; 059 private final String shortPrefix; 060 private final boolean burstEnabled; 061 private final int burstLength; 062 063 /** 064 * Creates a new DefaultOption 065 * 066 * @param shortPrefix the prefix used for short options 067 * @param longPrefix the prefix used for long options 068 * @param burstEnabled should option bursting be enabled 069 * @param preferredName the preferred name for this Option, this should begin with either shortPrefix or longPrefix 070 * @param description a description of this Option 071 * @param aliases the alternative names for this Option 072 * @param burstAliases the aliases that can be burst 073 * @param required whether the Option is strictly required 074 * @param argument the Argument belonging to this Parent, or null 075 * @param children the Group children belonging to this Parent, ot null 076 * @param id the unique identifier for this Option 077 * @throws IllegalArgumentException if the preferredName or an alias isn't 078 * prefixed with shortPrefix or longPrefix 079 */ 080 public DefaultOption(final String shortPrefix, 081 final String longPrefix, 082 final boolean burstEnabled, 083 final String preferredName, 084 final String description, 085 final Set aliases, 086 final Set burstAliases, 087 final boolean required, 088 final Argument argument, 089 final Group children, 090 final int id) { 091 super(argument, children, description, id, required); 092 093 this.shortPrefix = shortPrefix; 094 this.burstEnabled = burstEnabled; 095 096 this.burstLength = shortPrefix.length() + 1; 097 098 this.preferredName = preferredName; 099 this.aliases = 100 (aliases == null) ? Collections.EMPTY_SET 101 : Collections.unmodifiableSet(new HashSet(aliases)); 102 103 this.burstAliases = 104 (burstAliases == null) ? Collections.EMPTY_SET 105 : Collections.unmodifiableSet(new HashSet(burstAliases)); 106 107 final Set newTriggers = new HashSet(); 108 newTriggers.add(preferredName); 109 newTriggers.addAll(this.aliases); 110 newTriggers.addAll(this.burstAliases); 111 this.triggers = Collections.unmodifiableSet(newTriggers); 112 113 final Set newPrefixes = new HashSet(super.getPrefixes()); 114 newPrefixes.add(shortPrefix); 115 newPrefixes.add(longPrefix); 116 this.prefixes = Collections.unmodifiableSet(newPrefixes); 117 118 checkPrefixes(newPrefixes); 119 } 120 121 public boolean canProcess(final WriteableCommandLine commandLine, 122 final String argument) { 123 return (argument != null) && 124 (super.canProcess(commandLine, argument) || 125 ((argument.length() >= burstLength) && 126 burstAliases.contains(argument.substring(0, burstLength)))); 127 } 128 129 public void processParent(WriteableCommandLine commandLine, 130 ListIterator arguments) 131 throws OptionException { 132 final String argument = (String) arguments.next(); 133 134 if (triggers.contains(argument)) { 135 commandLine.addOption(this); 136 arguments.set(preferredName); 137 } else if (burstEnabled && (argument.length() >= burstLength)) { 138 final String burst = argument.substring(0, burstLength); 139 140 if (burstAliases.contains(burst)) { 141 commandLine.addOption(this); 142 143 //HMM test bursting all vs bursting one by one. 144 arguments.set(preferredName); 145 146 if (getArgument() == null) { 147 arguments.add(shortPrefix + argument.substring(burstLength)); 148 } else { 149 arguments.add(argument.substring(burstLength)); 150 } 151 152 arguments.previous(); 153 } else { 154 throw new OptionException(this, ResourceConstants.CANNOT_BURST, argument); 155 } 156 } else { 157 throw new OptionException(this, ResourceConstants.UNEXPECTED_TOKEN, argument); 158 } 159 } 160 161 public Set getTriggers() { 162 return triggers; 163 } 164 165 public Set getPrefixes() { 166 return prefixes; 167 } 168 169 public void validate(WriteableCommandLine commandLine) 170 throws OptionException { 171 if (isRequired() && !commandLine.hasOption(this)) { 172 throw new OptionException(this, ResourceConstants.OPTION_MISSING_REQUIRED, 173 getPreferredName()); 174 } 175 176 super.validate(commandLine); 177 } 178 179 public void appendUsage(final StringBuffer buffer, 180 final Set helpSettings, 181 final Comparator comp) { 182 // do we display optionality 183 final boolean optional = 184 !isRequired() && helpSettings.contains(DisplaySetting.DISPLAY_OPTIONAL); 185 final boolean displayAliases = helpSettings.contains(DisplaySetting.DISPLAY_ALIASES); 186 187 if (optional) { 188 buffer.append('['); 189 } 190 191 buffer.append(preferredName); 192 193 if (displayAliases && !aliases.isEmpty()) { 194 buffer.append(" ("); 195 196 final List list = new ArrayList(aliases); 197 Collections.sort(list); 198 199 for (final Iterator i = list.iterator(); i.hasNext();) { 200 final String alias = (String) i.next(); 201 buffer.append(alias); 202 203 if (i.hasNext()) { 204 buffer.append(','); 205 } 206 } 207 208 buffer.append(')'); 209 } 210 211 super.appendUsage(buffer, helpSettings, comp); 212 213 if (optional) { 214 buffer.append(']'); 215 } 216 } 217 218 public String getPreferredName() { 219 return preferredName; 220 } 221}