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