org.qkit.core.updater.JarConstruct.java Source code

Java tutorial

Introduction

Here is the source code for org.qkit.core.updater.JarConstruct.java

Source

/**
 * This file is part of ParaBot.
 *
 * ParaBot 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.
 *
 * ParaBot 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 ParaBot.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.qkit.core.updater;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;

import org.qkit.core.hierarchy.Constructable;
import org.qkit.ext.utils.logging.ConsoleLogger;

import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * A representation of a JAR content vector.
 *
 * @author trDna
 * @since 1.7
 */
public class JarConstruct implements Constructable {

    /**
     * The URLClassLoader that loads the JAR from a given path.
     */
    private URLClassLoader url;

    /**
     * This is where the classes are stored. For use only in the loader package!
     */
    protected HashMap<String, ClassNode> loadedClassNodes = new HashMap<String, ClassNode>();

    /**
     * The JAR's path.
     */
    private String jarPath;

    /**
     * The JAR's URL
     */
    private String jarUrl;

    /**
     * The JAR's URL path.
     */
    private URL jarUrlPath;

    /**
     * Creates a representation of a loaded jar.
     *
     * @param jarPath The path to the JAR.
     */
    public JarConstruct(final String jarPath) {
        try {

            //Set up logger and print out the path.
            ConsoleLogger.setAppName("JarConstruct " + getClass().hashCode());
            ConsoleLogger.printlnInfo("Path to JAR: " + jarPath);

            //Creates a new URLClassLoader and loads the JAR.
            jarUrlPath = new URL("file:" + jarPath);

            //Referencing the JAR's path.
            this.jarPath = jarPath;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Creates a representation of a loaded JAR.
     *
     * @param jarUrl The URL to the JAR.
     * @param flags For future use
     *
     */
    public JarConstruct(final String jarUrl, int flags) {
        try {

            //Set up logger and print out the path.
            ConsoleLogger.setAppName("JarConstruct " + getClass().hashCode());
            ConsoleLogger.printlnInfo("Path to JAR: " + (jarUrl + "!").replace("http://", "file:"));

            //Creates a new URLClassLoader and loads the JAR.
            url = new URLClassLoader(new URL[] { new URL((jarUrl + "!/").replace("http://", "jar:http://")) });

            //Referencing the JAR's URL.
            this.jarUrl = jarUrl;

            jarUrlPath = new URL((jarUrl + "!/").replace("http://", "jar:http://"));

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Loads all classes from the given JAR file and stores them into a HashMap for future use.
     *
     * @return True if it was successful, False if it was not.
     */
    @SuppressWarnings("resource")
    public boolean loadClasses() {
        short count = 0;

        try {
            //Startup
            p("---------------------------------------------------------------------");
            p("--------------------      Jar Loader     ----------------------------");
            p("File: " + jarPath);

            p("JC Hash: " + getClass().hashCode());

            JarFile jf;

            //Referencing the JAR file.
            if (jarUrl != null) {

                System.out.println(jarUrlPath.toString());

                //Connect to the JAR directly online
                JarURLConnection u = (JarURLConnection) jarUrlPath.openConnection();

                //Get the JarFile representation from the JarURLConnection
                jf = u.getJarFile();

            } else {

                //If the if statement leads here, then the JAR is being run locally
                jf = new JarFile(jarPath);

            }

            //Make sure that a non-null value was passed in from either constructor
            assert jarPath != null || jarUrl != null : "Jar loader failure!";

            //Print out the size of the JarFile
            p("JarFile Size = " + jf.size());
            p("-----------------------------------------------------------------");

            //Referencing the entries.
            Enumeration<? extends JarEntry> en = jf.entries();

            //Looping through the elements (the entries).
            while (en.hasMoreElements()) {

                //The entry to work with.
                JarEntry entry = en.nextElement();

                //Grabbing solely the class files
                if (entry.getName().endsWith(".class")) {

                    //Count out the entries
                    ++count;

                    //Print out the entry
                    p("Entry " + count + ") " + entry.getName());
                    p(" -> Decompressed Size = " + entry.getSize() + " Bytes" + "\n");

                    //ClassReader retrieves the bytes from a given entry.
                    ClassReader cr = new ClassReader(jf.getInputStream(entry));

                    //Creating a new ClassNode to act as a representative of a class.
                    ClassNode cn = new ClassNode();

                    //Delegating all method calls and data from ClassReader to ClassNode.
                    //Think of it as data from 'cr' are being entrusted or put into 'cn' (such as the class bytes).
                    cr.accept(cn, 0);

                    //Put it into the local package's HashMap as a ClassNode.
                    loadedClassNodes.put(cn.name, cn);
                }
            }

            System.out.println(count + " classes were loaded and stored!");
            p("-----------------------------------------------------------------");
            p("-----------------------------------------------------------------");

            ConsoleLogger.printlnInfo("Load successful.");

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * Retrieves a given class from the class HashMap.
     *
     * @param clazz - The class name.
     * @return - A Class object.
     */
    public ClassNode retrieveClass(final String clazz) {
        //Assume that the HashMap
        return loadedClassNodes.get(clazz);
    }

    private void p(Object msg) {
        System.out.println(msg);
    }

    @Override
    public ClassNode queryProduct(final String param) {
        return loadedClassNodes.get(param);
    }

    @Override
    public HashMap<?, ?> queryProduct() {
        return loadedClassNodes;
    }
}