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