/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This 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 software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.remoting.transport.async;

import java.io.IOException;

import javax.management.ObjectName;

import EDU.oswego.cs.dl.util.concurrent.Executor;
import org.jboss.logging.Logger;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.ServerInvoker;

/**
 * AsyncServerInvoker allows the remoting system to start up
 * the server side of the 'async' protocol.
 *
 * @author <a href="mailto:hiram@coredevelopers.net">Hiram Chirino</a>
 */
public class AsyncServerInvoker extends ServerInvoker {

	Logger log = Logger.getLogger(AsyncServerInvoker.class);
	
	private boolean started = false;
	private ChannelServer server;

	private ObjectName workManagerName;
	private Executor workManager;
	
	public AsyncServerInvoker(InvokerLocator locator)
		throws IOException {
		super(locator);
		try {
			log.debug("created.");
			workManager = Registry.getWorkManager();
			server = Registry.createAsynchChannelServer();
			server.bind(locator);
			this.locator = server.getLocalURI();
			Registry.setDefaultServer(server);	
			Registry.setServerInvoker(this);	
		} catch (Exception e) {
			log.error("AsynchServerInvoker could not be initialized: ",e);
			throw new RuntimeException(e.getMessage());
		}
	}


	protected void finalize() throws Throwable {
		stop();
		super.finalize();
	}

	public synchronized void start() throws IOException {
		if (!this.started) { 
			log.debug("started.");
			this.server.start();
			this.started = true;
			super.start();
		}
	}

	public synchronized void stop() {
		if (started) {
			log.debug("stopped.");
			this.started = false;
			this.server.stop();
			this.server.close();
		}
		super.stop();
	}

	/**
	 * returns true if the transport is bi-directional in nature, for example,
	 * SOAP in unidirectional and SOCKETs are bi-directional (unless behind a firewall
	 * for example).
	 *
	 * @return
	 */
	public boolean isTransportBiDirectional() {
		return true;
	}	
	
	/**
	 * A ChannelPool will receive data from a Channel and if it is 
	 * new request, it will forward it to the AsynchChannelServer
	 * for it to dispatch the work the appropriate subsystem.
	 *
	 * This a datagram that does not require a response message
	 * to be sent back. 
	 * 
	 * @param data
	 * @param source - the channel pool that the datagram came over.
	 */
	public void dispatchDatagram(final byte[] data, final ChannelPool source) throws InterruptedException {
		Runnable work = new Runnable() {
			public void run() {
				try {
					invoke(data);
				} catch (Throwable e) {
					log.trace("Request Failed.", e);
				}
			}
		};
		workManager.execute(work);
	}

	/**
	 * A ChannelPool will receive data from a Channel and if it is 
	 * new request, it will forward it to the AsynchChannelServer
	 * for it to dispatch the work the appropriate subsystem.
	 * 
	 * This a request and requires a response message
	 * to be sent back. 
	 * 
	 * @param data
	 * @param source - the channel pool that the request came over.
	 * @param requestId - the requestid of the message.
	 */
	public void dispatchRequest(final byte[] data, final ChannelPool source, final int requestId) throws InterruptedException {
		Runnable work = new Runnable() {
			public void run() {
				try {
					byte[] result = invoke(data);
					source.sendResponse(result, requestId);
				} catch (Throwable e) {
					log.trace("Request failed.", e);
				}
			}
		};
		workManager.execute(work);
	}
	
}
