1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.codec;
21
22 import org.apache.mina.common.ByteBuffer;
23 import org.apache.mina.common.ByteBufferProxy;
24 import org.apache.mina.common.IoFilter;
25 import org.apache.mina.common.IoFilterAdapter;
26 import org.apache.mina.common.IoFilterChain;
27 import org.apache.mina.common.IoSession;
28 import org.apache.mina.common.WriteFuture;
29 import org.apache.mina.common.support.DefaultWriteFuture;
30 import org.apache.mina.filter.codec.support.SimpleProtocolDecoderOutput;
31 import org.apache.mina.filter.codec.support.SimpleProtocolEncoderOutput;
32 import org.apache.mina.util.SessionLog;
33
34
35
36
37
38
39
40
41
42 public class ProtocolCodecFilter extends IoFilterAdapter {
43 public static final String ENCODER = ProtocolCodecFilter.class.getName()
44 + ".encoder";
45
46 public static final String DECODER = ProtocolCodecFilter.class.getName()
47 + ".decoder";
48
49 private static final String DECODER_OUT = ProtocolCodecFilter.class.getName()
50 + ".decoderOut";
51
52 private static final Class[] EMPTY_PARAMS = new Class[0];
53
54 private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
55
56 private final ProtocolCodecFactory factory;
57
58 public ProtocolCodecFilter(ProtocolCodecFactory factory) {
59 if (factory == null) {
60 throw new NullPointerException("factory");
61 }
62 this.factory = factory;
63 }
64
65 public ProtocolCodecFilter(final ProtocolEncoder encoder,
66 final ProtocolDecoder decoder) {
67 if (encoder == null) {
68 throw new NullPointerException("encoder");
69 }
70 if (decoder == null) {
71 throw new NullPointerException("decoder");
72 }
73
74 this.factory = new ProtocolCodecFactory() {
75 public ProtocolEncoder getEncoder() {
76 return encoder;
77 }
78
79 public ProtocolDecoder getDecoder() {
80 return decoder;
81 }
82 };
83 }
84
85 public ProtocolCodecFilter(final Class encoderClass,
86 final Class decoderClass) {
87 if (encoderClass == null) {
88 throw new NullPointerException("encoderClass");
89 }
90 if (decoderClass == null) {
91 throw new NullPointerException("decoderClass");
92 }
93 if (!ProtocolEncoder.class.isAssignableFrom(encoderClass)) {
94 throw new IllegalArgumentException("encoderClass: "
95 + encoderClass.getName());
96 }
97 if (!ProtocolDecoder.class.isAssignableFrom(decoderClass)) {
98 throw new IllegalArgumentException("decoderClass: "
99 + decoderClass.getName());
100 }
101 try {
102 encoderClass.getConstructor(EMPTY_PARAMS);
103 } catch (NoSuchMethodException e) {
104 throw new IllegalArgumentException(
105 "encoderClass doesn't have a public default constructor.");
106 }
107 try {
108 decoderClass.getConstructor(EMPTY_PARAMS);
109 } catch (NoSuchMethodException e) {
110 throw new IllegalArgumentException(
111 "decoderClass doesn't have a public default constructor.");
112 }
113
114 this.factory = new ProtocolCodecFactory() {
115 public ProtocolEncoder getEncoder() throws Exception {
116 return (ProtocolEncoder) encoderClass.newInstance();
117 }
118
119 public ProtocolDecoder getDecoder() throws Exception {
120 return (ProtocolDecoder) decoderClass.newInstance();
121 }
122 };
123 }
124
125 public void onPreAdd(IoFilterChain parent, String name,
126 NextFilter nextFilter) throws Exception {
127 if (parent.contains(ProtocolCodecFilter.class)) {
128 throw new IllegalStateException(
129 "A filter chain cannot contain more than one ProtocolCodecFilter.");
130 }
131 }
132
133 public void onPostRemove(IoFilterChain parent, String name,
134 NextFilter nextFilter) throws Exception {
135 disposeEncoder(parent.getSession());
136 disposeDecoder(parent.getSession());
137 disposeDecoderOut(parent.getSession());
138 }
139
140 public void messageReceived(NextFilter nextFilter, IoSession session,
141 Object message) throws Exception {
142 if (!(message instanceof ByteBuffer)) {
143 nextFilter.messageReceived(session, message);
144 return;
145 }
146
147 ByteBuffer in = (ByteBuffer) message;
148 ProtocolDecoder decoder = getDecoder(session);
149 ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
150
151 try {
152 synchronized (decoderOut) {
153 decoder.decode(session, in, decoderOut);
154 }
155 } catch (Throwable t) {
156 ProtocolDecoderException pde;
157 if (t instanceof ProtocolDecoderException) {
158 pde = (ProtocolDecoderException) t;
159 } else {
160 pde = new ProtocolDecoderException(t);
161 }
162 pde.setHexdump(in.getHexDump());
163 throw pde;
164 } finally {
165
166 in.release();
167
168 decoderOut.flush();
169 }
170 }
171
172 public void messageSent(NextFilter nextFilter, IoSession session,
173 Object message) throws Exception {
174 if (message instanceof HiddenByteBuffer) {
175 return;
176 }
177
178 if (!(message instanceof MessageByteBuffer)) {
179 nextFilter.messageSent(session, message);
180 return;
181 }
182
183 nextFilter.messageSent(session, ((MessageByteBuffer) message).message);
184 }
185
186 public void filterWrite(NextFilter nextFilter, IoSession session,
187 WriteRequest writeRequest) throws Exception {
188 Object message = writeRequest.getMessage();
189 if (message instanceof ByteBuffer) {
190 nextFilter.filterWrite(session, writeRequest);
191 return;
192 }
193
194 ProtocolEncoder encoder = getEncoder(session);
195 ProtocolEncoderOutputImpl encoderOut = getEncoderOut(session,
196 nextFilter, writeRequest);
197
198 try {
199 encoder.encode(session, message, encoderOut);
200 encoderOut.flush();
201 nextFilter.filterWrite(session, new WriteRequest(
202 new MessageByteBuffer(writeRequest.getMessage()),
203 writeRequest.getFuture(), writeRequest.getDestination()));
204 } catch (Throwable t) {
205 ProtocolEncoderException pee;
206 if (t instanceof ProtocolEncoderException) {
207 pee = (ProtocolEncoderException) t;
208 } else {
209 pee = new ProtocolEncoderException(t);
210 }
211 throw pee;
212 } finally {
213
214 if (session.getTransportType().isConnectionless()) {
215 disposeEncoder(session);
216 }
217 }
218 }
219
220 public void sessionClosed(NextFilter nextFilter, IoSession session)
221 throws Exception {
222
223 ProtocolDecoder decoder = getDecoder(session);
224 ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
225 try {
226 decoder.finishDecode(session, decoderOut);
227 } catch (Throwable t) {
228 ProtocolDecoderException pde;
229 if (t instanceof ProtocolDecoderException) {
230 pde = (ProtocolDecoderException) t;
231 } else {
232 pde = new ProtocolDecoderException(t);
233 }
234 throw pde;
235 } finally {
236
237 disposeEncoder(session);
238 disposeDecoder(session);
239 disposeDecoderOut(session);
240 decoderOut.flush();
241 }
242
243 nextFilter.sessionClosed(session);
244 }
245
246 private ProtocolEncoder getEncoder(IoSession session) throws Exception {
247 ProtocolEncoder encoder = (ProtocolEncoder) session
248 .getAttribute(ENCODER);
249 if (encoder == null) {
250 encoder = factory.getEncoder();
251 session.setAttribute(ENCODER, encoder);
252 }
253 return encoder;
254 }
255
256 private ProtocolEncoderOutputImpl getEncoderOut(IoSession session,
257 NextFilter nextFilter, WriteRequest writeRequest) {
258 return new ProtocolEncoderOutputImpl(session, nextFilter, writeRequest);
259 }
260
261 private ProtocolDecoder getDecoder(IoSession session) throws Exception {
262 ProtocolDecoder decoder = (ProtocolDecoder) session
263 .getAttribute(DECODER);
264 if (decoder == null) {
265 decoder = factory.getDecoder();
266 session.setAttribute(DECODER, decoder);
267 }
268 return decoder;
269 }
270
271 private ProtocolDecoderOutput getDecoderOut(IoSession session,
272 NextFilter nextFilter) {
273 ProtocolDecoderOutput out = (ProtocolDecoderOutput) session.getAttribute(DECODER_OUT);
274 if (out == null) {
275 out = new SimpleProtocolDecoderOutput(session, nextFilter);
276 session.setAttribute(DECODER_OUT, out);
277 }
278
279 return out;
280 }
281
282 private void disposeEncoder(IoSession session) {
283 ProtocolEncoder encoder = (ProtocolEncoder) session
284 .removeAttribute(ENCODER);
285 if (encoder == null) {
286 return;
287 }
288
289 try {
290 encoder.dispose(session);
291 } catch (Throwable t) {
292 SessionLog.warn(session, "Failed to dispose: "
293 + encoder.getClass().getName() + " (" + encoder + ')');
294 }
295 }
296
297 private void disposeDecoder(IoSession session) {
298 ProtocolDecoder decoder = (ProtocolDecoder) session
299 .removeAttribute(DECODER);
300 if (decoder == null) {
301 return;
302 }
303
304 try {
305 decoder.dispose(session);
306 } catch (Throwable t) {
307 SessionLog.warn(session, "Falied to dispose: "
308 + decoder.getClass().getName() + " (" + decoder + ')');
309 }
310 }
311
312 private void disposeDecoderOut(IoSession session) {
313 session.removeAttribute(DECODER_OUT);
314 }
315
316 private static class HiddenByteBuffer extends ByteBufferProxy {
317 private HiddenByteBuffer(ByteBuffer buf) {
318 super(buf);
319 }
320 }
321
322 private static class MessageByteBuffer extends ByteBufferProxy {
323 private final Object message;
324
325 private MessageByteBuffer(Object message) {
326 super(EMPTY_BUFFER);
327 this.message = message;
328 }
329
330 public void acquire() {
331
332 }
333
334 public void release() {
335
336 }
337 }
338
339 private static class ProtocolEncoderOutputImpl extends
340 SimpleProtocolEncoderOutput {
341 private final IoSession session;
342
343 private final NextFilter nextFilter;
344
345 private final WriteRequest writeRequest;
346
347 public ProtocolEncoderOutputImpl(IoSession session,
348 NextFilter nextFilter, WriteRequest writeRequest) {
349 this.session = session;
350 this.nextFilter = nextFilter;
351 this.writeRequest = writeRequest;
352 }
353
354 protected WriteFuture doFlush(ByteBuffer buf) {
355 WriteFuture future = new DefaultWriteFuture(session);
356 nextFilter.filterWrite(session, new WriteRequest(
357 new HiddenByteBuffer(buf), future, writeRequest
358 .getDestination()));
359 return future;
360 }
361 }
362 }