/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.SecureClassLoader; /** * This is a class loader which can load the same classes as another class loader. */ public class CloneClassLoader extends SecureClassLoader { /** * The class loaded to clone. */ private final ClassLoader toClone; /** * Creates a class loader which can load the same classes as the loader which * loaded the CloneClassLoader class itself. * * @param toClone the class loader to mimic. The clone class loader will be able to * load the same classes as the 'toClone' loader. */ public CloneClassLoader(ClassLoader toClone) { super("Clone", null); this.toClone = toClone; } /** * @see java.lang.ClassLoader#findClass(java.lang.String) */ @Override protected Class findClass(String name) throws ClassNotFoundException { // We just ask the wrapper class loader to find the resource for us URL res = toClone.getResource(name.replace('.', '/') + ".class"); if (res == null) { throw new ClassNotFoundException(name); } try { InputStream is = res.openStream(); byte[] code = readStreamIntoBuffer(is, 8192); is.close(); return defineClass(name, code, 0, code.length); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } /** * Reads all data of a stream into a byte array. The method allocates as * much memory as necessary to put the whole data into that byte * array. The data is read in chunks of chunkSize * chunks.

* Implementation Note: The data is read in chunks of * chunkSize bytes. The data is copied to the result * array. The memory consumption at the end of the reading is * 2 x [size of resulting array] + chunkSize. * * @param is the stream to read the data from * @param chunkSize the size of the chunks the data should be read in * @return the whole data of the stream read into an byte array * @throws IllegalArgumentException if chunkSize <= 0 * @throws NullPointerException if is == null * @throws IOException thrown if the provided stream encounters IO problems */ public static byte[] readStreamIntoBuffer(InputStream is, int chunkSize) throws IOException { // check preconditions if (chunkSize <= 0) { throw new IllegalArgumentException("chunkSize <= 0"); } else if (is == null) { throw new NullPointerException("is is null"); } // temporary buffer for read operations and result buffer byte[] tempBuffer = new byte[chunkSize]; byte[] buffer = new byte[0]; int bytesRead = 0; // bytes actual read int oldSize = 0; // size of the resulting buffer while ((bytesRead = is.read(tempBuffer)) > 0) { // temporary reference to the buffer for the copy operation byte[] oldBuffer = buffer; // create a new buffer with the size needed and copy data buffer = new byte[oldSize + bytesRead]; System.arraycopy(oldBuffer, 0, buffer, 0, oldBuffer.length); // copy the new data System.arraycopy(tempBuffer, 0, buffer, oldSize, bytesRead); oldSize += bytesRead; } return buffer; } }