package uk.ac.cam.em487.fjava.tick2star;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import uk.ac.cam.cl.fjava.messages.Message;
import uk.ac.cam.cl.fjava.messages.Execute;
import uk.ac.cam.cl.fjava.messages.NewMessageType;
import uk.ac.cam.cl.fjava.messages.RelayMessage;
import uk.ac.cam.cl.fjava.messages.StatusMessage;
import uk.ac.cam.em487.fjava.tick2star.FurtherJavaPreamble.Ticker;
@FurtherJavaPreamble(author = "Eduardo Munoz", date = "2011/11/13", crsid = "em487", summary = "Class to implement a thread that is always polling on the server", ticker = Ticker.A)
public class ReceiverTask implements Runnable {
SafeChatClient client;
InputStream is;
SafeObjectInputStream dois;
public ReceiverTask(SafeChatClient client) {
this.client = client;
try {
is = client.getSocket().getInputStream();
dois = new SafeObjectInputStream(is);
}
catch (IOException e) {
e.printStackTrace();
SafeChatClient.printBadInput();
return;
}
}
@Override
public void run() {
while (true) {
Message m = null;
try {
m = (Message) dois.readObject();
}
catch (IOException e) {
e.printStackTrace();
SafeChatClient.printBadInput();
return;
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
processMessage(m);
}
}
private void processMessage(Message m) {
String username = null;
String text = null;
if (m instanceof RelayMessage) {
username = ((RelayMessage) m).getFrom();
text = ((RelayMessage) m).getMessage();
}
else if (m instanceof StatusMessage) {
username = "Server";
text = ((StatusMessage) m).getMessage();
}
else if (m instanceof NewMessageType) {
dois.addClass(((NewMessageType) m).getName(), ((NewMessageType) m)
.getClassData());
username = "Client";
// for some reason, test wants me to print package name along with
// class name for "loaded" statements
text = String.format("New class %s loaded.", ((NewMessageType) m)
.getName());
}
else {
username = "Client";
Class<?> unknownClass = m.getClass();
String className = getClassNameNoPackage(m);
Field[] fields = unknownClass.getDeclaredFields();
Field.setAccessible(fields, true);
StringBuffer fieldsSB = new StringBuffer();
// maybe use StringUtils.join() from apache?
// it would require to build a new Array though
try {
// add first field
fieldsSB.append(String.format("%s(%s)", fields[0].getName(),
fields[0].get(m)));
// add rest with separator
for (int i = 1; i < fields.length; i++) {
fieldsSB.append(", ");
fieldsSB.append(String.format("%s(%s)",
fields[i].getName(), fields[i].get(m)));
}
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
text = String.format("%s: %s", className, fieldsSB.toString());
}
SafeChatClient.printMessage(m.getCreationTime(), username, text);
executeMethods(m);
}
public static String getClassNameNoPackage(Object o) {
Class<?> c = o.getClass();
String name = c.getName();
int firstChar;
firstChar = name.lastIndexOf('.') + 1;
if (firstChar > 0) {
name = name.substring(firstChar);
}
return name;
}
public static void executeMethods(Message m) {
// invoke methods which take no parameters and are annotated with
// Execute
Class<?> cls = m.getClass();
Method[] methods = cls.getDeclaredMethods();
Method.setAccessible(methods, true);
for (Method mthd : methods) {
if (mthd.getParameterTypes().length == 0) {
for (Annotation an : mthd.getDeclaredAnnotations()) {
if (an.annotationType().equals(Execute.class)) {
try {
mthd.invoke(m);
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}
}