1 # autoimports script requires -scripting mode
   2 
   3 /*
   4  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  *   - Redistributions of source code must retain the above copyright
  11  *     notice, this list of conditions and the following disclaimer.
  12  *
  13  *   - Redistributions in binary form must reproduce the above copyright
  14  *     notice, this list of conditions and the following disclaimer in the
  15  *     documentation and/or other materials provided with the distribution.
  16  *
  17  *   - Neither the name of Oracle nor the names of its
  18  *     contributors may be used to endorse or promote products derived
  19  *     from this software without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  22  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 
  34 /**
  35  * It is tedious to import Java classes used in a script. Sometimes
  36  * it is easier use simple names of java classes and have a script
  37  * auto import Java classes. You can load this script at the statt of
  38  * interactive jjs session or at the start of your script. This script
  39  * defines a __noSuchProperty__ hook to auto import Java classes as
  40  * and when referred first time in your script. You can also call 
  41  * "autoimports" function to print script statements that you need to
  42  * use in your script. i.e., generates script to import Java classes
  43  * used by your script so far. After running your script, you can call
  44  * autoimports to get exact java imports you need and replace autoimports
  45  * load with the generated import statements (to avoid costly init of
  46  * this autoimports script).
  47  */
  48 
  49 (function() {
  50     var ArrayList = Java.type("java.util.ArrayList");
  51     var HashMap = Java.type("java.util.HashMap");
  52     var Files = Java.type("java.nio.file.Files");
  53     var FileSystems = Java.type("java.nio.file.FileSystems");
  54     var URI = Java.type("java.net.URI");
  55 
  56     // initialize a class to package map by iterating all
  57     // classes available in the system by walking through "jrt fs"
  58     var fs = FileSystems.getFileSystem(URI.create("jrt:/"));
  59     var root = fs.getPath('/');
  60 
  61     var clsToPkg = new HashMap();
  62 
  63     function addToClsToPkg(c, p) {
  64         if (clsToPkg.containsKey(c)) {
  65             var val = clsToPkg.get(c);
  66             if (val instanceof ArrayList) {
  67                 val.add(p);
  68             } else {
  69                 var al = new ArrayList();
  70                 al.add(val);
  71                 al.add(p);
  72                 clsToPkg.put(c, al);
  73             }
  74         } else {
  75             clsToPkg.put(c, p);
  76         }
  77     }
  78 
  79     // handle collision and allow user to choose package
  80     function getPkgOfCls(c) {
  81         var val = clsToPkg.get(c);
  82         if (val instanceof ArrayList) {
  83             var count = 1;
  84             print("Multiple matches for " + c + ", choose package:");
  85             for each (var v in val) {
  86                 print(count + ". " + v);
  87                 count++;
  88             }
  89             var choice = parseInt(readLine());
  90             if (isNaN(choice) || choice < 1 || choice > val.size()) {
  91                 print("invalid choice: " + choice);
  92                 return undefined;
  93             }
  94             return val.get(choice - 1);
  95         } else {
  96             return val;
  97         }
  98     }
  99 
 100     Files.walk(root).forEach(function(p) {
 101         if (Files.isRegularFile(p)) {
 102             var str = p.toString();
 103             if (str.endsWith(".class")) {
 104                 str = str.substring(1);
 105                 var idx = str.indexOf('/');
 106                 if (idx != -1) {
 107                     str = str.substring(idx + 1);
 108                     if (str.startsWith("java") ||
 109                         str.startsWith("javax") ||
 110                         str.startsWith("org")) {
 111                         var lastIdx = str.lastIndexOf('/');
 112                         if (lastIdx != -1) {
 113                             var pkg = str.substring(0, lastIdx).replaceAll('/', '.');
 114                             var cls = str.substring(lastIdx + 1, str.lastIndexOf(".class"));
 115                             addToClsToPkg(cls, pkg);
 116                         }
 117                     }
 118                 }
 119             }
 120         } 
 121     });
 122 
 123     var imports = new ArrayList();
 124     var global = this;
 125     var oldNoSuchProp = global.__noSuchProperty__;
 126     this.__noSuchProperty__ = function(name) {
 127         'use strict';
 128 
 129         if (clsToPkg.containsKey(name)) {
 130             var pkg = getPkgOfCls(name);
 131             if (pkg) {
 132                 var clsName = pkg + "." + name;
 133                 imports.add("var " + name + " = Java.type('" + clsName + "');");
 134                 return global[name] = Java.type(clsName);
 135             }
 136         } else if (typeof oldNoSuchProp == 'function') {
 137             return oldNoSuchProp.call(this, name);
 138         }
 139 
 140         if (typeof this == 'undefined') {
 141             throw new ReferenceError(name);
 142         } else {
 143             return undefined;
 144         }
 145     }
 146 
 147     this.autoimports = function() {
 148         for each (var im in imports) {
 149             print(im);
 150         }
 151     }
 152 })();