![JAR search and dependency download from the Maven repository](/logo.png)
com.generallycloud.baseio.container.URLDynamicClassLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of baseio-all Show documentation
Show all versions of baseio-all Show documentation
The all in one project of baseio
/*
* Copyright 2015-2017 GenerallyCloud.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.generallycloud.baseio.container;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import com.generallycloud.baseio.common.CloseUtil;
import com.generallycloud.baseio.common.FileUtil;
import com.generallycloud.baseio.common.Logger;
import com.generallycloud.baseio.common.LoggerFactory;
import com.generallycloud.baseio.common.LoggerUtil;
public class URLDynamicClassLoader extends URLClassLoader implements DynamicClassLoader {
private Map clazzEntries = new HashMap<>();
private Logger logger = LoggerFactory.getLogger(getClass());
private ClassLoader parentClassLoader;
private Map resourceMap = new HashMap<>();
private Map> resourcesMap = new HashMap<>();
public URLDynamicClassLoader() {
this(null);
}
public URLDynamicClassLoader(ClassLoader parent) {
super(new URL[] {}, parent == null ? getSystemClassLoader() : parent);
this.parentClassLoader = getParent();
if (parentClassLoader == null) {
parentClassLoader = getSystemClassLoader();
}
}
private void addResource(URL url, String pathName, String fileName)
throws DuplicateClassException {
if (resourceMap.containsKey(pathName) && !pathName.equals(".")) {
throw new DuplicateClassException(pathName);
}
resourceMap.put(pathName, url);
List urls = resourcesMap.get(fileName);
if (urls == null) {
urls = new ArrayList<>();
resourcesMap.put(fileName, urls);
}
urls.add(url);
}
private Class> defineClass(ClassEntry entry) {
if (entry.loadedClass != null) {
return entry.loadedClass;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
String name = entry.className;
int i = name.lastIndexOf('.');
if (i != -1) {
sm.checkPackageAccess(name.substring(0, i));
}
}
String name = entry.className;
byte[] cb = entry.classBinary;
Class> clazz = defineClass(name, cb, 0, cb.length);
entry.loadedClass = clazz;
LoggerUtil.prettyNIOServerLog(logger, "define class [ {} ]", name);
return clazz;
}
private Class> defineClass(String name) throws ClassNotFoundException {
ClassEntry entry = clazzEntries.get(name);
if (entry == null) {
return null;
}
return defineClass(entry);
}
private Class> entrustLoadClass(ClassLoader classLoader, String name) {
try {
return classLoader.loadClass(name);
} catch (Throwable e) {
return null;
}
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
Class> clazz = findLoadedClass0(name);
if (clazz == null) {
return loadClass(name);
}
return clazz;
}
private Class> findLoadedClass0(String name) throws ClassNotFoundException {
ClassEntry entry = clazzEntries.get(name);
if (entry == null) {
return null;
}
return entry.loadedClass;
}
@Override
public URL findResource(String name) {
URL url = resourceMap.get(name);
if (url == null) {
return super.findResource(name);
}
return url;
}
@Override
public Enumeration findResources(String name) throws IOException {
@SuppressWarnings("unchecked")
Enumeration[] temp = new Enumeration[2];
temp[0] = findResources0(name);
temp[1] = super.findResources(name);
return new CompoundEnumeration(temp);
}
private Enumeration findResources0(String name) throws IOException {
List urls = resourcesMap.get(name);
if (urls == null) {
return java.util.Collections.emptyEnumeration();
}
return new Enumeration() {
private int index = 0;
@Override
public boolean hasMoreElements() {
return index < urls.size();
}
@Override
public URL nextElement() {
if (!hasMoreElements()) {
throw new NoSuchElementException();
}
return urls.get(index++);
}
};
}
@Override
public Class> forName(String name) throws ClassNotFoundException {
return this.findClass(name);
}
@Override
public Class> loadClass(String name) throws ClassNotFoundException {
Class> clazz = defineClass(name);
if (clazz != null) {
return clazz;
}
clazz = entrustLoadClass(parentClassLoader, name);
if (clazz != null) {
return clazz;
}
throw new ClassNotFoundException(name);
}
public boolean matchExtend(String name) {
return false;
}
public boolean matchSystem(String name) {
return name.startsWith("java") || name.startsWith("sun") || name.startsWith("com/sun")
|| matchExtend(name);
}
@Override
public void scan(File file) throws IOException {
this.scanFile(file, "");
this.addResource(file, "/." , ".");
LoggerUtil.prettyNIOServerLog(logger, "load class count [ {} ] from [ {} ]",
clazzEntries.size(), file.getAbsolutePath());
}
@Override
public void scan(String file) throws IOException {
this.scan(new File(file));
}
private void scanFile(File file, String pathName) throws IOException {
if (!file.exists()) {
LoggerUtil.prettyNIOServerLog(logger, "file or directory [ {} ] not found",
file.getAbsoluteFile());
return;
}
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File _file : files) {
scanFile(_file, pathName + "/" + _file.getName());
}
return;
}
addResource(file, pathName);
}
private void addResource(File file,String pathName) throws IOException{
String fileName = file.getName();
addResource(file, pathName, fileName);
}
private void addResource(File file,String pathName,String fileName) throws IOException{
URL url = file.toURI().toURL();
if (fileName.endsWith(".jar")) {
scanZip(new JarFile(file));
addURL(url);
return;
}
pathName = pathName.substring(1);
addResource(url, pathName, fileName);
}
private void scanZip(JarFile file) throws IOException {
try {
LoggerUtil.prettyNIOServerLog(logger, "load file [ {} ]", file.getName());
Enumeration entries = file.entries();
for (; entries.hasMoreElements();) {
JarEntry entry = entries.nextElement();
if (entry.isDirectory()) {
continue;
}
String filePathName = entry.getName();
if (filePathName.endsWith(".class") && !matchSystem(filePathName)) {
storeClass(file, entry);
}
}
} finally {
CloseUtil.close(file);
}
}
private void storeClass(JarFile file, JarEntry entry) throws IOException {
String filePathName = entry.getName();
String className = filePathName.replace('/', '.').replace(".class", "");
if (clazzEntries.containsKey(className)) {
throw new DuplicateClassException(className);
}
try {
parentClassLoader.loadClass(className);
throw new DuplicateClassException(className);
} catch (ClassNotFoundException e) {
}
InputStream inputStream = file.getInputStream(entry);
byte[] binaryContent = FileUtil.inputStream2ByteArray(inputStream);
ClassEntry classEntry = new ClassEntry();
classEntry.classBinary = binaryContent;
classEntry.className = className;
clazzEntries.put(className, classEntry);
}
private void unloadClass(Class> clazz) {
CloseUtil.close(this);
if (clazz == null) {
return;
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers())) {
continue;
}
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(null, null);
} catch (Throwable e) {
logger.debug(e);
}
}
}
@Override
public void unloadClassLoader() {
Collection es = clazzEntries.values();
for (ClassEntry e : es) {
unloadClass(e.loadedClass);
}
}
class ClassEntry {
private byte[] classBinary;
private String className;
private Class> loadedClass;
}
class ResourceEnumeration implements Enumeration{
private int index = 0;
private List urls;
ResourceEnumeration(List urls) {
this.urls = urls;
}
@Override
public boolean hasMoreElements() {
return index < urls.size();
}
@Override
public URL nextElement() {
if (!hasMoreElements()) {
throw new NoSuchElementException();
}
return urls.get(index++);
}
};
class CompoundEnumeration implements Enumeration {
private Enumeration[] enums;
private int index = 0;
public CompoundEnumeration(Enumeration[] paramArrayOfEnumeration) {
this.enums = paramArrayOfEnumeration;
}
public boolean hasMoreElements() {
while (this.index < this.enums.length) {
if ((this.enums[this.index] != null)
&& (this.enums[this.index].hasMoreElements())) {
return true;
}
this.index += 1;
}
return false;
}
public E nextElement() {
if (!hasMoreElements()) {
throw new NoSuchElementException();
}
return this.enums[this.index].nextElement();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy