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