1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.jshell.execution;
  26 
  27 import java.io.File;
  28 import java.net.URL;
  29 import java.net.URLClassLoader;
  30 import java.security.CodeSource;
  31 import java.util.Map;
  32 import java.util.TreeMap;
  33 import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
  34 import jdk.jshell.spi.ExecutionControl.ClassInstallException;
  35 import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
  36 import jdk.jshell.spi.ExecutionControl.InternalException;
  37 import jdk.jshell.spi.ExecutionControl.NotImplementedException;
  38 
  39 /**
  40  * The standard implementation of {@link LoaderDelegate} using
  41  * a {@link URLClassLoader}.
  42  *
  43  * @author Robert Field
  44  */
  45 class DefaultLoaderDelegate implements LoaderDelegate {
  46 
  47     private final RemoteClassLoader loader;
  48     private final Map<String, Class<?>> klasses = new TreeMap<>();
  49 
  50     class RemoteClassLoader extends URLClassLoader {
  51 
  52         private final Map<String, byte[]> classObjects = new TreeMap<>();
  53 
  54         RemoteClassLoader() {
  55             super(new URL[0]);
  56         }
  57 
  58         void delare(String name, byte[] bytes) {
  59             classObjects.put(name, bytes);
  60         }
  61 
  62         @Override
  63         protected Class<?> findClass(String name) throws ClassNotFoundException {
  64             byte[] b = classObjects.get(name);
  65             if (b == null) {
  66                 return super.findClass(name);
  67             }
  68             return super.defineClass(name, b, 0, b.length, (CodeSource) null);
  69         }
  70 
  71         @Override
  72         public void addURL(URL url) {
  73             super.addURL(url);
  74         }
  75 
  76     }
  77 
  78     public DefaultLoaderDelegate() {
  79         this.loader = new RemoteClassLoader();
  80     }
  81 
  82     @Override
  83     public void load(ClassBytecodes[] cbcs)
  84             throws ClassInstallException, EngineTerminationException {
  85         boolean[] loaded = new boolean[cbcs.length];
  86         try {
  87             for (ClassBytecodes cbc : cbcs) {
  88                 loader.delare(cbc.name(), cbc.bytecodes());
  89             }
  90             for (int i = 0; i < cbcs.length; ++i) {
  91                 ClassBytecodes cbc = cbcs[i];
  92                 Class<?> klass = loader.loadClass(cbc.name());
  93                 klasses.put(cbc.name(), klass);
  94                 loaded[i] = true;
  95                 // Get class loaded to the point of, at least, preparation
  96                 klass.getDeclaredMethods();
  97             }
  98         } catch (Throwable ex) {
  99             throw new ClassInstallException("load: " + ex.getMessage(), loaded);
 100         }
 101     }
 102 
 103 
 104     @Override
 105     public void addToClasspath(String cp)
 106             throws EngineTerminationException, InternalException {
 107         try {
 108             for (String path : cp.split(File.pathSeparator)) {
 109                 loader.addURL(new File(path).toURI().toURL());
 110             }
 111         } catch (Exception ex) {
 112             throw new InternalException(ex.toString());
 113         }
 114     }
 115 
 116     @Override
 117     public void setClasspath(String path)
 118             throws EngineTerminationException, InternalException {
 119         throw new NotImplementedException("setClasspath: Not supported yet.");
 120     }
 121 
 122     @Override
 123     public Class<?> findClass(String name) throws ClassNotFoundException {
 124         Class<?> klass = klasses.get(name);
 125         if (klass == null) {
 126             throw new ClassNotFoundException(name + " not found");
 127         } else {
 128             return klass;
 129         }
 130     }
 131 
 132 }