All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apfloat.samples.OperationServer Maven / Gradle / Ivy

/*
 * Apfloat arbitrary precision arithmetic library
 * Copyright (C) 2002-2017  Mikko Tommila
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.apfloat.samples;

import java.nio.channels.Channels;
import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.net.InetSocketAddress;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.Iterator;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * Server for executing {@link Operation}s from remote calls. The client
 * should simply send a class implementing the {@link Operation}
 * interface serialized through a socket connection. Obviously, the
 * class must exist also in the server's classpath. The server will then
 * simply call {@link Operation#execute()} on the operation, and send
 * the resulting object back in the socket, serialized. If an exception
 * occurs during the operation execution, nothing is returned and
 * the socket connection is closed.
 *
 * @version 1.4
 * @author Mikko Tommila
 */

public class OperationServer
{
    private static class Request
        implements Runnable
    {
        public Request(SocketChannel channel)
        {
            this.channel = channel;
        }

        public void run()
        {
            try
            {
                info("Request processing started");

                ObjectInputStream in = new ObjectInputStream(Channels.newInputStream(this.channel));
                info("Ready to receive input data");
                Operation operation = (Operation) in.readObject();

                info("Executing operation");
                Object result = operation.execute();

                ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Channels.newOutputStream(this.channel), BUFFER_SIZE));
                info("Ready to write output data");
                out.writeObject(result);
                out.flush();

                info("Request processing complete");
            }
            catch (Exception e)
            {
                // Avoid exiting the thread
                warning("Request processing failed", e);
            }
            finally
            {
                try
                {
                    this.channel.socket().shutdownOutput();
                    this.channel.close();
                }
                catch (Exception e)
                {
                    // Ignore
                }
            }
        }

        private SocketChannel channel;
    }

    private OperationServer()
    {
    }

    /**
     * Command-line entry point.
     *
     * @param args Command-line parameters.
     *
     * @exception IOException In case of unexpected network error.
     */

    public static void main(String[] args)
        throws IOException
    {
        int port,
            workerThreads = 1;

        if (args.length < 1)
        {
            System.err.println("USAGE: OperationServer port [workerThreads] [messageLevel]");

            return;
        }

        try
        {
            port = Integer.parseInt(args[0]);
        }
        catch (NumberFormatException nfe)
        {
            System.err.println("Invalid port: " + args[0]);

            return;
        }

        try
        {
            if (args.length > 1)
            {
                workerThreads = Integer.parseInt(args[1]);
                if (workerThreads <= 0)
                {
                    throw new NumberFormatException();
                }
            }
        }
        catch (NumberFormatException nfe)
        {
            System.err.println("Invalid number of workerThreads: " + args[0]);

            return;
        }

        try
        {
            if (args.length > 2)
            {
                messageLevel = Integer.parseInt(args[2]);
            }
        }
        catch (NumberFormatException nfe)
        {
            System.err.println("Invalid messageLevel: " + args[0]);

            return;
        }

        // Create a selector object to monitor all open client connections.
        Selector selector = Selector.open();

        // Create a new non-blocking ServerSocketChannel, bind it to a port, and register it with the Selector
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();   // Open channel
        serverSocketChannel.configureBlocking(false);                           // Set non-blocking mode
        serverSocketChannel.socket().bind(new InetSocketAddress(port));         // Bind to port
        SelectionKey serverKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // Create a pool of worker threads that will run independently
        Executor executor = Executors.newFixedThreadPool(workerThreads);

        info("Waiting for connections to port " + port);

        while (true)    // The main server loop.  The server runs forever.
        {
            // This call blocks until there is activity on one of the registered channels
            selector.select();

            // Get a java.util.Set containing the SelectionKey objects for all channels that are ready for I/O
            Set keys = selector.selectedKeys();

            // Use a java.util.Iterator to loop through the selected keys
            for (Iterator i = keys.iterator(); i.hasNext(); )
            {
                SelectionKey key = i.next();
                i.remove();             // Remove the key from the set of selected keys

                // Check whether this key is the SelectionKey we got when we registered the ServerSocketChannel
                if (key == serverKey)
                {
                    // Activity on the ServerSocketChannel means a client is trying to connect to the server
                    if (key.isAcceptable())
                    {
                        // Accept the client connection
                        // Note that the client channel is in blocking mode; a separate thread will use it
                        SocketChannel clientSocketChannel = serverSocketChannel.accept();

                        info("New connection accepted");

                        // Put a new request to the queue so a worker thread can pick it up from there
                        executor.execute(new Request(clientSocketChannel));
                    }
                }
            }
        }
    }

    private static void warning(String message, Exception e)
    {
        if (messageLevel >= WARNING)
        {
            System.err.println("WARNING: " + Thread.currentThread().getName() + ": " + message);
            e.printStackTrace(System.err);
        }
    }

    private static void info(String message)
    {
        if (messageLevel >= INFO)
        {
            System.err.println("INFO: " + Thread.currentThread().getName() + ": " + message);
        }
    }

    private static void debug(String message)
    {
        if (messageLevel >= DEBUG)
        {
            System.err.println("DEBUG: " + Thread.currentThread().getName() + ": " + message);
        }
    }

    private static final int BUFFER_SIZE = 8192;
    private static final int ERROR = 0;
    private static final int WARNING = 1;
    private static final int INFO = 2;
    private static final int DEBUG = 3;

    private static int messageLevel = WARNING;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy