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