View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.filter.codec;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.net.SocketAddress;
28  
29  import org.apache.mina.core.buffer.IoBuffer;
30  import org.apache.mina.core.service.DefaultTransportMetadata;
31  import org.apache.mina.core.session.IoSession;
32  import org.apache.mina.core.session.IoSessionConfig;
33  import org.junit.After;
34  import org.junit.Before;
35  import org.junit.Test;
36  
37  /**
38   * Tests {@link CumulativeProtocolDecoder}.
39   *
40   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
41   */
42  public class CumulativeProtocolDecoderTest {
43      private final ProtocolCodecSession session = new ProtocolCodecSession();
44  
45      private IoBuffer buf;
46  
47      private IntegerDecoder decoder;
48  
49      @Before
50      public void setUp() throws Exception {
51          buf = IoBuffer.allocate(16);
52          decoder = new IntegerDecoder();
53          session.setTransportMetadata(new DefaultTransportMetadata("mina", "dummy", false, true, SocketAddress.class,
54                  IoSessionConfig.class, IoBuffer.class));
55      }
56  
57      @After
58      public void tearDown() throws Exception {
59          decoder.dispose(session);
60      }
61  
62      @Test
63      public void testCumulation() throws Exception {
64          buf.put((byte) 0);
65          buf.flip();
66  
67          decoder.decode(session, buf, session.getDecoderOutput());
68          assertEquals(0, session.getDecoderOutputQueue().size());
69          assertEquals(buf.limit(), buf.position());
70  
71          buf.clear();
72          buf.put((byte) 0);
73          buf.put((byte) 0);
74          buf.put((byte) 1);
75          buf.flip();
76  
77          decoder.decode(session, buf, session.getDecoderOutput());
78          assertEquals(1, session.getDecoderOutputQueue().size());
79          assertEquals(new Integer(1), session.getDecoderOutputQueue().poll());
80          assertEquals(buf.limit(), buf.position());
81      }
82  
83      @Test
84      public void testRepeatitiveDecode() throws Exception {
85          for (int i = 0; i < 4; i++) {
86              buf.putInt(i);
87          }
88          buf.flip();
89  
90          decoder.decode(session, buf, session.getDecoderOutput());
91          assertEquals(4, session.getDecoderOutputQueue().size());
92          assertEquals(buf.limit(), buf.position());
93  
94          for (int i = 0; i < 4; i++) {
95              assertTrue(session.getDecoderOutputQueue().contains(i));
96          }
97      }
98  
99      @Test
100     public void testWrongImplementationDetection() throws Exception {
101         try {
102             new WrongDecoder().decode(session, buf, session.getDecoderOutput());
103             fail();
104         } catch (IllegalStateException e) {
105             // OK
106         }
107     }
108 
109     @Test
110     public void testBufferDerivation() throws Exception {
111         decoder = new DuplicatingIntegerDecoder();
112 
113         buf.putInt(1);
114 
115         // Put some extra byte to make the decoder create an internal buffer.
116         buf.put((byte) 0);
117         buf.flip();
118 
119         decoder.decode(session, buf, session.getDecoderOutput());
120         assertEquals(1, session.getDecoderOutputQueue().size());
121         assertEquals(1, session.getDecoderOutputQueue().poll());
122         assertEquals(buf.limit(), buf.position());
123 
124         // Keep appending to the internal buffer.
125         // DuplicatingIntegerDecoder will keep duplicating the internal
126         // buffer to disable auto-expansion, and CumulativeProtocolDecoder
127         // should detect that user derived its internal buffer.
128         // Consequently, CumulativeProtocolDecoder will perform 
129         // reallocation to avoid putting incoming data into
130         // the internal buffer with auto-expansion disabled.
131         for (int i = 2; i < 10; i++) {
132             buf.clear();
133             buf.putInt(i);
134             // Put some extra byte to make the decoder keep the internal buffer.
135             buf.put((byte) 0);
136             buf.flip();
137             buf.position(1);
138 
139             decoder.decode(session, buf, session.getDecoderOutput());
140             assertEquals(1, session.getDecoderOutputQueue().size());
141             assertEquals(i, session.getDecoderOutputQueue().poll());
142             assertEquals(buf.limit(), buf.position());
143         }
144     }
145 
146     private static class IntegerDecoder extends CumulativeProtocolDecoder {
147         /**
148          * Default constructor
149          */
150         public IntegerDecoder() {
151             super();
152         }
153 
154         @Override
155         protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
156             assertTrue(in.hasRemaining());
157 
158             if (in.remaining() < 4) {
159                 return false;
160             }
161 
162             out.write(new Integer(in.getInt()));
163             return true;
164         }
165     }
166 
167     private static class WrongDecoder extends CumulativeProtocolDecoder {
168         /**
169          * Default constructor
170          */
171         public WrongDecoder() {
172             super();
173         }
174 
175         @Override
176         protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
177             return true;
178         }
179     }
180 
181     private static class DuplicatingIntegerDecoder extends IntegerDecoder {
182         /**
183          * Default constructor
184          */
185         public DuplicatingIntegerDecoder() {
186             super();
187         }
188 
189         @Override
190         protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
191             in.duplicate(); // Will disable auto-expansion.
192             assertFalse(in.isAutoExpand());
193             return super.doDecode(session, in, out);
194         }
195     }
196 }