KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > net > protocol > ProtocolSwitch


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.net.protocol;
5
6 import com.tc.async.api.Sink;
7 import com.tc.bytes.TCByteBuffer;
8 import com.tc.bytes.TCByteBufferFactory;
9 import com.tc.net.core.TCConnection;
10 import com.tc.util.Assert;
11
12 import java.io.IOException JavaDoc;
13 import java.net.Socket JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Set JavaDoc;
17
18 /**
19  * Inspects the first few bytes from a socket to decide if it should stay in the TC comms stack, or if it should be
20  * handed off to Jetty. Evolving this switch behaviour to more protocols should probably involve refactoring the generic
21  * comms code, not just this class
22  */

23 public class ProtocolSwitch implements TCProtocolAdaptor {
24
25   private static final String JavaDoc[] HTTP_METHODS = new String JavaDoc[] { "GET", "POST", "HEAD", "PUT", "OPTIONS", "DELETE",
26       "TRACE", "CONNECT" };
27
28   private static final Set JavaDoc METHODS = new HashSet JavaDoc(Arrays.asList(HTTP_METHODS));
29
30   // The longest HTTP method is 7 chars, +1 for the space
31
private static final int INSPECT = 8;
32
33   private static final int PROTOCOL_UNKNOWN = 0;
34   private static final int PROTOCOL_NOT_HTTP = 1;
35   private static final int PROTOCOL_HTTP = 2;
36
37   private volatile int protocol = PROTOCOL_UNKNOWN;
38   private final TCByteBuffer[] buffer = new TCByteBuffer[] { TCByteBufferFactory.wrap(new byte[INSPECT]) };
39   private final TCProtocolAdaptor delegate;
40   private final Sink httpSink;
41
42   public ProtocolSwitch(TCProtocolAdaptor delegate, Sink httpSink) {
43     this.delegate = delegate;
44     this.httpSink = httpSink;
45   }
46
47   public void addReadData(TCConnection source, TCByteBuffer[] data, int length) throws TCProtocolException {
48     switch (protocol) {
49       case PROTOCOL_NOT_HTTP: {
50         delegate.addReadData(source, data, length);
51         return;
52       }
53       case PROTOCOL_UNKNOWN: {
54         Assert.assertEquals(1, data.length);
55         TCByteBuffer buf = data[0];
56         if (buf.hasRemaining()) {
57           // didn't get enough bytes yet to make a decision
58
return;
59         }
60
61         buf.flip();
62         boolean isHttp = isHttp(buf);
63         buf.rewind();
64
65         if (isHttp) {
66           protocol = PROTOCOL_HTTP;
67           final Socket JavaDoc socket;
68           try {
69             socket = source.detach();
70           } catch (IOException JavaDoc e) {
71             throw new TCProtocolException(e);
72           }
73           httpSink.add(new HttpConnectionContext(socket, buf));
74           return;
75         } else {
76           protocol = PROTOCOL_NOT_HTTP;
77           feedDataToDelegate(source, buf);
78           return;
79         }
80       }
81       default:
82         throw new AssertionError JavaDoc("Protocol is " + protocol);
83     }
84
85     // unreachable
86
}
87
88   private void feedDataToDelegate(TCConnection source, TCByteBuffer src) throws TCProtocolException {
89     while (src.hasRemaining()) {
90       int count = 0;
91
92       TCByteBuffer[] readBuffers = delegate.getReadBuffers();
93       for (int i = 0; i < readBuffers.length; i++) {
94         TCByteBuffer dest = readBuffers[i];
95         int len = Math.min(src.remaining(), dest.remaining());
96         count += len;
97         for (int j = 0; j < len; j++) {
98           dest.put(src.get());
99         }
100         if (!src.hasRemaining()) {
101           break;
102         }
103       }
104
105       delegate.addReadData(source, readBuffers, count);
106     }
107   }
108
109   private static boolean isHttp(TCByteBuffer buf) {
110     Assert.assertEquals(INSPECT, buf.limit());
111     byte[] bytes = new byte[buf.limit()];
112     buf.get(bytes);
113
114     final String JavaDoc s;
115     try {
116       s = new String JavaDoc(bytes);
117     } catch (Exception JavaDoc e) {
118       return false;
119     }
120
121     int spaceIndex = s.indexOf(' ');
122     if (spaceIndex < 0) { return false; }
123
124     String JavaDoc token = s.substring(0, spaceIndex);
125
126     // best I can tell, HTTP methods are case sensitive, so I'm not uppercase'ing the token here
127
return METHODS.contains(token);
128   }
129
130   public TCByteBuffer[] getReadBuffers() {
131     switch (protocol) {
132       case PROTOCOL_NOT_HTTP: {
133         return delegate.getReadBuffers();
134       }
135       case PROTOCOL_UNKNOWN: {
136         return buffer;
137       }
138       default:
139         throw new AssertionError JavaDoc("Protocol is " + protocol);
140     }
141
142     // unreachable
143
}
144 }
145
Popular Tags