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  import java.util.ArrayList;
29  import java.util.List;
30  
31  import org.apache.mina.core.buffer.IoBuffer;
32  import org.apache.mina.core.service.DefaultTransportMetadata;
33  import org.apache.mina.core.session.IoSession;
34  import org.apache.mina.core.session.IoSessionConfig;
35  import org.junit.After;
36  import org.junit.Before;
37  import org.junit.Test;
38  
39  /**
40   * Tests {@link CumulativeProtocolDecoder}.
41   *
42   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
43   */
44  public class CumulativeProtocolDecoderTest {
45      private final ProtocolCodecSession session = new ProtocolCodecSession();
46  
47      private IoBuffer buf;
48  
49      private IntegerDecoder decoder;
50  
51      @Before
52      public void setUp() throws Exception {
53          buf = IoBuffer.allocate(16);
54          decoder = new IntegerDecoder();
55          session.setTransportMetadata(new DefaultTransportMetadata("mina", "dummy", false, true, SocketAddress.class,
56                  IoSessionConfig.class, IoBuffer.class));
57      }
58  
59      @After
60      public void tearDown() throws Exception {
61          decoder.dispose(session);
62      }
63  
64      @Test
65      public void testCumulation() throws Exception {
66          buf.put((byte) 0);
67          buf.flip();
68  
69          decoder.decode(session, buf, session.getDecoderOutput());
70          assertEquals(0, session.getDecoderOutputQueue().size());
71          assertEquals(buf.limit(), buf.position());
72  
73          buf.clear();
74          buf.put((byte) 0);
75          buf.put((byte) 0);
76          buf.put((byte) 1);
77          buf.flip();
78  
79          decoder.decode(session, buf, session.getDecoderOutput());
80          assertEquals(1, session.getDecoderOutputQueue().size());
81          assertEquals(new Integer(1), session.getDecoderOutputQueue().poll());
82          assertEquals(buf.limit(), buf.position());
83      }
84  
85      @Test
86      public void testRepeatitiveDecode() throws Exception {
87          for (int i = 0; i < 4; i++) {
88              buf.putInt(i);
89          }
90          buf.flip();
91  
92          decoder.decode(session, buf, session.getDecoderOutput());
93          assertEquals(4, session.getDecoderOutputQueue().size());
94          assertEquals(buf.limit(), buf.position());
95  
96          List<Object> expected = new ArrayList<Object>();
97  
98          for (int i = 0; i < 4; i++) {
99              assertTrue(session.getDecoderOutputQueue().contains(i));
100         }
101     }
102 
103     @Test
104     public void testWrongImplementationDetection() throws Exception {
105         try {
106             new WrongDecoder().decode(session, buf, session.getDecoderOutput());
107             fail();
108         } catch (IllegalStateException e) {
109             // OK
110         }
111     }
112 
113     @Test
114     public void testBufferDerivation() throws Exception {
115         decoder = new DuplicatingIntegerDecoder();
116 
117         buf.putInt(1);
118 
119         // Put some extra byte to make the decoder create an internal buffer.
120         buf.put((byte) 0);
121         buf.flip();
122 
123         decoder.decode(session, buf, session.getDecoderOutput());
124         assertEquals(1, session.getDecoderOutputQueue().size());
125         assertEquals(1, session.getDecoderOutputQueue().poll());
126         assertEquals(buf.limit(), buf.position());
127 
128         // Keep appending to the internal buffer.
129         // DuplicatingIntegerDecoder will keep duplicating the internal
130         // buffer to disable auto-expansion, and CumulativeProtocolDecoder
131         // should detect that user derived its internal buffer.
132         // Consequently, CumulativeProtocolDecoder will perform 
133         // reallocation to avoid putting incoming data into
134         // the internal buffer with auto-expansion disabled.
135         for (int i = 2; i < 10; i++) {
136             buf.clear();
137             buf.putInt(i);
138             // Put some extra byte to make the decoder keep the internal buffer.
139             buf.put((byte) 0);
140             buf.flip();
141             buf.position(1);
142 
143             decoder.decode(session, buf, session.getDecoderOutput());
144             assertEquals(1, session.getDecoderOutputQueue().size());
145             assertEquals(i, session.getDecoderOutputQueue().poll());
146             assertEquals(buf.limit(), buf.position());
147         }
148     }
149 
150     private static class IntegerDecoder extends CumulativeProtocolDecoder {
151         /**
152          * Default constructor
153          */
154         public IntegerDecoder() {
155             super();
156         }
157 
158         @Override
159         protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
160             assertTrue(in.hasRemaining());
161 
162             if (in.remaining() < 4) {
163                 return false;
164             }
165 
166             out.write(new Integer(in.getInt()));
167             return true;
168         }
169 
170         public void dispose() throws Exception {
171             // Do nothing
172         }
173     }
174 
175     private static class WrongDecoder extends CumulativeProtocolDecoder {
176         /**
177          * Default constructor
178          */
179         public WrongDecoder() {
180             super();
181         }
182 
183         @Override
184         protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
185             return true;
186         }
187 
188         public void dispose() throws Exception {
189             // Do nothing
190         }
191     }
192 
193     private static class DuplicatingIntegerDecoder extends IntegerDecoder {
194         /**
195          * Default constructor
196          */
197         public DuplicatingIntegerDecoder() {
198             super();
199         }
200 
201         @Override
202         protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
203             in.duplicate(); // Will disable auto-expansion.
204             assertFalse(in.isAutoExpand());
205             return super.doDecode(session, in, out);
206         }
207 
208         public void dispose() throws Exception {
209             // Do nothing
210         }
211     }
212 }