rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 28 Apr 2016 06:21:04 +0200
changeset 1957 85f1fbb0f2f6
parent 1787 ea12a3bb4b33
permissions -rw-r--r--
Exclude classes needed only when running on classical JVM
jaroslav@106
     1
/**
jaroslav@106
     2
 * Back 2 Browser Bytecode Translator
jaroslav@1787
     3
 * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@106
     4
 *
jaroslav@106
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@106
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@106
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@106
     8
 *
jaroslav@106
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@106
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@106
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@106
    12
 * GNU General Public License for more details.
jaroslav@106
    13
 *
jaroslav@106
    14
 * You should have received a copy of the GNU General Public License
jaroslav@106
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@106
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@106
    17
 */
jaroslav@29
    18
package org.apidesign.vm4brwsr;
jaroslav@29
    19
jaroslav@29
    20
import java.io.BufferedWriter;
jaroslav@1058
    21
import java.io.File;
jaroslav@1762
    22
import java.io.FileOutputStream;
jaroslav@29
    23
import java.io.IOException;
jaroslav@1762
    24
import java.io.OutputStreamWriter;
jaroslav@29
    25
import java.io.Writer;
lubomir@1020
    26
import java.net.URI;
lubomir@1020
    27
import java.net.URISyntaxException;
lubomir@1020
    28
import java.net.URL;
lubomir@1020
    29
import java.util.Enumeration;
lubomir@1020
    30
import java.util.jar.JarEntry;
lubomir@1020
    31
import java.util.jar.JarFile;
jaroslav@1957
    32
import org.apidesign.bck2brwsr.core.ExtraJavaScript;
jaroslav@29
    33
jaroslav@136
    34
/** Generator of JavaScript from bytecode of classes on classpath of the VM
jaroslav@136
    35
 * with a Main method.
jaroslav@29
    36
 *
jaroslav@29
    37
 * @author Jaroslav Tulach <jtulach@netbeans.org>
jaroslav@29
    38
 */
jaroslav@1957
    39
@ExtraJavaScript(processByteCode = false, resource="")
jaroslav@136
    40
final class Main {
jaroslav@136
    41
    private Main() {}
jaroslav@29
    42
    
lubomir@1020
    43
    public static void main(String... args) throws IOException, URISyntaxException {
jaroslav@881
    44
        final String obfuscate = "--obfuscatelevel";
lubomir@1029
    45
        final String extension = "--createextension";
lubomir@1029
    46
jaroslav@29
    47
        if (args.length < 2) {
jaroslav@298
    48
            System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012");
lubomir@1029
    49
            System.err.print("Usage: java -cp ... -jar ... [");
jaroslav@881
    50
            System.err.print(obfuscate);
jaroslav@881
    51
            System.err.print(" [");
jaroslav@881
    52
            boolean first = true;
jaroslav@881
    53
            for (ObfuscationLevel l : ObfuscationLevel.values()) {
jaroslav@881
    54
                if (!first) {
jaroslav@881
    55
                    System.err.print('|');
jaroslav@881
    56
                }
jaroslav@881
    57
                System.err.print(l.name());
jaroslav@881
    58
                first = false;
jaroslav@881
    59
            }
lubomir@1029
    60
            System.err.print("]] [");
lubomir@1029
    61
            System.err.print(extension);
jaroslav@881
    62
            System.err.println("] <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
jaroslav@881
    63
            System.exit(9);
jaroslav@29
    64
        }
lubomir@1020
    65
lubomir@1020
    66
        final ClassLoader mainClassLoader = Main.class.getClassLoader();
lubomir@1020
    67
jaroslav@881
    68
        ObfuscationLevel obfLevel = ObfuscationLevel.NONE;
lubomir@1029
    69
        boolean createExtension = false;
jaroslav@881
    70
        StringArray classes = new StringArray();
jaroslav@881
    71
        String generateTo = null;
jaroslav@881
    72
        for (int i = 0; i < args.length; i++) {
jaroslav@881
    73
            if (obfuscate.equals(args[i])) { // NOI18N
jaroslav@881
    74
                i++;
jaroslav@881
    75
                try {
jaroslav@881
    76
                    obfLevel = ObfuscationLevel.valueOf(args[i]);
jaroslav@881
    77
                } catch (Exception e) {
jaroslav@881
    78
                    System.err.print(obfuscate);
jaroslav@881
    79
                    System.err.print(" parameter needs to be followed by one of ");
jaroslav@881
    80
                    boolean first = true;
jaroslav@881
    81
                    for (ObfuscationLevel l : ObfuscationLevel.values()) {
jaroslav@881
    82
                        if (!first) {
jaroslav@881
    83
                            System.err.print(", ");
jaroslav@881
    84
                        }
jaroslav@881
    85
                        System.err.print(l.name());
jaroslav@881
    86
                        first = false;
jaroslav@881
    87
                    }
jaroslav@881
    88
                    System.err.println();
jaroslav@881
    89
                    System.exit(1);
jaroslav@881
    90
                }
jaroslav@881
    91
                continue;
jaroslav@881
    92
            }
lubomir@1029
    93
            if (extension.equals(args[i])) { // NOI18N
lubomir@1029
    94
                createExtension = true;
lubomir@1029
    95
                continue;
lubomir@1029
    96
            }
jaroslav@881
    97
            if (generateTo == null) {
jaroslav@881
    98
                generateTo = args[i];
jaroslav@881
    99
            } else {
lubomir@1020
   100
                collectClasses(classes, mainClassLoader, args[i]);
jaroslav@881
   101
            }
jaroslav@881
   102
        }
jaroslav@1058
   103
        
jaroslav@1058
   104
        File gt = new File(generateTo);
jaroslav@1058
   105
        if (Boolean.getBoolean("skip.if.exists") && gt.isFile()) {
jaroslav@1058
   106
            System.err.println("Skipping as " + gt + " exists.");
jaroslav@1058
   107
            System.exit(0);
jaroslav@1058
   108
        }
jaroslav@1058
   109
        
jaroslav@1762
   110
        try (Writer w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(gt), "UTF-8"))) {
jaroslav@1604
   111
            Bck2Brwsr c = Bck2Brwsr.newCompiler().
jaroslav@881
   112
                obfuscation(obfLevel).
jaroslav@881
   113
                addRootClasses(classes.toArray()).
jaroslav@1604
   114
                resources(new LdrRsrcs(Main.class.getClassLoader(), true));
jaroslav@1604
   115
            
jaroslav@1604
   116
            if (createExtension) {
jaroslav@1604
   117
                c = c.library();
jaroslav@1604
   118
            }
jaroslav@1604
   119
            
jaroslav@1604
   120
            c.generate(w);
lubomir@281
   121
        }
jaroslav@29
   122
    }
lubomir@1020
   123
lubomir@1020
   124
    private static void collectClasses(
lubomir@1020
   125
            final StringArray dest,
lubomir@1020
   126
            final ClassLoader cl, final String relativePath)
lubomir@1020
   127
                throws IOException, URISyntaxException {
lubomir@1020
   128
        final Enumeration<URL> urls = cl.getResources(relativePath);
lubomir@1020
   129
        if (!urls.hasMoreElements()) {
lubomir@1020
   130
            dest.add(relativePath);
lubomir@1020
   131
            return;
lubomir@1020
   132
        }
lubomir@1020
   133
        do {
lubomir@1020
   134
            final URL url = urls.nextElement();
lubomir@1020
   135
            switch (url.getProtocol()) {
lubomir@1020
   136
                case "file":
lubomir@1020
   137
                    collectClasses(dest, relativePath,
lubomir@1020
   138
                                   new File(new URI(url.toString())));
lubomir@1020
   139
                    continue;
lubomir@1020
   140
                case "jar":
lubomir@1020
   141
                    final String fullPath = url.getPath();
lubomir@1020
   142
                    final int sepIndex = fullPath.indexOf('!');
lubomir@1020
   143
                    final String jarFilePath =
lubomir@1020
   144
                            (sepIndex != -1) ? fullPath.substring(0, sepIndex)
lubomir@1020
   145
                                             : fullPath;
lubomir@1020
   146
lubomir@1020
   147
                    final URI jarUri = new URI(jarFilePath);
lubomir@1020
   148
                    if (jarUri.getScheme().equals("file")) {
lubomir@1020
   149
                        try (JarFile jarFile = new JarFile(new File(jarUri))) {
lubomir@1020
   150
                            collectClasses(dest, relativePath, jarFile);
lubomir@1020
   151
                            continue;
lubomir@1020
   152
                        }
lubomir@1020
   153
                    }
lubomir@1020
   154
                    break;
lubomir@1020
   155
            }
lubomir@1020
   156
lubomir@1020
   157
            dest.add(relativePath);
lubomir@1020
   158
        } while (urls.hasMoreElements());
lubomir@1020
   159
    }
lubomir@1020
   160
lubomir@1020
   161
    private static void collectClasses(final StringArray dest,
lubomir@1020
   162
                                       final String relativePath,
lubomir@1020
   163
                                       final File file) {
lubomir@1020
   164
        if (file.isDirectory()) {
lubomir@1020
   165
            final File[] subFiles = file.listFiles();
lubomir@1020
   166
            for (final File subFile: subFiles) {
lubomir@1020
   167
                collectClasses(dest,
lubomir@1020
   168
                               extendPath(relativePath, subFile.getName()),
lubomir@1020
   169
                               subFile);
lubomir@1020
   170
            }
lubomir@1020
   171
lubomir@1020
   172
            return;
lubomir@1020
   173
        }
lubomir@1020
   174
lubomir@1020
   175
        final String filePath = file.getPath();
lubomir@1020
   176
        if (filePath.endsWith(".class")) {
lubomir@1020
   177
            validateAndAddClass(dest, relativePath);
lubomir@1020
   178
        }
lubomir@1020
   179
    }
lubomir@1020
   180
lubomir@1020
   181
    private static void collectClasses(final StringArray dest,
lubomir@1020
   182
                                       final String relativePath,
lubomir@1020
   183
                                       final JarFile jarFile) {
lubomir@1020
   184
        if (relativePath.endsWith(".class")) {
lubomir@1020
   185
            if (jarFile.getJarEntry(relativePath) != null) {
lubomir@1020
   186
                validateAndAddClass(dest, relativePath);
lubomir@1020
   187
            }
lubomir@1020
   188
lubomir@1020
   189
            return;
lubomir@1020
   190
        }
lubomir@1020
   191
lubomir@1020
   192
        final String expectedPrefix =
lubomir@1020
   193
                relativePath.endsWith("/") ? relativePath
lubomir@1020
   194
                                           : relativePath + '/';
lubomir@1020
   195
        final Enumeration<JarEntry> entries = jarFile.entries();
lubomir@1020
   196
        while (entries.hasMoreElements()) {
lubomir@1020
   197
            final JarEntry entry = entries.nextElement();
lubomir@1020
   198
            if (!entry.isDirectory()) {
lubomir@1020
   199
                final String entryName = entry.getName();
lubomir@1020
   200
                if (entryName.startsWith(expectedPrefix)
lubomir@1020
   201
                        && entryName.endsWith(".class")) {
lubomir@1020
   202
                    validateAndAddClass(dest, entryName);
lubomir@1020
   203
                }
lubomir@1020
   204
            }
lubomir@1020
   205
        }
lubomir@1020
   206
    }
lubomir@1020
   207
lubomir@1020
   208
    private static String extendPath(final String relativePath,
lubomir@1020
   209
                                     final String fileName) {
lubomir@1020
   210
        return relativePath.endsWith("/") ? relativePath + fileName
lubomir@1020
   211
                                          : relativePath + '/' + fileName;
lubomir@1020
   212
    }
lubomir@1020
   213
lubomir@1020
   214
    private static void validateAndAddClass(final StringArray dest,
lubomir@1020
   215
                                            final String relativePath) {
lubomir@1020
   216
        final String className =
lubomir@1020
   217
                relativePath.substring(0, relativePath.length() - 6);
jaroslav@1763
   218
        dest.add(className);
lubomir@1020
   219
    }
jaroslav@29
   220
}