00001 package edu.stanford.hci.r3.actions.remote;
00002
00003 import java.io.BufferedReader;
00004 import java.io.IOException;
00005 import java.io.InputStream;
00006 import java.io.InputStreamReader;
00007 import java.net.InetAddress;
00008 import java.net.ServerSocket;
00009 import java.net.Socket;
00010 import java.net.UnknownHostException;
00011 import java.util.ArrayList;
00012 import java.util.Arrays;
00013 import java.util.HashSet;
00014 import java.util.List;
00015 import java.util.Set;
00016
00017 import com.thoughtworks.xstream.XStream;
00018
00019 import edu.stanford.hci.r3.actions.R3Action;
00020 import edu.stanford.hci.r3.config.Configuration;
00021 import edu.stanford.hci.r3.config.Constants;
00022 import edu.stanford.hci.r3.util.DebugUtils;
00023 import edu.stanford.hci.r3.util.networking.ClientServerType;
00024
00036 public class ActionReceiver {
00037
00041 public static final String CONFIG_FILE_KEY = "actionreceiver.trustedsenders";
00042
00046 public static final String CONFIG_FILE_VALUE = "/config/ActionReceiver.xml";
00047
00051 public static final int DEFAULT_JAVA_PORT = Constants.Ports.ACTION_RECEIVER_JAVA;
00052
00056 public static final int DEFAULT_PLAINTEXT_PORT = Constants.Ports.ACTION_RECEIVER_PLAINTEXT;
00057
00061 private static ActionReceiver javaDaemon;
00062
00066 private static final String PROPERTY_NAME = "trustedClients";
00067
00071 private static ActionReceiver textDaemon;
00072
00076 public static void startDaemons() {
00077 startDaemons(DEFAULT_JAVA_PORT, DEFAULT_PLAINTEXT_PORT);
00078 }
00079
00084 public static void startDaemons(int tcpipPortJava, int tcpipPortPlainText) {
00085 if (javaDaemon == null) {
00086 javaDaemon = new ActionReceiver(tcpipPortJava, ClientServerType.JAVA);
00087 }
00088 if (textDaemon == null) {
00089 textDaemon = new ActionReceiver(tcpipPortPlainText, ClientServerType.PLAINTEXT);
00090 }
00091 }
00092
00096 public static void stopDaemons() {
00097 DebugUtils.println("Stopping Action Receiver Daemons.");
00098 if (javaDaemon != null) {
00099 javaDaemon.stopDaemon();
00100 javaDaemon = null;
00101 }
00102
00103 if (textDaemon != null) {
00104 textDaemon.stopDaemon();
00105 textDaemon = null;
00106 }
00107 }
00108
00112 private List<ActionHandler> actionHandlers = new ArrayList<ActionHandler>();
00113
00117 private List<Socket> clients = new ArrayList<Socket>();
00118
00122 private ActionReceiverConnectionListener connectionListener;
00123
00127 private boolean exitFlag = false;
00128
00132 private String hostAddress;
00133
00137 private String hostName;
00138
00142 private int serverPort;
00143
00147 private ServerSocket serverSocket;
00148
00152 private ClientServerType serverType;
00153
00157 private Set<String> trustedSenders = new HashSet<String>();
00158
00165 public ActionReceiver(int tcpipPort, ClientServerType type) {
00166 this(tcpipPort, type, "localhost");
00167 }
00168
00173 public ActionReceiver(int tcpipPort, ClientServerType type, String... trusted) {
00174 trustedSenders.addAll(Arrays.asList(trusted));
00175 readTrustedClientsFromConfigFile();
00176 DebugUtils.println("Trusted Client Set: " + trustedSenders);
00177
00178 try {
00179 serverSocket = new ServerSocket(tcpipPort);
00180 } catch (IOException e) {
00181 System.out.println("Error with server socket: " + e.getLocalizedMessage());
00182 }
00183 serverType = type;
00184
00185
00186 serverPort = serverSocket.getLocalPort();
00187
00188 try {
00189 hostAddress = InetAddress.getLocalHost().getHostAddress();
00190 hostName = InetAddress.getLocalHost().getHostName();
00191 } catch (UnknownHostException e) {
00192 e.printStackTrace();
00193 }
00194
00195
00196 getDaemonThread().start();
00197 }
00198
00204 public void addActionHandler(ActionHandler handler) {
00205 actionHandlers.add(handler);
00206 }
00207
00213 private Thread getDaemonThread() {
00214 return new Thread() {
00215
00216 public void run() {
00217 while (true) {
00218 Socket client = null;
00219 try {
00220 if (exitFlag) {
00221 System.out.println("Closing Action Receiver Daemon.");
00222 break;
00223 }
00224
00225 log("ActionReceiver :: Waiting for a " + serverType + " connection on port ["
00226 + serverPort + "]");
00227
00228 client = serverSocket.accept();
00229
00230 final InetAddress inetAddress = client.getInetAddress();
00231 final String ipAddr = inetAddress.toString();
00232 final String dnsName = inetAddress.getHostName();
00233
00234
00235 log("ActionReceiver :: Got a connection on server port " + serverPort);
00236 log(" from client: " + ipAddr + " :: " + dnsName);
00237 if (connectionListener != null) {
00238 connectionListener.newConnectionFrom(dnsName, ipAddr);
00239 }
00240
00241
00242 boolean clientIsOK = false;
00243 for (String nameOrAddress : trustedSenders) {
00244 if (nameOrAddress.contains("*")) {
00245
00246 nameOrAddress = nameOrAddress.substring(0, nameOrAddress.indexOf("*"));
00247 }
00248
00249 if (dnsName.toLowerCase().endsWith(nameOrAddress)
00250 || ipAddr.startsWith(nameOrAddress)) {
00251
00252
00253
00254 DebugUtils.println("This is a trusted client. Matched: " + nameOrAddress);
00255 clientIsOK = true;
00256 } else {
00257 DebugUtils.println("Did not match our client. Filter [" + nameOrAddress
00258 + "] does not match " + dnsName + " next!");
00259 }
00260 }
00261 if (!clientIsOK) {
00262 client.close();
00263 continue;
00264 }
00265
00266
00267 clients.add(client);
00268 } catch (IOException ioe) {
00269 log("ActionReceiver :: Error with server socket: " + ioe.getLocalizedMessage());
00270 }
00271
00272 if (client != null) {
00273 if (serverType == ClientServerType.PLAINTEXT) {
00274 getTextClientHandlerThread(client).start();
00275 } else {
00276 getJavaClientHandlerThread(client).start();
00277 }
00278 }
00279 }
00280 }
00281 };
00282 }
00283
00287 public String getHostAddress() {
00288 return hostAddress;
00289 }
00290
00294 public String getHostName() {
00295 return hostName;
00296 }
00297
00302 private Thread getJavaClientHandlerThread(final Socket clientSocket) {
00303 return new Thread() {
00304 private BufferedReader br;
00305
00306 public void run() {
00307 try {
00308 final InputStream inputStream = clientSocket.getInputStream();
00309 br = new BufferedReader(new InputStreamReader(inputStream));
00310 String line = null;
00311 final XStream xml = new XStream();
00312 while ((line = br.readLine()) != null) {
00313
00314
00315 if (exitFlag) {
00316 break;
00317 }
00318
00319
00320 final R3Action action = (R3Action) xml.fromXML(line);
00321
00322
00323 for (ActionHandler ah : actionHandlers) {
00324 ah.receivedAction(action);
00325 }
00326 }
00327 } catch (IOException e) {
00328 DebugUtils.println(e);
00329 DebugUtils.println("The client " + clientSocket.getInetAddress().getHostName()
00330 + " has probably disconnected...");
00331 }
00332 }
00333 };
00334 }
00335
00340 private Thread getTextClientHandlerThread(final Socket clientSocket) {
00341 return new Thread() {
00342 private BufferedReader br;
00343
00344 public synchronized void disconnect() {
00345 try {
00346 if (!clientSocket.isClosed()) {
00347 clientSocket.close();
00348 }
00349 if (br != null) {
00350 br.close();
00351 br = null;
00352 }
00353 } catch (IOException e) {
00354 e.printStackTrace();
00355 }
00356 }
00357
00358 public void run() {
00359 try {
00360 final InputStream inputStream = clientSocket.getInputStream();
00361 br = new BufferedReader(new InputStreamReader(inputStream));
00362 String line = null;
00363 while ((line = br.readLine()) != null) {
00364 System.out.println(line);
00365
00366 if (line.toLowerCase().equals("[[exit]]")) {
00367 break;
00368 }
00369
00370
00371
00372 if (exitFlag) {
00373 break;
00374 }
00375
00376
00377 for (ActionHandler ah : actionHandlers) {
00378 ah.receivedActionText(line);
00379 }
00380 }
00381 } catch (IOException e) {
00382 e.printStackTrace();
00383 }
00384 disconnect();
00385 }
00386
00387 };
00388 }
00389
00395 private void log(String msg) {
00396 System.out.println(msg);
00397 }
00398
00402 private void readTrustedClientsFromConfigFile() {
00403 final String trustedClients = Configuration.getPropertyFromConfigFile(PROPERTY_NAME,
00404 CONFIG_FILE_KEY);
00405 final String[] clients = trustedClients.split("[,]");
00406 for (String client : clients) {
00407 trustedSenders.add(client.trim());
00408 }
00409 }
00410
00414 public void setConnectionListener(ActionReceiverConnectionListener listener) {
00415 connectionListener = listener;
00416 }
00417
00421 public void stopDaemon() {
00422 try {
00423 exitFlag = true;
00424 for (Socket client : clients) {
00425 client.close();
00426 }
00427 System.out.println("ActionReceiver :: " + serverType + " on port "
00428 + serverSocket.getLocalPort() + " is stopping...");
00429 serverSocket.close();
00430 } catch (IOException e) {
00431 e.printStackTrace();
00432 }
00433 }
00434 }