rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 24 Feb 2015 11:12:53 +0100
changeset 1787 ea12a3bb4b33
parent 1087 d868b5a67b9b
permissions -rw-r--r--
Using year range 2012-2015 in copyright header
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.vm4brwsr;
    19 
    20 import java.io.IOException;
    21 import java.io.InputStream;
    22 import java.util.HashMap;
    23 import java.util.Map;
    24 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
    25 import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
    26 import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
    27 import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
    28 
    29 @ExtraJavaScript(processByteCode = false, resource="")
    30 final class ClassDataCache {
    31     private static final Object MISSING_CLASS = new Object();
    32 
    33     private final Bck2Brwsr.Resources resources;
    34     private final Map<String, Object> classDataMap;
    35 
    36     ClassDataCache(final Bck2Brwsr.Resources resources) {
    37         this.resources = resources;
    38 
    39         classDataMap = new HashMap<String, Object>();
    40     }
    41 
    42     ClassData getClassData(String className) throws IOException {
    43         if (className.startsWith("[")) {
    44             // required for accessVirtualMethod, shouldn't be problematic for
    45             // calls from other sources
    46             className = "java/lang/Object";
    47         }
    48         Object cacheEntry = classDataMap.get(className);
    49         if (cacheEntry == null) {
    50             final InputStream is = loadClass(resources, className);
    51             cacheEntry = (is != null) ? new ClassData(is) : MISSING_CLASS;
    52             classDataMap.put(className, cacheEntry);
    53         }
    54 
    55         return (cacheEntry != MISSING_CLASS) ? (ClassData) cacheEntry : null;
    56     }
    57 
    58     MethodData findMethod(final String startingClass,
    59                           final String name,
    60                           final String signature) throws IOException {
    61         return findMethod(getClassData(startingClass), name, signature);
    62     }
    63 
    64     FieldData findField(final String startingClass,
    65                         final String name,
    66                         final String signature) throws IOException {
    67         return findField(getClassData(startingClass), name, signature);
    68     }
    69 
    70     MethodData findMethod(final ClassData startingClass,
    71                           final String name,
    72                           final String signature) throws IOException {
    73         final FindFirstTraversalCallback<MethodData> ffTraversalCallback =
    74                 new FindFirstTraversalCallback<MethodData>();
    75 
    76         findMethods(startingClass, name, signature, ffTraversalCallback);
    77         return ffTraversalCallback.getFirst();
    78     }
    79 
    80     FieldData findField(final ClassData startingClass,
    81                         final String name,
    82                         final String signature) throws IOException {
    83         final FindFirstTraversalCallback<FieldData> ffTraversalCallback =
    84                 new FindFirstTraversalCallback<FieldData>();
    85 
    86         findFields(startingClass, name, signature, ffTraversalCallback);
    87         return ffTraversalCallback.getFirst();
    88     }
    89 
    90     void findMethods(final ClassData startingClass,
    91                      final String methodName,
    92                      final String methodSignature,
    93                      final TraversalCallback<MethodData> mdTraversalCallback)
    94                              throws IOException {
    95         traverseHierarchy(
    96                 startingClass,
    97                 new FindMethodsTraversalCallback(methodName, methodSignature,
    98                                                  mdTraversalCallback));
    99     }
   100 
   101     void findFields(final ClassData startingClass,
   102                     final String fieldName,
   103                     final String fieldSignature,
   104                     final TraversalCallback<FieldData> fdTraversalCallback)
   105                             throws IOException {
   106         traverseHierarchy(
   107                 startingClass,
   108                 new FindFieldsTraversalCallback(fieldName, fieldSignature,
   109                                                 fdTraversalCallback));
   110     }
   111 
   112     private boolean traverseHierarchy(
   113             ClassData currentClass,
   114             final TraversalCallback<ClassData> cdTraversalCallback)
   115                 throws IOException {
   116         while (currentClass != null) {
   117             if (!cdTraversalCallback.traverse(currentClass)) {
   118                 return false;
   119             }
   120 
   121             for (final String superIfaceName:
   122                     currentClass.getSuperInterfaces()) {
   123                 if (!traverseHierarchy(getClassData(superIfaceName),
   124                                        cdTraversalCallback)) {
   125                     return false;
   126                 }
   127             }
   128 
   129             final String superClassName = currentClass.getSuperClassName();
   130             if (superClassName == null) {
   131                 break;
   132             }
   133 
   134             currentClass = getClassData(superClassName);
   135         }
   136 
   137         return true;
   138     }
   139 
   140     interface TraversalCallback<T> {
   141         boolean traverse(T object);
   142     }
   143 
   144     private final class FindFirstTraversalCallback<T>
   145             implements TraversalCallback<T> {
   146         private T firstObject;
   147 
   148         @Override
   149         public boolean traverse(final T object) {
   150             firstObject = object;
   151             return false;
   152         }
   153 
   154         public T getFirst() {
   155             return firstObject;
   156         }
   157     }
   158 
   159     private final class FindMethodsTraversalCallback
   160             implements TraversalCallback<ClassData> {
   161         private final String methodName;
   162         private final String methodSignature;
   163         private final TraversalCallback<MethodData> mdTraversalCallback;
   164 
   165         public FindMethodsTraversalCallback(
   166                 final String methodName,
   167                 final String methodSignature,
   168                 final TraversalCallback<MethodData> mdTraversalCallback) {
   169             this.methodName = methodName;
   170             this.methodSignature = methodSignature;
   171             this.mdTraversalCallback = mdTraversalCallback;
   172         }
   173 
   174         @Override
   175         public boolean traverse(final ClassData classData) {
   176             final MethodData methodData =
   177                     classData.findMethod(methodName, methodSignature);
   178             return (methodData != null)
   179                        ? mdTraversalCallback.traverse(methodData)
   180                        : true;
   181         }
   182     }
   183 
   184     private final class FindFieldsTraversalCallback
   185             implements TraversalCallback<ClassData> {
   186         private final String fieldName;
   187         private final String fieldSignature;
   188         private final TraversalCallback<FieldData> fdTraversalCallback;
   189 
   190         public FindFieldsTraversalCallback(
   191                 final String fieldName,
   192                 final String fieldSignature,
   193                 final TraversalCallback<FieldData> fdTraversalCallback) {
   194             this.fieldName = fieldName;
   195             this.fieldSignature = fieldSignature;
   196             this.fdTraversalCallback = fdTraversalCallback;
   197         }
   198 
   199         @Override
   200         public boolean traverse(final ClassData classData) {
   201             final FieldData fieldData =
   202                     classData.findField(fieldName, fieldSignature);
   203             return (fieldData != null)
   204                        ? fdTraversalCallback.traverse(fieldData)
   205                        : true;
   206         }
   207     }
   208 
   209     private static InputStream loadClass(Bck2Brwsr.Resources l, String name)
   210             throws IOException {
   211         return l.get(name + ".class"); // NOI18N
   212     }
   213 }