Recently I took the time to read the early draft of JSR-292, the invokedynamic bytecode specification. For those slightly less familiar with the subject, it makes it possible to perform late binding on method invocations, allowing for calling methods on objects without knowing the object type at compile time. This feature is important for projects such as Jython and JRuby, which provide Java bytecode compilation to the popular Python and Ruby languages.
One of the most classic patterns in software is the producer-consumer pattern. There is a module producing data, and a module reading it for further processing. Moreover, in order to achieve better performance, usually there are many consumer modules running on many different threads while the producer (or several producers) run on its own thread. This allows to distribute processing work between threads, and in the multi-core, multi-processor environment of today, between physical processors as well. Concurrent frameworks (such as java.util.concurrent) provide out-of-the-box solutions for these kind of problems.
Same pattern, multiple machines
This pattern also works well when wanting to distribute tasks between different physical machines as well. The producer machine somehow creates information, and offloads the task of processing that information to other machines. Since we want to distribute the work between different machines without coupling issues, the data is written to a physical disk and using some sort of a distribution system (e.g. JMS queues), a notification containing the full path to the data is sent. An available consumer receiving the notification can then read the data from the physical disk and process it. The following diagram illustrates this simple idea:
Ever since I started using TDD (test driven development) methods in my work, I never stopped. I rarely start a project without knowing how I’ll test it, and not just in Java: C#, Objective-C, and Python as well. I’ve found that TDD can be done in the most unlikely places, such as servlets using Cactus or Java EE using MockRunner.
However, when I started working with Project Darkstar recently, it seemed impossible to test. Mostly, because it requires you to use their interface, ManagedReference, to contain references between serialized objects (you can decide not to use them, but then performance goes down significantly). The problem is not with the interface but with the way it’s created, which is only by using the DataManager they provide, using the AppContext.getDataManager() method.
This is a problem, because to keep a ManagedPlayer object which holds a reference to a ManagedWeapon, you might have the code:
public final class ManagedPlayer implements ManagedObject, Serializable {
private ManagedReference<ManagedWeapon> weapon;
public void setWeapon(ManagedWeapon weapon) {
// alert early-on that this object is going to change; prevents
// collisions later.
AppContext.getDataManager().markForUpdate(this);
// sets the weapon as a managed reference
this.weapon = AppContext.getDataManager().createReference(weapon);
}
// ... the rest of the class
}
Within the Darkstar runtime context, this works great. However, within a JUnit context, this will fail as AppContext.getDataManager() will return null, and the code will throw an NPE.
For that reason, I have created a set of mocks, and I thought I’d share them in case someone wants to make this into a bigger project, Mockstar or something.
First, I created an interface to abstract everything to do with ManagedReference. Since ManagedObject is just a marker interface, I don’t care much about it; however, the creation of ManagedReference, and the creation of the scalable versions of Set and Map (ScalableHashSet and ScalableHashMap, respectively):
public interface ManagedFactory {
<T> ManagedReference<T> createReference(T item);
void markForUpdate(Object item);
<T> Collection<T> createCollection();
<T, K> Map<T, K> createMap();
}
Now, the previous code could be written as:
public final class ManagedPlayer implements ManagedObject, Serializable {
private ManagedFactory factory; // initialized in ctor
private ManagedReference<ManagedWeapon> weapon;
public void setWeapon(ManagedWeapon weapon) {
factory.markForUpdate(this);
this.weapon = factory.createReference(weapon);
}
// ... the rest of the class
}
The following are the implementations of MockManagedReference, DarkstarManagedFactory and MockManagedFactory:
MockManagedReference
Note that this class is serializable as to not break the original ManagedReference’s implementation’s intention.
public class MockManagedReference<T> implements ManagedReference<T>, Serializable {
private static int globalId = 1;
private T item;
private int id;
public ManagedReferenceMock(T item) {
this.item = item;
this.id = globalId++;
}
public T get() {
return item;
}
public T getForUpdate() {
return item;
}
public BigInteger getId() {
return BigInteger.valueOf(id);
}
}
DarkstarManagedFactory
This class is the one you would really use in the Darkstar context.
public final class DarkstarManagedFactory implements ManagedFactory {
public <T> ManagedReference<T> createReference(T item) {
return AppContext.getDataManager().createReference(item);
}
public void markForUpdate(Object item) {
AppContext.getDataManager().markForUpdate(item);
}
public <T> Collection<T> createCollection() {
return new ScalableHashSet<T>();
}
public <T, K> Map<T, K> createMap() {
return new ScalableHashMap<T,K>();
}
}
MockManagedFactory
This class will be used in a unit testing context.
public class ManagedObjectFactoryMock implements ManagedObjectFactory {
public <T> ManagedReference<T> createReference(T item) {
return new ManagedReferenceMock<T>(item);
}
public void markForUpdate(Object item) {
// empty.
}
public <T> Collection<T> createCollection() {
return new HashSet<T>();
}
public <T, K> Map<T, K> createMap() {
return new HashMap<T,K>();
}
}
Conclusion
I couldn’t find anything in my searches for a mock system for Darkstar. If someone knows of any, please let me know. On the other hand, if someone actually does something with what I wrote, I would be even more interesting in knowing!
Liked Chaotic Java? It's free! But I also make some other things that aren't, which you might like. Like Firewall, a rule changing, turn based strategy game for iOS.