org.darkstar.batch.utils.DarkstarUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.darkstar.batch.utils.DarkstarUtils.java

Source

package org.darkstar.batch.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/** 
 * Copyright (c) 2010-2014 Darkstar Dev Teams
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program 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.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/
 * 
 * This file is part of DarkStar-server source code.
 */

/**
 * Utility Methods for the Darkstar Batch Processes
 */
public class DarkstarUtils {
    private static List<String> badCharacterDataLines;

    public static final String FIELD_CLOSING_TAG = "</field>";
    public static final String FIELD_ID_OPENING_TAG = "<field name=\"id\">";
    public static final String FIELD_INDEX_OPENING_TAG = "<field name=\"index\">";
    public static final String FIELD_NAME_OPENING_TAG = "<field name=\"name\">";
    public static final String FIX_ME = "FIXME: ";
    public static final Logger LOG = Logger.getLogger(DarkstarUtils.class);

    public static final String NPC_LIST_INSERT_START = "INSERT INTO `npc_list` VALUES (";

    /**
     * Method to Collapse a String into one line, and Format It By Removing Escaped Characters
     * @param xmlString String to Collapse & Format
     * @return
     */
    public static String collapseAndFormatXmlString(final String xmlString) {
        String newString = xmlString;
        newString = newString.replaceAll("(" + System.getProperty("line.separator") + ")", " ");
        newString = StringEscapeUtils.unescapeXml(newString);
        return newString;
    }

    /**
     * Method to PolUtils Npc Id to Shortened Darkstar Sql Npc Id
     * @param polUtilsNpcId Long POLUtils NPC Id
     * @return Short Darkstar SQL Npc Id
     */
    public static int convertPolUtilsNpcIdToDarkstar(final int polUtilsNpcId) {
        final String hexString = Integer.toHexString(polUtilsNpcId);
        final String shortHexString = hexString.substring(hexString.length() - 3, hexString.length());
        final int npcId = Integer.parseInt(shortHexString, 16);
        LOG.debug(String.format("convertPolUtilsNpcIdToDarkstar: %d -> %s -> %s -> %d", polUtilsNpcId, hexString,
                shortHexString, npcId));
        return npcId;
    }

    /**
     * Method to Filter Out Known Bad Character Patterns
     * @param text Text to Filter
     * @return Filtered Text
     */
    public static String filterBadCharacters(final String text) {
        loadBadCharacterData();

        String newText = text;

        for (final String regex : badCharacterDataLines) {
            LOG.debug(String.format("Filtering Bad Character Pattern: %s", regex));
            newText = newText.replaceAll(regex, "");
        }

        return newText;
    }

    /**
     * Method to Find the Current Npc Id in the Npc List
     * @param npcListSqlLine Line in the Npc List File
     * @return Short Darkstar Npc Id of the Npc on this Line
     */
    public static int findCurrentNpcIdInNpcList(final String npcListSqlLine) {
        final int insertIndex = npcListSqlLine.indexOf(NPC_LIST_INSERT_START);

        if (insertIndex == -1 || npcListSqlLine.startsWith("--")) {
            return -1;
        }

        final int endIndex = npcListSqlLine.indexOf(",", insertIndex);
        String npcIdString = npcListSqlLine.substring(NPC_LIST_INSERT_START.length(), endIndex);

        if (npcIdString.startsWith("'")) {
            npcIdString = npcIdString.substring(1, npcIdString.length() - 1);

        }
        return Integer.valueOf(npcIdString);
    }

    /**
     * Method to Find the Name of the Npc on the Current Line
     * @param npcListSqlLine Current Line of the Npc List SQL
     * @return Name of the NPC as Listed in the SQL
     */
    public static String findCurrentNpcNameInNpcList(final String npcListSqlLine) {
        final int insertIndex = npcListSqlLine.indexOf(NPC_LIST_INSERT_START);

        if (insertIndex == -1 || npcListSqlLine.startsWith("--")) {
            return null;
        }

        int endIndex = npcListSqlLine.indexOf(",", insertIndex);
        endIndex = npcListSqlLine.indexOf(",", endIndex + 1);
        final int npcNameStartIndex = npcListSqlLine.indexOf("'", endIndex);
        int npcNameEndIndex = npcListSqlLine.indexOf("'", npcNameStartIndex + 1);

        if (npcListSqlLine.charAt(npcNameEndIndex - 1) == '\\') {
            npcNameEndIndex = npcListSqlLine.indexOf("'", npcNameEndIndex + 1);
        }

        final String name = npcListSqlLine.substring(npcNameStartIndex + 1, npcNameEndIndex);
        return name.replaceAll("\\\\\'", "'");
    }

    /**
     * Method to Find the Index of a Specified ID In the POLUtils Moblist
     * @param polUtilsMobListString String Representation of POLUtils Mob List
     * @param polUtilsNpcId POLUtils NPC ID
     * @return Index
     */
    public static int findPolUtilsIndexById(final String polUtilsMobListString, final int polUtilsNpcId) {
        return polUtilsMobListString.indexOf(String.valueOf(polUtilsNpcId));
    }

    /**
     * Method to Find a POLUtils NPC's Name By Id (Starting @ Beginning of File)
     * @param polUtilsMobListString String Representation of the Mob List File
     * @param npcId Npc Id to Find
     * @return Name of the Npc In POLUtils
     */
    public static String findPolUtilsNpcNameById(final String polUtilsMobListString, final int npcId) {
        return findPolUtilsNpcNameById(polUtilsMobListString, npcId, 0);
    }

    /**
     * Method to Find a POLUtils NPC's Name By Id (Starting at Specified Index)
     * @param polUtilsMobListString String Representation of the Mob List File
     * @param npcId Npc Id to Find
     * @param lastIndex Starting Index
     * @param searchBackwards TRUE if searching backwards, FALSE otherwise.
     * @return Name of the Npc In POLUtils
     */
    public static String findPolUtilsNpcNameById(final String polUtilsMobListString, final int npcId,
            final int lastIndex) {
        final int nameIndex = polUtilsMobListString.indexOf(String.valueOf(npcId), lastIndex);

        if (nameIndex == -1) {
            return "";
        }

        final int nameStartIndex = polUtilsMobListString.indexOf(FIELD_NAME_OPENING_TAG, nameIndex);
        final int nameEndIndex = polUtilsMobListString.indexOf(FIELD_CLOSING_TAG, nameStartIndex);
        final String polUtilsNpcName = polUtilsMobListString
                .substring(nameStartIndex + FIELD_NAME_OPENING_TAG.length(), nameEndIndex);

        LOG.debug(String.format("findPolUtilsNpcNameById: %d -> %s", npcId, polUtilsNpcName));
        return polUtilsNpcName;
    }

    /**
     * Scans a String Representation of <npc_list.sql> for the beginning of a specific zone's data
     * @param zoneName Zone Name
     * @param npcListSql String Representation of the SQL File
     * @return Starting Index
     */
    public static int findZoneInNpcListSql(final String zoneName, final List<String> npcListSqlLines) {
        int zoneLine = -1;

        for (int lineIndex = 0; lineIndex < npcListSqlLines.size(); lineIndex++) {
            final String npcListSqlLine = npcListSqlLines.get(lineIndex);

            int zoneIndex = npcListSqlLine.indexOf("-- " + zoneName);

            // Don't Mistake a WoTG Zone for the Regular Type
            if (npcListSqlLine.indexOf("-- " + zoneName + " [S]") == zoneIndex && zoneName.indexOf("[S]") == -1) {
                zoneIndex = npcListSqlLine.indexOf("-- " + zoneName,
                        zoneIndex + ("-- " + zoneName + " [S]").length());
            }

            if (zoneIndex >= 0) {
                zoneLine = lineIndex + 2; // +2 gets us past the closing comment
                break;
            }
        }

        return zoneLine;
    }

    /**
     * Method to Get the Path to the Dialog Table File By Zone ID
     * @param configProperties Handle to Batch Configuration Properties
     * @param zoneId Zone ID
     * @return Path to the Mob List File
     */
    public static String getDialogTablePathByZoneId(final Properties configProperties, final int zoneId) {
        final StringBuilder polUtilsMobListPath = new StringBuilder();
        polUtilsMobListPath.append(configProperties.getProperty("polutils_dump", "./polutils_dump/"));
        polUtilsMobListPath.append("dialog-table-");
        polUtilsMobListPath.append(String.format("%03d", zoneId));
        polUtilsMobListPath.append(".xml");
        return polUtilsMobListPath.toString();
    }

    /**
     * Method to get the Mapping File Key
     * @param zoneId Zone ID
     * @param npcName Npc Name
     * @return Mapping File Key
     */
    public static String getMappingKey(final Map<String, Integer> keyCountMap, final int zoneId,
            final String npcName) {
        final StringBuilder mappingKeyBuilder = new StringBuilder();
        mappingKeyBuilder.append(String.format("%03d", zoneId));
        mappingKeyBuilder.append('|');
        mappingKeyBuilder.append(npcName);

        final String keyWithoutCount = mappingKeyBuilder.toString();
        Integer keyCount = keyCountMap.get(keyWithoutCount);

        if (keyCount == null) {
            keyCount = 1;
        } else {
            keyCount++;
        }

        mappingKeyBuilder.append('|');
        mappingKeyBuilder.append(keyCount);

        keyCountMap.put(keyWithoutCount, keyCount);

        final String mappingKey = mappingKeyBuilder.toString();

        LOG.debug(String.format("getMappingKey: %s", mappingKey));

        return mappingKey;
    }

    /**
     * Method to Get the Path to the Mob List File By Zone ID
     * @param configProperties Handle to Batch Configuration Properties
     * @param zoneId Zone ID
     * @return Path to the Mob List File
     */
    public static String getMobListPathByZoneId(final Properties configProperties, final int zoneId) {
        final StringBuilder polUtilsMobListPath = new StringBuilder();
        polUtilsMobListPath.append(configProperties.getProperty("polutils_dump", "./polutils_dump/"));
        polUtilsMobListPath.append("mob-list-");
        polUtilsMobListPath.append(String.format("%03d", zoneId));
        polUtilsMobListPath.append(".xml");
        return polUtilsMobListPath.toString();
    }

    /**
     * Method to Get Read the NPC List SQL
     * @param configProperties Handle to Batch Configuration Properties
     * @return List of Strings Representing Each Line of the File
     */
    public static List<String> getNpcListFileLines(final Properties configProperties) {
        final StringBuilder npcListSqlPathBuilder = new StringBuilder();
        npcListSqlPathBuilder.append(configProperties.getProperty("darkstar_root", ""));
        npcListSqlPathBuilder.append("sql/npc_list.sql");

        final File npcIdFile = new File(npcListSqlPathBuilder.toString());

        List<String> npcListSqlLines = null;

        try {
            npcListSqlLines = FileUtils.readLines(npcIdFile);
        } catch (final IOException e) {
            throw new RuntimeException("Error Reading Npc List SQL!", e);
        }

        return npcListSqlLines;
    }

    /**
     * Method to get the Zone Comment as Mapped to the NPC List SQL File
     * @param configProperties Handle to Batch Configuration Properties
     * @param zoneId Zone ID
     * @return Zone Comment
     */
    public static String getNpcListSqlZoneCommentByZoneId(final Properties configProperties, final int zoneId) {
        final StringBuilder polUtilsMobListPath = new StringBuilder();
        polUtilsMobListPath.append("mob-list-");
        polUtilsMobListPath.append(String.format("%03d", zoneId));
        polUtilsMobListPath.append(".xml");
        return configProperties.getProperty(polUtilsMobListPath.toString());
    }

    /**
     * Method to Get the Text Id File Path for a Given Zone
     * @param configProperties Handle to the Batch Configuration Properties
     * @param zoneId Zone ID
     * @return Path to Text ID File
     */
    public static String getTextIdFilePath(final Properties configProperties, final int zoneId) {
        final StringBuilder textIdPath = new StringBuilder();
        textIdPath.append(getZonePath(configProperties, zoneId));
        textIdPath.append("TextIDs.lua");
        return textIdPath.toString();
    }

    /**
     * Method to Get the Zone Path
     * @param configProperties Handle to the Batch Configuration Properties
     * @param zoneId Zone ID
     * @return Path to the Zone's Root
     */
    public static String getZonePath(final Properties configProperties, final int zoneId) {
        final String darkstarRoot = configProperties.getProperty("darkstar_root", "../../");
        final String zoneIdString = String.format("%03d", zoneId);
        final String relativeZonePath = configProperties.getProperty(zoneIdString);
        return (darkstarRoot + relativeZonePath);
    }

    /**
     * Checks if a Zone is Mapped in the Batch Config Properties
     * @param configProperties Handle to the Batch Config Properties
     * @param zoneId Zone ID
     * @return TRUE if mapped, FALSE otherwise.
     */
    public static boolean isZoneMapped(final Properties configProperties, final int zoneId) {
        boolean isMapped = false;

        final String zoneIdString = String.format("%03d", zoneId);

        if (configProperties.containsKey(zoneIdString)) {
            isMapped = true;
        }

        return isMapped;
    }

    /**
     * Method to Load the Bad Character Data Resource
     */
    private static void loadBadCharacterData() {
        synchronized (DarkstarUtils.class) {
            if (badCharacterDataLines == null) {
                final InputStream configStream = DarkstarUtils.class.getResourceAsStream("/badcharacters.dat");
                try {
                    badCharacterDataLines = IOUtils.readLines(configStream);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                IOUtils.closeQuietly(configStream);
            }
        }
    }

    /**
     * Method to Load the Batch Configuration Properties, Creating a Config From the Embedded Default If Necessary
     * @return Configuration Properties
     */
    public static Properties loadBatchConfiguration() {
        Properties config = new Properties();

        try {
            final File configFile = new File("config.properties");

            if (!configFile.exists()) {
                final InputStream configStream = DarkstarUtils.class
                        .getResourceAsStream("/defaultconfig.properties");
                final byte[] configBytes = new byte[configStream.available()];
                IOUtils.readFully(configStream, configBytes);
                IOUtils.closeQuietly(configStream);
                FileUtils.writeByteArrayToFile(configFile, configBytes);
            }

            final FileInputStream configStream = new FileInputStream(configFile);
            config.load(configStream);
            IOUtils.closeQuietly(configStream);

        } catch (final Exception e) {
            throw new RuntimeException("Error Reading Config File!", e);
        }

        return config;
    }

    /**
     * Method to Load the Npc Id Mapping Properties
     * @return Mapping Properties
     */
    public static Properties loadMappingProperties(final Properties configProperties) {
        final Properties mappingProperties = new Properties() {
            private static final long serialVersionUID = 665397466355935210L;

            @Override
            public synchronized Enumeration<Object> keys() {
                return Collections.enumeration(new TreeSet<Object>(super.keySet()));
            }

            @Override
            public Set<Object> keySet() {
                return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
            }
        };

        try {
            final File mappingFile = new File(
                    configProperties.getProperty("mapping_file", "./npcid-mapping.properties"));
            if (mappingFile.exists()) {
                final FileInputStream mappingStream = new FileInputStream(mappingFile);
                mappingProperties.load(mappingStream);
                IOUtils.closeQuietly(mappingStream);
            }
        } catch (final Exception e) {
            throw new RuntimeException("Error Reading Mapping File!", e);
        }

        return mappingProperties;
    }

    /**
     * Method to Load the Npc Id Shift Properties
     * @return Shift Properties
     */
    public static Properties loadShiftProperties(final Properties configProperties) {
        final Properties shiftProperties = new Properties();

        try {
            final File shiftFile = new File(configProperties.getProperty("shift_file", "npcid-shift.properties"));
            if (shiftFile.exists()) {
                final FileInputStream mappingStream = new FileInputStream(shiftFile);
                shiftProperties.load(mappingStream);
                IOUtils.closeQuietly(mappingStream);
            }

            // Shift Properties are 1 time use.
            shiftFile.deleteOnExit();
        } catch (final Exception e) {
            throw new RuntimeException("Error Reading Mapping File!", e);
        }

        return shiftProperties;
    }

    /**
     * Method to Reconstruct the Long Npc Id as Used by POLUtils
     * @param hexPrefix Hex Prefix for this File
     * @param sqlNpcId Short NPC ID From Darkstar SQL
     * @return Long POLUtils NPC ID
     */
    public static int reconstructPolUtilsNpcId(final String hexPrefix, final int sqlNpcId) {
        String polUtilsHexId = Integer.toHexString(sqlNpcId);

        while (polUtilsHexId.length() < 3) {
            polUtilsHexId = "0" + polUtilsHexId;
        }

        polUtilsHexId = hexPrefix + polUtilsHexId;

        final int polUtilsNpcId = Integer.parseInt(polUtilsHexId, 16);
        LOG.debug(
                String.format("reconstructPolUtilsNpcId: %d -> %s -> %d", sqlNpcId, polUtilsHexId, polUtilsNpcId));

        return polUtilsNpcId;
    }

    /**
     * Method to Replace the NPC ID on the Current Line w/ a New One
     * @param npcListSqlLines Line Array of the NPC List SQL
     * @param lineIndex Index of Current Line
     * @param newNpcId New Short NPC ID
     */
    public static void replaceNpcId(final List<String> npcListSqlLines, final int lineIndex, final int newNpcId,
            final boolean markAsGuess) {
        final String npcIdLine = npcListSqlLines.get(lineIndex);
        final int endIndex = npcIdLine.indexOf(",");
        final String insertStringFragment = npcIdLine.substring(0, NPC_LIST_INSERT_START.length());
        final String postIdFragment = npcIdLine.substring(endIndex, npcIdLine.length());
        String newNpcIdLine = insertStringFragment + newNpcId + postIdFragment;

        if (markAsGuess) {
            newNpcIdLine = "FIXME: " + newNpcIdLine;
        }

        npcListSqlLines.set(lineIndex, newNpcIdLine);
    }

    public static void replacePolUtilsName(final List<String> npcListSqlLines, final int lineIndex,
            final String name) {
        final String npcIdLine = npcListSqlLines.get(lineIndex);

        int startIndex = npcIdLine.indexOf(",");
        startIndex = npcIdLine.indexOf(",", startIndex + 1);
        int nextQuote = npcIdLine.indexOf("'", startIndex + 2);
        int endIndex = npcIdLine.indexOf(",", startIndex + 1);

        if (endIndex < nextQuote) {
            endIndex = npcIdLine.indexOf(",", endIndex + 1);
        }

        final String newLine;

        if (name == null) {
            newLine = npcIdLine.substring(0, startIndex + 1) + "\'\'"
                    + npcIdLine.substring(endIndex, npcIdLine.length());
        } else {
            newLine = npcIdLine.substring(0, startIndex + 1) + '\'' + name.replaceAll("'", "\\\\'") + '\''
                    + npcIdLine.substring(endIndex, npcIdLine.length());
        }

        npcListSqlLines.set(lineIndex, newLine);
    }

    public static void removeZoneId(final List<String> npcListSqlLines, final int lineIndex) {
        final String npcIdLine = npcListSqlLines.get(lineIndex);
        final int startIndex = npcIdLine.lastIndexOf(",");
        npcListSqlLines.set(lineIndex, npcIdLine.substring(0, startIndex) + ");");
    }

    /**
     * Method to Save the Mapping Properties
     * @param configProperties Handle to Batch Configuration Properties
     * @param mappingProperties Handle to Mapping Properties
     */
    public static void saveMappingProperties(final Properties configProperties,
            final Properties mappingProperties) {
        try {
            final File mappingFile = new File(
                    configProperties.getProperty("mapping_file", "./npcid-mapping.properties"));
            final FileOutputStream mappingStream = new FileOutputStream(mappingFile);
            mappingProperties.store(mappingStream, "Darkstar<->POLUtils Npc Id Mappings");
            IOUtils.closeQuietly(mappingStream);
        } catch (final Exception e) {
            throw new RuntimeException("Error Reading Mapping File!", e);
        }
    }

    /**
     * Method to Save the Npc Id Shift Properties
     * @param configProperties Handle to Batch Configuration Properties
     * @param npcIdShiftProperties Shift Properties
     */
    public static void saveNpcIdShiftProperties(final Properties configProperties,
            final Properties npcIdShiftProperties) {
        try {
            final File shiftFile = new File(configProperties.getProperty("shift_file", "npcid-shift.properties"));
            final FileOutputStream mappingStream = new FileOutputStream(shiftFile);
            npcIdShiftProperties.store(mappingStream, "Darkstar Shifted Npc Ids");
            IOUtils.closeQuietly(mappingStream);
        } catch (final Exception e) {
            throw new RuntimeException("Error Reading Mapping File!", e);
        }

    }

    /**
     * Method to Save the NPC List SQL File
     * @param configProperties Handle to Batch Configuration Properties
     * @param npcListSqlLines Array of the NPC List SQL Lines to Save
     */
    public static void saveNpcListSqlFile(final Properties configProperties, final List<String> npcListSqlLines) {
        final StringBuilder npcListSqlPathBuilder = new StringBuilder();
        npcListSqlPathBuilder.append(configProperties.getProperty("darkstar_root", ""));
        npcListSqlPathBuilder.append("sql/npc_list.sql");

        final File npcIdFile = new File(npcListSqlPathBuilder.toString());

        try {
            FileUtils.writeLines(npcIdFile, npcListSqlLines);
        } catch (IOException e) {
            throw new RuntimeException("Failed to Write Npc List SQL File!", e);
        }
    }

    /**
     * Method to Write a Copy of the Filtered Dialog Table (Post RegEx Stripping)
     * @param configProperties Handle to Batch Configuration File
     * @param filteredDialogTable Filtered Dialog Table String
     * @param zoneId Zone ID
     */
    public static void writeFilteredDialogTable(final Properties configProperties, final String filteredDialogTable,
            final int zoneId) {
        final StringBuilder filteredDialogTablePathBuilder = new StringBuilder();
        filteredDialogTablePathBuilder
                .append(configProperties.getProperty("filtered_dialog_tables", "./filtered_dialog_tables/"));
        filteredDialogTablePathBuilder.append("filtered-dialog-table-");
        filteredDialogTablePathBuilder.append(String.format("%03d", zoneId));
        filteredDialogTablePathBuilder.append(".xml");

        final File filteredDialogTableFile = new File(filteredDialogTablePathBuilder.toString());

        try {
            FileUtils.writeStringToFile(filteredDialogTableFile, filteredDialogTable);
        } catch (IOException e) {
            throw new RuntimeException("Failed to Write Filtered Dialog Table File!", e);
        }
    }
}