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