First, the code:
ConfigurationLoader.java
Code:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Field;
public class ConfigurationLoader {
protected static ConfigurationFile loadFile(String path, Class<? extends Overlay> overlay, String[] map) {
return loadFile(new File(path), overlay, map);
}
protected static ConfigurationFile loadFile(File path, Class<? extends Overlay> overlay, String[] map) {
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line = "";
while((line = br.readLine()) != null) {
if(line.startsWith("[ENDOF") || line.startsWith("//") || line.equals("")) {
continue;
}
Overlay instance = (Overlay) overlay.newInstance();
String[] split = line.split("\t");
int index = 0;
for(String part : split) {
Field field = overlay.getField(map[index++]);
if(field.getType().equals(int.class)) {
field.setInt(instance, Integer.parseInt(part));
} else {
field.set(instance, part);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
NPCConfigurationFile.java
Code:
public class NPCConfigurationFile extends ConfigurationFile {
public NPCConfigurationFile() {
ConfigurationLoader.loadFile("data/npcs.cfg", NPCOverlay.class, new String[] { "id", "name", "combat", "health" });
}
}
Overlay.java
Code:
public interface Overlay {
}
NPCOverlay.java
Code:
public class NPCOverlay implements Overlay {
public int id, combat, health;
public String name;
}
data/npc.cfg
Code:
// This is an example comment
0 Hans 0 0
Now, the story/theory:
So, I noticed that someone wanted a rewrite on the aging (never so good in the first place) system used to load CFG files, which, as you probably know, hold most of a private server's static, persistent data. So, I decided that I would work one out for him. This lead to me getting some cool RoR (Ruby on Rails) kind of ideas, i.e. a lot of behind-the-scenes magic that makes the framework tick. Of course, there are downsides to this magic, as it increases the overall complexity of the server. But, in my opinion, it's too cool to pass up.
The theory behind the thing is that you specify a subclass of ConfigurationFile. I've provided an example above: NPCConfigurationFile. Now, ConfigurationFile is just an abstract class which contains no methods or fields: it just defines a ConfigurationFile for the behind-the-scenes magic. Next, you create a class that implements the Overlay interface. Again, it contains no methods or fields. All it does is provides an abstract interface between the ConfigurationLoader (getting to that) and the overlay to which the data will be transferred to (getting to that, too). Now for the magic: you instantiate a new ConfigurationFile subclass (in the example above, NPCConfigurationFile), and that automatically (as specified in the constructor) fires off the loadFile method to the ConfigurationLoader. The method takes three argument. The first is the configuration file's location, which should be obvious. Next is the Overlay implementation's class, which is used to instantiate new Overlays and fill them with data. Next is the map. This corresponds with the order of the fields in the configuration file and the fields on the Overlay. For instance, if the configuration file was in a format like "id name level" (as in the example), then you would pass those three names as a string array, and define them in NPCOverlay. The order must be the same as it is in the CFG file, although order doesn't matter for the Overlay. That's pretty much it.
Questions?