/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2012 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.undertow.test.util;

import io.undertow.server.HttpTransferEncodingHandler;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import org.xnio.ByteBufferSlicePool;
import org.xnio.ChannelListener;
import org.xnio.ChannelListeners;
import org.xnio.OptionMap;
import org.xnio.Options;
import org.xnio.Xnio;
import org.xnio.XnioWorker;
import org.xnio.channels.AcceptingChannel;
import org.xnio.channels.ConnectedStreamChannel;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpOpenListener;
import io.undertow.server.handlers.blocking.BlockingHandler;

/**
 * A class that starts a server before the test suite. By swapping out the root handler
 * tests can test various server functionality without continually starting and stopping the server.
 *
 * @author Stuart Douglas
 */
public class DefaultServer extends BlockJUnit4ClassRunner {

    private static final String DEFAULT = "default";

    private static boolean first = true;
    private static HttpOpenListener openListener;
    private static XnioWorker worker;
    private static AcceptingChannel<? extends ConnectedStreamChannel> server;
    private static Xnio xnio;

    /**
     * The executor service that is provided to
     */
    private static ExecutorService blockingExecutorService;

    /**
     * @return The base URL that can be used to make connections to this server
     */
    public static String getDefaultServerAddress() {
        return "http://" + getHostAddress(DEFAULT) + ":" + getHostPort(DEFAULT);
    }

    /**
     * This method returns a new blocking handler. The executor service it uses has its lifecycle controlled
     * by the test framework, so should not be shut down between tests.
     *
     * @return A new blocking handler
     */
    public static BlockingHandler newBlockingHandler() {
        final BlockingHandler ret = new BlockingHandler();
        ret.setExecutor(blockingExecutorService);
        return ret;
    }

    public DefaultServer(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    public Description getDescription() {
        return super.getDescription();
    }

    @Override
    public void run(final RunNotifier notifier) {
        if (first) {
            first = false;
            xnio = Xnio.getInstance("nio", DefaultServer.class.getClassLoader());
            try {
                blockingExecutorService = Executors.newFixedThreadPool(10);
                worker = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 2, Options.WORKER_READ_THREADS, 2));
                openListener = new HttpOpenListener(new ByteBufferSlicePool(10000, 10000));
                ChannelListener acceptListener = ChannelListeners.openListenerAdapter(openListener);
                server = worker.createStreamServer(new InetSocketAddress(Inet4Address.getByName(getHostAddress(DEFAULT)), getHostPort(DEFAULT)), acceptListener, OptionMap.EMPTY);
                server.resumeAccepts();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            notifier.addListener(new RunListener() {
                @Override
                public void testRunFinished(final Result result) throws Exception {
                    server.close();
                    worker.shutdown();
                    blockingExecutorService.shutdownNow();
                }
            });
        }
        super.run(notifier);
    }

    /**
     * Sets the root handler for the default web server
     *
     * @param rootHandler The handler to use
     */
    public static void setRootHandler(HttpHandler rootHandler) {
        final HttpTransferEncodingHandler ph = new HttpTransferEncodingHandler();
        ph.setNext(rootHandler);
        openListener.setRootHandler(ph);
    }

    private static String getHostAddress(String serverName) {
        return System.getProperty(serverName + ".server.address");
    }

    private static int getHostPort(String serverName) {
        return Integer.getInteger(serverName + ".server.port");
    }

    public static ExecutorService getBlockingExecutorService() {
        return blockingExecutorService;
    }
}

@@ -767,211 +767,177 @@
 Http
-TransferEncodingHandler;%0Aimport java.io.IOException;%0Aimport java.net.Inet4Address;%0Aimport java.net.InetSocketAddress;%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors
+Handler;%0Aimport io.undertow.server.HttpOpenListener;%0Aimport io.undertow.server.HttpTransferEncodingHandler;%0Aimport io.undertow.server.handlers.blocking.BlockingHandler
 ;%0A
-%0A
 impo
@@ -1202,16 +1202,49 @@
 nError;%0A
+import org.xnio.BufferAllocator;%0A
 import o
@@ -1537,150 +1537,184 @@
 el;%0A
+%0A
 import 
-io.undertow.server.HttpHandler;%0Aimport io.undertow.server.HttpOpenListener;%0Aimport io.undertow.server.handlers.blocking.BlockingHandler
+java.io.IOException;%0Aimport java.net.Inet4Address;%0Aimport java.net.InetSocketAddress;%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors
 ;%0A%0A/
@@ -3634,78 +3634,443 @@
 Map.
-create(Options.WORKER_WRITE_THREADS, 2, Options.WORKER_READ_THREADS, 2
+builder()%0A                        .set(Options.WORKER_WRITE_THREADS, 4)%0A                        .set(Options.WORKER_READ_THREADS, 4)%0A                        .set(Options.CONNECTION_HIGH_WATER, 1000000)%0A                        .set(Options.CONNECTION_LOW_WATER, 1000000)%0A                        .set(Options.WORKER_TASK_CORE_THREADS, 10)%0A                        .set(Options.WORKER_TASK_MAX_THREADS, 12)%0A                        .getMap(
 ));%0A
@@ -4149,20 +4149,71 @@
 ool(
-10000, 10000
+BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, 8192, 8192 * 8192
 ));%0A

Use more reasonable defaults from testsuite