edu.cuny.cat.comm.CallBasedInfrastructureImpl.java Source code

Java tutorial

Introduction

Here is the source code for edu.cuny.cat.comm.CallBasedInfrastructureImpl.java

Source

/*
 * JCAT - TAC Market Design Competition Platform
 * Copyright (C) 2006-2010 Jinzhong Niu, Kai Cai
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program 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.
 */

package edu.cuny.cat.comm;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections15.Buffer;
import org.apache.commons.collections15.BufferUtils;
import org.apache.commons.collections15.buffer.UnboundedFifoBuffer;
import org.apache.log4j.Logger;

import edu.cuny.util.Galaxy;
import edu.cuny.util.IdAllocator;

/**
 * <p>
 * The class implements a method-invocation-based infrastructure for catp.
 * </p>
 * 
 * <p>
 * With this infrstructure implementation, both the game server and the clients
 * share a single control thread, which also runs the game clock, unlike the
 * multi-threading scheme in {@link SocketBasedInfrastructureImpl} and
 * {@link QueueBasedInfrastructureImpl}. This implies that all parties run
 * inside a single process, similar to what happens in JASA. This
 * single-threading scheme overlooks the length of trading rounds, round breaks,
 * day breaks, and the like, therefore is expected to be much faster than the
 * asynchronous infrstructure implementations that have to configure with
 * sufficiently long rounds to allow message passing among the game server and
 * the clients.
 * </p>
 * 
 * <p>
 * It is worth noting that though there is a single control thread most of the
 * game duration, a game client may have a separate thread to set itself up
 * during the game initialization period.
 * 
 * <p>
 * <b>Parameters</b>
 * </p>
 * <table>
 * 
 * </table>
 * 
 * <p>
 * <b>Default Base</b>
 * </p>
 * <table>
 * <tr>
 * <td valign=top><tt>call_based_infrastructure</tt></td>
 * </tr>
 * </table>
 * 
 * @author Jinzhong Niu
 * @version $Revision: 1.8 $
 */

public class CallBasedInfrastructureImpl implements CatpInfrastructure {

    public static final String P_DEF_BASE = "call_based_infrastructure";

    protected Buffer<CallBasedCatpClientConnector> waitingClients;

    protected Map<Object, CallBasedCatpConnection> connections;

    protected IdAllocator idAllocator;

    static Logger logger = Logger.getLogger(CallBasedInfrastructureImpl.class);

    public CallBasedInfrastructureImpl() {
        waitingClients = BufferUtils.synchronizedBuffer(new UnboundedFifoBuffer<CallBasedCatpClientConnector>());
        connections = Collections.synchronizedMap(new HashMap<Object, CallBasedCatpConnection>());
        idAllocator = new IdAllocator();
    }

    public static CallBasedInfrastructureImpl getInstance() {
        final CatpInfrastructure infrast = Galaxy.getInstance().getDefaultTyped(CatpInfrastructure.class);
        if (infrast instanceof CallBasedInfrastructureImpl) {
            return (CallBasedInfrastructureImpl) infrast;
        } else {
            CallBasedInfrastructureImpl.logger.fatal("Unavailable CallBasedInfrastructureImpl !");
            return null;
        }
    }

    /**
     * @return an instance of {@link CallBasedCatpClientConnector}.
     */
    public ClientConnector<CatpMessage> createClientConnector() {
        return new CallBasedCatpClientConnector();
    }

    /**
     * @return an instance of {@link CallBasedCatpServerConnector}.
     */
    public ServerConnector<CatpMessage> createServerConnector() {
        return new CallBasedCatpServerConnector();
    }

    public CallBasedCatpConnection connectToServer(final CallBasedCatpClientConnector client) {

        synchronized (this) {
            waitingClients.add(client);
            notifyAll();
        }

        synchronized (client) {
            try {
                if (!connections.containsKey(client)) {
                    client.wait();
                }
                return connections.get(client);
            } catch (final InterruptedException e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    public CallBasedCatpConnection acceptClient(final CallBasedCatpServerConnector server)
            throws ConnectionException {
        CallBasedCatpClientConnector client = null;

        synchronized (this) {
            while (waitingClients.isEmpty()) {
                try {
                    wait();
                } catch (final InterruptedException e) {
                    e.printStackTrace();
                    CallBasedInfrastructureImpl.logger.error("Failed to serve any client connection request !");
                    return null;
                }

                if (server.isClosed()) {
                    throw new CatpServerUnavailableException(server + " closed already !");
                }
            }

            client = waitingClients.remove();
        }

        synchronized (client) {
            final long id_num = idAllocator.nextId();
            final CallBasedCatpConnection connForServer = new CallBasedCatpConnection(server,
                    "callserver" + id_num);
            final CallBasedCatpConnection connForClient = new CallBasedCatpConnection(client,
                    "callclient" + id_num);
            connForServer.setPeer(connForClient);
            connForClient.setPeer(connForServer);
            connections.put(client, connForClient);

            client.notifyAll();

            return connForServer;
        }
    }

    /**
     * frees the waiting {@link ServerConnector}.
     * 
     * @param server
     *          the waiting {@link ServerConnector}.
     */
    public void freeServerConnector(final CallBasedCatpServerConnector server) {
        synchronized (this) {
            notifyAll();
        }
    }

    public void cleanUp() {
        waitingClients.clear();
        connections.clear();
    }

    public void closeConnection(final Object connector) {
        if (connections.containsKey(connector)) {
            final CallBasedCatpConnection conn = connections.remove(connector);
            if (conn.getPeer() != null) {
                conn.getPeer().setPeer(null);
            }
        } else {
            CallBasedInfrastructureImpl.logger.error("Try to close Unknown connection !");
        }
    }

    public boolean isSynchronous() {
        return true;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName();
    }
}