org.javascool.compiler.JVSClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.javascool.compiler.JVSClassLoader.java

Source

/*
 * Java's Cool, IDE for French Computer Sciences Students
 * Copyright (C) 2012  Philippe VIENNE, INRIA
 *
 * 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 org.javascool.compiler;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Chargeur de Classe pour Java's Cool. Il permet de charger une classe qui n'&eacute;tait pas dans le classpath
 * d'origine.
 *
 * @author Philippe VIENNE (PhilippeGeek@gmail.com)
 * @version 5.0
 */
public class JVSClassLoader extends ClassLoader {
    /**
     * Le lieu o travail le ClassLoader
     */
    private File location = null;
    /**
     * Petit cache pour les classes dj chargs.
     */
    private final Hashtable<String, Class<?>> classes = new Hashtable<String, Class<?>>();

    /**
     * Construit un chargeur de classe. Il prend comme ClassLoader parent son propre ClassLoader. Il vrifie aussi
     * l'existance du dossier o serais les classes  charger.
     *
     * @param location Le dossier o sont stock les .class
     */
    public JVSClassLoader(File location) {
        super(JVSClassLoader.class.getClassLoader());
        this.location = location;
        if (location.isFile())
            throw new IllegalArgumentException(
                    "Le chargeur de classe ne peut pas fonctionner dans un fichier," + " il faut un dossier");
        if (!location.exists())
            throw new IllegalArgumentException("Le dossier " + location + " n'existe pas !");
    }

    /**
     * Charge une classe. Cette fonction prend soit la classe dans le cache local soit va tenter de la charger avec
     * {@link #findClass(String)}.
     *
     * @param className Le nom de la classe
     * @return L'objet reprsentant une classe Java
     * @throws ClassNotFoundException Voir {@link #findClass(String)}
     * @see #findClass(String)
     */
    @Override
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        if (classes.get(className) != null) // Si on a dj charg cette classe, alors elle est dans le cache
            return classes.get(className);
        else // Sinon on tente de la charger
            return findClass(className);
    }

    /**
     * Cherche une classe dans le classpath actuel et dans le rpertoire fournit au classloader
     *
     * @param className La classe  charger
     * @return L'objet reprsentant une classe en Java
     * @throws ClassNotFoundException Dans le cas o aucune classe n'as pu tre trouv.
     */
    @Override
    public Class<?> findClass(String className) throws ClassNotFoundException {
        byte classByte[];
        Class<?> result;

        result = classes.get(className); // On vrifie qu'elle n'est pas dans le cache
        if (result != null) {
            return result;
        }

        try { // On cherche si c'est une classe systme
            return findSystemClass(className);
        } catch (Exception e) {
            Logger.getAnonymousLogger().log(Level.OFF, className + " n'est pas une classe systme");
        }

        try { // Ou qu'elle est dans le chargeur parent
            return JVSClassLoader.class.getClassLoader().loadClass(className);
        } catch (Exception e) {
            Logger.getAnonymousLogger().log(Level.OFF, className + " n'est pas une classe du chargeur parent");
        }

        try { // On regarde aprs si elle n'est pas chez nous.
              // On en cre le pointeur vers le fichier de la classe
            File clazz = FileUtils.getFile(location, decomposePathForAClass(className));
            if (!clazz.exists()) { // Si le fichier de la classe n'existe pas, alors on cre une erreur
                throw new FileNotFoundException("Le fichier : " + clazz.toString() + " n'existe pas");
            }
            // On lit le fichier
            classByte = FileUtils.readFileToByteArray(clazz);
            // On dfinit la classe
            result = defineClass(className, classByte, 0, classByte.length, null);
            // On la stocke en cache
            classes.put(className, result);
            // On retourne le rsultat
            return result;
        } catch (Exception e) {
            throw new ClassNotFoundException(e.getMessage(), e);
        }
        //
    }

    /**
     * Dcompose un nom de classe vers le chemin de la classe. Permet de passer de "org.javascool.compiler.Main" 
     * ["org","javascool","compiler","Main.class"] qui une reprsentation du chemin de la classe sous la forme d'un
     * tableau de chaines.
     *
     * @param className Le nom de la classe au format Java
     * @return Le tableau reprsentant le chemin.
     */
    private static String[] decomposePathForAClass(String className) {
        ArrayList<String> path = new ArrayList<String>();
        for (String s : className.split("\\.")) {
            if (className.endsWith(s))
                path.add(s + ".class");
            else
                path.add(s);
        }
        return path.toArray(new String[path.size()]);
    }
}