1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.net.URL; 29 import java.security.SecureClassLoader; 30 31 /** 32 * This is a class loader which can load the same classes as another class loader. 33 */ 34 public class CloneClassLoader extends SecureClassLoader { 35 36 /** 37 * The class loaded to clone. 38 */ 39 private final ClassLoader toClone; 40 41 /** 42 * Creates a class loader which can load the same classes as the loader which 43 * loaded the <code>CloneClassLoader</code> class itself. 44 * 45 * @param toClone the class loader to mimic. The clone class loader will be able to 46 * load the same classes as the 'toClone' loader. 47 */ 48 public CloneClassLoader(ClassLoader toClone) { 49 super("Clone", null); 50 this.toClone = toClone; 51 } 52 53 /** 54 * @see java.lang.ClassLoader#findClass(java.lang.String) 55 */ 56 @Override 57 protected Class<?> findClass(String name) throws ClassNotFoundException { 58 // We just ask the wrapper class loader to find the resource for us 59 URL res = toClone.getResource(name.replace('.', '/') + ".class"); 60 61 if (res == null) { 62 throw new ClassNotFoundException(name); 63 } 64 65 try { 66 InputStream is = res.openStream(); 67 byte[] code = readStreamIntoBuffer(is, 8192); 68 is.close(); 69 return defineClass(name, code, 0, code.length); 70 } catch (IOException e) { 71 throw new ClassNotFoundException(name, e); 72 } 73 } 74 75 /** 76 * Reads all data of a stream into a byte array. The method allocates as 77 * much memory as necessary to put the whole data into that byte 78 * array. The data is read in chunks of <code>chunkSize</code> 79 * chunks.<br><br> 80 * <b>Implementation Note: </b> The data is read in chunks of 81 * <code>chunkSize</code> bytes. The data is copied to the result 82 * array. The memory consumption at the end of the reading is 83 * <code>2 x [size of resulting array] + chunkSize</code>. 84 * 85 * @param is the stream to read the data from 86 * @param chunkSize the size of the chunks the data should be read in 87 * @return the <b>whole</b> data of the stream read into an byte array 88 * @throws IllegalArgumentException if chunkSize <= 0 89 * @throws NullPointerException if is == null 90 * @throws IOException thrown if the provided stream encounters IO problems 91 */ 92 public static byte[] readStreamIntoBuffer(InputStream is, int chunkSize) 93 throws IOException { 94 95 // check preconditions 96 if (chunkSize <= 0) { 97 throw new IllegalArgumentException("chunkSize <= 0"); 98 } 99 else if (is == null) { 100 throw new NullPointerException("is is null"); 101 } 102 103 // temporary buffer for read operations and result buffer 104 byte[] tempBuffer = new byte[chunkSize]; 105 byte[] buffer = new byte[0]; 106 107 int bytesRead = 0; // bytes actual read 108 int oldSize = 0; // size of the resulting buffer 109 110 while ((bytesRead = is.read(tempBuffer)) > 0) { 111 112 // temporary reference to the buffer for the copy operation 113 byte[] oldBuffer = buffer; 114 115 // create a new buffer with the size needed and copy data 116 buffer = new byte[oldSize + bytesRead]; 117 System.arraycopy(oldBuffer, 0, buffer, 0, oldBuffer.length); 118 119 // copy the new data 120 System.arraycopy(tempBuffer, 0, buffer, oldSize, bytesRead); 121 oldSize += bytesRead; 122 } 123 124 return buffer; 125 } 126 }