177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair/*
277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Copyright 2007 the original author or authors.
377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair *
477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Licensed under the Apache License, Version 2.0 (the "License");
577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * you may not use this file except in compliance with the License.
677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * You may obtain a copy of the License at
777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair *
877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair *      http://www.apache.org/licenses/LICENSE-2.0
977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair *
1077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Unless required by applicable law or agreed to in writing, software
1177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * distributed under the License is distributed on an "AS IS" BASIS,
1277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * See the License for the specific language governing permissions and
1477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * limitations under the License.
1577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */
1677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairpackage org.mockftpserver.core.command;
1777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
1877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.util.Assert;
1977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport org.mockftpserver.core.util.AssertFailedException;
2077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
2177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.net.InetAddress;
2277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.Collections;
2377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.Date;
2477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.HashMap;
2577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.Map;
2677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairimport java.util.Set;
2777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
2877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair/**
2977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Represents information about a single FTP Command invocation. Manages and provides access to
3077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * the Command, the host address (<code>InetAddress</code>) of the client that submitted the
3177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * Command and the timestamp of the Command submission.
3277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * <p>
3377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * This class also supports storing zero or more arbitrary mappings of <i>key</i> to value, where <i>key</i> is
3477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * a String and <i>value</i> is any Object. Convenience methods are provided that enable retrieving
3577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * type-specific data by its <i>key</i>. The data stored in an {@link InvocationRecord} is CommandHandler-specific.
3677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * <p>
3777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * The {@link #lock()} method makes an instance of this class immutable. After an instance is locked,
3877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * calling the {@link #set(String, Object)} method will throw an <code>AssertFailedException</code>.
3977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair *
4077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @author Chris Mair
4177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair * @version $Revision$ - $Date$
4277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair */
4377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismairpublic class InvocationRecord {
4477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
4577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    private Command command;
4677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    private Date time;
4777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    private InetAddress clientHost;
4877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    private Map data = new HashMap();
4977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    private boolean locked = false;
5077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
5177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
5277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Create a new instance
5377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
5477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param command    - the Command
5577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param clientHost - the client host
5677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
5777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public InvocationRecord(Command command, InetAddress clientHost) {
5877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        this.command = command;
5977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        this.time = new Date();
6077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        this.clientHost = clientHost;
6177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
6277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
6377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
6477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Lock this instance, making it immutable. After an instance is locked,
6577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * calling the {@link #set(String, Object)} method will throw an
6677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * <code>AssertFailedException</code>.
6777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
6877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public void lock() {
6977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        locked = true;
7077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
7177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
7277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
7377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Return true if this object has been locked, false otherwise. See {@link #lock()}.
7477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
7577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return true if this object has been locked, false otherwise.
7677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
7777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public boolean isLocked() {
7877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return locked;
7977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
8077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
8177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
8277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return the client host that submitted the command, as an InetAddress
8377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
8477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public InetAddress getClientHost() {
8577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return clientHost;
8677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
8777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
8877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
8977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return the Command
9077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
9177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public Command getCommand() {
9277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return command;
9377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
9477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
9577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
9677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return the time that the command was processed; this may differ slightly from when the command was received.
9777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
9877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public Date getTime() {
9977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        // Return a copy of the Date object to preserve immutability
10077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return new Date(time.getTime());
10177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
10277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
10377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
10477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Store the value for the specified key. If this object already contained a mapping
10577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * for this key, the old value is replaced by the specified value. This method throws
10677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * an <code>AssertFailedException</code> if this object has been locked. See {@link #lock()}.
10777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
10877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param key   - the key; must not be null
10977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param value - the value to store for the specified key
11077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @throws AssertFailedException - if the key is null or this object has been locked.
11177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
11277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public void set(String key, Object value) {
11377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        Assert.notNull(key, "key");
11477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        Assert.isFalse(locked, "The InvocationRecord is locked!");
11577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        data.put(key, value);
11677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
11777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
11877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
11977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Returns <code>true</code> if this object contains a mapping for the specified key.
12077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
12177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param key - the key; must not be null
12277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return <code>true</code> if there is a mapping for the key
12377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @throws AssertFailedException - if the key is null
12477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
12577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public boolean containsKey(String key) {
12677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        Assert.notNull(key, "key");
12777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return data.containsKey(key);
12877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
12977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
13077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
13177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Returns a Set view of the keys for the data stored in this object.
13277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Changes to the returned Set have no effect on the data stored within this object
13377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * .
13477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
13577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return the Set of keys for the data stored within this object
13677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
13777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public Set keySet() {
13877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return Collections.unmodifiableSet(data.keySet());
13977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
14077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
14177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
14277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Get the String value associated with the specified key. Returns null if there is
14377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * no mapping for this key. A return value of null does not necessarily indicate that
14477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * this object contains no mapping for the key; it's also possible that the value was
14577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * explicitly set to null for the key. The containsKey operation may be used to
14677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * distinguish these two cases.
14777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
14877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param key - the key; must not be null
14977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return the String data stored at the specified key; may be null
15077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @throws ClassCastException    - if the object for the specified key is not a String
15177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @throws AssertFailedException - if the key is null
15277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
15377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public String getString(String key) {
15477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        Assert.notNull(key, "key");
15577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return (String) data.get(key);
15677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
15777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
15877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
15977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Get the Object value associated with the specified key. Returns null if there is
16077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * no mapping for this key. A return value of null does not necessarily indicate that
16177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * this object contains no mapping for the key; it's also possible that the value was
16277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * explicitly set to null for the key. The containsKey operation may be used to
16377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * distinguish these two cases.
16477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
16577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @param key - the key; must not be null
16677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @return the data stored at the specified key, as an Object; may be null
16777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @throws AssertFailedException - if the key is null
16877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
16977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public Object getObject(String key) {
17077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        Assert.notNull(key, "key");
17177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return data.get(key);
17277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
17377b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair
17477b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    /**
17577b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * Return the String representation of this object
17677b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     *
17777b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     * @see java.lang.Object#toString()
17877b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair     */
17977b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    public String toString() {
18077b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair        return "InvocationRecord[time=" + time + " client-host=" + clientHost + " command=" + command + " data=" + data + "]";
18177b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair    }
18277b8661f08d1379c0bdf2af93d8004fced9f1ab0chrismair}
183