package platform.ClassManager;
import java.util.Vector;
import java.io.File;
import util.Parameters;
import platform.servicesregister.ServiceClosedException;
import platform.servicesregister.ServicesRegisterManager;
import platform.plugins.installables.jarRepository.JarRepositoryManager;
/**
* Manages the classLoaders used by Kalimucho.<br>
* Allows to register/unregister classLoaders associated to jar files<br>
* The method loadClass loads a class accessible by the classLoader of the PF
* or by one of the registered classLoaders associated to jar files.<br>
* The method loadOrCreateClass acts as the java loadClass method but if the class cant be found
* it goes into the components repository in order to find it.<br>
*
* @author Dalmau
*/
public class KalimuchoClassLoader {
/**
* Type of the host (PC/CDC/Android) used to find jar file in repository
*/
public static final String MON_TYPE = "PC";
/**
* Key used in manifests to indicate BCs' classes
*/
public static String BC_CLASS = "BC"; // cle utilisee dans les manifest pour designer les classes de CM
/**
* Separator when there is more than one class associated to a key in the manifest
*/
public static String CLASS_SEPARATOR = " "; // separateur quand il y a plusieurs classes associees a une meme cle
// liste des classLoaders enregistres
private static Vector<ClassLoaderFromJarFile> registeredClassLoaders = new Vector<ClassLoaderFromJarFile>();
/**
* Registers a new class loader
* @param classLoader the class loader to register
*/
public static void addClassLoader(ClassLoaderFromJarFile classLoader) { // ajoute un classLoader a la liste
registeredClassLoaders.addElement(classLoader);
System.out.println("Adding jar file: "+classLoader.getJarFileName());
}
/**
* Unregisters a registered class loader
* @param classLoader the class loader to unregister
*/
public static void removeClassLoader(ClassLoaderFromJarFile classLoader) { // enleve un classLoader de la liste
int i = 0; boolean trouve = false;
while ((i < registeredClassLoaders.size()) && (!trouve)) {
if (registeredClassLoaders.elementAt(i) == classLoader) trouve = true;
else i++;
}
if (trouve) {
System.out.println("Removing jar file: "+classLoader.getJarFileName());
registeredClassLoaders.removeElementAt(i);
}
}
// Charge une classe accessible par le classLoader de base de la PF
// ou l'un des classLoaders sur fichier jar enregistres
/**
* Loads a class from the standard class loader or from a registered one
* @param name name of the class to load
* @return the loaded class
* @throws ClassNotFoundException if the class is neither loadable by the standard or a registered class loader
*/
public static Class<?> loadClass(String name) throws ClassNotFoundException {
// Il y a un bug pour le cas particuler des tableaux que le classLoader de base
// de java ne trouve pas => on traite ce cas a part
if (name.startsWith("[")) return Class.forName(name, false, KalimuchoClassLoader.class.getClassLoader());
Class<?> reponse = null;
try { // essayer d'abord de trouver la classe avec le classLoader de base de la PF
reponse = KalimuchoClassLoader.class.getClassLoader().loadClass(name);
return reponse; // si le classLoader de base de la PF l'a trouvee on le renvoie
}
catch (ClassNotFoundException cnfe) { // le classLoader de base de la PF ne trouve pas le classe demandee
int i = 0; boolean trouve = false;
while ((i < registeredClassLoaders.size()) && (!trouve)) { // essayer les classLoaders enregistres
try {
reponse = registeredClassLoaders.elementAt(i).loadClass(name);
trouve = true; // on a trouve la classe
}
catch (ClassNotFoundException cnfe2) {
i++; // on n'a pas trouve la classe => essayer un autre classLoader enregistre
}
}
if (trouve) {
return reponse; // renvoyer la classe trouve par un classLoader enregistre
}
else {
throw new ClassNotFoundException(); // classe introuvable
}
}
}
private static LoadedClass findLoadedClass(String name) throws ClassNotFoundException {
// Il y a un bug pour le cas particuler des tableaux que le classLoader de base
// de java ne trouve pas => on traite ce cas a part
if (name.startsWith("[")) {
return new LoadedClass(Class.forName(name, false, KalimuchoClassLoader.class.getClassLoader()), null);
}
Class<?> reponse = null;
try { // essayer d'abord de trouver la classe avec le classLoader de base de la PF
reponse = KalimuchoClassLoader.class.getClassLoader().loadClass(name);
return new LoadedClass(reponse, null); // si le classLoader de base de la PF l'a trouvee on le renvoie
}
catch (ClassNotFoundException cnfe) { // le classLoader de base de la PF ne trouve pas le classe demandee
int i = 0; boolean trouve = false;
while ((i < registeredClassLoaders.size()) && (!trouve)) { // essayer les classLoaders enregistres
try {
reponse = registeredClassLoaders.elementAt(i).loadClass(name);
trouve = true; // on a trouve la classe
}
catch (ClassNotFoundException cnfe2) {
i++; // on n'a pas trouve la classe => essayer un autre classLoader enregistre
}
}
if (trouve) {
return new LoadedClass(reponse,registeredClassLoaders.elementAt(i)); // renvoyer la classe trouve par un classLoader enregistre
}
else {
throw new ClassNotFoundException(); // classe introuvable
}
}
}
// Essaye de trouver la classe demandee par loadClass mais si la classe n'est pas trouvable
// Lancer une recherche dans le depot de composants pour la recuperer
/**
* Tries to load a class from the standard class loader or from a registered one.
* If the class can't be found, broascast a request on network to download it
* @param name name of the class to load
* @return the loaded class
* @throws ClassNotFoundException if the class can't be found
*/
public static LoadedClass loadOrCreateClass(String name) throws ClassNotFoundException {
LoadedClass reponse = null;
try { // essayer de trouver la classe demandee par loadClass
reponse = findLoadedClass(name);
return reponse; // on l'a trouvee car la classe demandee est deja connue
}
catch (ClassNotFoundException cnfe) { // La classe demandee n'est pas connue
try { // on va essayer de la trouver dans le depot
JarRepositoryManager depot = (JarRepositoryManager)ServicesRegisterManager.lookForService(Parameters.JAR_REPOSITORY_MANAGER);
File resultat = depot.findJarFileForClass("PC", name); // on l'a trouvee
ClassLoaderFromJarFile cl = new ClassLoaderFromJarFile(KalimuchoClassLoader.class.getClassLoader(), resultat.getAbsolutePath());
addClassLoader(cl); // memoriser le class loader associe
return new LoadedClass(cl.loadClass(name), cl); // renvoyer la classe trouvee et le classLoader associe
}
catch (ServiceClosedException sce) { // le depot n'est pas actif = la classe est introuvable
throw new ClassNotFoundException();
}
}
}
}