org.nuiton.topia.service.servers.RemoteClassLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of topia-soa Show documentation
Show all versions of topia-soa Show documentation
Service Oriented Architecture module
/* *##%
* ToPIA :: SOA
* Copyright (C) 2004 - 2009 CodeLutin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* ##%*/
package org.nuiton.topia.service.servers;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.rmi.Remote;
import java.rmi.RemoteException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.service.TopiaApplicationServiceFactory;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.CodeVisitor;
// Tout le code d'utilisation de truezip est present
// mais commente pour ne pas garder une dependance
// supplementaire
/*
* import de.schlichtherle.io.ArchiveException; import de.schlichtherle.io.File;
* import de.schlichtherle.io.FileOutputStream;
*/
/**
* RMIRemoteHelper.java
*
* Creer une nouvelle classe en transformant la classe passee en parametre.
*
* Ajoute une interface "Remote" Ajoute des exception a toutes les methodes
* "RemoteException"
*
* Utilise les API asm.
*
* @see java.rmi.Remote
* @see java.rmi.RemoteException
*
* @author chatellier
* @version $Revision: 1715 $
*
* Last update : $Date: 2009-12-15 01:26:16 +0100 (mar. 15 déc. 2009) $ By : $Author: tchemit $
*/
public class RemoteClassLoader implements ClassVisitor {
/** Logger (common logging) */
private static final Log logger = LogFactory
.getLog(RemoteClassLoader.class);
/** Ajout au nom de classe */
public static final String EXTENSION = "Remote";
/**
* Le writer (global necessaire parce que parcourt par patron visiteur)
*/
protected ClassWriter cWriter;
/**
* Constructeur
*/
protected RemoteClassLoader() {
}
/*
* (non-Javadoc)
*
* @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String,
* java.lang.String, java.lang.String[], java.lang.String)
*/
public void visit(int version, int access, String name, String superName,
String[] interfaces, String sourceFile) {
// creer un writer
cWriter = new ClassWriter(false);
logger.debug("Converting class " + name + " as remote class");
// nouveau nom de fichier
String newSourceFileName = sourceFile.replaceAll("(.*)\\.java$", "$1"
+ EXTENSION + ".java");
// liste des interfaces
String remoteInterface = Remote.class.getName().replaceAll("\\.",
String.valueOf(File.separatorChar));
String[] interfacesNew = null;
if (interfaces == null) {
interfacesNew = new String[] { remoteInterface };
} else {
interfacesNew = new String[interfaces.length + 1];
for (int i = 0; i < interfaces.length; ++i)
interfacesNew[i] = interfaces[i];
interfacesNew[interfacesNew.length - 1] = remoteInterface;
}
cWriter.visit(version, // version de la classe
access, // visibilite
name + EXTENSION, // nom
superName, // superclasse
interfacesNew, // les interface
newSourceFileName); // le fichier sources
}
/*
* (non-Javadoc)
*
* @see org.objectweb.asm.ClassVisitor#visitAttribute(org.objectweb.asm.Attribute)
*/
public void visitAttribute(Attribute attr) {
logger.warn("Attribute " + attr.toString()
+ " found : conversion not supported");
}
/*
* (non-Javadoc)
*
* @see org.objectweb.asm.ClassVisitor#visitEnd()
*/
public void visitEnd() {
cWriter.visitEnd();
}
/*
* (non-Javadoc)
*
* @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String,
* java.lang.String, java.lang.Object, org.objectweb.asm.Attribute)
*/
public void visitField(int access, String name, String desc, Object value,
Attribute attrs) {
logger.warn("Field " + name + " found : conversion not supported");
}
/*
* (non-Javadoc)
*
* @see org.objectweb.asm.ClassVisitor#visitInnerClass(java.lang.String,
* java.lang.String, java.lang.String, int)
*/
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
logger.warn("InnerClass " + name + " found : conversion not supported");
}
/*
* (non-Javadoc)
*
* @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String,
* java.lang.String, java.lang.String[], org.objectweb.asm.Attribute)
*/
public CodeVisitor visitMethod(int access, String name, String desc,
String[] exceptions, Attribute attrs) {
logger.debug("Processing method " + name);
// liste des interfaces
String remoteExceptionName = RemoteException.class.getName()
.replaceAll("\\.", String.valueOf(File.separatorChar));
String[] exceptionsNew = null;
if (exceptions == null) {
exceptionsNew = new String[] { remoteExceptionName };
} else {
exceptionsNew = new String[exceptions.length + 1];
for (int i = 0; i < exceptions.length; ++i)
exceptionsNew[i] = exceptions[i];
exceptionsNew[exceptionsNew.length - 1] = remoteExceptionName;
}
cWriter.visitMethod(access, // visibilite
name, // nom
desc, // arguments
exceptionsNew, // les exceptions lancees
attrs); // retour
return null;
}
/**
* Retourne le nom d'origine sans l'ajout
*
* @param clazz
* la classe remote
* @return le nom non-remote
*/
public static String getOriginClassName(Class clazz) {
return clazz.getName().replaceAll("(.*)" + EXTENSION + "$", "$1");
}
/**
* Retourne la classe version "remote" de celle specifiee
*
* @param clazz
* la classe non remote
* @return la classe remote
* @throws ClassNotFoundException
* si on ne peut pas genere la classe
*/
public static Class> getRemoteClass(Class clazz)
throws ClassNotFoundException {
Class remoteClass = null;
// onregarde si la ressource existe,
// sinon on la genere
URL url = ClassLoader.getSystemClassLoader().getResource(
clazz.getName().replaceAll("\\.", "/") + EXTENSION + ".class");
if (url == null) {
// classe non trouvee, on la genere
logger.debug("Remote class not found for '" + clazz.getName()
+ "', generating a new one");
RemoteClassLoader rcl = new RemoteClassLoader();
// recupere la classe generee
byte[] clazzBytes = rcl.getClassData(clazz);
try {
// la sauve en dur
rcl.saveOnDisk(clazz, clazzBytes);
} catch (IOException e2) {
logger.debug("Can't save generated class on disk", e2);
throw new ClassNotFoundException("Can't find class : "
+ clazz.getName() + EXTENSION, e2);
}
}
// retente un forName et devrai maintenant la trouver
try {
remoteClass = Class.forName(clazz.getName() + EXTENSION);
} catch (ClassNotFoundException e2) {
logger.debug("Can't find generated class", e2);
throw new ClassNotFoundException("Can't find class : "
+ clazz.getName() + EXTENSION, e2);
}
return remoteClass;
}
/**
* Sauve la classe generee sur le disque.
*
* Dans un jar, ou ds un fichier...
*
* @param clazz
* La class d'origine
* @param clazzBytes
* La classe generee
* @throws IOException
*/
protected void saveOnDisk(Class clazz, byte[] clazzBytes)
throws IOException {
// ensuite, on la sauve en dur, sur disque
// soit dans un jar, soit sur un fichier physique
// au meme endroit que la classe d'origine
URL originClazzPath = ClassLoader.getSystemClassLoader().getResource(
clazz.getName().replaceAll("\\.",
String.valueOf(File.separatorChar))
+ ".class");
// suivant le protocol
// file, jar...
String protocol = originClazzPath.getProtocol();
if ("file".equals(protocol)) {
saveInFile(originClazzPath, clazzBytes);
} else if (protocol.matches("ear|jar|war|zip")) {
saveInJarFile(originClazzPath, clazzBytes);
} else {
logger.warn("Unsupported protocol '" + protocol
+ "' for saving clazz.");
}
}
/**
* Sauve le fichier dans un jar.
*
* Java ne supporte pas le modification des jar. On le sauve maintenant dan
* le dossier topiagen.
*
* @param originClazzPath
* @param clazzBytes
* @throws IOException
* si erreur d'ecriture
*/
protected void saveInJarFile(URL originClazzPath, byte[] clazzBytes)
throws IOException {
/*
* TRUEZIP code // write class on disk String path =
* originClazzPath.getFile(); // chemin valid truezip String archive =
* path.replaceAll("^file:(.*)!(.*)\\.class$", "$1"); path =
* path.replaceAll("^file:(.*)!(.*)\\.class$", "$1$2" + EXTENSION +
* ".class"); // File f = new File(path); // f.createNewFile();
* FileOutputStream out = new FileOutputStream(path);
* out.write(clazzBytes, 0, clazzBytes.length); out.close(); // force
* l'update de l'archive // sinon la modification n'est pas prise en
* compte dans l'excecution // courante de la JVM // File.update(new
* File(archive));
*
* try { File.umount(new File(archive)); } catch (ArchiveException ouch) {
* logger .debug("ArchiveException , can't umount archive : " +
* archive); // At least one exception occured which is not just an //
* ArchiveWarningException. This is a severe situation that // needs to
* be handled. // Print the sequential chain of exceptions in order of //
* descending priority and ascending appearance. //
* ouch.printStackTrace(); // Print the sequential chain of exceptions
* in order of // appearance instead.
* ouch.sortAppearance().printStackTrace(); } TRUEZIP code
*/
String path = originClazzPath.getFile().replaceAll(
"^file:(.*)!(.*)\\.class$", "$2" + EXTENSION + ".class");
// creer les dossier et fichier
java.io.File fRemoteClass = new java.io.File(
TopiaApplicationServiceFactory.TOPIA_GENERATION_DIRECTORY
+ String.valueOf(File.separatorChar) + path);
fRemoteClass.getParentFile().mkdirs();
// ecrit les donnees
java.io.FileOutputStream out = new java.io.FileOutputStream(
fRemoteClass);
out.write(clazzBytes, 0, clazzBytes.length);
out.close();
logger.debug("Remote clazz saved into archive as path : "
+ fRemoteClass.getAbsolutePath());
}
/**
* Genere la classe dans son fichier phisyque
*
* /home/chatellier/tmp/toto.java file:/home/chatellier/tmp/toto.class
*
* @param originClazzPath
* l'url d'origine
* @param clazzBytes
* les donnees de la classe
* @throws IOException
* si erreur d'ecriture
*/
protected void saveInFile(URL originClazzPath, byte[] clazzBytes)
throws IOException {
// write class on disk
String path = originClazzPath.getFile();
// ajout de "Remote" au nom
path = path.replaceAll("\\.class$", EXTENSION + ".class");
java.io.File f = new java.io.File(path);
// f.createNewFile();
java.io.FileOutputStream out = new java.io.FileOutputStream(f);
out.write(clazzBytes, 0, clazzBytes.length);
out.close();
logger.debug("Remote class saved to : " + path);
}
/**
* Convertit la class en class "Remote"
*
* @param clazz
* la classe non remote
* @return la classe remote
*/
private byte[] getClassData(Class clazz) {
byte[] b = null;
ClassReader cr;
try {
cr = new ClassReader(clazz.getName());
cr.accept(this, false);
b = cWriter.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return b;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy