/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.common.data; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import javax.annotation.Nonnull; import javax.annotation.concurrent.NotThreadSafe; import java.io.IOException; import java.io.InputStream; /** * This class takes care for loading the skills from the XML file as required. Calling this function is required * before the skills and skill groups are used. * <p/> * This function blocks the execution of the current thread until loading the Skill is done for sure. * * @author Martin Karing <nitram@illarion.org> */ @NotThreadSafe public final class SkillLoader { /** * The logger instance of this class. */ @Nonnull private static final Logger log = LoggerFactory.getLogger(SkillLoader.class); /** * This value is turned {@code true} once the loading is finished. */ private static volatile boolean loadingFinished; /** * Load the skills from the XML file. */ @SuppressWarnings("OverlyLongMethod") public static void load() { if (loadingFinished) { return; } ClassLoader ccl = Thread.currentThread().getContextClassLoader(); synchronized (SkillLoader.class) { if (loadingFinished) { return; } try (InputStream skillXmlStream = ccl.getResourceAsStream("skills.xml")) { if (skillXmlStream == null) { throw new IllegalStateException("Skill XML was not found."); } XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); parser.setInput(skillXmlStream, "UTF-8"); parser.nextTag(); parser.require(XmlPullParser.START_TAG, null, "skills"); int currentTag = parser.nextTag(); while (currentTag == XmlPullParser.START_TAG) { parser.require(XmlPullParser.START_TAG, null, "group"); SkillGroup currentGroup = readSkillGroup(parser); SkillGroups.getInstance().addSkillGroup(currentGroup); currentTag = parser.nextTag(); while (currentTag == XmlPullParser.START_TAG) { parser.require(XmlPullParser.START_TAG, null, "skill"); Skill skill = readSkill(parser, currentGroup); Skills.getInstance().addSkill(skill); parser.nextTag(); parser.require(XmlPullParser.END_TAG, null, "skill"); currentTag = parser.nextTag(); } parser.require(XmlPullParser.END_TAG, null, "group"); currentTag = parser.nextTag(); } parser.require(XmlPullParser.END_TAG, null, "skills"); } catch (@Nonnull XmlPullParserException e) { log.error("Parsing the XML file failed.", e); } catch (@Nonnull IOException e) { log.error("Reading the XML file failed.", e); } loadingFinished = true; } } @Nonnull private static SkillGroup readSkillGroup(@Nonnull XmlPullParser parser) throws XmlPullParserException { int count = parser.getAttributeCount(); String germanName = null; String englishName = null; int id = -1; for (int i = 0; i < count; i++) { switch (parser.getAttributeName(i)) { case "german": germanName = parser.getAttributeValue(i); break; case "english": englishName = parser.getAttributeValue(i); break; case "id": id = Integer.parseInt(parser.getAttributeValue(i)); break; default: } } if ((germanName != null) && (englishName != null) && (id > -1)) { return new SkillGroup(id, germanName, englishName); } throw new XmlPullParserException("Group tag does not contain the required attributes.", parser, null); } @Nonnull private static Skill readSkill(@Nonnull XmlPullParser parser, @Nonnull SkillGroup group) throws XmlPullParserException { int count = parser.getAttributeCount(); String serverName = null; String germanName = null; String englishName = null; int serverId = -1; for (int i = 0; i < count; i++) { String attributeName = parser.getAttributeName(i); switch (attributeName) { case "name": serverName = parser.getAttributeValue(i); break; case "german": germanName = parser.getAttributeValue(i); break; case "english": englishName = parser.getAttributeValue(i); break; case "id": try { serverId = Integer.parseInt(parser.getAttributeValue(i)); } catch (NumberFormatException e) { throw new XmlPullParserException("Parsing the ID attribute failed.", parser, e); } break; default: break; } } if ((germanName != null) && (englishName != null) && (serverName != null) && (serverId >= 0)) { return new Skill(serverId, serverName, germanName, englishName, group); } throw new XmlPullParserException("Skill tag does not contain the required attributes.", parser, null); } /** * Private constructor to block the creation of a instance. */ private SkillLoader() { // nothing } }