rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 26 Apr 2014 21:30:06 +0200
branchclosure
changeset 1491 4a1398eff4fb
parent 1029 b1fe994d4267
child 1561 f6200b8decc4
permissions -rw-r--r--
Different meaning of root vs. added classes. Ability to explicitly enumerate classes that should be exported and available with fully qualified name.
lubomir@1029
     1
/**
lubomir@1029
     2
 * Back 2 Browser Bytecode Translator
lubomir@1029
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
lubomir@1029
     4
 *
lubomir@1029
     5
 * This program is free software: you can redistribute it and/or modify
lubomir@1029
     6
 * it under the terms of the GNU General Public License as published by
lubomir@1029
     7
 * the Free Software Foundation, version 2 of the License.
lubomir@1029
     8
 *
lubomir@1029
     9
 * This program is distributed in the hope that it will be useful,
lubomir@1029
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
lubomir@1029
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
lubomir@1029
    12
 * GNU General Public License for more details.
lubomir@1029
    13
 *
lubomir@1029
    14
 * You should have received a copy of the GNU General Public License
lubomir@1029
    15
 * along with this program. Look for COPYING file in the top folder.
lubomir@1029
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
lubomir@1029
    17
 */
lubomir@1029
    18
package org.apidesign.vm4brwsr;
lubomir@1029
    19
lubomir@1029
    20
import java.io.IOException;
lubomir@1029
    21
import java.io.InputStream;
lubomir@1029
    22
import java.util.HashMap;
lubomir@1029
    23
import java.util.Map;
lubomir@1029
    24
import org.apidesign.bck2brwsr.core.ExtraJavaScript;
lubomir@1029
    25
import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
lubomir@1029
    26
import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
lubomir@1029
    27
import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
lubomir@1029
    28
import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
lubomir@1029
    29
lubomir@1029
    30
@ExtraJavaScript(processByteCode = false, resource="")
lubomir@1029
    31
final class ExportedSymbols {
lubomir@1029
    32
    private final Bck2Brwsr.Resources resources;
jaroslav@1491
    33
    private final StringArray exported;
lubomir@1029
    34
    private final Map<Object, Boolean> isMarkedAsExportedCache;
lubomir@1029
    35
jaroslav@1491
    36
    ExportedSymbols(final Bck2Brwsr.Resources resources, StringArray explicitlyExported) {
lubomir@1029
    37
        this.resources = resources;
jaroslav@1491
    38
        this.exported = explicitlyExported;
lubomir@1029
    39
lubomir@1029
    40
        isMarkedAsExportedCache = new HashMap<Object, Boolean>();
lubomir@1029
    41
    }
lubomir@1029
    42
lubomir@1029
    43
    boolean isExported(ClassData classData) throws IOException {
jaroslav@1491
    44
        if (exported.contains(classData.getClassName())) {
jaroslav@1491
    45
            return true;
jaroslav@1491
    46
        }
lubomir@1029
    47
        return classData.isPublic() && isMarkedAsExportedPackage(
lubomir@1029
    48
                                           classData.getPkgName())
lubomir@1029
    49
                   || isMarkedAsExported(classData);
lubomir@1029
    50
    }
lubomir@1029
    51
lubomir@1029
    52
    boolean isExported(MethodData methodData) throws IOException {
lubomir@1029
    53
        return isAccessible(methodData.access) && isExported(methodData.cls)
lubomir@1029
    54
                   || isMarkedAsExported(methodData);
lubomir@1029
    55
    }
lubomir@1029
    56
lubomir@1029
    57
    boolean isExported(FieldData fieldData) throws IOException {
lubomir@1029
    58
        return isAccessible(fieldData.access) && isExported(fieldData.cls)
lubomir@1029
    59
                   || isMarkedAsExported(fieldData);
lubomir@1029
    60
    }
lubomir@1029
    61
lubomir@1029
    62
    private boolean isMarkedAsExportedPackage(String pkgName) {
lubomir@1029
    63
        if (pkgName == null) {
lubomir@1029
    64
            return false;
lubomir@1029
    65
        }
lubomir@1029
    66
lubomir@1029
    67
        final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName);
lubomir@1029
    68
        if (cachedValue != null) {
lubomir@1029
    69
            return cachedValue;
lubomir@1029
    70
        }
lubomir@1029
    71
lubomir@1029
    72
        final boolean newValue = resolveIsMarkedAsExportedPackage(pkgName);
lubomir@1029
    73
        isMarkedAsExportedCache.put(pkgName, newValue);
lubomir@1029
    74
lubomir@1029
    75
        return newValue;
lubomir@1029
    76
    }
lubomir@1029
    77
lubomir@1029
    78
    private boolean isMarkedAsExported(ClassData classData)
lubomir@1029
    79
            throws IOException {
lubomir@1029
    80
        final Boolean cachedValue = isMarkedAsExportedCache.get(classData);
lubomir@1029
    81
        if (cachedValue != null) {
lubomir@1029
    82
            return cachedValue;
lubomir@1029
    83
        }
lubomir@1029
    84
lubomir@1029
    85
        final boolean newValue =
lubomir@1029
    86
                isMarkedAsExported(classData.findAnnotationData(true),
lubomir@1029
    87
                                   classData);
lubomir@1029
    88
        isMarkedAsExportedCache.put(classData, newValue);
lubomir@1029
    89
lubomir@1029
    90
        return newValue;
lubomir@1029
    91
    }
lubomir@1029
    92
lubomir@1029
    93
    private boolean isMarkedAsExported(MethodData methodData)
lubomir@1029
    94
            throws IOException {
lubomir@1029
    95
        return isMarkedAsExported(methodData.findAnnotationData(true),
lubomir@1029
    96
                                  methodData.cls);
lubomir@1029
    97
    }
lubomir@1029
    98
lubomir@1029
    99
    private boolean isMarkedAsExported(FieldData fieldData)
lubomir@1029
   100
            throws IOException {
lubomir@1029
   101
        return isMarkedAsExported(fieldData.findAnnotationData(true),
lubomir@1029
   102
                                  fieldData.cls);
lubomir@1029
   103
    }
lubomir@1029
   104
lubomir@1029
   105
    private boolean resolveIsMarkedAsExportedPackage(String pkgName) {
lubomir@1029
   106
        try {
lubomir@1029
   107
            final InputStream is =
lubomir@1029
   108
                    resources.get(pkgName + "/package-info.class");
lubomir@1029
   109
            if (is == null) {
lubomir@1029
   110
                return false;
lubomir@1029
   111
            }
lubomir@1029
   112
lubomir@1029
   113
            try {
lubomir@1029
   114
                final ClassData pkgInfoClass = new ClassData(is);
lubomir@1029
   115
                return isMarkedAsExported(
lubomir@1029
   116
                               pkgInfoClass.findAnnotationData(true),
lubomir@1029
   117
                               pkgInfoClass);
lubomir@1029
   118
            } finally {
lubomir@1029
   119
                is.close();
lubomir@1029
   120
            }
lubomir@1029
   121
        } catch (final IOException e) {
lubomir@1029
   122
            return false;
lubomir@1029
   123
        }
lubomir@1029
   124
    }
lubomir@1029
   125
lubomir@1029
   126
    private boolean isMarkedAsExported(byte[] arrData, ClassData cd)
lubomir@1029
   127
            throws IOException {
lubomir@1029
   128
        if (arrData == null) {
lubomir@1029
   129
            return false;
lubomir@1029
   130
        }
lubomir@1029
   131
lubomir@1029
   132
        final boolean[] found = { false };
lubomir@1029
   133
        final AnnotationParser annotationParser =
lubomir@1029
   134
                new AnnotationParser(false, false) {
lubomir@1029
   135
                    @Override
lubomir@1029
   136
                    protected void visitAnnotationStart(
lubomir@1029
   137
                            String type,
lubomir@1029
   138
                            boolean top) {
lubomir@1029
   139
                        if (top && type.equals("Lorg/apidesign/bck2brwsr"
lubomir@1029
   140
                                                   + "/core/Exported;")) {
lubomir@1029
   141
                            found[0] = true;
lubomir@1029
   142
                        }
lubomir@1029
   143
                    }
lubomir@1029
   144
                };
lubomir@1029
   145
        annotationParser.parse(arrData, cd);
lubomir@1029
   146
        return found[0];
lubomir@1029
   147
    }
lubomir@1029
   148
lubomir@1029
   149
    private static boolean isAccessible(int access) {
lubomir@1029
   150
        return (access & (ByteCodeParser.ACC_PUBLIC
lubomir@1029
   151
                              | ByteCodeParser.ACC_PROTECTED)) != 0;
lubomir@1029
   152
    }
lubomir@1029
   153
}