001: // PushCacheProtocol.java
002: // $Id: PushCacheProtocol.java,v 1.1 2001/10/03 15:00:46 ylafon Exp $
003: // (c) COPYRIGHT MIT, INRIA and Keio, 2001.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.www.protocol.http.cache.push;
007:
008: import java.io.DataOutputStream;
009: import java.io.ByteArrayOutputStream;
010:
011: import java.util.TreeMap;
012:
013: /**
014: * PushCacheProtocol
015: * Characteristics of the protocol used to control the push cache, and
016: * methods for common operations
017: * <p>
018: * <b>Protocol Description</b>
019: * <p>
020: * To request that "/home/abc/page.html" is inserted in cache as
021: * "http://www.abc.com/page.html" the client sends a packet with
022: * command="ADD", and remain_len set to sizeof(add_packet_t) plus
023: * the sum of the lengths of the path and the urls including their
024: * null terminators. The client then sends an add_packet describing
025: * the lengths of the two strings followed by the path and then the
026: * url.
027: * <p>
028: * The server replies with either command="OK" and remain_len=0 or
029: * command="ERR" and remain_len set the the length of the error
030: * string that follows immediately. In the event of an "ERR" message
031: * the connection is closed by the server.
032: * <p>
033: * To request that the page associated with "http://www.abc.com/page.html"
034: * be removed from the cache the client sends a packet with command="DEL",
035: * and remain_len set to sizeof(int) plus the length of the url string
036: * including the trailing null character. The server replies as with
037: * ADD above. Attempting to remove a url that is not present in the cache
038: * results in an "OK" packet being returned, the cache is unchanged.
039: * <p>
040: * The client can ask if a url is present in the cache by sending a packet
041: * with command="PRS", and url information as with the DEL command. The
042: * server will reply with "OK" if the url is present, "NO" if the url is
043: * not present and "ERR" if an error was encountered.
044: * <p>
045: * The client can request that the cache be emptied of all urls by sending
046: * a packet with command="CLN" (clean). The remain_len field is set to zero.
047: * The server will reply with either OK or ERR.
048: *
049: * <p>
050: * The client can terminate the dialogue by sending a command="BYE"
051: * packet and then closing the connection.
052: *
053: * <p>
054: * 'C' code describing the packet structures are shown below
055: *
056: *
057: *<pre>
058: * typedef struct {
059: * // Bytes Notes
060: * // ----- -----
061: * char tag[4]; // 0-3 = {'P','C','P','P'}
062: * short major_version; // 4-5 = 1
063: * short minor_version; // 6-7 = 1
064: * char command[4]; // 8-11 Null terminated command string
065: * int remain_len; // 12-15 number of remaining bytes to read
066: * } packet_t;
067: *
068: * typedef struct {
069: * int path_len; // 4 Length of pathname (including null)
070: * int url_len; // 8 Length of URL (including null)
071: * } add_packet_t;
072: *
073: * Note that the command is always 4 characters in length and that the
074: * null characters are considered part of the command, so in Java (but
075: * not C) we must include the \0 when comparing strings:
076: * "ADD\0", "BYE\0", "OK\0\0", "ERR\0", "CLN\0", "PRS\0", "DEL\0"
077: *
078: * </pre>
079: *
080: * @author Paul Henshaw, The Fantastic Corporation, Paul.Henshaw@fantastic.com
081: * @version $Revision: 1.1 $
082: * $Id: PushCacheProtocol.java,v 1.1 2001/10/03 15:00:46 ylafon Exp $
083: */
084: public class PushCacheProtocol {
085: /*
086: * Protocol characteristics
087: */
088:
089: /**
090: * Size of basic packet in bytes
091: */
092: public final static int PACKET_LEN = 16;
093:
094: /**
095: * Size of command string in bytes (including null terminator)
096: */
097: public final static int COMMAND_LEN = 4;
098:
099: /**
100: * Combined size of tag and version information
101: */
102: public final static int HEADER_LEN = 8;
103:
104: /**
105: * Size of packet tag
106: */
107: public final static int TAG_LEN = 4;
108:
109: /**
110: * Maximum size of strings (urls, paths, error messages)
111: */
112: public final static int MAX_STRING_LEN = 1024;
113:
114: /**
115: * Maximum size of payload (follows basic packet)
116: */
117: public final static int MAX_PAYLOAD_LEN = 8192;
118:
119: /**
120: * Protocol Major version
121: */
122: public final static short MAJ_PROTO_VERSION = 1;
123:
124: /**
125: * Protocol minor version
126: */
127: public final static short MIN_PROTO_VERSION = 2;
128:
129: /**
130: * Numeric codes for commands,
131: */
132: public static final int NO_SUCH_COMMAND = -1, ERR = 0, ADD = 1,
133: DEL = 2, CLN = 3, PRS = 4, BYE = 5, OK = 6, NO = 7,
134: NOP = 8;
135:
136: private static PushCacheProtocol _instance;
137: private TreeMap _map;
138: private byte[] _ok_packet_bytes = null;
139: private byte[] _no_packet_bytes = null;
140: private byte[] _err_packet_bytes = null;
141: private byte[] _header = null;
142:
143: /**
144: * Access to single instance of this class
145: */
146: public static PushCacheProtocol instance() {
147: if (_instance == null) {
148: _instance = new PushCacheProtocol();
149: }
150: return _instance;
151: }
152:
153: /**
154: * Utility function for command string parsing
155: */
156: public int parseCommand(String command) {
157: Integer in = (Integer) _map.get(command);
158: if (in == null) {
159: return NO_SUCH_COMMAND;
160: }
161: return (in.intValue());
162: }
163:
164: /**
165: * Byte array for OK packet
166: */
167: public byte[] okPacket() {
168: return (_ok_packet_bytes);
169: }
170:
171: /**
172: * Byte array for NO packet
173: */
174: public byte[] noPacket() {
175: return (_no_packet_bytes);
176: }
177:
178: public byte[] header() {
179: return (_header);
180: }
181:
182: /**
183: * Create error packet for specified error message
184: */
185: public byte[] errorPacket(String message) {
186: try {
187: java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(
188: 16);
189: DataOutputStream dos = new DataOutputStream(baos);
190:
191: dos.write(_header, 0, _header.length);
192: dos.writeBytes("ERR\0");
193: dos.writeInt(message.length());
194: dos.writeBytes(message);
195: return baos.toByteArray();
196: } catch (Exception e) {
197: e.printStackTrace();
198: }
199: return (null);
200: }
201:
202: /**
203: * True iff first four bytes of packet are identical to the protocol tag
204: */
205: public boolean isValidProtocolTag(byte[] packet) {
206: return (packet[0] == (byte) 'P' && packet[1] == (byte) 'C' || packet[2] == (byte) 'P'
207: && packet[3] == (byte) 'P');
208: }
209:
210: /**
211: * Singleton, no public constructor, use {@link #instance}
212: * @see #instance
213: */
214: protected PushCacheProtocol() {
215: try {
216: _map = new TreeMap();
217: _map.put("ERR\0", new Integer(ERR));
218: _map.put("ADD\0", new Integer(ADD));
219: _map.put("DEL\0", new Integer(DEL));
220: _map.put("CLN\0", new Integer(CLN));
221: _map.put("PRS\0", new Integer(PRS));
222: _map.put("BYE\0", new Integer(BYE));
223: _map.put("OK\0\0", new Integer(OK));
224: _map.put("NO\0\0", new Integer(NO));
225: _map.put("NOP\0", new Integer(NOP));
226:
227: ByteArrayOutputStream baos = new ByteArrayOutputStream(
228: PACKET_LEN);
229: DataOutputStream dos = new DataOutputStream(baos);
230: dos.writeByte('P');
231: dos.writeByte('C');
232: dos.writeByte('P');
233: dos.writeByte('P');
234: dos.writeShort(MAJ_PROTO_VERSION);
235: dos.writeShort(MIN_PROTO_VERSION);
236: _header = baos.toByteArray();
237:
238: baos = new ByteArrayOutputStream(PACKET_LEN);
239: dos = new DataOutputStream(baos);
240:
241: dos.write(_header, 0, _header.length);
242: dos.writeBytes("OK\0\0");
243: dos.writeInt(0);
244:
245: _ok_packet_bytes = baos.toByteArray();
246:
247: baos = null;
248: dos = null;
249:
250: baos = new ByteArrayOutputStream(PACKET_LEN);
251: dos = new DataOutputStream(baos);
252: dos.write(_header, 0, _header.length);
253: dos.writeBytes("NO\0\0");
254: dos.writeInt(0);
255:
256: _no_packet_bytes = baos.toByteArray();
257: } catch (Exception e) {
258: e.printStackTrace();
259: }
260: }
261: }
|