package platform.plugins.installables.jarRepository;
import platform.servicesregister.ServicesRegisterManager;
import platform.servicesregister.ServiceInUseException;
import platform.servicesregister.ServiceClosedException;
import model.interfaces.platform.IPlatformPlugin;
import java.io.File;
import util.Parameters;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.HashMap;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import platform.ClassManager.KalimuchoClassLoader;
/**
* Plugin that looks in the repository for a given class
* These classes are are defined in the jar file by:
* BC: for the class of the BC
* Samples: for the classes of samples (names of classes separated by comas)
*
* @author Dalmau
*/
public class JarRepositoryManager implements IPlatformPlugin {
private HashMap<String, String>[] classesDisponibles;
private final static String[] types = {"PC" , "Android"};
/**
* Starts the plugin = register this plugin as a service.
*/
public void startPlugin() {
classesDisponibles = new HashMap[types.length];
try { // enregistrer le service d'acces aux depot de jars
ServicesRegisterManager.registerService(Parameters.JAR_REPOSITORY_MANAGER, this);
rescanRepository(); // creer les listes de classes disponibles a partir du depot
}
catch (ServiceInUseException mbiue) {
System.err.println("Jar Repository Manager service created twice");
}
}
/**
* Stops the plugin = unregister this plugin as a service.
*/
public void stopPlugin() {
try {
ServicesRegisterManager.removeService(Parameters.JAR_REPOSITORY_MANAGER);
}
catch (ServiceClosedException sce) {}
}
// Recherche dans le depot le jar contenant la classe demandee pour le type d'hote indique
// Cette classe doit etre indiquee dans le manifest par :
// BC: classe_du_CM pour un composant metier
// Samples: classe_d_echantillon1, classe_d_echantillon2 ... pour les echantillons
/**
* Find a class in the repository.<br>
* This class is identified in the jar file by:<br>
* BC: for the class of the BC<br>
* Sample: for the classes of samples (classes' names separated by comas)<br>
* @param type Type of host the class is for (Android, CD, PC)
* @param name Name of class to find
* @return The class byte code in a byte array
* @throws ClassNotFoundException When the class can't be found
*/
public byte[] findByteCodeForClass(String type, String name) throws ClassNotFoundException {
File resultat = findJarFileForClass(type, name);
try { // recuperer son contenu sous forme de tableau d'octets
ByteArrayOutputStream buffer = null;
FileInputStream lireOctets = new FileInputStream(resultat);
buffer = new ByteArrayOutputStream();
int cpt;
byte[] lu = new byte[1024]; // lecture par blocs de 1K => plus rapide
do {
cpt = lireOctets.read(lu);
if (cpt > 0) buffer.write(lu);
}
while (cpt == 1024 );
return buffer.toByteArray(); // revoyer la tableau d'octets
}
catch (IOException ioe) {
System.err.println("Can't open jar file "+resultat.getName());
throw new ClassNotFoundException();
}
}
/**
* Find a jar file in the repository containing a specified class.<br>
* This class is identified in the jar file by:<br>
* BC: for the class of the BC<br>
* Samples: for the classes of samples (classes' names separated by comas)<br>
* @param type Type of host the class is for (Android, CD, PC)
* @param name Name of class to find
* @return The jar file in which this class is
* @throws ClassNotFoundException When the class can't be found
*/
public File findJarFileForClass(String type, String name) throws ClassNotFoundException {
// On cherche la classe demandee parmi celles repertoriees lors du lancement de Kalimucho
// Si on ne la trouve pas on recree la liste (cas ou le fichier jar aurait ete ajoute apres le demarrage)
// Si on la trouve on revoie le fichier jar la contenant sinon on leve une exception
int index=0;
boolean trouve = false;
while ((index<types.length) && (!trouve)) { // recherche du type
if (type.equals(types[index])) trouve = true;
else index++;
}
if (!trouve) throw new ClassNotFoundException(); // type introuvable
else { // le type est connu on cherche la classe
int essais = 0;
while (essais != 2) {
String fich = classesDisponibles[index].get(name);
if (fich != null) { // classe repertoriee dans la liste
essais = 2; // on renvoie le fichier
return new File(Parameters.COMPONENTS_REPOSITORY+"/"+type+"/"+fich);
}
else { // la classe n'est pas dans la liste
essais++;
if (essais == 1) { // si on ne l'a pas deja fait on recree la liste a partir du depot
rescanRepository();
}
}
}
throw new ClassNotFoundException(); // Classe introuvable meme apres avoir recree la liste
}
}
/**
* Creates the list of available classes in repository
*/
public void rescanRepository() { // recree les liste de classes connues a partir du depot
// cette methode peut etre invoquee si on sait que le depot a ete modifie
for (int i=0; i<types.length; i++) {
classesDisponibles[i] = new HashMap<String, String>();
scanRepository(types[i], classesDisponibles[i]);
}
}
private void scanRepository(String type, HashMap<String, String> liste) {
// Chemin du depot defini dans parameters et complete par le type d'hote
String chemin = new String(Parameters.COMPONENTS_REPOSITORY+"/"+type);
//System.out.println("explore : "+chemin);
File depot = new File(chemin);
File[] fichiers = depot.listFiles(); // liste des fichiers contenus dans ce repertoire
for (int i = 0; i<fichiers.length; i++) { // explorer ces fichiers
if (fichiers[i].isFile()) { // c'est un fichier
if (fichiers[i].getName().endsWith(".jar")) { // c'est un fichier .jar
try {
JarFile accesJar = new JarFile(fichiers[i]);
Manifest manifest = accesJar.getManifest(); // recuperer le manifest de ce fichier
// Recuperer le nom de la classe du composant metier (dans ce manifest)
String classeCM = manifest.getMainAttributes().getValue(KalimuchoClassLoader.BC_CLASS);
liste.put(classeCM, fichiers[i].getName());
//System.out.println("ajoute : ("+classeCM+" , "+fichiers[i].getName()+")");
}
catch (IOException ioe) {
System.err.println("Can't access to jar file "+fichiers[i].getName()+" in "+chemin);
}
}
}
}
}
}