1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.spdy.server;
20
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Queue;
25 import java.util.concurrent.ConcurrentLinkedQueue;
26 import java.util.concurrent.atomic.AtomicBoolean;
27
28 import org.eclipse.jetty.io.Connection;
29 import org.eclipse.jetty.io.EndPoint;
30 import org.eclipse.jetty.server.AbstractConnectionFactory;
31 import org.eclipse.jetty.server.Connector;
32 import org.eclipse.jetty.spdy.CompressionFactory;
33 import org.eclipse.jetty.spdy.FlowControlStrategy;
34 import org.eclipse.jetty.spdy.StandardCompressionFactory;
35 import org.eclipse.jetty.spdy.StandardSession;
36 import org.eclipse.jetty.spdy.api.GoAwayInfo;
37 import org.eclipse.jetty.spdy.api.Session;
38 import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
39 import org.eclipse.jetty.spdy.client.FlowControlStrategyFactory;
40 import org.eclipse.jetty.spdy.client.SPDYConnection;
41 import org.eclipse.jetty.spdy.generator.Generator;
42 import org.eclipse.jetty.spdy.parser.Parser;
43 import org.eclipse.jetty.util.Callback;
44 import org.eclipse.jetty.util.annotation.ManagedAttribute;
45 import org.eclipse.jetty.util.annotation.ManagedObject;
46
47 @ManagedObject("SPDY Server Connection Factory")
48 public class SPDYServerConnectionFactory extends AbstractConnectionFactory
49 {
50
51
52
53 @Deprecated
54 public static void checkNPNAvailable()
55 {
56 checkProtocolNegotiationAvailable();
57 }
58
59 public static void checkProtocolNegotiationAvailable()
60 {
61 if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN") &&
62 !isAvailableInBootClassPath("org.eclipse.jetty.npn.NextProtoNego"))
63 throw new IllegalStateException("No ALPN nor NPN classes available");
64 }
65
66 private static boolean isAvailableInBootClassPath(String className)
67 {
68 try
69 {
70 Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(className);
71 if (klass.getClassLoader() != null)
72 throw new IllegalStateException(className + " must be on JVM boot classpath");
73 return true;
74 }
75 catch (ClassNotFoundException x)
76 {
77 return false;
78 }
79 }
80
81 private final Queue<Session> sessions = new ConcurrentLinkedQueue<>();
82 private final short version;
83 private final ServerSessionFrameListener listener;
84 private int initialWindowSize;
85 private boolean dispatchIO;
86
87 public SPDYServerConnectionFactory(int version)
88 {
89 this(version, null);
90 }
91
92 public SPDYServerConnectionFactory(int version, ServerSessionFrameListener listener)
93 {
94 super("spdy/" + version);
95 this.version = (short)version;
96 this.listener = listener;
97 setInitialWindowSize(65536);
98 setDispatchIO(true);
99 }
100
101 @ManagedAttribute("SPDY version")
102 public short getVersion()
103 {
104 return version;
105 }
106
107 public ServerSessionFrameListener getServerSessionFrameListener()
108 {
109 return listener;
110 }
111
112 @Override
113 public Connection newConnection(Connector connector, EndPoint endPoint)
114 {
115 CompressionFactory compressionFactory = new StandardCompressionFactory();
116 Parser parser = new Parser(compressionFactory.newDecompressor());
117 Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor());
118
119 ServerSessionFrameListener listener = provideServerSessionFrameListener(connector, endPoint);
120 SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener,
121 isDispatchIO(), getInputBufferSize());
122
123 FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version);
124
125 StandardSession session = new StandardSession(getVersion(), connector.getByteBufferPool(),
126 connector.getScheduler(), connection, endPoint, connection, 2, listener,
127 generator, flowControlStrategy);
128 session.setWindowSize(getInitialWindowSize());
129 parser.addListener(session);
130 connection.setSession(session);
131
132 sessionOpened(session);
133
134 return configure(connection, connector, endPoint);
135 }
136
137 protected FlowControlStrategy newFlowControlStrategy(short version)
138 {
139 return FlowControlStrategyFactory.newFlowControlStrategy(version);
140 }
141
142 protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint)
143 {
144 return listener;
145 }
146
147 @ManagedAttribute("Initial Window Size")
148 public int getInitialWindowSize()
149 {
150 return initialWindowSize;
151 }
152
153 public void setInitialWindowSize(int initialWindowSize)
154 {
155 this.initialWindowSize = initialWindowSize;
156 }
157
158 @ManagedAttribute("Dispatch I/O to a pooled thread")
159 public boolean isDispatchIO()
160 {
161 return dispatchIO;
162 }
163
164 public void setDispatchIO(boolean dispatchIO)
165 {
166 this.dispatchIO = dispatchIO;
167 }
168
169 protected boolean sessionOpened(Session session)
170 {
171
172 return sessions.offer(session);
173 }
174
175 protected boolean sessionClosed(Session session)
176 {
177
178
179 return sessions.remove(session);
180 }
181
182 void closeSessions()
183 {
184 for (Session session : sessions)
185 session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE);
186 sessions.clear();
187 }
188
189 @Override
190 protected void doStop() throws Exception
191 {
192 closeSessions();
193 super.doStop();
194 }
195
196 public Collection<Session> getSessions()
197 {
198 return Collections.unmodifiableCollection(sessions);
199 }
200
201 @Override
202 protected void dumpThis(Appendable out) throws IOException
203 {
204 super.dumpThis(out);
205 dump(out, "", sessions);
206 }
207
208 private class ServerSPDYConnection extends SPDYConnection implements Runnable
209 {
210 private final ServerSessionFrameListener listener;
211 private final AtomicBoolean connected = new AtomicBoolean();
212
213 private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser,
214 ServerSessionFrameListener listener, boolean dispatchIO, int bufferSize)
215 {
216 super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(),
217 dispatchIO, bufferSize);
218 this.listener = listener;
219 }
220
221 @Override
222 public void onOpen()
223 {
224 super.onOpen();
225 if (connected.compareAndSet(false, true))
226 getExecutor().execute(this);
227 }
228
229 @Override
230 public void onClose()
231 {
232 super.onClose();
233 sessionClosed(getSession());
234 }
235
236 @Override
237 public void run()
238 {
239
240 if (listener != null)
241 listener.onConnect(getSession());
242 }
243 }
244
245 }