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     */
017    package org.apache.commons.cli2.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 org.apache.commons.cli2.Argument;
029    import org.apache.commons.cli2.DisplaySetting;
030    import org.apache.commons.cli2.Group;
031    import org.apache.commons.cli2.OptionException;
032    import org.apache.commons.cli2.WriteableCommandLine;
033    import org.apache.commons.cli2.resource.ResourceConstants;
034    import org.apache.commons.cli2.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    public class Command
043        extends ParentImpl {
044        /** The display name for the command */
045        private final String preferredName;
046    
047        /** The aliases for this command */
048        private final Set aliases;
049    
050        /** All the names for this command */
051        private final Set triggers;
052    
053        /**
054         * Creates a new Command instance.
055         *
056         * @param preferredName
057         *            The name normally used to refer to the Command
058         * @param description
059         *            A description of the Command
060         * @param aliases
061         *            Alternative names for the Command
062         * @param required
063         *            Whether the Command is required
064         * @param argument
065         *            An Argument that the command takes
066         * @param children
067         *            The Group of child options for this Command
068         * @param id
069         *            A unique id for the Command
070         *
071         * @see ParentImpl#ParentImpl(Argument, Group, String, int, boolean)
072         */
073        public Command(final String preferredName,
074                       final String description,
075                       final Set aliases,
076                       final boolean required,
077                       final Argument argument,
078                       final Group children,
079                       final int id) {
080            super(argument, children, description, id, required);
081    
082            // check the preferred name is valid
083            if ((preferredName == null) || (preferredName.length() < 1)) {
084                throw new IllegalArgumentException(ResourceHelper.getResourceHelper().getMessage(ResourceConstants.COMMAND_PREFERRED_NAME_TOO_SHORT));
085            }
086    
087            this.preferredName = preferredName;
088    
089            // gracefully and defensively handle aliases
090            this.aliases =
091                (aliases == null) ? Collections.EMPTY_SET
092                                  : Collections.unmodifiableSet(new HashSet(aliases));
093    
094            // populate the triggers Set
095            final Set newTriggers = new HashSet();
096            newTriggers.add(preferredName);
097            newTriggers.addAll(this.aliases);
098            this.triggers = Collections.unmodifiableSet(newTriggers);
099        }
100    
101        public void processParent(final WriteableCommandLine commandLine,
102                                  final ListIterator arguments)
103            throws OptionException {
104            // grab the argument to process
105            final String arg = (String) arguments.next();
106    
107            // if we can process it
108            if (canProcess(commandLine, arg)) {
109                // then note the option
110                commandLine.addOption(this);
111    
112                // normalise the argument list
113                arguments.set(preferredName);
114            } else {
115                throw new OptionException(this, ResourceConstants.UNEXPECTED_TOKEN, arg);
116            }
117        }
118    
119        public Set getTriggers() {
120            return triggers;
121        }
122    
123        public void validate(WriteableCommandLine commandLine)
124            throws OptionException {
125            if (isRequired() && !commandLine.hasOption(this)) {
126                throw new OptionException(this, ResourceConstants.OPTION_MISSING_REQUIRED,
127                                          getPreferredName());
128            }
129    
130            super.validate(commandLine);
131        }
132    
133        public void appendUsage(final StringBuffer buffer,
134                                final Set helpSettings,
135                                final Comparator comp) {
136            // do we display optionality
137            final boolean optional =
138                !isRequired() && helpSettings.contains(DisplaySetting.DISPLAY_OPTIONAL);
139            final boolean displayAliases = helpSettings.contains(DisplaySetting.DISPLAY_ALIASES);
140    
141            if (optional) {
142                buffer.append('[');
143            }
144    
145            buffer.append(preferredName);
146    
147            if (displayAliases && !aliases.isEmpty()) {
148                buffer.append(" (");
149    
150                final List list = new ArrayList(aliases);
151                Collections.sort(list);
152    
153                for (final Iterator i = list.iterator(); i.hasNext();) {
154                    final String alias = (String) i.next();
155                    buffer.append(alias);
156    
157                    if (i.hasNext()) {
158                        buffer.append(',');
159                    }
160                }
161    
162                buffer.append(')');
163            }
164    
165            super.appendUsage(buffer, helpSettings, comp);
166    
167            if (optional) {
168                buffer.append(']');
169            }
170        }
171    
172        public String getPreferredName() {
173            return preferredName;
174        }
175    }