/*- Server.java ---------------------------------------------------+
| |
| Copyright (C) 2008-2009 Prateek Jain, pchat |
| prateekjainaa@gmail.com |
| http://prateekjainaa.blogspot.com |
| |
| 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. |
| |
| A copy of the GNU General Public License may be found in the |
| installation directory named "GNUGPL.txt" |
| |
+-----------------------------------------------------------------+
*/
package server;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import org.apache.log4j.Logger;
import commoms.CommandIF;
import commoms.CommandImpl;
import commoms.ProtocolConstants;
public class Server {
private static final Logger log = Logger.getLogger("chat-server");
// Tracer tracer1;
private Hashtable outputStreams = new Hashtable();
private HashMap<String, Socket> peers = new HashMap<String, Socket>();
/**
* @return the peers
*/
public HashMap<String, Socket> getPeers() {
return peers;
}
private ServerThread serverThread;
private ServerSocket ss;
// TODO try for volatile
static List<String> clientNames = new ArrayList<String>();
static boolean updateList = false;
static String documentRoot = "";
public static List<String> getClientNames() {
return clientNames;
}
public Server(int port) throws IOException {
listen(port);
}
private void listen(int port) throws IOException {
ss = new ServerSocket(port);
log.debug("Listening on port" + ss);
while (true) {
Socket s = ss.accept();
log.debug("connection from " + s);
ObjectOutputStream data = new ObjectOutputStream(s
.getOutputStream());
outputStreams.put(s, data);
serverThread = new ServerThread(this, s);
}// end while
}// end listen
Enumeration getoutputStreams() {
return outputStreams.elements();
}
void sendToAll(CommandIF command) {
synchronized (outputStreams) {
for (Enumeration e = getoutputStreams(); e.hasMoreElements();) {
// ... get the output stream ...
ObjectOutputStream dout = (ObjectOutputStream) e.nextElement();
// ... and send the message
try {
dout.writeObject(command);
// dout.writeUTF(message);
} catch (IOException ie) {
System.out.println(ie);
}
}
}
}
//TODO correctly implement it
// donot use it. not implemented
void sendMsgToSelected(CommandIF command) {
synchronized (outputStreams) {
ppp: for (Enumeration e = getoutputStreams(); e.hasMoreElements();) {
// ... get the output stream ...
ObjectOutputStream dout = (ObjectOutputStream) e.nextElement();
// ... and send the message
CommandIF com = makeCommandForConfirmation(command.getRecipientNames());
try {
dout.writeObject(com);
ObjectInputStream ois = serverThread.getDin();
synchronized (ois) {
CommandIF com1 = null;
while (true) {
com1 = (CommandIF) ois.readObject();
if(!com1.isConfirmation()) {
break ppp;
}
if(com1.isConfirmation()) {
dout.writeObject(command);
return;
}
}
}//sync
} catch (IOException ie) {
System.out.println(ie);
} catch (ClassNotFoundException cnfe) {
// TODO Auto-generated catch block
cnfe.printStackTrace();
}
}
}
}
// Remove a socket, and it's corresponding output stream, from our
// list. This is usually called by a connection thread that has
// discovered that the connectin to the client is dead.
void removeConnection(String senderName, Socket s) {
// Synchronize so we don't mess up sendToAll() while it walks
// down the list of all output streamsa
synchronized (outputStreams) {
// Tell the world
log.error("Removing connection to " + senderName);
CommandIF comm = updateRemovedPeerList(senderName, s);
// Remove it from our hashtable/list
outputStreams.remove(s);
// Make sure it's closed
try {
s.close();
} catch (IOException ie) {
log.error("Error closing " + senderName);
ie.printStackTrace();
}
// send all peers notification.
sendToAll(comm);
}
}
// Main routine
// Usage: java Server <port>
static public void main(String args[]) {
int port = 0;
try {
// Get the port # from the command line
if(args.length != 2) {
System.out.println("### Invalid arguments ###");
System.out.println("Use java server.Server <port> <documentRoot>");
return;
}
port = Integer.parseInt(args[0]);
documentRoot = args[1];
System.out.println("\n\n");
System.out.println("\t\t#########################################");
System.out.println("\t\t######## Chat Server started ##########");
System.out.println("\t\t######## Using port " + port
+ " ##########");
System.out.println("\t\t### @Author prateekjainaa@gmail.com ###");
System.out.println("\t\t#########################################");
// Create a Server object, which will automatically begin
// accepting connections.
new Server(port);
} catch (Throwable throwable) {
System.out.println("#########################################");
System.out.println("######## Chat Server stopped #######");
System.out.println("######## Releasing port " + port
+ " ###########");
System.out.println("### @Author prateekjainaa@gmail.com ###");
System.out.println("#########################################");
}
}
void updatePeerList(CommandIF com, Socket store) {
String userId = "";
try {
userId = com.getMsgFrom();
} catch (NullPointerException npe) {
//return;
// don't do anything
}
if ((userId != null) && (!userId.equals("")) && (!userId.equals("null")) && (!peers.containsKey(userId))) {
peers.put(userId, store);
// send message to all.
CommandIF comm = makeCommandOfPeerList();
comm.setMessage(userId + " joined in!\n");
sendToAll(comm);
}// if
}
// while removing
CommandIF updateRemovedPeerList(String userName, Socket store) {
peers.remove(userName);
CommandIF comm = makeCommandOfPeerList();
comm.setMessage(" " + userName + " gone away!\n");
return comm;
}
CommandIF makeCommandOfPeerList() {
CommandImpl impl = new CommandImpl();
impl.setPeerListChanged(true);
impl.setPrivateMessage(false);
impl.setCommand(ProtocolConstants.UPDATE_PEER_LIST);
impl.setNewPeerList(Arrays.asList(peers.keySet().toArray()));
return impl;
}
CommandIF makeCommandForConfirmation(List recpList) {
CommandImpl impl = new CommandImpl();
impl.setPeerListChanged(false);
impl.setPrivateMessage(false);
impl.setCommand(ProtocolConstants.CONFIRM_USER);
impl.setRecipientNames(recpList);
return impl;
}
}// end class