org.shaman.rpg.battle.attack.MonsterAttackLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.shaman.rpg.battle.attack.MonsterAttackLoader.java

Source

/*
 * 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();
    }
}