Author: echatellier Date: 2014-08-29 15:39:04 +0200 (Fri, 29 Aug 2014) New Revision: 4104 Url: http://forge.codelutin.com/projects/isis-fish/repository/revisions/4104 Log: refs #568: D?\195?\169pendances non incluses dans la simulation Added: branches/4.3.0-log4j2/src/main/java/fr/ifremer/isisfish/util/DependencyUtil.java branches/4.3.0-log4j2/src/test/java/fr/ifremer/isisfish/util/DependencyUtilTest.java Modified: branches/4.3.0-log4j2/pom.xml Modified: branches/4.3.0-log4j2/pom.xml =================================================================== --- branches/4.3.0-log4j2/pom.xml 2014-08-29 08:58:39 UTC (rev 4103) +++ branches/4.3.0-log4j2/pom.xml 2014-08-29 13:39:04 UTC (rev 4104) @@ -75,6 +75,13 @@ </dependency> <dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm</artifactId> + <version>5.0.3</version> + <scope>compile</scope> + </dependency> + + <dependency> <groupId>org.nuiton</groupId> <artifactId>nuiton-profiling</artifactId> <version>3.0</version> @@ -325,6 +332,24 @@ <artifactId>svnkit</artifactId> <version>1.8.5</version> <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>jna</artifactId> + <groupId>net.java.dev.jna</groupId> + </exclusion> + <exclusion> + <artifactId>jsch.agentproxy.connector-factory</artifactId> + <groupId>com.jcraft</groupId> + </exclusion> + <exclusion> + <artifactId>sqljet</artifactId> + <groupId>org.tmatesoft.sqljet</groupId> + </exclusion> + <exclusion> + <artifactId>platform</artifactId> + <groupId>net.java.dev.jna</groupId> + </exclusion> + </exclusions> </dependency> <!-- fin svnkit pour communication subversion --> @@ -352,13 +377,6 @@ <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> - - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-core</artifactId> - <version>1.3</version> - <scope>test</scope> - </dependency> </dependencies> <!-- ************************************************************* --> Added: branches/4.3.0-log4j2/src/main/java/fr/ifremer/isisfish/util/DependencyUtil.java =================================================================== --- branches/4.3.0-log4j2/src/main/java/fr/ifremer/isisfish/util/DependencyUtil.java (rev 0) +++ branches/4.3.0-log4j2/src/main/java/fr/ifremer/isisfish/util/DependencyUtil.java 2014-08-29 13:39:04 UTC (rev 4104) @@ -0,0 +1,252 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2014 Ifremer, Code Lutin, Chatellier Eric + * %% + * 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/gpl-3.0.html>. + * #L% + */ + +package fr.ifremer.isisfish.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.TypePath; + +import fr.ifremer.isisfish.datastore.ExportStorage; +import fr.ifremer.isisfish.datastore.FormuleStorage; +import fr.ifremer.isisfish.datastore.ObjectiveStorage; +import fr.ifremer.isisfish.datastore.OptimizationStorage; +import fr.ifremer.isisfish.datastore.RuleStorage; +import fr.ifremer.isisfish.datastore.ScriptStorage; +import fr.ifremer.isisfish.datastore.SensitivityAnalysisStorage; +import fr.ifremer.isisfish.datastore.SensitivityExportStorage; +import fr.ifremer.isisfish.datastore.SimulationPlanStorage; +import fr.ifremer.isisfish.datastore.SimulatorStorage; + +/** + * Class utilitaire chargées d'inspecter le bytecode de certaines classe des scripts utilisateur + * d'IsisFish pour en extraire des informations. + * + * @author Eric Chatellier + */ +public class DependencyUtil { + + private static final Log log = LogFactory.getLog(DependencyUtil.class); + + /** + * Extrait les dépendences d'une class compilé à partir de son bytecode en ne conservant que + * les dependances des scripts utilisateurs. + * + * @param clazz la classe à analyser + * @return extract class set + */ + public static Set<String> extractDependencies(Class<?> clazz) { + return extractDependencies(clazz, true); + } + + /** + * Extrait les dépendences d'une class compilé à partir de son bytecode. + * + * @param clazz la classe à analyser + * @param onlyUserScript only keep user script types + * @return extract class set + */ + public static Set<String> extractDependencies(Class<?> clazz, final boolean onlyUserScript) { + final Set<String> result = new HashSet<>(); + + // method body visitor + final MethodVisitor mv = new MethodVisitor(Opcodes.ASM5) { + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + registerDescriptor(result, desc, onlyUserScript); + return super.visitAnnotation(desc, visible); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + registerDescriptor(result, desc, onlyUserScript); + return super.visitTypeAnnotation(typeRef, typePath, desc, visible); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { + registerDescriptor(result, desc, onlyUserScript); + return super.visitParameterAnnotation(parameter, desc, visible); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + registerType(result, type, onlyUserScript); + super.visitTypeInsn(opcode, type); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + registerType(result, owner, onlyUserScript); + registerDescriptor(result, desc, onlyUserScript); + super.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + registerType(result, owner, onlyUserScript); + registerDescriptor(result, desc, onlyUserScript); + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + + @Override + public void visitLdcInsn(Object cst) { + if (cst instanceof Type) { + registerType(result, ((Type)cst).getClassName(), onlyUserScript); + } + super.visitLdcInsn(cst); + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + registerType(result, type, onlyUserScript); + super.visitTryCatchBlock(start, end, handler, type); + } + + @Override + public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { + registerDescriptor(result, desc, onlyUserScript); + super.visitLocalVariable(name, desc, signature, start, end, index); + } + }; + + // class visitor + ClassVisitor visitor = new ClassVisitor(Opcodes.ASM5) { + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + registerType(result, superName, onlyUserScript); + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, + boolean visible) { + registerDescriptor(result, desc, onlyUserScript); + return super.visitAnnotation(desc, visible); + } + + @Override + public FieldVisitor visitField(int access, String name, + String desc, String signature, Object value) { + registerDescriptor(result, desc, onlyUserScript); + return super.visitField(access, name, desc, signature, value); + } + + @Override + public MethodVisitor visitMethod(int access, String name, + String desc, String signature, String[] exceptions) { + registerDescriptor(result, desc, onlyUserScript); + return mv; + } + }; + + // parse inpu class + try (InputStream in = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class")) { + ClassReader classReader = new ClassReader(in); + classReader.accept(visitor, 0); + } catch (IOException ex) { + if (log.isErrorEnabled()) { + log.error("Can't extract dependencies", ex); + } + } + + return result; + } + + /** + * Register type if necessary (depends on another user script). + * + * @param types types collection + * @param type type to add + * @param onlyUserScript only keep user script types + */ + protected static void registerType(Set<String> types, String type, boolean onlyUserScript) { + //System.out.println("==> " + type); + if (!onlyUserScript || StringUtils.startsWithAny(type, + ExportStorage.EXPORT_PATH, + FormuleStorage.FORMULE_PATH, + ObjectiveStorage.OBJECTIVE_PATH, + OptimizationStorage.OPTIMIZATION_PATH, + RuleStorage.RULE_PATH, + ScriptStorage.SCRIPT_PATH, + SensitivityAnalysisStorage.SENSITIVITY_ANALYSIS_PATH, + SensitivityExportStorage.SENSITIVITY_EXPORT_PATH, + SimulationPlanStorage.SIMULATION_PLAN_PATH, + SimulatorStorage.SIMULATOR_PATH)) { + String dotType = type.replace('/', '.'); + types.add(dotType); + } + } + + /** + * Clean type to extract valid class name. + * + * Ex: + * <ul> + * <li>Lfr/ifremer/isisfish/types/Month;</li> + * <li>[Ljava/lang/String;</li> + * <li>(Ljava/lang/Class;)Lorg/apache/commons/logging/Log;</li> + * + * @param types types collection + * @param descriptor descriptor + * @param onlyUserScript only keep user script types + */ + protected static void registerDescriptor(Set<String> types, String descriptor, boolean onlyUserScript) { + if (descriptor.startsWith("(")) { + int endIndex = descriptor.indexOf(')'); + registerDescriptor(types, descriptor.substring(1, endIndex), onlyUserScript); + registerDescriptor(types, descriptor.substring(endIndex + 1), onlyUserScript); + } else { + Pattern pattern = Pattern.compile("\\[*L([^;]+);|\\[[ZBCSIFDJ]|[ZBCSIFDJ]"); + Matcher matcher = pattern.matcher(descriptor); + while (matcher.find()) { + String match = matcher.group(1); + // sinon c'est un type primitif + if (match != null) { + registerType(types, match, onlyUserScript); + } + } + } + } +} Property changes on: branches/4.3.0-log4j2/src/main/java/fr/ifremer/isisfish/util/DependencyUtil.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Added: branches/4.3.0-log4j2/src/test/java/fr/ifremer/isisfish/util/DependencyUtilTest.java =================================================================== --- branches/4.3.0-log4j2/src/test/java/fr/ifremer/isisfish/util/DependencyUtilTest.java (rev 0) +++ branches/4.3.0-log4j2/src/test/java/fr/ifremer/isisfish/util/DependencyUtilTest.java 2014-08-29 13:39:04 UTC (rev 4104) @@ -0,0 +1,142 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2014 Ifremer, Code Lutin, Chatellier Eric + * %% + * 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/gpl-3.0.html>. + * #L% + */ +package fr.ifremer.isisfish.util; + +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +import fr.ifremer.isisfish.AbstractIsisFishTest; +import fr.ifremer.isisfish.IsisFishException; +import fr.ifremer.isisfish.datastore.RuleStorage; +import fr.ifremer.isisfish.datastore.ScriptStorage; +import fr.ifremer.isisfish.datastore.SimulatorStorage; + +/** + * Test concernant la gestion du bytecode des scripts utilisateur. + * + * @author Eric Chatellier + */ +public class DependencyUtilTest extends AbstractIsisFishTest { + + /** + * Récupère une classe parmis les scripts de test et vérifie que les dépendances sont bien + * extraites. + * + * @throws IsisFishException + */ + @Test + public void testExtractDependencies1() throws IsisFishException { + SimulatorStorage simulatorByCell = SimulatorStorage.getSimulator("SimulatorEffortByCell"); + Class<?> clazz = simulatorByCell.getCodeClass(); + Set<String> deps = DependencyUtil.extractDependencies(clazz, false); + Assert.assertTrue(deps.size() >= 10); + Assert.assertTrue(deps.contains("simulators.DefaultSimulator")); + } + + /** + * Récupère une classe parmis les scripts de test et vérifie que les dépendances sont bien + * extraites. + * + * @throws IsisFishException + */ + @Test + public void testExtractDependencies2() throws IsisFishException { + SimulatorStorage simulator = SimulatorStorage.getSimulator("DefaultSimulator"); + Class<?> clazz = simulator.getCodeClass(); + Set<String> deps = DependencyUtil.extractDependencies(clazz, false); + Assert.assertTrue(deps.size() >= 35); + Assert.assertTrue(deps.contains("scripts.GravityModel")); + Assert.assertTrue(deps.contains("scripts.ResultName")); + Assert.assertTrue(deps.contains("scripts.SiMatrix")); + + } + + /** + * Récupère une classe parmis les scripts de test et vérifie que les dépendances sont bien + * extraites. + * + * @throws IsisFishException + */ + @Test + public void testExtractDependencies3() throws IsisFishException { + RuleStorage cantonnement = RuleStorage.getRule("Cantonnement"); + Class<?> clazz = cantonnement.getCodeClass(); + Set<String> deps = DependencyUtil.extractDependencies(clazz, false); + Assert.assertTrue(deps.size() >= 30); + Assert.assertTrue(deps.contains("scripts.ResultName")); + } + + /** + * Récupère une classe parmis les scripts de test et vérifie que les dépendances sont bien + * extraites. + * + * @throws IsisFishException + */ + @Test + public void testExtractDependencies4() throws IsisFishException { + ScriptStorage script = ScriptStorage.getScript("SiMatrix"); + Class<?> clazz = script.getCodeClass(); + Set<String> deps = DependencyUtil.extractDependencies(clazz, false); + Assert.assertTrue(deps.size() >= 51); + Assert.assertTrue(deps.contains("scripts.ObjectiveFunctionBaranov")); + Assert.assertTrue(deps.contains("scripts.ObjectiveFunction")); + Assert.assertTrue(deps.contains("scripts.MinimisationUtil")); + Assert.assertTrue(deps.contains("scripts.ResultName")); + } + + /** + * Récupère une classe parmis les scripts de test et vérifie que les dépendances sont bien + * extraites. + * + * @throws IsisFishException + */ + @Test + public void testExtractDependencies5() throws IsisFishException { + ScriptStorage script = ScriptStorage.getScript("GravityModel"); + Class<?> clazz = script.getCodeClass(); + Set<String> deps = DependencyUtil.extractDependencies(clazz, false); + Assert.assertTrue(deps.size() >= 31); + Assert.assertTrue(deps.contains("scripts.SiMatrix")); + Assert.assertTrue(deps.contains("scripts.ResultName")); + } + + /** + * Récupère une classe parmis les scripts de test et vérifie que les dépendances sont bien + * extraites. + * + * @throws IsisFishException + */ + @Test + public void testExtractDependencies6() throws IsisFishException { + ScriptStorage script = ScriptStorage.getScript("ObjectiveFunctionBaranov"); + Class<?> clazz = script.getCodeClass(); + Set<String> deps = DependencyUtil.extractDependencies(clazz, false); + Assert.assertTrue(deps.size() >= 4); + Assert.assertTrue(deps.contains("scripts.ObjectiveFunction")); + Assert.assertTrue(deps.contains("fr.ifremer.isisfish.util.Nocache")); + } +} Property changes on: branches/4.3.0-log4j2/src/test/java/fr/ifremer/isisfish/util/DependencyUtilTest.java ___________________________________________________________________ Added: svn:eol-style + native Added: svn:keywords + Author Date Id Revision HeadURL