lubomir@1084: /** lubomir@1084: * Back 2 Browser Bytecode Translator jaroslav@1787: * Copyright (C) 2012-2015 Jaroslav Tulach lubomir@1084: * lubomir@1084: * This program is free software: you can redistribute it and/or modify lubomir@1084: * it under the terms of the GNU General Public License as published by lubomir@1084: * the Free Software Foundation, version 2 of the License. lubomir@1084: * lubomir@1084: * This program is distributed in the hope that it will be useful, lubomir@1084: * but WITHOUT ANY WARRANTY; without even the implied warranty of lubomir@1084: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the lubomir@1084: * GNU General Public License for more details. lubomir@1084: * lubomir@1084: * You should have received a copy of the GNU General Public License lubomir@1084: * along with this program. Look for COPYING file in the top folder. lubomir@1084: * If not, see http://opensource.org/licenses/GPL-2.0. lubomir@1084: */ lubomir@1084: package org.apidesign.vm4brwsr; lubomir@1084: lubomir@1084: import java.io.IOException; lubomir@1084: import java.io.InputStream; lubomir@1084: import java.util.HashMap; lubomir@1084: import java.util.Map; lubomir@1084: import org.apidesign.bck2brwsr.core.ExtraJavaScript; lubomir@1084: import org.apidesign.vm4brwsr.ByteCodeParser.ClassData; lubomir@1085: import org.apidesign.vm4brwsr.ByteCodeParser.FieldData; lubomir@1085: import org.apidesign.vm4brwsr.ByteCodeParser.MethodData; lubomir@1084: lubomir@1084: @ExtraJavaScript(processByteCode = false, resource="") lubomir@1084: final class ClassDataCache { lubomir@1084: private static final Object MISSING_CLASS = new Object(); lubomir@1084: lubomir@1084: private final Bck2Brwsr.Resources resources; lubomir@1084: private final Map classDataMap; lubomir@1084: lubomir@1084: ClassDataCache(final Bck2Brwsr.Resources resources) { lubomir@1084: this.resources = resources; lubomir@1084: lubomir@1084: classDataMap = new HashMap(); lubomir@1084: } lubomir@1084: lubomir@1085: ClassData getClassData(String className) throws IOException { lubomir@1085: if (className.startsWith("[")) { lubomir@1085: // required for accessVirtualMethod, shouldn't be problematic for lubomir@1085: // calls from other sources lubomir@1085: className = "java/lang/Object"; lubomir@1085: } lubomir@1084: Object cacheEntry = classDataMap.get(className); lubomir@1084: if (cacheEntry == null) { lubomir@1084: final InputStream is = loadClass(resources, className); lubomir@1084: cacheEntry = (is != null) ? new ClassData(is) : MISSING_CLASS; lubomir@1084: classDataMap.put(className, cacheEntry); lubomir@1084: } lubomir@1084: lubomir@1084: return (cacheEntry != MISSING_CLASS) ? (ClassData) cacheEntry : null; lubomir@1084: } lubomir@1084: lubomir@1085: MethodData findMethod(final String startingClass, lubomir@1085: final String name, lubomir@1085: final String signature) throws IOException { lubomir@1085: return findMethod(getClassData(startingClass), name, signature); lubomir@1085: } lubomir@1085: lubomir@1085: FieldData findField(final String startingClass, lubomir@1085: final String name, lubomir@1085: final String signature) throws IOException { lubomir@1085: return findField(getClassData(startingClass), name, signature); lubomir@1085: } lubomir@1085: lubomir@1087: MethodData findMethod(final ClassData startingClass, lubomir@1085: final String name, lubomir@1085: final String signature) throws IOException { lubomir@1087: final FindFirstTraversalCallback ffTraversalCallback = lubomir@1087: new FindFirstTraversalCallback(); lubomir@1087: lubomir@1087: findMethods(startingClass, name, signature, ffTraversalCallback); lubomir@1087: return ffTraversalCallback.getFirst(); lubomir@1087: } lubomir@1087: lubomir@1087: FieldData findField(final ClassData startingClass, lubomir@1087: final String name, lubomir@1087: final String signature) throws IOException { lubomir@1087: final FindFirstTraversalCallback ffTraversalCallback = lubomir@1087: new FindFirstTraversalCallback(); lubomir@1087: lubomir@1087: findFields(startingClass, name, signature, ffTraversalCallback); lubomir@1087: return ffTraversalCallback.getFirst(); lubomir@1087: } lubomir@1087: lubomir@1087: void findMethods(final ClassData startingClass, lubomir@1087: final String methodName, lubomir@1087: final String methodSignature, lubomir@1087: final TraversalCallback mdTraversalCallback) lubomir@1087: throws IOException { lubomir@1087: traverseHierarchy( lubomir@1087: startingClass, lubomir@1087: new FindMethodsTraversalCallback(methodName, methodSignature, lubomir@1087: mdTraversalCallback)); lubomir@1087: } lubomir@1087: lubomir@1087: void findFields(final ClassData startingClass, lubomir@1087: final String fieldName, lubomir@1087: final String fieldSignature, lubomir@1087: final TraversalCallback fdTraversalCallback) lubomir@1087: throws IOException { lubomir@1087: traverseHierarchy( lubomir@1087: startingClass, lubomir@1087: new FindFieldsTraversalCallback(fieldName, fieldSignature, lubomir@1087: fdTraversalCallback)); lubomir@1087: } lubomir@1087: lubomir@1087: private boolean traverseHierarchy( lubomir@1087: ClassData currentClass, lubomir@1087: final TraversalCallback cdTraversalCallback) lubomir@1087: throws IOException { lubomir@1085: while (currentClass != null) { lubomir@1087: if (!cdTraversalCallback.traverse(currentClass)) { lubomir@1087: return false; lubomir@1087: } lubomir@1087: lubomir@1087: for (final String superIfaceName: lubomir@1087: currentClass.getSuperInterfaces()) { lubomir@1087: if (!traverseHierarchy(getClassData(superIfaceName), lubomir@1087: cdTraversalCallback)) { lubomir@1087: return false; lubomir@1087: } lubomir@1085: } lubomir@1085: lubomir@1085: final String superClassName = currentClass.getSuperClassName(); lubomir@1085: if (superClassName == null) { lubomir@1085: break; lubomir@1085: } lubomir@1087: lubomir@1085: currentClass = getClassData(superClassName); lubomir@1085: } lubomir@1085: lubomir@1087: return true; lubomir@1085: } lubomir@1085: lubomir@1087: interface TraversalCallback { lubomir@1087: boolean traverse(T object); lubomir@1087: } lubomir@1085: lubomir@1087: private final class FindFirstTraversalCallback lubomir@1087: implements TraversalCallback { lubomir@1087: private T firstObject; lubomir@1087: lubomir@1087: @Override lubomir@1087: public boolean traverse(final T object) { lubomir@1087: firstObject = object; lubomir@1087: return false; lubomir@1085: } lubomir@1085: lubomir@1087: public T getFirst() { lubomir@1087: return firstObject; lubomir@1087: } lubomir@1087: } lubomir@1087: lubomir@1087: private final class FindMethodsTraversalCallback lubomir@1087: implements TraversalCallback { lubomir@1087: private final String methodName; lubomir@1087: private final String methodSignature; lubomir@1087: private final TraversalCallback mdTraversalCallback; lubomir@1087: lubomir@1087: public FindMethodsTraversalCallback( lubomir@1087: final String methodName, lubomir@1087: final String methodSignature, lubomir@1087: final TraversalCallback mdTraversalCallback) { lubomir@1087: this.methodName = methodName; lubomir@1087: this.methodSignature = methodSignature; lubomir@1087: this.mdTraversalCallback = mdTraversalCallback; lubomir@1087: } lubomir@1087: lubomir@1087: @Override lubomir@1087: public boolean traverse(final ClassData classData) { lubomir@1087: final MethodData methodData = lubomir@1087: classData.findMethod(methodName, methodSignature); lubomir@1087: return (methodData != null) lubomir@1087: ? mdTraversalCallback.traverse(methodData) lubomir@1087: : true; lubomir@1087: } lubomir@1087: } lubomir@1087: lubomir@1087: private final class FindFieldsTraversalCallback lubomir@1087: implements TraversalCallback { lubomir@1087: private final String fieldName; lubomir@1087: private final String fieldSignature; lubomir@1087: private final TraversalCallback fdTraversalCallback; lubomir@1087: lubomir@1087: public FindFieldsTraversalCallback( lubomir@1087: final String fieldName, lubomir@1087: final String fieldSignature, lubomir@1087: final TraversalCallback fdTraversalCallback) { lubomir@1087: this.fieldName = fieldName; lubomir@1087: this.fieldSignature = fieldSignature; lubomir@1087: this.fdTraversalCallback = fdTraversalCallback; lubomir@1087: } lubomir@1087: lubomir@1087: @Override lubomir@1087: public boolean traverse(final ClassData classData) { lubomir@1087: final FieldData fieldData = lubomir@1087: classData.findField(fieldName, fieldSignature); lubomir@1087: return (fieldData != null) lubomir@1087: ? fdTraversalCallback.traverse(fieldData) lubomir@1087: : true; lubomir@1087: } lubomir@1085: } lubomir@1085: lubomir@1084: private static InputStream loadClass(Bck2Brwsr.Resources l, String name) lubomir@1084: throws IOException { lubomir@1084: return l.get(name + ".class"); // NOI18N lubomir@1084: } lubomir@1084: }