/*
 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/* @test
 * @bug 4607272 6842687
 * @summary Unit test for AsynchronousChannelGroup
 */

import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

/**
 * Tests that the completion handler is invoked by a thread with
 * the expected identity.
 */

public class Identity {
    static final Random rand = new Random();
    static final CountDownLatch done = new CountDownLatch(1);
    static final AtomicBoolean failed = new AtomicBoolean(false);

    static void fail(String msg) {
        failed.set(true);
        done.countDown();
        throw new RuntimeException(msg);
    }

    // thread-local identifies the thread
    private static final ThreadLocal<Integer> myGroup =
        new ThreadLocal<Integer>() {
            @Override protected Integer initialValue() {
                return Integer.valueOf(-1);
            }
        };

    // creates a ThreadFactory that constructs groups with the given identity
    static final ThreadFactory createThreadFactory(final int groupId) {
        return new ThreadFactory() {
            @Override
            public Thread newThread(final Runnable r) {
                Thread t = new Thread(new Runnable() {
                    public void run() {
                        myGroup.set(groupId);
                        r.run();
                    }});
                t.setDaemon(true);
                return t;
            }
        };
    }

    public static void main(String[] args) throws Exception {
        // create listener to accept connections
        final AsynchronousServerSocketChannel listener =
            AsynchronousServerSocketChannel.open()
                .bind(new InetSocketAddress(0));
        listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
            public void completed(final AsynchronousSocketChannel ch, Void att) {
                listener.accept((Void)null, this);

                final ByteBuffer buf = ByteBuffer.allocate(100);
                ch.read(buf, (Void)null, new CompletionHandler<Integer,Void>() {
                    public void completed(Integer bytesRead, Void att) {
                        buf.clear();
                        ch.read(buf, (Void)null, this);
                    }
                    public void failed(Throwable exc, Void att) {
                    }
                });
            }
            public void failed(Throwable exc, Void att) {
            }
        });
        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
        SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);

        // create 3-10 channels, each in its own group
        final int groupCount = 3 + rand.nextInt(8);
        final AsynchronousSocketChannel[] channel = new AsynchronousSocketChannel[groupCount];
        for (int i=0; i<groupCount; i++) {
            ThreadFactory factory = createThreadFactory(i);
            AsynchronousChannelGroup group;
            if (rand.nextBoolean()) {
                int nThreads = 1 + rand.nextInt(10);
                group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory);
            } else {
                ExecutorService pool = Executors.newCachedThreadPool(factory);
                group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5));
            }

            // create channel in group and connect it to the server
            AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
            ch.connect(sa).get();
            channel[i] = ch;
        }

        // randomly write to each channel, ensuring that the completion handler
        // is always invoked by a thread with the right identity.
        final AtomicInteger writeCount = new AtomicInteger(100);
        channel[0].write(getBuffer(), 0, new CompletionHandler<Integer,Integer>() {
            public void completed(Integer bytesWritten, Integer groupId) {
                if (bytesWritten != 1)
                    fail("Expected 1 byte to be written");
                if (!myGroup.get().equals(groupId))
                    fail("Handler invoked by thread with the wrong identity");
                if (writeCount.decrementAndGet() > 0) {
                    int id = rand.nextInt(groupCount);
                    channel[id].write(getBuffer(), id, this);
                } else {
                    done.countDown();
                }
            }
            public void failed(Throwable exc, Integer groupId) {
                fail(exc.getMessage());
            }
        });

        // wait until
        done.await();
        if (failed.get())
            throw new RuntimeException("Test failed - see log for details");
    }

    static ByteBuffer getBuffer() {
        ByteBuffer buf;
        if (rand.nextBoolean()) {
            buf = ByteBuffer.allocateDirect(1);
        } else {
            buf = ByteBuffer.allocate(1);
        }
        buf.put((byte)0);
        buf.flip();
        return buf;
    }
}
