Path: blob/master/test/functional/cmdLineTests/shareClassTests/utils/src/CustomCLs/CustomURLClassLoader.java
6005 views
/*******************************************************************************1* Copyright (c) 2005, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/21package CustomCLs;2223import java.io.ByteArrayOutputStream;24import java.io.File;25import java.io.FileInputStream;26import java.io.IOException;27import java.io.InputStream;28import java.net.JarURLConnection;29import java.net.MalformedURLException;30import java.net.URL;31import java.security.CodeSource;32import java.security.SecureClassLoader;33import java.util.Hashtable;34import java.util.jar.Attributes;35import java.util.jar.JarEntry;36import java.util.jar.JarFile;37import java.util.jar.Manifest;38import java.util.jar.Attributes.Name;3940import com.ibm.oti.shared.HelperAlreadyDefinedException;41import com.ibm.oti.shared.Shared;42import com.ibm.oti.shared.SharedClassHelperFactory;43import com.ibm.oti.shared.SharedClassTokenHelper;44import com.ibm.oti.shared.SharedClassURLClasspathHelper;45import com.ibm.oti.shared.SharedClassURLHelper;4647/**48* @author Matthew Kilner49*/50public class CustomURLClassLoader extends SecureClassLoader {5152URL[] urls, orgUrls;5354private Hashtable jarCache = new Hashtable(32);55int loaderType;5657SharedClassURLClasspathHelper scHelper;5859CustomLoaderMetaDataCache[] metaDataArray;6061FoundAtIndex foundAtIndex = new FoundAtIndex();6263public CustomURLClassLoader(URL[] passedUrls, ClassLoader parent){64super(parent);65loaderType = ClassLoaderType.CACHEDURL.ord;66int urlLength = passedUrls.length;67urls = new URL[urlLength];68orgUrls = new URL[urlLength];69for (int i=0; i < urlLength; i++) {70try {71urls[i] = createSearchURL(passedUrls[i]);72} catch (MalformedURLException e) {}73orgUrls[i] = passedUrls[i];74}75metaDataArray = new CustomLoaderMetaDataCache[urls.length];76initMetaData();77SharedClassHelperFactory schFactory = Shared.getSharedClassHelperFactory();78if(schFactory != null){79try{80scHelper = schFactory.getURLClasspathHelper(this, passedUrls);81if(null != scHelper){82scHelper.confirmAllEntries();83}84} catch (HelperAlreadyDefinedException e){85e.printStackTrace();86}87}88}8990public CustomURLClassLoader(URL[] passedUrls){91super();92loaderType = ClassLoaderType.CACHEDURL.ord;93int urlLength = passedUrls.length;94urls = new URL[urlLength];95orgUrls = new URL[urlLength];96for (int i=0; i < urlLength; i++) {97try {98urls[i] = createSearchURL(passedUrls[i]);99} catch (MalformedURLException e) {}100orgUrls[i] = passedUrls[i];101}102metaDataArray = new CustomLoaderMetaDataCache[urls.length];103initMetaData();104SharedClassHelperFactory schFactory = Shared.getSharedClassHelperFactory();105if(schFactory != null){106try{107scHelper = schFactory.getURLClasspathHelper(this, passedUrls);108if(null != scHelper){109scHelper.confirmAllEntries();110}111} catch (HelperAlreadyDefinedException e){112e.printStackTrace();113}114}115}116117public boolean getHelper(){118SharedClassHelperFactory schFactory = Shared.getSharedClassHelperFactory();119SharedClassURLClasspathHelper newHelper = null;120try{121newHelper = schFactory.getURLClasspathHelper(this, orgUrls);122} catch (HelperAlreadyDefinedException e){123return false;124}125126if(newHelper.equals(scHelper)){127return true;128} else {129return false;130}131}132133public void getHelper(URL[] urls)throws HelperAlreadyDefinedException {134SharedClassHelperFactory schFactory = Shared.getSharedClassHelperFactory();135SharedClassURLClasspathHelper newHelper = null;136newHelper = schFactory.getURLClasspathHelper(this, urls);137}138139public void getURLHelper()throws Exception {140SharedClassHelperFactory schFactory = Shared.getSharedClassHelperFactory();141SharedClassURLHelper newHelper = null;142newHelper = schFactory.getURLHelper(this);143}144145public void getTokenHelper()throws Exception {146SharedClassHelperFactory schFactory = Shared.getSharedClassHelperFactory();147SharedClassTokenHelper newHelper = null;148newHelper = schFactory.getTokenHelper(this);149}150151public boolean duplicateStore(String name){152Class clazz = null;153try{154clazz = this.loadClass(name);155} catch (ClassNotFoundException e){156e.printStackTrace();157}158if (clazz != null){159int indexFoundAt = locateClass(name);160if(indexFoundAt != -1){161scHelper.storeSharedClass(clazz, indexFoundAt);162return true;163}164}165return false;166}167168private static boolean isDirectory(URL url) {169String file = url.getFile();170return (file.length() > 0 && file.charAt(file.length()-1) == '/');171}172173private URL createSearchURL(URL url) throws MalformedURLException {174if (url == null) return url;175String protocol = url.getProtocol();176177if (isDirectory(url) || protocol.equals("jar")) {178return url;179} else {180return new URL("jar", "", -1, url.toString() + "!/");181}182}183184private void initMetaData(){185for(int loopIndex = 0; loopIndex < metaDataArray.length; loopIndex++){186metaDataArray[loopIndex] = null;187}188}189190private void addMetaDataEntry(){191CustomLoaderMetaDataCache[] newArray = new CustomLoaderMetaDataCache[(metaDataArray.length)];192System.arraycopy(metaDataArray,0,newArray,0,metaDataArray.length);193metaDataArray = newArray;194metaDataArray[(metaDataArray.length - 1)] = null;195}196197public void addUrl(URL url){198URL searchURL = null;199try{200searchURL = createSearchURL(url);201} catch (Exception e){202e.printStackTrace();203}204URL[] newOrgUrls = new URL[(orgUrls.length)];205System.arraycopy(orgUrls,0,newOrgUrls,0,orgUrls.length);206orgUrls = newOrgUrls;207orgUrls[(orgUrls.length - 1)] = url;208URL[] newUrls = new URL[urls.length];209System.arraycopy(urls,0,newUrls,0,urls.length);210urls = newUrls;211urls[(urls.length - 1)] = searchURL;212scHelper.addClasspathEntry(url);213scHelper.confirmAllEntries();214addMetaDataEntry();215}216217public URL[] getURLS(){218return orgUrls;219}220221private static byte[] getBytes(InputStream is, boolean readAvailable) throws IOException {222if (readAvailable) {223byte[] buf = new byte[is.available()];224is.read(buf, 0, buf.length);225is.close();226return buf;227}228byte[] buf = new byte[4096];229int size = is.available();230if (size < 1024) size = 1024;231ByteArrayOutputStream bos = new ByteArrayOutputStream(size);232int count;233while ((count = is.read(buf)) > 0)234bos.write(buf, 0, count);235return bos.toByteArray();236}237238private int locateClass(String className){239int classAtEntry = -1;240String name = className.replace('.','/').concat(".class");241for(int index = 0; index < urls.length; index ++){242URL currentUrl = urls[index];243if(currentUrl.getProtocol().equals("jar")){244JarEntry entry = null;245JarFile jf = (JarFile)jarCache.get(currentUrl);246if(jf == null){247/* First time we have encountered this jar.248* Lets cache its metaData.249*/250try{251URL jarFileUrl = ((JarURLConnection)currentUrl.openConnection()).getJarFileURL();252JarURLConnection jarUrlConnection = (JarURLConnection)new URL("jar", "", jarFileUrl.toExternalForm() + "!/").openConnection();253try{254jf = jarUrlConnection.getJarFile();255}catch(Exception e){256}257if(jf != null){258jarCache.put(currentUrl, jf);259}260} catch (Exception e){261e.printStackTrace();262}263if(jf != null){264Manifest manifest = null;265java.security.cert.Certificate[] certs = null;266URL csUrl = currentUrl;267CodeSource codeSource;268try{269manifest = jf.getManifest();270} catch(Exception e){271e.printStackTrace();272}273entry = jf.getJarEntry(name);274if(entry != null){275certs = entry.getCertificates();276}277codeSource = new CodeSource(csUrl, certs);278CustomLoaderMetaDataCache metaData = new CustomLoaderMetaDataCache();279metaData.manifest = manifest;280metaData.codeSource = codeSource;281metaDataArray[index] = metaData;282}283}284if(entry == null && jf != null){285entry = jf.getJarEntry(name);286}287if(entry != null){288/* We have the first match on the class path, return the current url index */289return index;290}291} else {292String filename = currentUrl.getFile();293String host = currentUrl.getHost();294if (host != null && host.length() > 0) {295filename = new StringBuffer(host.length() + filename.length() + name.length() + 2).296append("//").append(host).append(filename).append(name).toString();297} else {298filename = new StringBuffer(filename.length() + name.length()).299append(filename).append(name).toString();300}301File file = new File(filename);302// Don't throw exceptions for speed303if (file.exists()) {304if(metaDataArray[index] == null){305java.security.cert.Certificate[] certs = null;306CustomLoaderMetaDataCache metaData = new CustomLoaderMetaDataCache();307metaData.manifest = null;308metaData.codeSource = new CodeSource(currentUrl, certs);309metaDataArray[index] = metaData;310}311return index;312}313}314}315return classAtEntry;316}317318private byte[] loadClassBytes(String className, int urlIndex){319byte[] bytes = null;320String name = className.replace('.','/').concat(".class");321URL classLocation = urls[urlIndex];322if(classLocation.getProtocol().equals("jar")){323JarFile jf = (JarFile)jarCache.get(classLocation);324JarEntry entry = jf.getJarEntry(name);325try{326InputStream stream = jf.getInputStream(entry);327bytes = getBytes(stream, true);328} catch (Exception e){329e.printStackTrace();330}331} else {332String filename = classLocation.getFile();333String host = classLocation.getHost();334if (host != null && host.length() > 0) {335filename = new StringBuffer(host.length() + filename.length() + name.length() + 2).336append("//").append(host).append(filename).append(name).toString();337} else {338filename = new StringBuffer(filename.length() + name.length()).339append(filename).append(name).toString();340}341File file = new File(filename);342// Don't throw exceptions for speed343if (file.exists()) {344try{345FileInputStream stream = new FileInputStream(file);346bytes = getBytes(stream, true);347} catch(Exception e){348e.printStackTrace();349}350}351}352return bytes;353}354355public Class findClass(String name) throws ClassNotFoundException {356Class clazz = null;357if(scHelper != null){358byte[] classBytes = scHelper.findSharedClass(name, foundAtIndex);359if(classBytes != null){360if(metaDataArray[foundAtIndex.getIndex()] != null){361checkPackage(name, foundAtIndex.getIndex());362CustomLoaderMetaDataCache metadata = metaDataArray[foundAtIndex.getIndex()];363CodeSource codeSource = metadata.codeSource;364clazz = defineClass(name, classBytes, 0, classBytes.length, codeSource);365}366}367}368if(clazz == null) {369int indexFoundAt = locateClass(name);370if(indexFoundAt != -1){371try{372byte[] classBytes = loadClassBytes(name, indexFoundAt);373checkPackage(name, indexFoundAt);374CustomLoaderMetaDataCache metadata = metaDataArray[indexFoundAt];375CodeSource codeSource = metadata.codeSource;376clazz = defineClass(name, classBytes, 0, classBytes.length, codeSource);377if(clazz != null){378if(scHelper != null)379{380scHelper.storeSharedClass(clazz, indexFoundAt);381}382}383} catch (Exception e){384e.printStackTrace();385}386}387if(clazz == null){388throw new ClassNotFoundException(name);389}390}391return clazz;392}393394private void checkPackage(String name, int urlIndex){395int index = name.lastIndexOf('.');396if(index != -1){397String packageString = name.substring(0, index);398Manifest manifest = metaDataArray[urlIndex].manifest;399CodeSource codeSource = metaDataArray[urlIndex].codeSource;400synchronized(this){401Package packageInst = getPackage(packageString);402if(packageInst == null){403if (manifest != null){404definePackage(packageString, manifest, codeSource.getLocation());405} else {406definePackage(packageString, null, null, null, null, null, null, null);407}408} else {409boolean exception = false;410if (manifest != null) {411String dirName = packageString.replace('.', '/') + "/";412if (isSealed(manifest, dirName))413exception = !packageInst.isSealed(codeSource.getLocation());414} else415exception = packageInst.isSealed();416if (exception)417throw new SecurityException(com.ibm.oti.util.Msg.getString("Package exception"));418}419}420}421}422423private boolean isSealed(Manifest manifest, String dirName) {424Attributes mainAttributes = manifest.getMainAttributes();425String value = mainAttributes.getValue(Attributes.Name.SEALED);426boolean sealed = value != null &&427value.toLowerCase().equals ("true");428Attributes attributes = manifest.getAttributes(dirName);429if (attributes != null) {430value = attributes.getValue(Attributes.Name.SEALED);431if (value != null)432sealed = value.toLowerCase().equals("true");433}434return sealed;435}436437protected Package definePackage(String name, Manifest man, URL url) throws IllegalArgumentException {438String path = name.replace('.','/').concat("/");439String[] attrs = new String[7];440URL sealedAtURL = null;441442Attributes attr = man.getAttributes(path);443Attributes mainAttr = man.getMainAttributes();444445if(attr != null){446attrs[0] = attr.getValue(Name.SPECIFICATION_TITLE);447attrs[1] = attr.getValue(Name.SPECIFICATION_VERSION);448attrs[2] = attr.getValue(Name.SPECIFICATION_VENDOR);449attrs[3] = attr.getValue(Name.IMPLEMENTATION_TITLE);450attrs[4] = attr.getValue(Name.IMPLEMENTATION_VERSION);451attrs[5] = attr.getValue(Name.IMPLEMENTATION_VENDOR);452attrs[6] = attr.getValue(Name.SEALED);453}454455if(mainAttr != null){456if (attrs[0] == null) {457attrs[0] = mainAttr.getValue(Name.SPECIFICATION_TITLE);458}459if (attrs[1] == null) {460attrs[1] = mainAttr.getValue(Name.SPECIFICATION_VERSION);461}462if (attrs[2] == null) {463attrs[2] = mainAttr.getValue(Name.SPECIFICATION_VENDOR);464}465if (attrs[3] == null) {466attrs[3] = mainAttr.getValue(Name.IMPLEMENTATION_TITLE);467}468if (attrs[4] == null) {469attrs[4] = mainAttr.getValue(Name.IMPLEMENTATION_VERSION);470}471if (attrs[5] == null) {472attrs[5] = mainAttr.getValue(Name.IMPLEMENTATION_VENDOR);473}474if (attrs[6] == null) {475attrs[6] = mainAttr.getValue(Name.SEALED);476}477}478if ("true".equalsIgnoreCase(attrs[6])){479sealedAtURL = url;480}481return definePackage(name, attrs[0], attrs[1], attrs[2], attrs[3], attrs[4], attrs[5], sealedAtURL);482}483484public boolean isClassInSharedCache(String className){485byte[] sharedClass = null;486if (scHelper!=null) {487sharedClass = scHelper.findSharedClass(className, foundAtIndex);488if (sharedClass !=null){489return true;490} else {491return false;492}493}494return false;495}496497public Class getClassFromCache(String name){498Class clazz = null;499byte[] classBytes = scHelper.findSharedClass(name, foundAtIndex);500if(classBytes != null){501CodeSource cs = null;502clazz = defineClass(name, classBytes, 0, classBytes.length, cs);503}504return clazz;505}506507public static class FoundAtIndex implements SharedClassURLClasspathHelper.IndexHolder {508509int indexFoundAt = -1;510511public void setIndex(int index) {512indexFoundAt = index;513}514515public int getIndex(){516return indexFoundAt;517}518519public void reset(){520indexFoundAt = -1;521}522523}524}525526527