Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.shaman.rpg.battle.attack; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.xml.transform.stream.StreamSource; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.Namespace; import org.jdom2.input.SAXBuilder; import org.jdom2.input.sax.XMLReaderJDOMFactory; import org.jdom2.input.sax.XMLReaderXSDFactory; import org.netbeans.api.annotations.common.StaticResource; import org.openide.util.Exceptions; import org.shaman.database.Database; import org.shaman.database.util.DynamicContainer; import org.shaman.database.util.DynamicList; /** * Loads and saves attacks used by monsters to and from xml. * @author Sebastian Wei */ public class MonsterAttackLoader { @StaticResource private static final String SCHEMA = "org/shaman/rpg/battle/attack/attack.xsd"; private XMLReaderJDOMFactory xsdFactory; private SAXBuilder saxBuilder; private Namespace namespace; private MonsterAttackLoader() { } public static MonsterAttackLoader getInstance() { return MonsterAttackLoaderHolder.INSTANCE; } /** * Loads the monster attacks from database. * The database has to have a DynamicContainer containing MonsterAttack-instances * as root. This method directly returns the backing array, so changes to this * database directly will reflect on the monster attacks and vice versa. * @param db the database to load * @return a list with the loaded attacks * @see #saveToDatabase(java.util.List) */ public List<MonsterAttack> loadFromDatabase(Database<? extends DynamicList<MonsterAttack>> db) { return db.getRoot(); } /** * Saves the monster attacks to database. * @param attacks the attacks to save * @return the database containing the attacks * @see #loadFromDatabase(org.shaman.database.Database) */ public Database<? extends DynamicList<MonsterAttack>> saveToDatabase(List<MonsterAttack> attacks) { if (attacks instanceof ArrayList) { return new Database<DynamicList<MonsterAttack>>( new DynamicList<MonsterAttack>((ArrayList<MonsterAttack>) attacks)); } else { return new Database<DynamicList<MonsterAttack>>( new DynamicList<MonsterAttack>(new ArrayList<MonsterAttack>(attacks))); } } private void initSaxBuilder() { if (saxBuilder == null) { //read schema InputStream in = null; try { in = new BufferedInputStream( MonsterAttackLoader.class.getClassLoader().getResourceAsStream(SCHEMA)); StreamSource source = new StreamSource(in, SCHEMA); xsdFactory = new XMLReaderXSDFactory(source); } catch (JDOMException ex) { throw new ExceptionInInitializerError(ex); } finally { if (in != null) { try { in.close(); } catch (IOException ex) { } //ignore } } //create sax builder saxBuilder = new SAXBuilder(xsdFactory); //Create the namespace namespace = Namespace.getNamespace("Engine/Battle/Attacks"); } } /** * Loads the attacks used by monsters from the specified xml file. * The xml file has to be valid against the xsd-schema. * @param xml the xml file * @return a list with all loaded attacks */ public List<MonsterAttack> loadFromXml(File xml) throws IOException, JDOMException { initSaxBuilder(); return loadFromXml(saxBuilder.build(xml)); } /** * Loads the attacks used by monsters from the specified input stream. * This can be used to load the attacks from e.g. the class path. Note: the * input stream might be closed automatically. * The xml file has to be valid against the xsd-schema. * @param xml the xml file * @return a list with all loaded attacks */ public List<MonsterAttack> loadFromXml(InputStream in) throws IOException, JDOMException { initSaxBuilder(); return loadFromXml(saxBuilder.build(in)); } private List<MonsterAttack> loadFromXml(Document doc) { //the document is valid, so start with analysing it Collection<Element> attacks = doc.getRootElement().getChildren("Attack", namespace); List<MonsterAttack> list = new ArrayList<MonsterAttack>(attacks.size()); //load races for (Element e : attacks) { MonsterAttack attack = new MonsterAttack(); //load name attack.setName(e.getChildTextTrim("name", namespace)); //load attack class AttackClass ac = new AttackClass(Integer.parseInt(e.getChildTextTrim("element", namespace)), AttackClass.Category.valueOf(e.getChildTextTrim("category", namespace)), AttackClass.School.valueOf(e.getChildTextTrim("school", namespace)), AttackClass.CalculationType.valueOf(e.getChildTextTrim("calculation", namespace)), AttackClass.Target.valueOf(e.getChildTextTrim("target", namespace))); attack.setAttackClass(ac); //load strength attack.setBaseStrength(Integer.parseInt(e.getChildTextTrim("strength", namespace))); //load precision attack.setPrecision(Integer.parseInt(e.getChildTextTrim("precision", namespace)) / 100f); //load attack points attack.setActionPoints(Integer.parseInt(e.getChildTextTrim("attackPoints", namespace))); //TODO: custom attributes //add to list list.add(attack); } return list; } private static class MonsterAttackLoaderHolder { private static final MonsterAttackLoader INSTANCE = new MonsterAttackLoader(); } }