001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.core;
021
022import org.apache.mina.core.filterchain.DefaultIoFilterChain;
023import org.apache.mina.core.filterchain.IoFilter;
024import org.apache.mina.core.filterchain.IoFilterAdapter;
025import org.apache.mina.core.filterchain.IoFilterChain;
026import org.apache.mina.core.filterchain.IoFilterChain.Entry;
027import org.apache.mina.core.service.IoHandler;
028import org.apache.mina.core.service.IoHandlerAdapter;
029import org.apache.mina.core.session.DummySession;
030import org.apache.mina.core.session.IdleStatus;
031import org.apache.mina.core.session.IoSession;
032import org.apache.mina.core.write.DefaultWriteRequest;
033import org.apache.mina.core.write.WriteRequest;
034import org.apache.mina.filter.util.NoopFilter;
035import org.junit.After;
036import org.junit.Before;
037import org.junit.Test;
038
039import static org.junit.Assert.assertEquals;
040import static org.junit.Assert.assertSame;
041
042/**
043 * Tests {@link DefaultIoFilterChain}.
044 *
045 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
046 */
047public class IoFilterChainTest {
048    private DummySession dummySession;
049
050    private IoFilterChain chain;
051
052    String testResult;
053
054    private final IoHandler handler = new IoHandlerAdapter() {
055        @Override
056        public void sessionCreated(IoSession session) {
057            testResult += "HS0";
058        }
059
060        @Override
061        public void sessionOpened(IoSession session) {
062            testResult += "HSO";
063        }
064
065        @Override
066        public void sessionClosed(IoSession session) {
067            testResult += "HSC";
068        }
069
070        @Override
071        public void sessionIdle(IoSession session, IdleStatus status) {
072            testResult += "HSI";
073        }
074
075        @Override
076        public void exceptionCaught(IoSession session, Throwable cause) {
077            testResult += "HEC";
078            if (cause.getClass() != Exception.class) {
079                //cause.printStackTrace(System.out);
080            }
081        }
082
083        @Override
084        public void messageReceived(IoSession session, Object message) {
085            testResult += "HMR";
086        }
087
088        @Override
089        public void messageSent(IoSession session, Object message) {
090            testResult += "HMS";
091        }
092    };
093
094    @Before
095    public void setUp() {
096        dummySession = new DummySession();
097        dummySession.setHandler(handler);
098        chain = dummySession.getFilterChain();
099        testResult = "";
100    }
101
102    @After
103    public void tearDown() {
104        // Do nothing
105    }
106
107    @Test
108    public void testAdd() throws Exception {
109        chain.addFirst("A", new EventOrderTestFilter('A'));
110        chain.addLast("B", new EventOrderTestFilter('A'));
111        chain.addFirst("C", new EventOrderTestFilter('A'));
112        chain.addLast("D", new EventOrderTestFilter('A'));
113        chain.addBefore("B", "E", new EventOrderTestFilter('A'));
114        chain.addBefore("C", "F", new EventOrderTestFilter('A'));
115        chain.addAfter("B", "G", new EventOrderTestFilter('A'));
116        chain.addAfter("D", "H", new EventOrderTestFilter('A'));
117
118        String actual = "";
119        for (Entry e : chain.getAll()) {
120            actual += e.getName();
121        }
122
123        assertEquals("FCAEBGDH", actual);
124    }
125
126    @Test
127    public void testGet() throws Exception {
128        IoFilter filterA = new NoopFilter();
129        IoFilter filterB = new NoopFilter();
130        IoFilter filterC = new NoopFilter();
131        IoFilter filterD = new NoopFilter();
132
133        chain.addFirst("A", filterA);
134        chain.addLast("B", filterB);
135        chain.addBefore("B", "C", filterC);
136        chain.addAfter("A", "D", filterD);
137
138        assertSame(filterA, chain.get("A"));
139        assertSame(filterB, chain.get("B"));
140        assertSame(filterC, chain.get("C"));
141        assertSame(filterD, chain.get("D"));
142    }
143
144    @Test
145    public void testRemove() throws Exception {
146        chain.addLast("A", new EventOrderTestFilter('A'));
147        chain.addLast("B", new EventOrderTestFilter('A'));
148        chain.addLast("C", new EventOrderTestFilter('A'));
149        chain.addLast("D", new EventOrderTestFilter('A'));
150        chain.addLast("E", new EventOrderTestFilter('A'));
151
152        chain.remove("A");
153        chain.remove("E");
154        chain.remove("C");
155        chain.remove("B");
156        chain.remove("D");
157
158        assertEquals(0, chain.getAll().size());
159    }
160
161    @Test
162    public void testClear() throws Exception {
163        chain.addLast("A", new EventOrderTestFilter('A'));
164        chain.addLast("B", new EventOrderTestFilter('A'));
165        chain.addLast("C", new EventOrderTestFilter('A'));
166        chain.addLast("D", new EventOrderTestFilter('A'));
167        chain.addLast("E", new EventOrderTestFilter('A'));
168
169        chain.clear();
170
171        assertEquals(0, chain.getAll().size());
172    }
173
174    @Test
175    public void testToString() throws Exception {
176        // When the chain is empty
177        assertEquals("{ empty }", chain.toString());
178
179        // When there's one filter
180        chain.addLast("A", new IoFilterAdapter() {
181            @Override
182            public String toString() {
183                return "B";
184            }
185        });
186        assertEquals("{ (A:B) }", chain.toString());
187
188        // When there are two
189        chain.addLast("C", new IoFilterAdapter() {
190            @Override
191            public String toString() {
192                return "D";
193            }
194        });
195        assertEquals("{ (A:B), (C:D) }", chain.toString());
196    }
197
198    @Test
199    public void testDefault() {
200        run("HS0 HSO HMR HMS HSI HEC HSC");
201    }
202
203    @Test
204    public void testChained() throws Exception {
205        chain.addLast("A", new EventOrderTestFilter('A'));
206        chain.addLast("B", new EventOrderTestFilter('B'));
207        run("AS0 BS0 HS0" + "ASO BSO HSO" + "AMR BMR HMR" + "BFW AFW AMS BMS HMS" + "ASI BSI HSI" + "AEC BEC HEC"
208                + "ASC BSC HSC");
209    }
210
211    @Test
212    public void testAddRemove() throws Exception {
213        IoFilter filter = new AddRemoveTestFilter();
214
215        chain.addFirst("A", filter);
216        assertEquals("ADDED", testResult);
217
218        chain.remove("A");
219        assertEquals("ADDEDREMOVED", testResult);
220    }
221
222    private void run(String expectedResult) {
223        chain.fireSessionCreated();
224        chain.fireSessionOpened();
225        chain.fireMessageReceived(new Object());
226        chain.fireFilterWrite(new DefaultWriteRequest(new Object()));
227        chain.fireSessionIdle(IdleStatus.READER_IDLE);
228        chain.fireExceptionCaught(new Exception());
229        chain.fireSessionClosed();
230
231        testResult = formatResult(testResult);
232        String formatedExpectedResult = formatResult(expectedResult);
233
234        assertEquals(formatedExpectedResult, testResult);
235    }
236
237    private String formatResult(String result) {
238        String newResult = result.replaceAll("\\s", "");
239        StringBuilder buf = new StringBuilder(newResult.length() * 4 / 3);
240
241        for (int i = 0; i < newResult.length(); i++) {
242            buf.append(newResult.charAt(i));
243
244            if (i % 3 == 2) {
245                buf.append(' ');
246            }
247        }
248
249        return buf.toString();
250    }
251
252    private class EventOrderTestFilter extends IoFilterAdapter {
253        private final char id;
254
255        EventOrderTestFilter(char id) {
256            this.id = id;
257        }
258
259        @Override
260        public void sessionCreated(NextFilter nextFilter, IoSession session) {
261            testResult += id + "S0";
262            nextFilter.sessionCreated(session);
263        }
264
265        @Override
266        public void sessionOpened(NextFilter nextFilter, IoSession session) {
267            testResult += id + "SO";
268            nextFilter.sessionOpened(session);
269        }
270
271        @Override
272        public void sessionClosed(NextFilter nextFilter, IoSession session) {
273            testResult += id + "SC";
274            nextFilter.sessionClosed(session);
275        }
276
277        @Override
278        public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) {
279            testResult += id + "SI";
280            nextFilter.sessionIdle(session, status);
281        }
282
283        @Override
284        public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) {
285            testResult += id + "EC";
286            nextFilter.exceptionCaught(session, cause);
287        }
288
289        @Override
290        public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
291            testResult += id + "FW";
292            nextFilter.filterWrite(session, writeRequest);
293        }
294
295        @Override
296        public void messageReceived(NextFilter nextFilter, IoSession session, Object message) {
297            testResult += id + "MR";
298            nextFilter.messageReceived(session, message);
299        }
300
301        @Override
302        public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
303            testResult += id + "MS";
304            nextFilter.messageSent(session, writeRequest);
305        }
306
307        @Override
308        public void filterClose(NextFilter nextFilter, IoSession session) throws Exception {
309            nextFilter.filterClose(session);
310        }
311    }
312
313    private class AddRemoveTestFilter extends IoFilterAdapter {
314        /**
315         * Default constructor
316         */
317        public AddRemoveTestFilter() {
318            super();
319        }
320
321        @Override
322        public void onPostAdd(IoFilterChain parent, String name, NextFilter nextFilter) {
323            testResult += "ADDED";
324        }
325
326        @Override
327        public void onPostRemove(IoFilterChain parent, String name, NextFilter nextFilter) {
328            testResult += "REMOVED";
329        }
330    }
331}