12ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair/*
22ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * Copyright 2007 the original author or authors.
32ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair *
42ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * Licensed under the Apache License, Version 2.0 (the "License");
52ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * you may not use this file except in compliance with the License.
62ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * You may obtain a copy of the License at
72ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair *
82ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair *      http://www.apache.org/licenses/LICENSE-2.0
92ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair *
102ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * Unless required by applicable law or agreed to in writing, software
112ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * distributed under the License is distributed on an "AS IS" BASIS,
122ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * See the License for the specific language governing permissions and
142ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * limitations under the License.
152ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair */
162ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairpackage org.mockftpserver.core.command;
172ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
182ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport org.mockftpserver.core.util.Assert;
192ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport org.mockftpserver.core.util.AssertFailedException;
202ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
212ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport java.net.InetAddress;
222ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport java.util.Collections;
232ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport java.util.Date;
242ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport java.util.HashMap;
252ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport java.util.Map;
262ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairimport java.util.Set;
272ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
282ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair/**
292ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * Represents information about a single FTP Command invocation. Manages and provides access to
302ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * the Command, the host address (<code>InetAddress</code>) of the client that submitted the
312ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * Command and the timestamp of the Command submission.
322ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * <p>
332ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * This class also supports storing zero or more arbitrary mappings of <i>key</i> to value, where <i>key</i> is
342ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * a String and <i>value</i> is any Object. Convenience methods are provided that enable retrieving
352ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * type-specific data by its <i>key</i>. The data stored in an {@link InvocationRecord} is CommandHandler-specific.
362ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * <p>
372ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * The {@link #lock()} method makes an instance of this class immutable. After an instance is locked,
382ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * calling the {@link #set(String, Object)} method will throw an <code>AssertFailedException</code>.
392ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair *
402ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * @author Chris Mair
412ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair * @version $Revision$ - $Date$
422ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair */
432ab05e83458f35931075adca0d7b0fce4ea7cccbchrismairpublic class InvocationRecord {
442ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
452ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    private Command command;
462ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    private Date time;
472ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    private InetAddress clientHost;
482ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    private Map data = new HashMap();
492ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    private boolean locked = false;
502ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
512ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
522ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Create a new instance
532ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
542ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param command    - the Command
552ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param clientHost - the client host
562ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
572ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public InvocationRecord(Command command, InetAddress clientHost) {
582ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        this.command = command;
592ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        this.time = new Date();
602ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        this.clientHost = clientHost;
612ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
622ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
632ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
642ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Lock this instance, making it immutable. After an instance is locked,
652ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * calling the {@link #set(String, Object)} method will throw an
662ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * <code>AssertFailedException</code>.
672ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
682ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public void lock() {
692ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        locked = true;
702ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
712ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
722ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
732ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Return true if this object has been locked, false otherwise. See {@link #lock()}.
742ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
752ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return true if this object has been locked, false otherwise.
762ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
772ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public boolean isLocked() {
782ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return locked;
792ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
802ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
812ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
822ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return the client host that submitted the command, as an InetAddress
832ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
842ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public InetAddress getClientHost() {
852ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return clientHost;
862ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
872ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
882ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
892ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return the Command
902ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
912ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public Command getCommand() {
922ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return command;
932ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
942ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
952ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
962ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return the time that the command was processed; this may differ slightly from when the command was received.
972ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
982ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public Date getTime() {
992ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        // Return a copy of the Date object to preserve immutability
1002ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return new Date(time.getTime());
1012ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1022ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
1032ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
1042ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Store the value for the specified key. If this object already contained a mapping
1052ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * for this key, the old value is replaced by the specified value. This method throws
1062ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * an <code>AssertFailedException</code> if this object has been locked. See {@link #lock()}.
1072ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
1082ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param key   - the key; must not be null
1092ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param value - the value to store for the specified key
1102ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @throws AssertFailedException - if the key is null or this object has been locked.
1112ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
1122ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public void set(String key, Object value) {
1132ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        Assert.notNull(key, "key");
1142ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        Assert.isFalse(locked, "The InvocationRecord is locked!");
1152ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        data.put(key, value);
1162ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1172ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
1182ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
1192ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Returns <code>true</code> if this object contains a mapping for the specified key.
1202ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
1212ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param key - the key; must not be null
1222ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return <code>true</code> if there is a mapping for the key
1232ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @throws AssertFailedException - if the key is null
1242ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
1252ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public boolean containsKey(String key) {
1262ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        Assert.notNull(key, "key");
1272ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return data.containsKey(key);
1282ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1292ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
1302ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
1312ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Returns a Set view of the keys for the data stored in this object.
1322ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Changes to the returned Set have no effect on the data stored within this object
1332ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * .
1342ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
1352ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return the Set of keys for the data stored within this object
1362ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
1372ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public Set keySet() {
1382ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return Collections.unmodifiableSet(data.keySet());
1392ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1402ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
1412ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
1422ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Get the String value associated with the specified key. Returns null if there is
1432ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * no mapping for this key. A return value of null does not necessarily indicate that
1442ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * this object contains no mapping for the key; it's also possible that the value was
1452ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * explicitly set to null for the key. The containsKey operation may be used to
1462ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * distinguish these two cases.
1472ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
1482ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param key - the key; must not be null
1492ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return the String data stored at the specified key; may be null
1502ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @throws ClassCastException    - if the object for the specified key is not a String
1512ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @throws AssertFailedException - if the key is null
1522ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
1532ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public String getString(String key) {
1542ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        Assert.notNull(key, "key");
1552ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return (String) data.get(key);
1562ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1572ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
1582ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
1592ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Get the Object value associated with the specified key. Returns null if there is
1602ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * no mapping for this key. A return value of null does not necessarily indicate that
1612ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * this object contains no mapping for the key; it's also possible that the value was
1622ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * explicitly set to null for the key. The containsKey operation may be used to
1632ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * distinguish these two cases.
1642ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
1652ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @param key - the key; must not be null
1662ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @return the data stored at the specified key, as an Object; may be null
1672ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @throws AssertFailedException - if the key is null
1682ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
1692ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public Object getObject(String key) {
1702ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        Assert.notNull(key, "key");
1712ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return data.get(key);
1722ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1732ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair
1742ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    /**
1752ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * Return the String representation of this object
1762ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     *
1772ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     * @see java.lang.Object#toString()
1782ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair     */
1792ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    public String toString() {
1802ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair        return "InvocationRecord[time=" + time + " client-host=" + clientHost + " command=" + command + " data=" + data + "]";
1812ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair    }
1822ab05e83458f35931075adca0d7b0fce4ea7cccbchrismair}
183