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;
034import 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 */
042public 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}