us.derfers.tribex.rapids.Loader.java Source code

Java tutorial

Introduction

Here is the source code for us.derfers.tribex.rapids.Loader.java

Source

/*
RapidS - Web style development for the desktop.
Copyright (C) 2014 TribeX Software Development
    
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/>.
 */

package us.derfers.tribex.rapids;

import static us.derfers.tribex.rapids.Utilities.debugMsg;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;

import javax.swing.UIManager;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import us.derfers.tribex.rapids.GUI.Swing.GUI;
import us.derfers.tribex.rapids.jvCoreLib.Sys;

/**
 * Starts the JavaScript engine and begins loading XML for widgets and layout information.
 *
 * @author TribeX, Nateowami
 *
 */
public class Loader {
    //Javascript engine initialization
    /** The initial JavaScript engine */
    public ScriptEngine engine = new ScriptEngine();

    public GUI GUI = new GUI();

    /**
     * Where widget variables are stored.  Format: WIDGETID {WIDGETID {WIDGET}, class {CLASSNAME}, And so on for the rest of the parameters}
     */
    //public Map<String, Map<String, Object>> XMLObjects = new HashMap<String, Map<String, Object>>();

    /** Counts Taken ID's for ID-less widgets */
    public Integer XMLObjects__NO__ID = 0;

    /** The escaped compiled RSM file(s) */
    public String escapedFile = "";

    /**
     * The startup method. Starts the JavaScript engine and runs loadAll.
     * @param filePath The file to load initially.
     */
    public void startLoader(String filePath) {
        String fileEscaped = "";
        try {
            fileEscaped = Utilities.EscapeScriptTags(FileUtils.readFileToString(new File(filePath)));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //JavaScript Engine Initialization
        //---------------------------------------------------------------------------//
        //Start Engine:
        debugMsg("JavaScript Engine Started", 4);

        //Import standard functions. Runs before the file loads
        try {
            //Import the standard JavaScript library (Java section)
            engine.eval("importPackage(Packages.us.derfers.tribex.rapids.jvCoreLib);", "RapidS Loader: Line 92");

            debugMsg("Imported JavaScript Standard Library (Java-based)", 3);

        } catch (Exception e1) {
            e1.printStackTrace();
            Utilities.showError("Error initializing JavaScript engine, please make sure you have Java 6+\n\n"
                    + "If you do, please report this error:\n" + e1.getMessage());
            System.exit(1);
        }

        //XXX: Loader section :XXX\\
        //JAVASCRIPT INITIALIZATION:
        //Run JavaScript that must be run before preload. Mainly provides require() and similar routines.
        recursiveLoadJS(engine, "core/init");
        debugMsg("Imported JavaScript Initialization Library (Init)", 4);

        //PRELOAD:
        //Loop through the JavaScript standard library for JavaScript and import all .js files in the preload folder.
        recursiveLoadJS(engine, "core/preload");
        debugMsg("Imported JavaScript Standard Library (PreLoad)", 3);

        //LOAD:
        //Begin loading the XML file(s)
        debugMsg("Loading " + filePath + "", 2);
        loadAll(fileEscaped);

        //POSTLOAD:
        //Loop through the JavaScript standard library for JavaScript and import all .js files in the postload folder.
        recursiveLoadJS(engine, "core/postload");
        debugMsg("Imported JavaScript Standard Library (PostLoad)", 3);

        //Run the program.onload property to allow the program to run scripts after the GUI has loaded.
        engine.call("program.onload", (Object[]) Main.programArguments);

        //XXX: End loader :XXX\\
    }

    /**
     * Starts loading the GUI. Sets Swing look and feel, then loads the GUI using the GUI_Swing object.
     * @param escapedFile The content .rsm file to load UI elements from.
     * @param parent The (optional) parent Object, Eg, a JFrame or JPanel.
     * @param engine The JavaScript engine to pass to GUI_Swing
     */
    public void loadAll(String escapedFile) {

        //Attempt to load .rsm file filePath
        try {

            //Parse filePath
            Document doc = Utilities.XMLStringToDocument(escapedFile);

            //Stabilize parsed document
            doc.normalize();

            //Get body element
            NodeList mainNodeList = doc.getElementsByTagName("rsm");

            //Make sure there is only ONE body element
            if (mainNodeList.getLength() == 1) {
                debugMsg("Parsing Main Element", 4);
                //Get rsm Element
                Element mainElement = (Element) mainNodeList.item(0);

                debugMsg("Setting Theme", 4);
                //If the mainElement has the attribute "theme"
                if (mainElement.getAttributeNode("theme") != null) {
                    //Get the value of the attribute theme for the body element
                    Attr swing_Theme = mainElement.getAttributeNode("theme");

                    //See if the rsm file specifies a theme other than camo
                    if (swing_Theme != null && !swing_Theme.getNodeValue().equalsIgnoreCase("camo")) {
                        try {
                            //Split the theme into the jarfile and the classname (JARFILE.jar : com.stuff.stuff.theme)
                            String[] splitTheme = swing_Theme.getNodeValue().split(":");

                            System.out.println(splitTheme[0].trim() + "**" + splitTheme[1].trim());
                            //Attempt to dynamically load the specified jarfile
                            Sys.addJarToClasspath(Globals.getCWD(splitTheme[0].trim()));

                            //Attempt to set the look'n'feel to the theme specified by the file
                            UIManager.setLookAndFeel(splitTheme[1].trim());

                            debugMsg("Look and Feel set to '" + swing_Theme.getNodeValue() + "'.", 3);

                        } catch (Exception e) {
                            //If unable to set to .rsm's theme, use the system look'n'feel
                            try {
                                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                            } catch (Exception a) {
                                UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
                            }
                            Utilities.showError(
                                    "Error loading Look and Feel Specified, Look and Feel set to System");
                            e.printStackTrace();

                        }
                    } else {
                        //If swing_Theme == camo or is not set, use the system look'n'feel
                        try {
                            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                        } catch (Exception a) {
                            a.printStackTrace();
                            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
                        }
                        debugMsg("Look and Feel (Swing) set to System", 3);
                    }
                } else {
                    //If swing_Theme == camo or is not set, use the system look'n'feel
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (Exception a) {
                        a.printStackTrace();
                        UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
                    }
                    debugMsg("Look and Feel (Swing) set to System", 3);

                }

                //Parse styles
                for (int i = 0; i < mainElement.getElementsByTagName("style").getLength(); i++) {
                    Element styleElement = (Element) mainElement.getElementsByTagName("style").item(i);
                    //Load all styles from the style tags
                    if (styleElement.getAttributeNode("href") != null) {
                        loadStyles(null, styleElement.getTextContent());
                    } else {
                        loadStyles(styleElement.getTextContent(), null);

                    }
                }

                //Parse links
                for (int i = 0; i < mainElement.getElementsByTagName("link").getLength(); i++) {
                    Element linkElement = (Element) mainElement.getElementsByTagName("link").item(i);
                    parseLinks(linkElement, engine);
                }

                //Parse JavaScript in <script> tags
                Main.loader.loadJS(escapedFile, engine);

                //Parse GUI
                for (int i = 0; i < mainElement.getElementsByTagName("window").getLength(); i++) {
                    GUI.loadWindow((Element) mainElement.getElementsByTagName("window").item(i), engine);
                }

            } else { //There was more than one body tag, or 0 body tags

                //Display Error and quit, as we cannot recover from an abnormally formatted file
                Utilities.showError("Error: More or less than one <rsm> tag in '" + escapedFile + "'.\n\n"
                        + "Please add ONE <rsm> tag to '" + escapedFile + "'.");
                System.exit(1);
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

    }

    /**
     * Discovers any script tags in the document and sends them to JSIterator to be parsed.
     * @param escapedFile The escaped file containing script(s) to run.
     * @param engine the JavaScript engine to load the script tags into.
     * @return Boolean telling whether or not it completed
     */
    public boolean loadJS(String escapedFile, ScriptEngine engine) {
        Utilities.debugMsg("Loading JavaScript from <script> tags.");
        //XXX: JAVASCRIPT HANDLING SECTION :XXX\\
        try {
            //Parse filePath
            Document doc = Utilities.XMLStringToDocument(escapedFile);

            //Stabilize parsed document
            doc.normalize();
            //Execute anything in script tags. JavaScript
            //Load all <script> tags

            NodeList scriptNodes = doc.getElementsByTagName("script");

            JSIterator(scriptNodes, engine);

            return true;
            //XXX: END JAVASCRIPT HANDLING :XXX\\
        } catch (Exception e) {
            e.printStackTrace();
            Utilities.showError(
                    "Error loading Javascripts from '" + escapedFile + "'. Please check their validity.");
            return false;
        }
    }

    /**
     * Iterates through a nodelist of script tags and parses them into the JavaScript engine.
     * @param scriptNodes A NodeList of all script tags.
     * @param engine The engine to run the scripts in.
     */
    private void JSIterator(NodeList scriptNodes, ScriptEngine engine) {
        for (int i = 0; i < scriptNodes.getLength(); i++) {
            //Get the specific <script> tag for this loop
            Node scriptNode = scriptNodes.item(i);

            //Load code in <script> tags
            if (scriptNode.getNodeName().equals("script")) {
                debugMsg("Loading Script tag: " + (i + 1));
                //Run all the code inside the <script> tags
                try {
                    engine.eval(scriptNode.getTextContent(), "<script></script> element in rsm file.");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Loads all JavaScript files under 'folder' into 'engine'
     * @param engine The ScriptEngine to run all files in folder in.
     * @param folder The folder to load .js files from.
     */
    private static void recursiveLoadJS(ScriptEngine engine, String folder) {
        File dir = new File(Utilities.getJarDirectory() + "/" + folder);
        try {

            File[] fileList = dir.listFiles();

            Arrays.sort(fileList);

            for (File file : fileList) {
                if (file.isDirectory()) {
                    recursiveLoadJS(engine, folder + "/" + file.getName());
                } else if (file.toString().endsWith(".js")) {
                    engine.eval(
                            new FileReader(new File(Utilities.getJarDirectory() + folder + "/" + file.getName())),
                            folder + "/" + file.getName());
                    debugMsg("Imported JavaScript File: " + file.getName(), 4);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Loads scripts and styles from link tags.
     * @param linkElement The element from which to load the content from.
     * @param engine The ScriptEngine to run links to scripts in.
     * @return
     */
    private boolean parseLinks(Element linkElement, ScriptEngine engine) {

        //Check and see if the <link> tag contains a rel and href attribute
        if (linkElement.getAttribute("href") != null) {
            //If it links to a stylesheet
            if ((linkElement.getAttributeNode("rel") != null
                    && linkElement.getAttributeNode("rel").getTextContent().equals("stylesheet"))
                    || linkElement.getAttributeNode("href").getTextContent().endsWith(".css")) {

                //Check and see if the href and URL exist.
                if (linkElement.getAttributeNode("href").getNodeValue().contains("://")) {
                    try {
                        if (this.loadStyles(
                                IOUtils.toString(new URL(linkElement.getAttributeNode("href").getNodeValue())),
                                null) == false) {
                            Utilities.showError("Error: invalid file in link tag pointing to "
                                    + linkElement.getAttributeNode("href").getTextContent());
                            return false;
                        }

                        if (linkElement.getAttributeNode("cache") != null) {
                            try {
                                FileUtils.writeStringToFile(
                                        new File(Globals
                                                .getCWD(linkElement.getAttributeNode("cache").getTextContent())),
                                        IOUtils.toString(
                                                new URL(linkElement.getAttributeNode("href").getNodeValue())));
                            } catch (Exception e2) {
                                Utilities.showError("Error: unable to cache to file "
                                        + linkElement.getAttributeNode("cache").getTextContent());
                            }
                        }

                    } catch (Exception e) {
                        Utilities.showError(
                                "Unable to locate " + linkElement.getAttributeNode("href").getNodeValue());
                        //Attempt to load from the fallback file. (If tag and file exist)
                        if (linkElement.getAttributeNode("fallback") != null) {
                            if (this.loadStyles(null, Globals
                                    .getCWD(linkElement.getAttributeNode("fallback").getTextContent())) == false) {
                                Utilities.showError("Error: invalid file in fallback tag pointing to "
                                        + linkElement.getAttributeNode("fallback").getTextContent());
                                return false;
                            }
                            ;
                        }
                    }
                    //Load from file
                } else {
                    if (this.loadStyles(null,
                            Globals.getCWD(linkElement.getAttributeNode("href").getTextContent())) == false) {
                        Utilities.showError("Error: invalid file in link tag pointing to "
                                + linkElement.getAttributeNode("href").getTextContent());
                        return false;
                    }
                    ;
                }

                //If it links to a script
            } else if ((linkElement.getAttributeNode("rel") != null
                    && linkElement.getAttributeNode("rel").getTextContent().equals("script"))
                    || linkElement.getAttributeNode("href").getTextContent().endsWith(".js")) {

                //Check and see if the file exists
                if (linkElement.getAttributeNode("href").getNodeValue().contains("://")) {
                    //Run script in file
                    URL url;
                    try {
                        url = new URL(linkElement.getAttributeNode("href").getTextContent());

                        URLConnection connection = url.openConnection();
                        connection.setConnectTimeout(10000);
                        connection.setReadTimeout(10000);
                        engine.eval(new InputStreamReader(connection.getInputStream()),
                                "Remote file: " + linkElement.getAttributeNode("href").getTextContent());

                        if (linkElement.getAttributeNode("cache") != null) {
                            try {
                                FileUtils.writeStringToFile(
                                        new File(Globals
                                                .getCWD(linkElement.getAttributeNode("cache").getTextContent())),
                                        IOUtils.toString(
                                                new URL(linkElement.getAttributeNode("href").getNodeValue())));
                            } catch (Exception e2) {
                                Utilities.showError("Error: unable to cache to file "
                                        + linkElement.getAttributeNode("cache").getTextContent());
                            }
                        }

                        return true;
                    } catch (Exception e) {
                        //Attempt to load from the fallback file. (If tag and file exist)
                        if (linkElement.getAttributeNode("fallback") != null) {
                            try {
                                engine.eval(
                                        new java.io.FileReader(Globals
                                                .getCWD(linkElement.getAttributeNode("fallback").getTextContent())),
                                        linkElement.getAttributeNode("fallback").getTextContent());
                            } catch (Exception e2) {
                                Utilities.showError("Error: invalid file in fallback tag pointing to "
                                        + linkElement.getAttributeNode("fallback").getTextContent());
                            }
                        } else {
                            Utilities.showError(
                                    "Unable to load " + linkElement.getAttributeNode("href").getTextContent()
                                            + ". No fallback found.");
                        }

                    }

                } else {
                    try {
                        //Run script in file
                        engine.eval(
                                new java.io.FileReader(
                                        Globals.getCWD(linkElement.getAttributeNode("href").getTextContent())),
                                linkElement.getAttributeNode("href").getTextContent());
                        return true;

                    } catch (FileNotFoundException e) {
                        Utilities.showError("Error: invalid file in link tag pointing to "
                                + linkElement.getAttributeNode("href").getTextContent());
                        e.printStackTrace();
                        return false;
                    } catch (DOMException e) {
                        Utilities.showError("Error: Improperly formatted XML");
                        e.printStackTrace();
                        return false;
                    } catch (Exception e) {
                        Utilities.showError("Error: invalid script in file "
                                + linkElement.getAttributeNode("href").getTextContent());
                        e.printStackTrace();
                        return false;
                    }
                }
            } else {
                //Attempt to load as a .rsm file

                //If the file is a URL on the internet:
                if (linkElement.getAttributeNode("href").getNodeValue().contains("://")) {
                    try {
                        //Load the file from the internet.
                        Main.loader.loadAll(Utilities.EscapeScriptTags(
                                IOUtils.toString(new URL(linkElement.getAttributeNode("href").getNodeValue()))));

                        if (linkElement.getAttributeNode("cache") != null) {
                            try {
                                FileUtils.writeStringToFile(
                                        new File(Globals
                                                .getCWD(linkElement.getAttributeNode("cache").getTextContent())),
                                        IOUtils.toString(
                                                new URL(linkElement.getAttributeNode("href").getNodeValue())));
                            } catch (Exception e2) {
                                Utilities.showError("Error: unable to cache to file "
                                        + linkElement.getAttributeNode("cache").getTextContent());
                            }
                        }
                    } catch (Exception e) {
                        if (linkElement.getAttributeNode("fallback") != null) {
                            try {
                                Main.loader.loadAll(Utilities.EscapeScriptTags(FileUtils.readFileToString(new File(
                                        Globals.getCWD(linkElement.getAttributeNode("fallback").getNodeValue())))));
                            } catch (Exception e2) {
                                Utilities.showError("Error: invalid file in fallback tag pointing to "
                                        + linkElement.getAttributeNode("fallback").getTextContent());
                            }
                        }
                    }

                    //Load the file from the Hard Drive
                } else {
                    try {
                        Main.loader.loadAll(Utilities.EscapeScriptTags(FileUtils.readFileToString(
                                new File(Globals.getCWD(linkElement.getAttributeNode("href").getNodeValue())))));
                    } catch (DOMException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        } else {
            System.out.println(linkElement.toString());
            Utilities.showError(
                    "Warning: <link> tags must contain a href attribute and a rel attribute. Skipping tag.");
        }
        return false;
    }

    /**
     * Gets all styles from the String content, or file.
     * @param content String containing valid CSS, or null.
     * @param file String containing the path to a valid CSS file, or null.
     * @return True on success, false on failure.
     */
    private boolean loadStyles(String content, String file) {
        //If the user has specified loading from a string, not file
        if (file == null && content != null) {
            engine.call("css.parseString", content);
        } else if (content == null) {
            //Attempt to get the style information from the file
            try {
                //Load the file into the string toParse
                String toParse = FileUtils.readFileToString(new File(file));

                engine.call("css.parseString", toParse);
                return true;
            } catch (IOException e) {
                Utilities.showError("Error: Invalid CSS formatting in file: " + file);
                e.printStackTrace();
                return false;
            }

        }
        //In case something went wrong that was not caught
        return false;
    }
}