1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.common.extensions;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.ListIterator;
25
26 import org.eclipse.jetty.util.annotation.ManagedAttribute;
27 import org.eclipse.jetty.util.annotation.ManagedObject;
28 import org.eclipse.jetty.util.component.ContainerLifeCycle;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.websocket.api.WriteCallback;
32 import org.eclipse.jetty.websocket.api.extensions.Extension;
33 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
34 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
35 import org.eclipse.jetty.websocket.api.extensions.Frame;
36 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
37 import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
38 import org.eclipse.jetty.websocket.common.Generator;
39 import org.eclipse.jetty.websocket.common.Parser;
40
41
42
43
44 @ManagedObject("Extension Stack")
45 public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames, OutgoingFrames
46 {
47 private static final Logger LOG = Log.getLogger(ExtensionStack.class);
48 private final ExtensionFactory factory;
49 private List<Extension> extensions;
50 private IncomingFrames nextIncoming;
51 private OutgoingFrames nextOutgoing;
52
53 public ExtensionStack(ExtensionFactory factory)
54 {
55 this.factory = factory;
56 }
57
58 public void configure(Generator generator)
59 {
60 generator.configureFromExtensions(extensions);
61 }
62
63 public void configure(Parser parser)
64 {
65 parser.configureFromExtensions(extensions);
66 }
67
68 @Override
69 protected void doStart() throws Exception
70 {
71 super.doStart();
72 LOG.debug("doStart");
73
74
75 if ((extensions != null) && (extensions.size() > 0))
76 {
77 ListIterator<Extension> eiter = extensions.listIterator();
78
79
80 while (eiter.hasNext())
81 {
82 Extension ext = eiter.next();
83 ext.setNextOutgoingFrames(nextOutgoing);
84 nextOutgoing = ext;
85 }
86
87
88 while (eiter.hasPrevious())
89 {
90 Extension ext = eiter.previous();
91 ext.setNextIncomingFrames(nextIncoming);
92 nextIncoming = ext;
93 }
94 }
95 }
96
97 @Override
98 public void dump(Appendable out, String indent) throws IOException
99 {
100 super.dump(out,indent);
101
102 IncomingFrames websocket = getLastIncoming();
103 OutgoingFrames network = getLastOutgoing();
104
105 out.append(indent).append(" +- Stack\n");
106 out.append(indent).append(" +- Network : ").append(network.toString()).append('\n');
107 for (Extension ext : extensions)
108 {
109 out.append(indent).append(" +- Extension: ").append(ext.toString()).append('\n');
110 }
111 out.append(indent).append(" +- Websocket: ").append(websocket.toString()).append('\n');
112 }
113
114 @ManagedAttribute(name = "Extension List", readonly = true)
115 public List<Extension> getExtensions()
116 {
117 return extensions;
118 }
119
120 private IncomingFrames getLastIncoming()
121 {
122 IncomingFrames last = nextIncoming;
123 boolean done = false;
124 while (!done)
125 {
126 if (last instanceof AbstractExtension)
127 {
128 last = ((AbstractExtension)last).getNextIncoming();
129 }
130 else
131 {
132 done = true;
133 }
134 }
135 return last;
136 }
137
138 private OutgoingFrames getLastOutgoing()
139 {
140 OutgoingFrames last = nextOutgoing;
141 boolean done = false;
142 while (!done)
143 {
144 if (last instanceof AbstractExtension)
145 {
146 last = ((AbstractExtension)last).getNextOutgoing();
147 }
148 else
149 {
150 done = true;
151 }
152 }
153 return last;
154 }
155
156
157
158
159
160
161 public List<ExtensionConfig> getNegotiatedExtensions()
162 {
163 List<ExtensionConfig> ret = new ArrayList<>();
164 if (extensions == null)
165 {
166 return ret;
167 }
168
169 for (Extension ext : extensions)
170 {
171 ret.add(ext.getConfig());
172 }
173 return ret;
174 }
175
176 @ManagedAttribute(name = "Next Incoming Frames Handler", readonly = true)
177 public IncomingFrames getNextIncoming()
178 {
179 return nextIncoming;
180 }
181
182 @ManagedAttribute(name = "Next Outgoing Frames Handler", readonly = true)
183 public OutgoingFrames getNextOutgoing()
184 {
185 return nextOutgoing;
186 }
187
188 public boolean hasNegotiatedExtensions()
189 {
190 return (this.extensions != null) && (this.extensions.size() > 0);
191 }
192
193 @Override
194 public void incomingError(Throwable e)
195 {
196 nextIncoming.incomingError(e);
197 }
198
199 @Override
200 public void incomingFrame(Frame frame)
201 {
202 nextIncoming.incomingFrame(frame);
203 }
204
205
206
207
208
209
210
211
212
213 public void negotiate(List<ExtensionConfig> configs)
214 {
215 LOG.debug("Extension Configs={}",configs);
216 this.extensions = new ArrayList<>();
217 for (ExtensionConfig config : configs)
218 {
219 Extension ext = factory.newInstance(config);
220 if (ext == null)
221 {
222
223 continue;
224 }
225 extensions.add(ext);
226 LOG.debug("Adding Extension: {}",ext);
227 }
228
229 addBean(extensions);
230 }
231
232 @Override
233 public void outgoingFrame(Frame frame, WriteCallback callback)
234 {
235 nextOutgoing.outgoingFrame(frame,callback);
236 }
237
238 public void setNextIncoming(IncomingFrames nextIncoming)
239 {
240 this.nextIncoming = nextIncoming;
241 }
242
243 public void setNextOutgoing(OutgoingFrames nextOutgoing)
244 {
245 this.nextOutgoing = nextOutgoing;
246 }
247
248 @Override
249 public String toString()
250 {
251 StringBuilder s = new StringBuilder();
252 s.append("ExtensionStack[");
253 s.append("extensions=");
254 if (extensions == null)
255 {
256 s.append("<null>");
257 }
258 else
259 {
260 s.append('[');
261 boolean delim = false;
262 for (Extension ext : extensions)
263 {
264 if (delim)
265 {
266 s.append(',');
267 }
268 if (ext == null)
269 {
270 s.append("<null>");
271 }
272 else
273 {
274 s.append(ext.getName());
275 }
276 delim = true;
277 }
278 s.append(']');
279 }
280 s.append(",incoming=").append((this.nextIncoming == null)?"<null>":this.nextIncoming.getClass().getName());
281 s.append(",outgoing=").append((this.nextOutgoing == null)?"<null>":this.nextOutgoing.getClass().getName());
282 s.append("]");
283 return s.toString();
284 }
285 }
286