160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair/*
260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Copyright 2007 the original author or authors.
360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Licensed under the Apache License, Version 2.0 (the "License");
560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * you may not use this file except in compliance with the License.
660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * You may obtain a copy of the License at
760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *      http://www.apache.org/licenses/LICENSE-2.0
960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
1060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Unless required by applicable law or agreed to in writing, software
1160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * distributed under the License is distributed on an "AS IS" BASIS,
1260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * See the License for the specific language governing permissions and
1460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * limitations under the License.
1560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair */
1660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairpackage org.mockftpserver.core.command;
1760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
1860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport org.mockftpserver.core.util.Assert;
1960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport org.mockftpserver.core.util.AssertFailedException;
2060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
2160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.net.InetAddress;
2260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.util.Collections;
2360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.util.Date;
2460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.util.HashMap;
2560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.util.Map;
2660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.util.Set;
2760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
2860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair/**
2960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Represents information about a single FTP Command invocation. Manages and provides access to
3060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * the Command, the host address (<code>InetAddress</code>) of the client that submitted the
3160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Command and the timestamp of the Command submission.
3260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p>
3360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * This class also supports storing zero or more arbitrary mappings of <i>key</i> to value, where <i>key</i> is
3460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * a String and <i>value</i> is any Object. Convenience methods are provided that enable retrieving
3560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * type-specific data by its <i>key</i>. The data stored in an {@link InvocationRecord} is CommandHandler-specific.
3660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p>
3760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * The {@link #lock()} method makes an instance of this class immutable. After an instance is locked,
3860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * calling the {@link #set(String, Object)} method will throw an <code>AssertFailedException</code>.
3960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
4060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * @author Chris Mair
4160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * @version $Revision$ - $Date$
4260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair */
4360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairpublic class InvocationRecord {
4460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
4560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private Command command;
4660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private Date time;
4760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private InetAddress clientHost;
4860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private Map data = new HashMap();
4960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private boolean locked = false;
5060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
5160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
5260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Create a new instance
5360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
5460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param command    - the Command
5560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param clientHost - the client host
5660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
5760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public InvocationRecord(Command command, InetAddress clientHost) {
5860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.command = command;
5960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.time = new Date();
6060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.clientHost = clientHost;
6160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
6260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
6360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
6460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Lock this instance, making it immutable. After an instance is locked,
6560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * calling the {@link #set(String, Object)} method will throw an
6660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * <code>AssertFailedException</code>.
6760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
6860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void lock() {
6960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        locked = true;
7060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
7160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
7260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
7360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true if this object has been locked, false otherwise. See {@link #lock()}.
7460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
7560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if this object has been locked, false otherwise.
7660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
7760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean isLocked() {
7860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return locked;
7960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
8060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
8160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
8260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the client host that submitted the command, as an InetAddress
8360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
8460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public InetAddress getClientHost() {
8560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return clientHost;
8660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
8760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
8860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
8960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the Command
9060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
9160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public Command getCommand() {
9260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return command;
9360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
9460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
9560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
9660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the time that the command was processed; this may differ slightly from when the command was received.
9760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
9860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public Date getTime() {
9960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        // Return a copy of the Date object to preserve immutability
10060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return new Date(time.getTime());
10160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
10260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
10360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
10460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Store the value for the specified key. If this object already contained a mapping
10560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * for this key, the old value is replaced by the specified value. This method throws
10660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * an <code>AssertFailedException</code> if this object has been locked. See {@link #lock()}.
10760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
10860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param key   - the key; must not be null
10960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param value - the value to store for the specified key
11060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @throws AssertFailedException - if the key is null or this object has been locked.
11160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
11260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void set(String key, Object value) {
11360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Assert.notNull(key, "key");
11460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Assert.isFalse(locked, "The InvocationRecord is locked!");
11560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        data.put(key, value);
11660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
11760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
11860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
11960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Returns <code>true</code> if this object contains a mapping for the specified key.
12060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
12160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param key - the key; must not be null
12260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return <code>true</code> if there is a mapping for the key
12360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @throws AssertFailedException - if the key is null
12460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
12560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean containsKey(String key) {
12660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Assert.notNull(key, "key");
12760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return data.containsKey(key);
12860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
12960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
13060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
13160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Returns a Set view of the keys for the data stored in this object.
13260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Changes to the returned Set have no effect on the data stored within this object
13360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * .
13460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
13560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the Set of keys for the data stored within this object
13660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
13760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public Set keySet() {
13860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return Collections.unmodifiableSet(data.keySet());
13960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
14060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
14160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
14260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Get the String value associated with the specified key. Returns null if there is
14360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * no mapping for this key. A return value of null does not necessarily indicate that
14460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * this object contains no mapping for the key; it's also possible that the value was
14560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * explicitly set to null for the key. The containsKey operation may be used to
14660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * distinguish these two cases.
14760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
14860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param key - the key; must not be null
14960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the String data stored at the specified key; may be null
15060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @throws ClassCastException    - if the object for the specified key is not a String
15160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @throws AssertFailedException - if the key is null
15260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
15360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String getString(String key) {
15460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Assert.notNull(key, "key");
15560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return (String) data.get(key);
15660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
15760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
15860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
15960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Get the Object value associated with the specified key. Returns null if there is
16060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * no mapping for this key. A return value of null does not necessarily indicate that
16160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * this object contains no mapping for the key; it's also possible that the value was
16260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * explicitly set to null for the key. The containsKey operation may be used to
16360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * distinguish these two cases.
16460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
16560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param key - the key; must not be null
16660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the data stored at the specified key, as an Object; may be null
16760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @throws AssertFailedException - if the key is null
16860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
16960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public Object getObject(String key) {
17060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Assert.notNull(key, "key");
17160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return data.get(key);
17260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
17360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
17460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
17560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return the String representation of this object
17660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
17760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @see java.lang.Object#toString()
17860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
17960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String toString() {
18060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return "InvocationRecord[time=" + time + " client-host=" + clientHost + " command=" + command + " data=" + data + "]";
18160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
18260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair}
183