--- /dev/null
+// PushCacheProtocol.java\r
+// $Id: PushCacheProtocol.java,v 1.1 2010/06/15 12:25:43 smhuang Exp $\r
+// (c) COPYRIGHT MIT, INRIA and Keio, 2001.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.www.protocol.http.cache.push;\r
+\r
+import java.io.DataOutputStream;\r
+import java.io.ByteArrayOutputStream;\r
+\r
+import java.util.TreeMap;\r
+\r
+/**\r
+ * PushCacheProtocol\r
+ * Characteristics of the protocol used to control the push cache, and \r
+ * methods for common operations\r
+ * <p>\r
+ * <b>Protocol Description</b>\r
+ * <p>\r
+ * To request that "/home/abc/page.html" is inserted in cache as \r
+ * "http://www.abc.com/page.html" the client sends a packet with\r
+ * command="ADD", and remain_len set to sizeof(add_packet_t) plus\r
+ * the sum of the lengths of the path and the urls including their\r
+ * null terminators. The client then sends an add_packet describing\r
+ * the lengths of the two strings followed by the path and then the\r
+ * url.\r
+ * <p>\r
+ * The server replies with either command="OK" and remain_len=0 or\r
+ * command="ERR" and remain_len set the the length of the error\r
+ * string that follows immediately. In the event of an "ERR" message\r
+ * the connection is closed by the server.\r
+ * <p>\r
+ * To request that the page associated with "http://www.abc.com/page.html"\r
+ * be removed from the cache the client sends a packet with command="DEL",\r
+ * and remain_len set to sizeof(int) plus the length of the url string\r
+ * including the trailing null character. The server replies as with\r
+ * ADD above. Attempting to remove a url that is not present in the cache\r
+ * results in an "OK" packet being returned, the cache is unchanged.\r
+ * <p>\r
+ * The client can ask if a url is present in the cache by sending a packet\r
+ * with command="PRS", and url information as with the DEL command. The\r
+ * server will reply with "OK" if the url is present, "NO" if the url is\r
+ * not present and "ERR" if an error was encountered.\r
+ * <p>\r
+ * The client can request that the cache be emptied of all urls by sending\r
+ * a packet with command="CLN" (clean). The remain_len field is set to zero.\r
+ * The server will reply with either OK or ERR.\r
+ * \r
+ * <p>\r
+ * The client can terminate the dialogue by sending a command="BYE" \r
+ * packet and then closing the connection.\r
+ * \r
+ * <p>\r
+ * 'C' code describing the packet structures are shown below\r
+ *\r
+ *\r
+ *<pre>\r
+ * typedef struct {\r
+ * // Bytes Notes\r
+ * // ----- -----\r
+ * char tag[4]; // 0-3 = {'P','C','P','P'}\r
+ * short major_version; // 4-5 = 1\r
+ * short minor_version; // 6-7 = 1\r
+ * char command[4]; // 8-11 Null terminated command string \r
+ * int remain_len; // 12-15 number of remaining bytes to read\r
+ * } packet_t;\r
+ *\r
+ * typedef struct {\r
+ * int path_len; // 4 Length of pathname (including null)\r
+ * int url_len; // 8 Length of URL (including null)\r
+ * } add_packet_t;\r
+ * \r
+ * Note that the command is always 4 characters in length and that the\r
+ * null characters are considered part of the command, so in Java (but\r
+ * not C) we must include the \0 when comparing strings:\r
+ * "ADD\0", "BYE\0", "OK\0\0", "ERR\0", "CLN\0", "PRS\0", "DEL\0"\r
+ *\r
+ * </pre>\r
+ *\r
+ * @author Paul Henshaw, The Fantastic Corporation, Paul.Henshaw@fantastic.com\r
+ * @version $Revision: 1.1 $\r
+ * $Id: PushCacheProtocol.java,v 1.1 2010/06/15 12:25:43 smhuang Exp $\r
+ */\r
+public class PushCacheProtocol {\r
+ /*\r
+ * Protocol characteristics\r
+ */\r
+\r
+ /**\r
+ * Size of basic packet in bytes\r
+ */\r
+ public final static int PACKET_LEN=16;\r
+\r
+ /**\r
+ * Size of command string in bytes (including null terminator)\r
+ */\r
+ public final static int COMMAND_LEN=4;\r
+\r
+ /**\r
+ * Combined size of tag and version information\r
+ */\r
+ public final static int HEADER_LEN=8;\r
+\r
+ /**\r
+ * Size of packet tag\r
+ */\r
+ public final static int TAG_LEN=4;\r
+ \r
+ /**\r
+ * Maximum size of strings (urls, paths, error messages)\r
+ */\r
+ public final static int MAX_STRING_LEN=1024;\r
+\r
+ /**\r
+ * Maximum size of payload (follows basic packet)\r
+ */\r
+ public final static int MAX_PAYLOAD_LEN=8192;\r
+\r
+ /**\r
+ * Protocol Major version\r
+ */\r
+ public final static short MAJ_PROTO_VERSION=1;\r
+\r
+ /**\r
+ * Protocol minor version\r
+ */\r
+ public final static short MIN_PROTO_VERSION=2;\r
+\r
+ /**\r
+ * Numeric codes for commands, \r
+ */\r
+ public static final int NO_SUCH_COMMAND=-1, \r
+ ERR=0, ADD=1, DEL=2, CLN=3, PRS=4, BYE=5, OK=6, NO=7, NOP=8;\r
+\r
+ private static PushCacheProtocol _instance;\r
+ private TreeMap _map;\r
+ private byte[] _ok_packet_bytes=null;\r
+ private byte[] _no_packet_bytes=null;\r
+ private byte[] _err_packet_bytes=null;\r
+ private byte[] _header=null;\r
+\r
+ /**\r
+ * Access to single instance of this class\r
+ */\r
+ public static PushCacheProtocol instance() {\r
+ if(_instance==null) {\r
+ _instance=new PushCacheProtocol();\r
+ }\r
+ return _instance;\r
+ }\r
+ \r
+ /**\r
+ * Utility function for command string parsing\r
+ */\r
+ public int parseCommand(String command) {\r
+ Integer in=(Integer)_map.get(command);\r
+ if(in==null) {\r
+ return NO_SUCH_COMMAND;\r
+ }\r
+ return(in.intValue());\r
+ }\r
+\r
+ /**\r
+ * Byte array for OK packet\r
+ */\r
+ public byte[] okPacket() {\r
+ return(_ok_packet_bytes);\r
+ }\r
+\r
+ /**\r
+ * Byte array for NO packet\r
+ */\r
+ public byte[] noPacket() {\r
+ return(_no_packet_bytes);\r
+ }\r
+\r
+ public byte[] header() {\r
+ return(_header);\r
+ }\r
+\r
+ /**\r
+ * Create error packet for specified error message\r
+ */\r
+ public byte[] errorPacket(String message) {\r
+ try {\r
+ java.io.ByteArrayOutputStream baos=\r
+ new java.io.ByteArrayOutputStream(16);\r
+ DataOutputStream dos=new \r
+ DataOutputStream(baos);\r
+ \r
+ dos.write(_header,0,_header.length);\r
+ dos.writeBytes("ERR\0");\r
+ dos.writeInt(message.length());\r
+ dos.writeBytes(message);\r
+ return baos.toByteArray();\r
+ }\r
+ catch(Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ return(null);\r
+ }\r
+\r
+ /**\r
+ * True iff first four bytes of packet are identical to the protocol tag\r
+ */\r
+ public boolean isValidProtocolTag(byte[] packet) {\r
+ return(packet[0]==(byte)'P' && packet[1]==(byte)'C' || \r
+ packet[2]==(byte)'P' && packet[3]==(byte)'P');\r
+ }\r
+\r
+ /**\r
+ * Singleton, no public constructor, use {@link #instance}\r
+ * @see #instance\r
+ */ \r
+ protected PushCacheProtocol() {\r
+ try {\r
+ _map=new TreeMap();\r
+ _map.put("ERR\0",new Integer(ERR));\r
+ _map.put("ADD\0",new Integer(ADD));\r
+ _map.put("DEL\0",new Integer(DEL));\r
+ _map.put("CLN\0",new Integer(CLN));\r
+ _map.put("PRS\0",new Integer(PRS));\r
+ _map.put("BYE\0",new Integer(BYE));\r
+ _map.put("OK\0\0",new Integer(OK));\r
+ _map.put("NO\0\0",new Integer(NO));\r
+ _map.put("NOP\0",new Integer(NOP));\r
+\r
+ ByteArrayOutputStream baos=new ByteArrayOutputStream(PACKET_LEN);\r
+ DataOutputStream dos=new DataOutputStream(baos);\r
+ dos.writeByte('P');\r
+ dos.writeByte('C');\r
+ dos.writeByte('P');\r
+ dos.writeByte('P');\r
+ dos.writeShort(MAJ_PROTO_VERSION);\r
+ dos.writeShort(MIN_PROTO_VERSION);\r
+ _header=baos.toByteArray();\r
+\r
+ baos=new ByteArrayOutputStream(PACKET_LEN);\r
+ dos=new DataOutputStream(baos);\r
+ \r
+ dos.write(_header,0,_header.length);\r
+ dos.writeBytes("OK\0\0");\r
+ dos.writeInt(0);\r
+\r
+ _ok_packet_bytes=baos.toByteArray();\r
+\r
+ baos=null;\r
+ dos=null;\r
+\r
+ baos=new ByteArrayOutputStream(PACKET_LEN);\r
+ dos=new DataOutputStream(baos);\r
+ dos.write(_header,0,_header.length);\r
+ dos.writeBytes("NO\0\0");\r
+ dos.writeInt(0);\r
+\r
+ _no_packet_bytes=baos.toByteArray();\r
+ }\r
+ catch(Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+}\r