1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java Fri Apr 26 18:48:34 2013 +0200
1.3 @@ -0,0 +1,148 @@
1.4 +/**
1.5 + * Back 2 Browser Bytecode Translator
1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, version 2 of the License.
1.11 + *
1.12 + * This program is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 + * GNU General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU General Public License
1.18 + * along with this program. Look for COPYING file in the top folder.
1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
1.20 + */
1.21 +package org.apidesign.vm4brwsr;
1.22 +
1.23 +import java.io.IOException;
1.24 +import java.io.InputStream;
1.25 +import java.util.HashMap;
1.26 +import java.util.Map;
1.27 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
1.28 +import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
1.29 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
1.30 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
1.31 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
1.32 +
1.33 +@ExtraJavaScript(processByteCode = false, resource="")
1.34 +final class ExportedSymbols {
1.35 + private final Bck2Brwsr.Resources resources;
1.36 + private final Map<Object, Boolean> isMarkedAsExportedCache;
1.37 +
1.38 + ExportedSymbols(final Bck2Brwsr.Resources resources) {
1.39 + this.resources = resources;
1.40 +
1.41 + isMarkedAsExportedCache = new HashMap<Object, Boolean>();
1.42 + }
1.43 +
1.44 + boolean isExported(ClassData classData) throws IOException {
1.45 + return classData.isPublic() && isMarkedAsExportedPackage(
1.46 + classData.getPkgName())
1.47 + || isMarkedAsExported(classData);
1.48 + }
1.49 +
1.50 + boolean isExported(MethodData methodData) throws IOException {
1.51 + return isAccessible(methodData.access) && isExported(methodData.cls)
1.52 + || isMarkedAsExported(methodData);
1.53 + }
1.54 +
1.55 + boolean isExported(FieldData fieldData) throws IOException {
1.56 + return isAccessible(fieldData.access) && isExported(fieldData.cls)
1.57 + || isMarkedAsExported(fieldData);
1.58 + }
1.59 +
1.60 + private boolean isMarkedAsExportedPackage(String pkgName) {
1.61 + if (pkgName == null) {
1.62 + return false;
1.63 + }
1.64 +
1.65 + final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName);
1.66 + if (cachedValue != null) {
1.67 + return cachedValue;
1.68 + }
1.69 +
1.70 + final boolean newValue = resolveIsMarkedAsExportedPackage(pkgName);
1.71 + isMarkedAsExportedCache.put(pkgName, newValue);
1.72 +
1.73 + return newValue;
1.74 + }
1.75 +
1.76 + private boolean isMarkedAsExported(ClassData classData)
1.77 + throws IOException {
1.78 + final Boolean cachedValue = isMarkedAsExportedCache.get(classData);
1.79 + if (cachedValue != null) {
1.80 + return cachedValue;
1.81 + }
1.82 +
1.83 + final boolean newValue =
1.84 + isMarkedAsExported(classData.findAnnotationData(true),
1.85 + classData);
1.86 + isMarkedAsExportedCache.put(classData, newValue);
1.87 +
1.88 + return newValue;
1.89 + }
1.90 +
1.91 + private boolean isMarkedAsExported(MethodData methodData)
1.92 + throws IOException {
1.93 + return isMarkedAsExported(methodData.findAnnotationData(true),
1.94 + methodData.cls);
1.95 + }
1.96 +
1.97 + private boolean isMarkedAsExported(FieldData fieldData)
1.98 + throws IOException {
1.99 + return isMarkedAsExported(fieldData.findAnnotationData(true),
1.100 + fieldData.cls);
1.101 + }
1.102 +
1.103 + private boolean resolveIsMarkedAsExportedPackage(String pkgName) {
1.104 + try {
1.105 + final InputStream is =
1.106 + resources.get(pkgName + "/package-info.class");
1.107 + if (is == null) {
1.108 + return false;
1.109 + }
1.110 +
1.111 + try {
1.112 + final ClassData pkgInfoClass = new ClassData(is);
1.113 + return isMarkedAsExported(
1.114 + pkgInfoClass.findAnnotationData(true),
1.115 + pkgInfoClass);
1.116 + } finally {
1.117 + is.close();
1.118 + }
1.119 + } catch (final IOException e) {
1.120 + return false;
1.121 + }
1.122 + }
1.123 +
1.124 + private boolean isMarkedAsExported(byte[] arrData, ClassData cd)
1.125 + throws IOException {
1.126 + if (arrData == null) {
1.127 + return false;
1.128 + }
1.129 +
1.130 + final boolean[] found = { false };
1.131 + final AnnotationParser annotationParser =
1.132 + new AnnotationParser(false, false) {
1.133 + @Override
1.134 + protected void visitAnnotationStart(
1.135 + String type,
1.136 + boolean top) {
1.137 + if (top && type.equals("Lorg/apidesign/bck2brwsr"
1.138 + + "/core/Exported;")) {
1.139 + found[0] = true;
1.140 + }
1.141 + }
1.142 + };
1.143 + annotationParser.parse(arrData, cd);
1.144 + return found[0];
1.145 + }
1.146 +
1.147 + private static boolean isAccessible(int access) {
1.148 + return (access & (ByteCodeParser.ACC_PUBLIC
1.149 + | ByteCodeParser.ACC_PROTECTED)) != 0;
1.150 + }
1.151 +}