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