package tk.amberide.ide.data.state.xml; import tk.amberide.ide.data.io.XML; import tk.amberide.ide.data.state.AbstractStateManager; import tk.amberide.ide.data.state.Scope; import tk.amberide.ide.data.state.node.FieldState; import tk.amberide.ide.data.state.node.IState; import tk.amberide.ide.data.state.node.SimpleState; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.List; import nu.xom.Attribute; import nu.xom.Builder; import nu.xom.Document; import nu.xom.Element; import nu.xom.Elements; import nu.xom.Serializer; import nu.xom.Text; public class XMLStateManager extends AbstractStateManager { @Override public void emitStates(int id) throws Exception { Element root = new Element("storage"); Document doc = new Document(root); Element fields = new Element("fields"); List<IState> statesList = states.get(id); for (int i = 0; i != statesList.size(); i++) { IState state = statesList.get(i); if (state instanceof FieldState) { FieldState fs = (FieldState) state; Object data = fs.get(); if (data != null) { Element field = new Element("field"); field.addAttribute(new Attribute("path", fs.getName())); field.appendChild(new Text(XML.toXML(data))); fields.appendChild(field); } } else { Element store = new Element("state"); store.addAttribute(new Attribute("name", state.getName())); store.appendChild(new Text(XML.toXML(state.get()))); root.appendChild(store); } } root.appendChild(fields); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); Serializer serializer = new Serializer(buffer, "UTF-8") { @Override protected void write(Text text) throws IOException { writeRaw(text.getValue()); } }; serializer.write(doc); serializer.flush(); Scope scope = Scope.predefinedScope(id); File output = new File(resolveMacros(scope.location()) + File.separator + scope.name() + ".xml"); output.mkdirs(); if (!output.delete()) { System.err.println("Failed to delete states file..."); } if (!output.createNewFile()) { System.err.println("Failed to create states file..."); } FileOutputStream fos = new FileOutputStream(output); fos.write(buffer.toString("UTF-8").getBytes()); fos.close(); } @Override public void loadStates(int id) throws Exception { Scope scope = Scope.predefinedScope(id); File storage = new File(resolveMacros(scope.location()) + File.separator + scope.name() + ".xml"); try { Document doc = new Builder().build(storage); Element root = doc.getRootElement(); Elements states = root.getChildElements(); for (int s = 0; s != states.size(); s++) { Element state = states.get(s); if (state.getLocalName().equals("fields")) { Elements fields = state.getChildElements(); for (int i = 0; i != fields.size(); i++) { Element fieldState = fields.get(i); String path = fieldState.getAttributeValue("path"); String[] split = path.split("/"); Class owner = Class.forName(split[0]); if (owner != null) { Field f = owner.getDeclaredField(split[1]); if (f != null && Modifier.isStatic(f.getModifiers())) { Object data; try { data = XML.fromXML(fieldState.getChild(0).toXML()); } catch (Exception e) { e.printStackTrace(); continue; } f.setAccessible(true); f.set(null, data); IState loaded = new FieldState(f); addState(id, loaded); fireStateLoaded(loaded, id); } } } } else { String name = state.getAttributeValue("name"); Object data; try { data = XML.fromXML(state.getChild(0).toXML()); } catch (Exception e) { System.err.println("Failed to read state " + name + "!" + state.getChild(0).toXML()); e.printStackTrace(); continue; } IState loaded = new SimpleState(name, data); addState(id, loaded); fireStateLoaded(loaded, id); } } } catch (FileNotFoundException e) { System.err.println("Umm... Storage file " + storage + " doesn't exist."); e.printStackTrace(); } } }