1c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair/*
2c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * Copyright 20078 the original author or authors.
3c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair *
4c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * Licensed under the Apache License, Version 2.0 (the "License");
5c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * you may not use this file except in compliance with the License.
6c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * You may obtain a copy of the License at
7c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair *
8c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair *      http://www.apache.org/licenses/LICENSE-2.0
9c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair *
10c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * Unless required by applicable law or agreed to in writing, software
11c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * distributed under the License is distributed on an "AS IS" BASIS,
12c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * See the License for the specific language governing permissions and
14c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * limitations under the License.
15c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair */
16c1de24f1bfa6699e54b069e300af5e4246b34a34chrismairpackage org.mockftpserver.core.command;
17c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
18c1de24f1bfa6699e54b069e300af5e4246b34a34chrismairimport org.mockftpserver.core.CommandSyntaxException;
19c1de24f1bfa6699e54b069e300af5e4246b34a34chrismairimport org.mockftpserver.core.util.Assert;
20c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
21c1de24f1bfa6699e54b069e300af5e4246b34a34chrismairimport java.util.Arrays;
22c1de24f1bfa6699e54b069e300af5e4246b34a34chrismairimport java.util.List;
23c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
24c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair/**
25c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * Represents a command received from an FTP client, containing a command name and parameters.
26c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * Objects of this class are immutable.
27c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair *
28c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * @author Chris Mair
29c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair * @version $Revision$ - $Date$
30c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair */
31c1de24f1bfa6699e54b069e300af5e4246b34a34chrismairpublic final class Command {
32c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
33c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    private String name;
34c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    private String[] parameters;
35c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
36c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
37c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Construct a new immutable instance with the specified command name and parameters
38c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
39c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param name       - the command name; may not be null
40c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param parameters - the command parameters; may be empty; may not be null
41c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
42c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public Command(String name, String[] parameters) {
43c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        Assert.notNull(name, "name");
44c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        Assert.notNull(parameters, "parameters");
45c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        this.name = name;
46c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        this.parameters = copy(parameters);
47c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
48c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
49c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
50c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Construct a new immutable instance with the specified command name and parameters
51c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
52c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param name       - the command name; may not be null
53c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param parameters - the command parameters; may be empty; may not be null
54c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
55c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public Command(String name, List parameters) {
56c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        this(name, (String[]) parameters.toArray(new String[parameters.size()]));
57c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
58c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
59c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
60c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return the name
61c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
62c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public String getName() {
63c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return name;
64c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
65c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
66c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
67c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return the parameters
68c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
69c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public String[] getParameters() {
70c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return copy(parameters);
71c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
72c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
73c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
74c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Get the String value of the parameter at the specified index
75c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
76c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param index - the index
77c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return the parameter value as a String
78c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @throws org.mockftpserver.core.util.AssertFailedException
79c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *          if the parameter index is invalid or the value is not a valid String
80c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
81c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public String getRequiredParameter(int index) {
82c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        assertValidIndex(index);
83c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return parameters[index];
84c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
85c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
86c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
87c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Get the String value of the parameter at the specified index; return null if no parameter exists for the index
88c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
89c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param index - the index
90c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return the parameter value as a String, or null if this Command does not have a parameter for that index
91c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
92c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public String getParameter(int index) {
93c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return (parameters.length > index) ? parameters[index] : null;
94c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
95c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
96c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
97c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Get the String value of the parameter at the specified index; return null if no
98c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * parameter exists for the index. This is an alias for {@link #getParameter(int)}.
99c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
100c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param index - the index
101c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return the parameter value as a String, or null if this Command does not have a parameter for that index
102c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
103c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public String getOptionalString(int index) {
104c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return getParameter(index);
105c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
106c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
107c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
108c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @see java.lang.Object#equals(java.lang.Object)
109c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
110c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public boolean equals(Object obj) {
111c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        if (this == obj) {
112c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair            return true;
113c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        }
114c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        if (obj == null || !(obj instanceof Command)) {
115c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair            return false;
116c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        }
117c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return this.hashCode() == obj.hashCode();
118c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
119c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
120c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
121c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @see java.lang.Object#hashCode()
122c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
123c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public int hashCode() {
124c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        String str = name + Arrays.asList(parameters);
125c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return str.hashCode();
126c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
127c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
128c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
129c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Return the String representation of this object
130c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
131c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @see java.lang.Object#toString()
132c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
133c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public String toString() {
134c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return "Command[" + name + ":" + Arrays.asList(parameters) + "]";
135c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
136c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
137c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
138c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Return the name, normalized to a common format - convert to upper case.
139c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
140c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return the name converted to upper case
141c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
142c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    public static String normalizeName(String name) {
143c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return name.toUpperCase();
144c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
145c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
146c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
147c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Construct a shallow copy of the specified array
148c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
149c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param array - the array to copy
150c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @return a new array with the same contents
151c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
152c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    private static String[] copy(String[] array) {
153c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        String[] newArray = new String[array.length];
154c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        System.arraycopy(array, 0, newArray, 0, array.length);
155c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        return newArray;
156c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
157c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
158c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    /**
159c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * Assert that the index is valid
160c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *
161c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @param index - the index
162c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     * @throws org.mockftpserver.core.CommandSyntaxException
163c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     *          - if the parameter index is invalid
164c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair     */
165c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    private void assertValidIndex(int index) {
166c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        if (index < 0 || index >= parameters.length) {
167c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair            throw new CommandSyntaxException("The parameter index " + index + " is not valid for " + this);
168c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair        }
169c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair    }
170c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair
171c1de24f1bfa6699e54b069e300af5e4246b34a34chrismair}
172