/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software
 * License version 1.1, a copy of which has been included with this
 * distribution in the LICENSE.txt file.  */

package org.apache.log4j.net;

import java.util.Vector;
import java.net.Socket;
import java.net.ServerSocket;

import org.apache.log4j.Logger;
import org.apache.log4j.ReceiverBase;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.helpers.LogLog;

/**
  SocketReceiver to receive logging events and "post" them to
  a LoggerRepository. This class is the matching class of
  SocketAppender. 
*/
public class SocketReceiver
extends ReceiverBase implements Runnable {
  
  protected int port;
  protected boolean running = false;
  
  private ServerSocket serverSocket;
  private Vector socketList = new Vector();
  
  public SocketReceiver() { }
  
  public SocketReceiver(int _port) {
    port = _port;
  }
  
  public SocketReceiver(int _port, LoggerRepository _repository) {
    port = _port;
    repository = _repository;
  }
  
  /**
    Get the port to receive logging events from. */
  protected int getPort() {
    return port;
  }
  
  /**
    Set the port to receive logging events from. */
  protected void setPort(int _port) {
    port = _port;
  }
  
  /**
    Start receiving logging events. */
  public synchronized void startReceiving() {
    // start the server socket
    try {
      serverSocket = new ServerSocket(port);
    } catch (Exception e) {
      LogLog.error("error starting SocketReceiver (" + 
        this.getName() + "), receiver did not start", e);
      return;
    }
    
    // start thread to watch server socket
    running = true;
    new Thread(this).start();
  }
  
  /**
    Stop receiving events. */
  public synchronized void stopReceiving() {
    // mark this as no longer running
    running = false;
    
    // close the server socket
    try {
      if (serverSocket != null)
        serverSocket.close();
    } catch (Exception e) {
      // ignore for now
    }
    
    // close all of the accepted sockets
    for (int x = 0; x < socketList.size(); x++) {
      try {
        ((Socket)socketList.get(x)).close();
      } catch (Exception e) {
        // ignore for now
      }
    }
    
    // clear member variables
    serverSocket = null;
    socketList.clear();
  }
  
  /**
    Loop, accepting new socket connections. */
  public void run() {    
    try {
      Socket socket = null;
      
      while(running) {
        // if we have a socket, start watching it
        if (socket != null) {
          socketList.add(socket);
          SocketNode node = new SocketNode(socket, getLoggerRepository());
          new Thread(node).start();
          socket = null;
        }
        
        // wait for a socket to open, then loop to start it
        socket = serverSocket.accept();
      }
      
      // socket not watched because we a no longer running
      // so close it now.
      if (socket != null) {
        socket.close();
      }
    } catch (Exception e) {
      LogLog.warn("exception while watching socket server in SocketReceiver (" +
        this.getName() + "), stopping", e);
    }
  }
}
