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.transport;
021
022import static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertTrue;
024
025import java.io.File;
026import java.io.FileOutputStream;
027import java.io.IOException;
028import java.net.InetSocketAddress;
029import java.nio.ByteBuffer;
030import java.nio.channels.FileChannel;
031import java.util.concurrent.CountDownLatch;
032
033import org.apache.mina.core.buffer.IoBuffer;
034import org.apache.mina.core.future.ConnectFuture;
035import org.apache.mina.core.service.IoAcceptor;
036import org.apache.mina.core.service.IoConnector;
037import org.apache.mina.core.service.IoHandlerAdapter;
038import org.apache.mina.core.session.IoSession;
039import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
040import org.apache.mina.util.AvailablePortFinder;
041import org.junit.Test;
042
043/**
044 * TODO Add documentation
045 * 
046 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
047 */
048public abstract class AbstractFileRegionTest {
049
050    private static final int FILE_SIZE = 1 * 1024 * 1024; // 1MB file
051
052    protected abstract IoAcceptor createAcceptor();
053
054    protected abstract IoConnector createConnector();
055
056    @Test
057    public void testSendLargeFile() throws Throwable {
058        File file = createLargeFile();
059        assertEquals("Test file not as big as specified", FILE_SIZE, file.length());
060
061        final CountDownLatch latch = new CountDownLatch(1);
062        final boolean[] success = { false };
063        final Throwable[] exception = { null };
064
065        int port = AvailablePortFinder.getNextAvailable(1025);
066        IoAcceptor acceptor = createAcceptor();
067        IoConnector connector = createConnector();
068
069        try {
070            acceptor.setHandler(new IoHandlerAdapter() {
071                private int index = 0;
072
073                @Override
074                public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
075                    exception[0] = cause;
076                    session.close(true);
077                }
078
079                @Override
080                public void messageReceived(IoSession session, Object message) throws Exception {
081                    IoBuffer buffer = (IoBuffer) message;
082                    while (buffer.hasRemaining()) {
083                        int x = buffer.getInt();
084                        if (x != index) {
085                            throw new Exception(String.format("Integer at %d was %d but should have been %d", index, x,
086                                    index));
087                        }
088                        index++;
089                    }
090                    if (index > FILE_SIZE / 4) {
091                        throw new Exception("Read too much data");
092                    }
093                    if (index == FILE_SIZE / 4) {
094                        success[0] = true;
095                        session.close(true);
096                    }
097                }
098            });
099
100            ((NioSocketAcceptor) acceptor).setReuseAddress(true);
101
102            acceptor.bind(new InetSocketAddress(port));
103
104            connector.setHandler(new IoHandlerAdapter() {
105                @Override
106                public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
107                    exception[0] = cause;
108                    session.close(true);
109                }
110
111                @Override
112                public void sessionClosed(IoSession session) throws Exception {
113                    latch.countDown();
114                }
115            });
116
117            ConnectFuture future = connector.connect(new InetSocketAddress("localhost", port));
118            future.awaitUninterruptibly();
119
120            IoSession session = future.getSession();
121            session.write(file);
122
123            latch.await();
124
125            if (exception[0] != null) {
126                throw exception[0];
127            }
128            assertTrue("Did not complete file transfer successfully", success[0]);
129
130            assertEquals("Written messages should be 1 (we wrote one file)", 1, session.getWrittenMessages());
131            assertEquals("Written bytes should match file size", FILE_SIZE, session.getWrittenBytes());
132        } finally {
133            try {
134                connector.dispose();
135            } finally {
136                acceptor.dispose();
137            }
138        }
139    }
140
141    private File createLargeFile() throws IOException {
142        File largeFile = File.createTempFile("mina-test", "largefile");
143        largeFile.deleteOnExit();
144        FileChannel channel = null;
145        FileOutputStream out = null;
146        
147        try {
148            out =  new FileOutputStream(largeFile);
149            channel = out.getChannel();
150            ByteBuffer buffer = createBuffer();
151            channel.write(buffer);
152            channel.close();
153            out.close();
154        } finally {
155            if (channel != null) {
156                channel.close();
157            }
158            
159            if (out != null) {
160                out.close();
161            }
162        }
163        
164        return largeFile;
165    }
166
167    private ByteBuffer createBuffer() {
168        ByteBuffer buffer = ByteBuffer.allocate(FILE_SIZE);
169        for (int i = 0; i < FILE_SIZE / 4; i++) {
170            buffer.putInt(i);
171        }
172        buffer.flip();
173        return buffer;
174    }
175}