I'm currently working on a game project with networking. What should have a simple P2P topology has evolved into something so arcane, I can't make out what half out code is doing.
Stupid networking...
I'm currently working on a game project with networking. What should have a simple P2P topology has evolved into something so arcane, I can't make out what half out code is doing.
Stupid networking...
I live on-campus at Hanszen College at Rice University. Hanszen shares the South Servery with Weiss college, which is one of the three main, larger serveries on campus. Each college which is not attached to one of the big three has their own, but the three large ones are open on days when the smaller ones would be closed, and they generally have better food to boot.
Tonight, one of the things available was a smoked roast beef, carved to order by one of the chefs, and accompanied by 'homemade' barbecue sauce and horseradish cream sauce. This is a story of the events surrounding the roast.
Now, the servery opens for dinner at 5:30pm. I arrived at about 5:40pm, and saw some slices of the roast leaving on someone else's plate. I knew what I wanted for dinner immediately. Of course, as a special dish, there was a line to get any. It wasn't exceptionally long, though, so I was ready to wait. When I reached the front of the line, I ended up asking for a few more slices, since the first few I was given were from the tail end of the previous slab, and were 50% solid fat. I wanted meat.
With my plate filled with delicious roast and some sides, I sat with some friends and chatted as I ate. This was approximately 5:50pm. During our conversation, I realized that it was Thursday, and there ought to be cinnamon rolls available for dessert. I bused my part of the table and hurried back into the servery to see if my assumption was true. Unfortunately, there was no sign of extra deliciousness. This was approximately 6:05pm
What I did see, however, was the carving station. Or rather, what used to be the carving station. The location was devoid of even the scent of the smoked roast. Did I dream it? No, surely not: many others were still eating their roast in the commons. The roast was real. The students had simply consumed all of it that had been prepared. The servery is used by approximately 300 students over the course of a meal, between Hanszen and Weiss and the individual students from other colleges who visit for a meal. In under half an hour, the delectable meat prepared for them had vanished.
Rice students, it seems, are ravenous sharks.
Java does not have callbacks. Most commonly, I see people working around this by implementing the Observer Pattern, or simply having an interface for each method they need to use as a callback.
On a recent project, I felt the need for more direct callbacks in my Java code. Java's reflection package seemed to hold my answer. Given a Class, a method name, and (in the case of overloaded methods) a list of parameter types, you can retrieve an instance of the Method class. Then, given a list of arguments to pass to the method, it can be invoked via reflection.
Java reflection isn't particularly fast, so I recommend against this approach in applications where performance is important. But reflection works, so I present my Callback class here:
package com.bs;
import java.lang.reflect.*;
/**
* Implements callback functionality for Java.
* Callbacks are implemented using reflection, so should
* be avoided if possible.
*
* @author Brian Shields <http://clockworkgear.blogspot.com/>
*/
public class Callback {
private Object parentObj;
private Method method;
private Class<?>[] parameters;
public Callback(Class<?> clazz, String methodName, Object parentObj) {
// Find a method with the matching name
Method[] allMethods;
try { allMethods = clazz.getMethods(); }
catch(SecurityException se) { allMethods = new Method[0]; }
int count = 0;
Method single = null;
for(Method m : allMethods) {
if(m.getName().equals(methodName)) {
single = m;
count++;
}
// Can't have more than one instance
if(count > 1)
throw new IllegalArgumentException(clazz.getName()
+ " has more than one method named " + methodName);
}
if(count == 0) // No instances found
throw new IllegalArgumentException(clazz.getName()
+ " has no method named " + methodName);
this.parentObj = parentObj;
this.method = single;
this.parameters = single.getParameterTypes();
}
public Callback(
Class<?> clazz,
String methodName,
Object parentObj,
Class<?>...parameters)
{
try { this.method = clazz.getMethod(methodName, parameters); }
catch(NoSuchMethodException nsme) { nsme.printStackTrace(); }
catch(SecurityException se) { se.printStackTrace(); }
this.parentObj = parentObj;
this.parameters = parameters;
}
public Object call(Object...vals) {
if(parameters.length != vals.length)
throw new IllegalArgumentException(
"Wrong number of method parameters given. Found "
+ vals.length + ", expected " + parameters.length);
Object ret = null;
try { ret = method.invoke(parentObj, vals); }
catch(IllegalAccessException iae) { iae.printStackTrace(); }
catch(InvocationTargetException ite) { ite.printStackTrace(); }
return ret;
}
}