/* * MicroJIAC - A Lightweight Agent Framework * This file is part of MicroJIAC Config. * * Copyright (c) 2007-2012 DAI-Labor, Technische Universität Berlin * * This library includes software developed at DAI-Labor, Technische * Universität Berlin (http://www.dai-labor.de) * * This library 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 library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see <http://www.gnu.org/licenses/>. */ /* * $Id$ */ package de.jiac.micro.config.analysis; import java.io.InputStream; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.objectweb.asm.ClassReader; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.EmptyVisitor; /** * @author Marcel Patzlaff * @version $Revision:$ */ public class ClassInfoPool { public static boolean ignoreClass(String className) { return className.startsWith("java.") || className.startsWith("javax."); } final class ClassInfoCreator extends EmptyVisitor implements Opcodes { protected String owner; protected ClassInfo classInfo; private final HashMap<String, Integer> _classStates; private final HashMap<String, Integer> _interfaceStates; protected ClassInfoCreator() { _classStates= new HashMap<String, Integer>(); _classStates.put("de.jiac.micro.core.AbstractNodeComponent", Integer.valueOf(ClassInfo.NODE_COMPONENT)); _classStates.put("de.jiac.micro.agent.AbstractActiveBehaviour", Integer.valueOf(ClassInfo.BEHAVIOUR)); _classStates.put("de.jiac.micro.agent.AbstractReactiveBehaviour", Integer.valueOf(ClassInfo.BEHAVIOUR)); _interfaceStates= new HashMap<String, Integer>(); _interfaceStates.put("de.jiac.micro.core.IHandle", Integer.valueOf(ClassInfo.HANDLE)); _interfaceStates.put("de.jiac.micro.agent.IActuator", Integer.valueOf(ClassInfo.ACTUATOR)); _interfaceStates.put("de.jiac.micro.agent.ISensor", Integer.valueOf(ClassInfo.SENSOR)); _interfaceStates.put("de.jiac.micro.core.feature.ILifecycleAware", Integer.valueOf(ClassInfo.LIFECYCLE_AWARE)); _interfaceStates.put("de.jiac.micro.core.feature.IConnectionFactory", Integer.valueOf(ClassInfo.CONNECTION_FACTORY)); } public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { owner= name; String className= name.replace('/', '.'); HashSet<String> superInterfaceNames= new HashSet<String>(); for(int i= 0; interfaces != null && i < interfaces.length; ++i) { superInterfaceNames.add(interfaces[i].replace('/', '.')); } requestClassInfos(superInterfaceNames); Integer state= null; if((access & ACC_INTERFACE) > 0) { classInfo= ClassInfo.createInterfaceInfo(ClassInfoPool.this, version, className, superInterfaceNames); state= _interfaceStates.get(className); } else { String superClassName= superName == null ? null : superName.replace('/', '.'); classInfo= ClassInfo.createClassInfo(ClassInfoPool.this, version, className, superClassName, superInterfaceNames); state= _classStates.get(className); if(superClassName != null) { requestClassInfo(superClassName); } } if(state != null) { classInfo.setState(state.intValue()); } } public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { Type type= Type.getType(desc); if(type.getSort() == Type.ARRAY) { type.getElementType(); } if(type.getSort() == Type.OBJECT) { String className= type.getClassName(); if(!ignoreClass(className)) { requestClassInfo(className); classInfo.referencedFieldClasses.add(className); } } // TODO Auto-generated method stub return null; } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if(classInfo.isInterface || (access & ACC_ABSTRACT) != 0 || (access & ACC_SYNTHETIC) != 0) { return null; } return new MethodAnalyser(this, access, name, desc, signature, exceptions); } protected ClassInfo getInfo() { ClassInfo result= classInfo; classInfo= null; return result; } protected void registerDependencyForMethod(MethodKey methodKey, String className) { if(className == null || ignoreClass(className)) { return; } requestClassInfo(className); Set<String> references= classInfo.referencedClassesInMethods.get(methodKey); references.add(className); } } private final ClassLoader _classLoader; private final ClassInfoCreator _classInfoCreator; private final HashSet<String> _requestedInfo; private final HashMap<String, ClassInfo> _pool; public ClassInfoPool(ClassLoader classLoader) { _classLoader= classLoader; _requestedInfo= new HashSet<String>(); _pool= new HashMap<String, ClassInfo>(); _classInfoCreator= new ClassInfoCreator(); } public void requestClassInfo(String className) { if(ignoreClass(className)) { return; } _requestedInfo.add(className); } public void requestClassInfos(Collection<String> classNames) { for(String className : classNames) { requestClassInfo(className); } } public void buildPool() { while(!_requestedInfo.isEmpty()) { String next= _requestedInfo.iterator().next(); _requestedInfo.remove(next); if(!_pool.containsKey(next)) { try { InputStream in= _classLoader.getResourceAsStream(next.replace('.', '/') + ".class"); ClassReader reader= new ClassReader(in); reader.accept(_classInfoCreator, 0); _pool.put(next, _classInfoCreator.getInfo()); } catch (Exception e) { e.printStackTrace(); _pool.put(next, null); } } _requestedInfo.removeAll(_pool.keySet()); } } public ClassInfo getClassInfo(String className) { return _pool.get(className); } public HashSet<ClassInfo> getDerivativeClassInfos(ClassInfo root) { HashSet<ClassInfo> result= new HashSet<ClassInfo>(); for(ClassInfo ci : _pool.values()) { if(ci == root) { continue; } if(root.isAssignableFrom(ci)) { result.add(ci); } } return result; } @Override public String toString() { StringBuilder builder= new StringBuilder(); for(Map.Entry<String, ClassInfo> entry : _pool.entrySet()) { if(entry.getValue() == null) { System.out.println("MISSING: " + entry.getKey()); } else { builder.append(entry.getValue().toString()).append('\n'); } } return builder.toString(); } }