177391c2a01ce1fed085906743cc240a4d58edd92chrismair/*
277391c2a01ce1fed085906743cc240a4d58edd92chrismair * Copyright 2007 the original author or authors.
377391c2a01ce1fed085906743cc240a4d58edd92chrismair *
477391c2a01ce1fed085906743cc240a4d58edd92chrismair * Licensed under the Apache License, Version 2.0 (the "License");
577391c2a01ce1fed085906743cc240a4d58edd92chrismair * you may not use this file except in compliance with the License.
677391c2a01ce1fed085906743cc240a4d58edd92chrismair * You may obtain a copy of the License at
777391c2a01ce1fed085906743cc240a4d58edd92chrismair *
877391c2a01ce1fed085906743cc240a4d58edd92chrismair *      http://www.apache.org/licenses/LICENSE-2.0
977391c2a01ce1fed085906743cc240a4d58edd92chrismair *
1077391c2a01ce1fed085906743cc240a4d58edd92chrismair * Unless required by applicable law or agreed to in writing, software
1177391c2a01ce1fed085906743cc240a4d58edd92chrismair * distributed under the License is distributed on an "AS IS" BASIS,
1277391c2a01ce1fed085906743cc240a4d58edd92chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1377391c2a01ce1fed085906743cc240a4d58edd92chrismair * See the License for the specific language governing permissions and
1477391c2a01ce1fed085906743cc240a4d58edd92chrismair * limitations under the License.
1577391c2a01ce1fed085906743cc240a4d58edd92chrismair */
1677391c2a01ce1fed085906743cc240a4d58edd92chrismairpackage org.mockftpserver.core.command;
1777391c2a01ce1fed085906743cc240a4d58edd92chrismair
1877391c2a01ce1fed085906743cc240a4d58edd92chrismairimport java.net.InetAddress;
1977391c2a01ce1fed085906743cc240a4d58edd92chrismairimport java.util.Collections;
2077391c2a01ce1fed085906743cc240a4d58edd92chrismairimport java.util.Date;
2177391c2a01ce1fed085906743cc240a4d58edd92chrismairimport java.util.HashMap;
2277391c2a01ce1fed085906743cc240a4d58edd92chrismairimport java.util.Map;
2377391c2a01ce1fed085906743cc240a4d58edd92chrismairimport java.util.Set;
2477391c2a01ce1fed085906743cc240a4d58edd92chrismair
2577391c2a01ce1fed085906743cc240a4d58edd92chrismairimport org.mockftpserver.core.util.Assert;
2677391c2a01ce1fed085906743cc240a4d58edd92chrismairimport org.mockftpserver.core.util.AssertFailedException;
2777391c2a01ce1fed085906743cc240a4d58edd92chrismair
2877391c2a01ce1fed085906743cc240a4d58edd92chrismair/**
2977391c2a01ce1fed085906743cc240a4d58edd92chrismair * Represents information about a single FTP Command invocation. Manages and provides access to
3077391c2a01ce1fed085906743cc240a4d58edd92chrismair * the Command, the host address (<code>InetAddress</code>) of the client that submitted the
3177391c2a01ce1fed085906743cc240a4d58edd92chrismair * Command and the timestamp of the Command submission.
3277391c2a01ce1fed085906743cc240a4d58edd92chrismair * <p>
3377391c2a01ce1fed085906743cc240a4d58edd92chrismair * This class also supports storing zero or more arbitrary mappings of <i>key</i> to value, where <i>key</i> is
3477391c2a01ce1fed085906743cc240a4d58edd92chrismair * a String and <i>value</i> is any Object. Convenience methods are provided that enable retrieving
3577391c2a01ce1fed085906743cc240a4d58edd92chrismair * type-specific data by its <i>key</i>. The data stored in an {@link InvocationRecord} is CommandHandler-specific.
3677391c2a01ce1fed085906743cc240a4d58edd92chrismair * <p>
3777391c2a01ce1fed085906743cc240a4d58edd92chrismair * The {@link #lock()} method makes an instance of this class immutable. After an instance is locked,
3877391c2a01ce1fed085906743cc240a4d58edd92chrismair * calling the {@link #set(String, Object)} method will throw an <code>AssertFailedException</code>.
3977391c2a01ce1fed085906743cc240a4d58edd92chrismair *
4077391c2a01ce1fed085906743cc240a4d58edd92chrismair * @version $Revision$ - $Date$
4177391c2a01ce1fed085906743cc240a4d58edd92chrismair *
4277391c2a01ce1fed085906743cc240a4d58edd92chrismair * @author Chris Mair
4377391c2a01ce1fed085906743cc240a4d58edd92chrismair */
4477391c2a01ce1fed085906743cc240a4d58edd92chrismairpublic class InvocationRecord {
4577391c2a01ce1fed085906743cc240a4d58edd92chrismair
4677391c2a01ce1fed085906743cc240a4d58edd92chrismair    private Command command;
4777391c2a01ce1fed085906743cc240a4d58edd92chrismair    private Date time;
4877391c2a01ce1fed085906743cc240a4d58edd92chrismair    private InetAddress clientHost;
4977391c2a01ce1fed085906743cc240a4d58edd92chrismair    private Map data = new HashMap();
5077391c2a01ce1fed085906743cc240a4d58edd92chrismair    private boolean locked = false;
5177391c2a01ce1fed085906743cc240a4d58edd92chrismair
5277391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
5377391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Create a new instance
5477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param command - the Command
5577391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param clientHost - the client host
5677391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
5777391c2a01ce1fed085906743cc240a4d58edd92chrismair    public InvocationRecord(Command command, InetAddress clientHost) {
5877391c2a01ce1fed085906743cc240a4d58edd92chrismair        this.command = command;
5977391c2a01ce1fed085906743cc240a4d58edd92chrismair        this.time = new Date();
6077391c2a01ce1fed085906743cc240a4d58edd92chrismair        this.clientHost = clientHost;
6177391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
6277391c2a01ce1fed085906743cc240a4d58edd92chrismair
6377391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
6477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Lock this instance, making it immutable. After an instance is locked,
6577391c2a01ce1fed085906743cc240a4d58edd92chrismair     * calling the {@link #set(String, Object)} method will throw an
6677391c2a01ce1fed085906743cc240a4d58edd92chrismair     * <code>AssertFailedException</code>.
6777391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
6877391c2a01ce1fed085906743cc240a4d58edd92chrismair    public void lock() {
6977391c2a01ce1fed085906743cc240a4d58edd92chrismair        locked = true;
7077391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
7177391c2a01ce1fed085906743cc240a4d58edd92chrismair
7277391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
7377391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Return true if this object has been locked, false otherwise. See {@link #lock()}.
7477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return true if this object has been locked, false otherwise.
7577391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
7677391c2a01ce1fed085906743cc240a4d58edd92chrismair    public boolean isLocked() {
7777391c2a01ce1fed085906743cc240a4d58edd92chrismair        return locked;
7877391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
7977391c2a01ce1fed085906743cc240a4d58edd92chrismair
8077391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
8177391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return the client host that submitted the command, as an InetAddress
8277391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
8377391c2a01ce1fed085906743cc240a4d58edd92chrismair    public InetAddress getClientHost() {
8477391c2a01ce1fed085906743cc240a4d58edd92chrismair        return clientHost;
8577391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
8677391c2a01ce1fed085906743cc240a4d58edd92chrismair
8777391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
8877391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return the Command
8977391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
9077391c2a01ce1fed085906743cc240a4d58edd92chrismair    public Command getCommand() {
9177391c2a01ce1fed085906743cc240a4d58edd92chrismair        return command;
9277391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
9377391c2a01ce1fed085906743cc240a4d58edd92chrismair
9477391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
9577391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return the time that the command was processed; this may differ slightly from when the command was received.
9677391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
9777391c2a01ce1fed085906743cc240a4d58edd92chrismair    public Date getTime() {
9877391c2a01ce1fed085906743cc240a4d58edd92chrismair        // Return a copy of the Date object to preserve immutability
9977391c2a01ce1fed085906743cc240a4d58edd92chrismair        return new Date(time.getTime());
10077391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
10177391c2a01ce1fed085906743cc240a4d58edd92chrismair
10277391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
10377391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Store the value for the specified key. If this object already contained a mapping
10477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * for this key, the old value is replaced by the specified value. This method throws
10577391c2a01ce1fed085906743cc240a4d58edd92chrismair     * an <code>AssertFailedException</code> if this object has been locked. See {@link #lock()}.
10677391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
10777391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param key - the key; must not be null
10877391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param value - the value to store for the specified key
10977391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
11077391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @throws AssertFailedException - if the key is null or this object has been locked.
11177391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
11277391c2a01ce1fed085906743cc240a4d58edd92chrismair    public void set(String key, Object value) {
11377391c2a01ce1fed085906743cc240a4d58edd92chrismair        Assert.notNull(key, "key");
11477391c2a01ce1fed085906743cc240a4d58edd92chrismair        Assert.isFalse(locked, "The InvocationRecord is locked!");
11577391c2a01ce1fed085906743cc240a4d58edd92chrismair        data.put(key, value);
11677391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
11777391c2a01ce1fed085906743cc240a4d58edd92chrismair
11877391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
11977391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Returns <code>true</code> if this object contains a mapping for the specified key.
12077391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
12177391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param key - the key; must not be null
12277391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return <code>true</code> if there is a mapping for the key
12377391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
12477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @throws AssertFailedException - if the key is null
12577391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
12677391c2a01ce1fed085906743cc240a4d58edd92chrismair    public boolean containsKey(String key) {
12777391c2a01ce1fed085906743cc240a4d58edd92chrismair        Assert.notNull(key, "key");
12877391c2a01ce1fed085906743cc240a4d58edd92chrismair        return data.containsKey(key);
12977391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
13077391c2a01ce1fed085906743cc240a4d58edd92chrismair
13177391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
13277391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Returns a Set view of the keys for the data stored in this object.
13377391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Changes to the returned Set have no effect on the data stored within this object
13477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * .
13577391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return the Set of keys for the data stored within this object
13677391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
13777391c2a01ce1fed085906743cc240a4d58edd92chrismair    public Set keySet() {
13877391c2a01ce1fed085906743cc240a4d58edd92chrismair        return Collections.unmodifiableSet(data.keySet());
13977391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
14077391c2a01ce1fed085906743cc240a4d58edd92chrismair
14177391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
14277391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Get the String value associated with the specified key. Returns null if there is
14377391c2a01ce1fed085906743cc240a4d58edd92chrismair     * no mapping for this key. A return value of null does not necessarily indicate that
14477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * this object contains no mapping for the key; it's also possible that the value was
14577391c2a01ce1fed085906743cc240a4d58edd92chrismair     * explicitly set to null for the key. The containsKey operation may be used to
14677391c2a01ce1fed085906743cc240a4d58edd92chrismair     * distinguish these two cases.
14777391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
14877391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param key - the key; must not be null
14977391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return the String data stored at the specified key; may be null
15077391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
15177391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @throws ClassCastException - if the object for the specified key is not a String
15277391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @throws AssertFailedException - if the key is null
15377391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
15477391c2a01ce1fed085906743cc240a4d58edd92chrismair    public String getString(String key) {
15577391c2a01ce1fed085906743cc240a4d58edd92chrismair        Assert.notNull(key, "key");
15677391c2a01ce1fed085906743cc240a4d58edd92chrismair        return (String) data.get(key);
15777391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
15877391c2a01ce1fed085906743cc240a4d58edd92chrismair
15977391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
16077391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Get the Object value associated with the specified key. Returns null if there is
16177391c2a01ce1fed085906743cc240a4d58edd92chrismair     * no mapping for this key. A return value of null does not necessarily indicate that
16277391c2a01ce1fed085906743cc240a4d58edd92chrismair     * this object contains no mapping for the key; it's also possible that the value was
16377391c2a01ce1fed085906743cc240a4d58edd92chrismair     * explicitly set to null for the key. The containsKey operation may be used to
16477391c2a01ce1fed085906743cc240a4d58edd92chrismair     * distinguish these two cases.
16577391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
16677391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @param key - the key; must not be null
16777391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @return the data stored at the specified key, as an Object; may be null
16877391c2a01ce1fed085906743cc240a4d58edd92chrismair     *
16977391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @throws AssertFailedException - if the key is null
17077391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
17177391c2a01ce1fed085906743cc240a4d58edd92chrismair    public Object getObject(String key) {
17277391c2a01ce1fed085906743cc240a4d58edd92chrismair        Assert.notNull(key, "key");
17377391c2a01ce1fed085906743cc240a4d58edd92chrismair        return data.get(key);
17477391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
17577391c2a01ce1fed085906743cc240a4d58edd92chrismair
17677391c2a01ce1fed085906743cc240a4d58edd92chrismair    /**
17777391c2a01ce1fed085906743cc240a4d58edd92chrismair     * Return the String representation of this object
17877391c2a01ce1fed085906743cc240a4d58edd92chrismair     * @see java.lang.Object#toString()
17977391c2a01ce1fed085906743cc240a4d58edd92chrismair     */
18077391c2a01ce1fed085906743cc240a4d58edd92chrismair    public String toString() {
18177391c2a01ce1fed085906743cc240a4d58edd92chrismair        return "InvocationRecord[time=" + time + " client-host=" + clientHost + " command=" + command + " data="+ data + "]";
18277391c2a01ce1fed085906743cc240a4d58edd92chrismair    }
18377391c2a01ce1fed085906743cc240a4d58edd92chrismair}
184