- * @param
- * @return
- * @throws Exception
- */
- public static P get(Class targetType, Class proxyType) throws Exception {
- Assert.notNull(targetType, "被代理类类型不能为空!");
- Assert.notNull(proxyType, "代理类类型不能为空!");
- if (targetType == proxyType) {
- return get(proxyType);
- }
- if (!proxyType.isAssignableFrom(targetType)) {
- throw new RuntimeException(String.format("期望的代理类类型[%s]不是目标类型[%s]的超类!", proxyType.getName(), targetType.getName()));
- }
- return (P)LockUtil.doubleCheckProcess(
- () -> !otherProxyBeanCache.containsKey(targetType) || !otherProxyBeanCache.get(targetType).containsKey(proxyType),
- targetType,
- () -> {
- if (!otherProxyBeanCache.containsKey(targetType)) {
- otherProxyBeanCache.set(targetType, new MemoryCache<>());
- }
- otherProxyBeanCache.get(targetType).set(proxyType, getProxyFactory(targetType, proxyType).get(targetType, proxyType));
- },
- () -> otherProxyBeanCache.get(targetType).get(proxyType)
- );
- }
-
- /**
- * 获取代理工厂
- * 1、如果被代理类是一个接口,则采用jdk动态代理,减少避免不必要的字节码编译开销
- * 2、其他情况则采用子类代理(AsgcProxy)
- * @return
- */
- private static ProxyFactory getProxyFactory(Class> clazz) {
- if (proxyStrategy == ProxyStrategy.AUTO) {
- if (ClassUtil.isInterface(clazz)) {
- return Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY);
- }
- return Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY);
- }
- return Proxy.getProxyFactory(proxyStrategy);
- }
-
- /**
- * 获取代理工厂
- * 1、如果被代理类是一个接口,则采用jdk动态代理,减少避免不必要的字节码编译开销
- * 2、其他情况则采用子类代理(AsgcProxy)
- * @return
- */
- private static ProxyFactory getProxyFactory(Class> targetType, Class> proxyType) {
- if (targetType == proxyType) {
- return getProxyFactory(targetType);
- }
- if (proxyStrategy == ProxyStrategy.AUTO) {
- if (ClassUtil.isInterface(proxyType)) {
- return Proxy.getProxyFactory(ProxyStrategy.JDK_DYNAMIC_PROXY);
- }
- return Proxy.getProxyFactory(ProxyStrategy.ASGC_PROXY);
- }
- return Proxy.getProxyFactory(proxyStrategy);
- }
-
- /**
- * 设置代理策略
- * @param proxyStrategy
- */
- public static synchronized void setProxyStrategy(ProxyStrategy proxyStrategy) {
- Assert.notNull(proxyStrategy, "代理策略不能为空!");
- Aop.proxyStrategy = proxyStrategy;
- }
-
- /**
- * 注册全局拦截器
- * @param clazz
- */
- public static void intercept(Class extends Interceptor> interceptorType) {
- InterceptorFactory.registerGlobalInterceptor(interceptorType);
- }
-
- /**
- * 注册类级别的拦截器
- * @param targetType
- * @param interceptorType
- */
- public static void intercept(Class> targetType, Class extends Interceptor> interceptorType) {
- InterceptorFactory.registerInterceptor(targetType, interceptorType);
- }
-
- /**
- * 注册方法级别的拦截器
- * @param targetMethod
- * @param interceptorType
- */
- public static void intercept(Method targetMethod, Class extends Interceptor> interceptorType) {
- InterceptorFactory.registerInterceptor(targetMethod, interceptorType);
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/AopCallback.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/AopCallback.java
deleted file mode 100644
index e8d14ff8..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/AopCallback.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop;
-
-/**
- * aop回调
- * @author: aoshiguchen
- * @date: 2022/6/30
- */
-@FunctionalInterface
-public interface AopCallback {
- /**
- * 回调
- * @return
- */
- T callback() throws Exception;
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Intercept.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Intercept.java
deleted file mode 100644
index 676aa20f..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Intercept.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop;
-
-import fun.asgc.neutrino.core.aop.interceptor.ExceptionHandler;
-import fun.asgc.neutrino.core.aop.interceptor.Filter;
-import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
-import fun.asgc.neutrino.core.aop.interceptor.ResultAdvice;
-
-import java.lang.annotation.*;
-
-/**
- *
- * @author: aoshiguchen
- * @date: 2022/6/24
- */
-@Inherited
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD})
-public @interface Intercept {
- /**
- * 指定拦截器
- * @return
- */
- Class extends Interceptor>[] value() default {};
-
- /**
- * 排除拦截器
- * @return
- */
- Class extends Interceptor>[] exclude() default {};
-
- /**
- * 忽略一切全局拦截器
- * @return
- */
- boolean ignoreGlobal() default false;
-
- /**
- * 指定过滤器
- * @return
- */
- Class extends Filter>[] filter() default {};
-
- /**
- * 指定异常处理器
- * @return
- */
- Class extends ExceptionHandler>[] exceptionHandler() default {};
-
- /**
- * 指定结果处理器
- * @return
- */
- Class extends ResultAdvice>[] resultAdvice() default {};
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Invocation.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Invocation.java
deleted file mode 100644
index 86b1a96a..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/Invocation.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop;
-
-import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
-import fun.asgc.neutrino.core.aop.interceptor.InterceptorFactory;
-import fun.asgc.neutrino.core.aop.proxy.ProxyCache;
-import fun.asgc.neutrino.core.util.CollectionUtil;
-import fun.asgc.neutrino.core.util.TypeUtil;
-import lombok.extern.slf4j.Slf4j;
-
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.function.Supplier;
-
-/**
- *
- * @author: aoshiguchen
- * @date: 2022/6/24
- */
-@Slf4j
-public class Invocation {
- private Class> targetClass;
- private Method targetMethod;
- private Object proxy;
- private AopCallback callback;
- private Object[] args;
- private List interceptors;
- private volatile int index = 0;
- private Object returnValue;
-
- public Invocation(Long methodId, Object proxy, AopCallback callback, Object... args) {
- this.targetMethod = ProxyCache.getMethod(methodId);
- this.targetClass = this.targetMethod.getDeclaringClass();
- this.proxy = proxy;
- this.callback = callback;
- this.args = args;
- this.interceptors = InterceptorFactory.getListByTargetMethod(this.targetMethod);
- this.returnValue = TypeUtil.getDefaultValue(this.targetMethod.getReturnType());
- }
-
- public void invoke() throws Exception {
- if (CollectionUtil.notEmpty(this.interceptors) && index < this.interceptors.size()) {
- this.interceptors.get(index++).intercept(this);
- } else {
- returnValue = callback.callback();
- returnValue = TypeUtil.conversion(returnValue, this.targetMethod.getReturnType());
- }
- }
-
- public T getReturnValue() {
- return (T)returnValue;
- }
-
- public Class> getReturnType() {
- return targetMethod.getReturnType();
- }
-
- public void setReturnValue(Object returnValue) {
- this.returnValue = returnValue;
- }
-
- public Class> getTargetClass() {
- return targetClass;
- }
-
- public Method getTargetMethod() {
- return targetMethod;
- }
-
- public Object[] getArgs() {
- return args;
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/ProxyStrategy.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/ProxyStrategy.java
deleted file mode 100644
index 7c0da4f0..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/ProxyStrategy.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop;
-
-/**
- * 代理策略
- * @author: aoshiguchen
- * @date: 2022/6/24
- */
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-@Getter
-@AllArgsConstructor
-@SuppressWarnings("all")
-public enum ProxyStrategy {
- // 在该模式下,代理策略由框架根据一定策略自动选择
- AUTO(0, "自动选择"),
- JDK_DYNAMIC_PROXY(1, "JDK动态代理"),
- ASGC_PROXY(2, "asgc子类代理");
-
- private Integer strategy;
- private String desc;
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/AsgcCompiler.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/AsgcCompiler.java
deleted file mode 100644
index 503f7a55..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/AsgcCompiler.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import com.google.common.collect.Lists;
-import fun.asgc.neutrino.core.aop.compiler.internal.SpringBootJarClassLoader;
-import fun.asgc.neutrino.core.base.GlobalConfig;
-import fun.asgc.neutrino.core.util.CollectionUtil;
-import fun.asgc.neutrino.core.util.FileUtil;
-import fun.asgc.neutrino.core.util.SystemUtil;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.tools.*;
-import java.io.File;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * asgc编译器
- * @author: aoshiguchen
- * @date: 2022/8/17
- */
-@Slf4j
-@SuppressWarnings("all")
-public class AsgcCompiler {
- private final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
- private final DiagnosticCollector collector;
- private final StandardJavaFileManager standardJavaFileManager;
- private final List options = new ArrayList<>();
- private final List defaultClassPathList = new ArrayList<>();
- private final List classpathList = new ArrayList<>();
- private final Collection compilationUnits = new ArrayList();
- private boolean isSaveSourceCodeFile;
- private boolean isSaveClassFile;
- private String generatorCodeSavePath;
- private DynamicClassLoader dynamicClassLoader;
- private SpringBootJarClassLoader springBootJarClassLoader;
-
- private final List> errors = new ArrayList>();
- private final List> warnings = new ArrayList>();
-
- /**
- * 构造编译器
- */
- public AsgcCompiler() {
- this(ClassLoader.getSystemClassLoader());
- }
-
- /**
- * 构造编译器
- * @param classLoader
- */
- public AsgcCompiler(ClassLoader classLoader) {
- if (null == javaCompiler) {
- throw new RuntimeException("Can not load JavaCompiler from javax.tools.ToolProvider#getSystemJavaCompiler(),\n please confirm the application running in JDK not JRE.");
- }
- this.springBootJarClassLoader = new SpringBootJarClassLoader(classLoader);
-// if (SystemUtil.isStartupFromJar() && GlobalConfig.isIsUseSpringBootJar()) {
-// try {
-// log.debug("使用LaunchedURLClassLoader jar路径:{}", SystemUtil.getCurrentJarFilePath());
-// parent = new SpringBootJarClassLoader(classLoader);
-// log.debug("使用LaunchedURLClassLoader instance:{}", parent);
-// } catch (Exception e) {
-// // ignore
-// log.error("使用LaunchedURLClassLoader异常", e);
-// }
-// }
- this.collector = new DiagnosticCollector<>();
- this.standardJavaFileManager = javaCompiler.getStandardFileManager(collector, null, null);
- this.isSaveClassFile = false;
- this.generatorCodeSavePath = GlobalConfig.getGeneratorCodeSavePath();
- this.dynamicClassLoader = new DynamicClassLoader(springBootJarClassLoader, this);
-
- addOption("-Xlint:unchecked");
- addOption("-implicit:class");
- addOption("-source", "1.8");
- addOption("-target", "1.8");
- }
-
- /**
- * 添加类路径
- * @param classpath
- */
- public void addClasspath(String classpath) {
- if (this.classpathList.contains(classpath)) {
- return;
- }
- this.classpathList.add(classpath);
- }
-
- /**
- * 设置是否保存类文件
- * @param saveClassFile
- */
- public void setSaveClassFile(boolean saveClassFile) {
- this.isSaveClassFile = saveClassFile;
- }
-
- /**
- * 设置是否保存源代码文件
- * @param saveSourceCodeFile
- */
- public void setSaveSourceCodeFile(boolean saveSourceCodeFile) {
- isSaveSourceCodeFile = saveSourceCodeFile;
- }
-
- /**
- * 设置保存代码路径
- * @param generatorCodeSavePath
- */
- public void setGeneratorCodeSavePath(String generatorCodeSavePath) {
- this.generatorCodeSavePath = generatorCodeSavePath;
- }
-
- /**
- * 获取options
- * @return
- */
- private List getOptions() {
- List list = Lists.newArrayList(options);
- List cp = getClasspathList();
- if (!CollectionUtil.isEmpty(cp)) {
- list.add("-classpath");
- list.add(cp.stream().collect(Collectors.joining(File.pathSeparator)));
- }
- return list;
- }
-
- /**
- * 添加option
- * @param option
- */
- private void addOption(String option) {
- this.options.add(option);
- }
-
- /**
- * 添加option
- * @param key
- * @param val
- */
- private void addOption(String key, String val) {
- this.options.add(key);
- this.options.add(val);
- }
-
- /**
- * 添加源代码
- * @param className
- * @param source
- */
- private void addSource(String className, String source) {
- addSource(new StringSource(className, source));
- }
-
- /**
- * 添加源代码
- * @param javaFileObject
- */
- private void addSource(JavaFileObject javaFileObject) {
- compilationUnits.add(javaFileObject);
- }
-
- public void addDependSpringBootJar(String path) {
- try {
- this.springBootJarClassLoader.addJar(path);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 编译代码
- * @param className 类名
- * @param sourceCode 源代码
- */
- public Class> compile(String className, String sourceCode) throws ClassNotFoundException {
- log.info("options:" + getOptions());
- int index = className.lastIndexOf(".");
- String pkg = "";
- String simpleClassName = className;
- if (index >= 0) {
- pkg = className.substring(0, index);
- simpleClassName = className.substring(index + 1);
- }
- JavaFileManager javaFileManager = new DynamicJavaFileManager(standardJavaFileManager, dynamicClassLoader);
- Iterable extends JavaFileObject> compilationUnits = Lists.newArrayList(new StringSource(className, sourceCode));
- if (GlobalConfig.isSaveGeneratorCode()) {
- javaFileManager = standardJavaFileManager;
- File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + pkg.replaceAll("\\.", "/"), simpleClassName + ".java", sourceCode);
- compilationUnits = standardJavaFileManager.getJavaFileObjects(file);
- addClasspath(GlobalConfig.getGeneratorCodeSavePath());
- }
-
- Boolean result = javaCompiler.getTask(null, javaFileManager, collector, getOptions(), null, compilationUnits).call();
- if (!result || collector.getDiagnostics().size() > 0) {
- if (!result || collector.getDiagnostics().size() > 0) {
- for (Diagnostic extends JavaFileObject> diagnostic : collector.getDiagnostics()) {
- switch (diagnostic.getKind()) {
- case NOTE:
- case MANDATORY_WARNING:
- case WARNING:
- warnings.add(diagnostic);
- break;
- case OTHER:
- case ERROR:
- default:
- errors.add(diagnostic);
- break;
- }
- }
-
- log();
- }
- }
-
- return dynamicClassLoader.findClass(className);
- }
-
- /**
- * 获取编译诊断信息
- * @param diagnostics
- * @return
- */
- private List diagnosticToString(List> diagnostics) {
-
- List diagnosticMessages = new ArrayList();
-
- for (Diagnostic extends JavaFileObject> diagnostic : diagnostics) {
- diagnosticMessages.add(
- "line: " + diagnostic.getLineNumber() + ", message: " + diagnostic.getMessage(Locale.US));
- }
-
- return diagnosticMessages;
-
- }
-
- /**
- * 获取异常信息
- * @return
- */
- public List getErrors() {
- return diagnosticToString(errors);
- }
-
- /**
- * 获取警告信息
- * @return
- */
- public List getWarnings() {
- return diagnosticToString(warnings);
- }
-
- /**
- * 打印编译日志
- */
- private void log() {
- List warnings = getWarnings();
- List errors = getErrors();
-// if (!CollectionUtil.isEmpty(warnings)) {
-// log.warn(warnings.stream().collect(Collectors.joining()));
-// }
- if (!CollectionUtil.isEmpty(errors)) {
- log.error(errors.stream().collect(Collectors.joining()));
- }
- }
-
- /**
- * 获取URL类路径加载器
- * @return
- */
- private URLClassLoader getURLClassLoader() {
- ClassLoader ret = Thread.currentThread().getContextClassLoader();
- if (null == ret) {
- ret = AsgcCompiler.class.getClassLoader();
- }
- return (ret instanceof URLClassLoader) ? (URLClassLoader)ret : null;
- }
-
- /**
- * 获取类路径列表
- * @return
- */
- public List getClasspathList() {
- List classpathList = new ArrayList<>();
- List defaultClasspathList = getDefaultClasspathList();
- List customClasspathList = this.classpathList;
- if (!CollectionUtil.isEmpty(defaultClasspathList)) {
- classpathList.addAll(defaultClasspathList);
- }
- if (!CollectionUtil.isEmpty(customClasspathList)) {
- classpathList.addAll(customClasspathList);
- }
- return classpathList;
- }
-
- /**
- * 获取默认的类路径列表
- * @return
- */
- private synchronized List getDefaultClasspathList() {
- if (!CollectionUtil.isEmpty(defaultClassPathList)) {
- return defaultClassPathList;
- }
- URLClassLoader classLoader = getURLClassLoader();
- if (null == classLoader) {
- return defaultClassPathList;
- }
-
- boolean isWindows = SystemUtil.isWindows();
- for (URL url : classLoader.getURLs()) {
- String path = url.getFile();
-
- // 如果是 windows 系统,去除前缀字符 '/'
- if (isWindows && path.startsWith("/")) {
- path = path.substring(1);
- }
-
- // 去除后缀字符 '/'
- if (path.length() > 1 && (path.endsWith("/") || path.endsWith(File.separator))) {
- path = path.substring(0, path.length() - 1);
- }
-
- defaultClassPathList.add(path);
- }
-
- return defaultClassPathList;
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/CustomJavaFileObject.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/CustomJavaFileObject.java
deleted file mode 100644
index 5423370f..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/CustomJavaFileObject.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.SpringBootJarParser;
-
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.NestingKind;
-import javax.tools.JavaFileObject;
-import java.io.*;
-import java.net.URI;
-
-/**
- * 自定义java文件对象
- * @author: aoshiguchen
- * @date: 2022/8/25
- */
-public class CustomJavaFileObject implements JavaFileObject {
- private final String binaryName;
- private final URI uri;
- private final String name;
-
- public CustomJavaFileObject(String binaryName, URI uri) {
- this.uri = uri;
- this.binaryName = binaryName;
- name = uri.getPath() == null ? uri.getSchemeSpecificPart() : uri.getPath(); // for FS based URI the path is not null, for JAR URI the scheme specific part is not null
- }
-
- @Override
- public URI toUri() {
- return uri;
- }
-
- @Override
- public InputStream openInputStream() throws IOException {
- InputStream in = SpringBootJarParser.getInputStream(uri);
- if (null != in) {
- return in;
- }
- return uri.toURL().openStream();
- }
-
- @Override
- public OutputStream openOutputStream() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public Reader openReader(boolean ignoreEncodingErrors) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Writer openWriter() throws IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long getLastModified() {
- return 0;
- }
-
- @Override
- public boolean delete() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Kind getKind() {
- return Kind.CLASS;
- }
-
- @Override
- public boolean isNameCompatible(String simpleName, Kind kind) {
- String baseName = simpleName + kind.extension;
- return kind.equals(getKind())
- && (baseName.equals(getName())
- || getName().endsWith("/" + baseName));
- }
-
- @Override
- public NestingKind getNestingKind() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Modifier getAccessLevel() {
- throw new UnsupportedOperationException();
- }
-
- public String binaryName() {
- return binaryName;
- }
-
- @Override
- public String toString() {
- return this.getClass().getName() + "[" + this.toUri() + "]";
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/DynamicClassLoader.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/DynamicClassLoader.java
deleted file mode 100644
index d25ed611..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/DynamicClassLoader.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import fun.asgc.neutrino.core.util.ArrayUtil;
-import fun.asgc.neutrino.core.util.CollectionUtil;
-import fun.asgc.neutrino.core.util.FileUtil;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.net.JarURLConnection;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.*;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-/**
- * 动态类加载器
- * @author: aoshiguchen
- * @date: 2022/8/25
- */
-public class DynamicClassLoader extends ClassLoader {
- private final Map byteCodes = new HashMap<>();
- private AsgcCompiler compiler;
- private Map> classMap = new HashMap<>();
-
- public DynamicClassLoader(ClassLoader classLoader) {
- super(classLoader);
- }
-
- public DynamicClassLoader(ClassLoader classLoader, AsgcCompiler compiler) {
- super(classLoader);
- this.compiler = compiler;
- }
-
- public void registerCompiledSource(MemoryByteCode byteCode) {
- byteCodes.put(byteCode.getClassName(), byteCode);
- }
-
- @Override
- protected Class> findClass(String name) throws ClassNotFoundException {
- if (classMap.containsKey(name)) {
- return classMap.get(name);
- }
- MemoryByteCode byteCode = byteCodes.get(name);
- if (null != byteCode) {
- return super.defineClass(name, byteCode.getByteCode(), 0, byteCode.getByteCode().length);
- }
- if (null != this.compiler) {
- Class> ret = doFindClass(name, compiler.getClasspathList());
- if (null != ret) {
- return ret;
- }
- }
- return super.findClass(name);
- }
-
- private Class> doFindClass(String name, List classpathList) throws ClassNotFoundException {
- if (CollectionUtil.isEmpty(classpathList)) {
- return null;
- }
- String packageName = "";
- if (name.lastIndexOf(".") != -1) {
- packageName = name.substring(0, name.lastIndexOf("."));
- }
- for (String path : classpathList) {
- try {
- URL url = new URL("file:" + path);
- if (path.endsWith(".jar")) {
- url = new URL("jar:file:" + path + "!/");
- }
- Set> classSet = scan(packageName, url);
- if (CollectionUtil.isEmpty(classSet)) {
- continue;
- }
- Optional> classOptional = classSet.stream().filter(c -> c.getName().equals(name)).findFirst();
- if (classOptional.isPresent()) {
- return classOptional.get();
- }
- } catch (Exception e) {
- // ignore
- }
- }
- return null;
- }
-
- public Set> scan(String packageName, URL url) throws IOException, ClassNotFoundException, URISyntaxException {
- Set> result = new HashSet<>();
- if (null == url) {
- return result;
- }
- String packagePath = packageName.replace(".", "/");
- URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
- String protocol = url.getProtocol();
- if ("jar".equals(protocol)) {
- JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
- JarFile jarFile = jarURLConnection.getJarFile();
- Enumeration entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- JarEntry jarEntry = entries.nextElement();
- String name = jarEntry.getName();
- int index = name.indexOf(packagePath);
- if (index != -1 && name.endsWith(".class")) {
- String replace = name.substring(index, name.length() - 6).replace("/", ".");
- Class clazz = urlClassLoader.loadClass(replace);
- result.add(clazz);
- }
- }
- } else if ("file".endsWith(protocol)) {
- String path = url.getPath();
- String targetPath = path + "/" + packagePath;
- addClasses(targetPath, result, packageName);
- }
- return result;
- }
-
- private synchronized void addClasses(String path, Set> classes, String packageName) throws ClassNotFoundException, URISyntaxException {
- File[] files = new File(path).listFiles(new FileFilter() {
- @Override
- public boolean accept(File file) {
- return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
- }
- });
- if (ArrayUtil.isEmpty(files)) {
- return;
- }
-
- for (File file : files) {
- String fileName = file.getName();
- if (file.isFile()) {
- String className = fileName.substring(0, fileName.lastIndexOf("."));
- String fullClassName = packageName + "." + className;
- Class clazz = null;
- try {
- clazz = Thread.currentThread().getContextClassLoader().loadClass(fullClassName);
- } catch (ClassNotFoundException e) {
- if (this.classMap.containsKey(fullClassName)) {
- clazz = this.classMap.get(fileName);
- } else {
- byte[] byteCode = FileUtil.readBytes(file);
- clazz = super.defineClass(fullClassName, byteCode, 0, byteCode.length);
- this.classMap.put(fullClassName, clazz);
- }
- }
- if (null != clazz) {
- classes.add(clazz);
- }
- } else {
- String subPackagePath = path + "/" + fileName;
- String subPackageName = packageName + "." + fileName;
- addClasses(subPackagePath, classes, subPackageName);
- }
- }
- }
-
- public Map> getClasses() throws ClassNotFoundException {
- Map> classes = new HashMap<>();
- for (MemoryByteCode byteCode : byteCodes.values()) {
- classes.put(byteCode.getClassName(), findClass(byteCode.getClassName()));
- }
- return classes;
- }
-
- public Map getByteCodes() {
- Map result = new HashMap<>(byteCodes.size());
- for (Map.Entry entry : byteCodes.entrySet()) {
- result.put(entry.getKey(), entry.getValue().getByteCode());
- }
- return result;
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/DynamicJavaFileManager.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/DynamicJavaFileManager.java
deleted file mode 100644
index a42b66e1..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/DynamicJavaFileManager.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import javax.tools.*;
-import java.io.IOException;
-import java.util.*;
-
-/**
- * 动态java文件管理器
- * @author: aoshiguchen
- * @date: 2022/8/17
- */
-public class DynamicJavaFileManager extends ForwardingJavaFileManager {
- private static final String[] superLocationNames = { StandardLocation.PLATFORM_CLASS_PATH.name(),
- /** JPMS StandardLocation.SYSTEM_MODULES **/
- "SYSTEM_MODULES" };
- private final PackageInternalsFinder finder;
- private final DynamicClassLoader classLoader;
- private final List byteCodes = new ArrayList();
-
- public DynamicJavaFileManager(JavaFileManager fileManager, DynamicClassLoader classLoader) {
- super(fileManager);
- this.classLoader = classLoader;
- this.finder = new PackageInternalsFinder(classLoader);
- }
-
- @Override
- public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className,
- JavaFileObject.Kind kind, FileObject sibling) throws IOException {
-
- for (MemoryByteCode byteCode : byteCodes) {
- if (byteCode.getClassName().equals(className)) {
- return byteCode;
- }
- }
-
- MemoryByteCode innerClass = new MemoryByteCode(className);
- byteCodes.add(innerClass);
- classLoader.registerCompiledSource(innerClass);
- return innerClass;
-
- }
- @Override
- public ClassLoader getClassLoader(JavaFileManager.Location location) {
- return classLoader;
- }
-
- @Override
- public String inferBinaryName(Location location, JavaFileObject file) {
- if (file instanceof CustomJavaFileObject) {
- return ((CustomJavaFileObject) file).binaryName();
- } else {
- /**
- * if it's not CustomJavaFileObject, then it's coming from standard file manager
- * - let it handle the file
- */
- return super.inferBinaryName(location, file);
- }
- }
-
- @Override
- public Iterable list(Location location, String packageName, Set kinds,
- boolean recurse) throws IOException {
- if (location instanceof StandardLocation) {
- String locationName = ((StandardLocation) location).name();
- for (String name : superLocationNames) {
- if (name.equals(locationName)) {
- return super.list(location, packageName, kinds, recurse);
- }
- }
- }
-
- // merge JavaFileObjects from specified ClassLoader
- if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {
- return new IterableJoin<>(super.list(location, packageName, kinds, recurse),
- finder.find(packageName));
- }
-
- return super.list(location, packageName, kinds, recurse);
- }
-
- static class IterableJoin implements Iterable {
- private final Iterable first, next;
-
- public IterableJoin(Iterable first, Iterable next) {
- this.first = first;
- this.next = next;
- }
-
- @Override
- public Iterator iterator() {
- return new IteratorJoin(first.iterator(), next.iterator());
- }
- }
-
- static class IteratorJoin implements Iterator {
- private final Iterator first, next;
-
- public IteratorJoin(Iterator first, Iterator next) {
- this.first = first;
- this.next = next;
- }
-
- @Override
- public boolean hasNext() {
- return first.hasNext() || next.hasNext();
- }
-
- @Override
- public T next() {
- if (first.hasNext()) {
- return first.next();
- }
- return next.next();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/MemoryByteCode.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/MemoryByteCode.java
deleted file mode 100644
index 16f3b363..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/MemoryByteCode.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import javax.tools.SimpleJavaFileObject;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-/**
- * 内存字节码
- * @author: aoshiguchen
- * @date: 2022/8/25
- */
-public class MemoryByteCode extends SimpleJavaFileObject {
- private static final char PKG_SEPARATOR = '.';
- private static final char DIR_SEPARATOR = '/';
- private static final String CLASS_FILE_SUFFIX = ".class";
-
- private ByteArrayOutputStream byteArrayOutputStream;
- private byte[] byteCode;
-
- public MemoryByteCode(String className) {
- super(URI.create("byte:///" + className.replace(PKG_SEPARATOR, DIR_SEPARATOR)
- + Kind.CLASS.extension), Kind.CLASS);
- }
-
- public MemoryByteCode(String className, ByteArrayOutputStream byteArrayOutputStream)
- throws URISyntaxException {
- this(className);
- this.byteArrayOutputStream = byteArrayOutputStream;
- }
-
- public MemoryByteCode(String className, byte[] byteCode)
- throws URISyntaxException {
- this(className);
- this.byteCode = byteCode;
- }
-
- @Override
- public OutputStream openOutputStream() throws IOException {
- if (byteArrayOutputStream == null) {
- byteArrayOutputStream = new ByteArrayOutputStream();
- }
- return byteArrayOutputStream;
- }
-
- public byte[] getByteCode() {
- return null == byteCode ? byteArrayOutputStream.toByteArray() : byteCode;
- }
-
- public String getClassName() {
- String className = getName();
- className = className.replace(DIR_SEPARATOR, PKG_SEPARATOR);
- className = className.substring(1, className.indexOf(CLASS_FILE_SUFFIX));
- return className;
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/PackageInternalsFinder.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/PackageInternalsFinder.java
deleted file mode 100644
index 24c65628..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/PackageInternalsFinder.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import javax.tools.JavaFileObject;
-import java.io.File;
-import java.io.IOException;
-import java.net.JarURLConnection;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.jar.JarEntry;
-
-/**
- * 包内部查询器
- * @author: aoshiguchen
- * @date: 2022/8/25
- */
-public class PackageInternalsFinder {
- private final ClassLoader classLoader;
- private static final String CLASS_FILE_EXTENSION = ".class";
-
- public PackageInternalsFinder(ClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
- public List find(String packageName) throws IOException {
- String javaPackageName = packageName.replaceAll("\\.", "/");
-
- List result = new ArrayList<>();
-
- Enumeration urlEnumeration = classLoader.getResources(javaPackageName);
- while (urlEnumeration.hasMoreElements()) { // one URL for each jar on the classpath that has the given package
- URL packageFolderURL = urlEnumeration.nextElement();
- result.addAll(listUnder(packageName, packageFolderURL));
- }
-
- return result;
- }
-
- private Collection listUnder(String packageName, URL packageFolderURL) {
- File directory = new File(decode(packageFolderURL.getFile()));
- if (directory.isDirectory()) { // browse local .class files - useful for local execution
- return processDir(packageName, directory);
- } else { // browse a jar file
- return processJar(packageFolderURL);
- } // maybe there can be something else for more involved class loaders
- }
-
- private List processJar(URL packageFolderURL) {
- List result = new ArrayList();
- try {
- String jarUri = packageFolderURL.toExternalForm().substring(0, packageFolderURL.toExternalForm().lastIndexOf("!/"));
-
- JarURLConnection jarConn = (JarURLConnection) packageFolderURL.openConnection();
- String rootEntryName = jarConn.getEntryName();
- int rootEnd = rootEntryName.length() + 1;
-
- Enumeration entryEnum = jarConn.getJarFile().entries();
- while (entryEnum.hasMoreElements()) {
- JarEntry jarEntry = entryEnum.nextElement();
- String name = jarEntry.getName();
- if (name.startsWith(rootEntryName) && name.indexOf('/', rootEnd) == -1 && name.endsWith(CLASS_FILE_EXTENSION)) {
- URI uri = URI.create(jarUri + "!/" + name);
- String binaryName = name.replaceAll("/", ".");
- binaryName = binaryName.replaceAll(CLASS_FILE_EXTENSION + "$", "");
-
- result.add(new CustomJavaFileObject(binaryName, uri));
- }
- }
- } catch (Exception e) {
- throw new RuntimeException("Wasn't able to open " + packageFolderURL + " as a jar file", e);
- }
- return result;
- }
-
- private List processDir(String packageName, File directory) {
- List result = new ArrayList();
-
- File[] childFiles = directory.listFiles();
- if (childFiles != null) {
- for (File childFile : childFiles) {
- if (childFile.isFile()) {
- // We only want the .class files.
- if (childFile.getName().endsWith(CLASS_FILE_EXTENSION)) {
- String binaryName = packageName + "." + childFile.getName();
- binaryName = binaryName.replaceAll(CLASS_FILE_EXTENSION + "$", "");
-
- result.add(new CustomJavaFileObject(binaryName, childFile.toURI()));
- }
- }
- }
- }
-
- return result;
- }
-
- private String decode(String filePath) {
- try {
- return URLDecoder.decode(filePath, "utf-8");
- } catch (Exception e) {
- // ignore, return original string
- }
-
- return filePath;
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/StringSource.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/StringSource.java
deleted file mode 100644
index a6f3ad18..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/StringSource.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Copyright (c) 2022 aoshiguchen
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package fun.asgc.neutrino.core.aop.compiler;
-
-import javax.tools.SimpleJavaFileObject;
-import java.io.IOException;
-import java.net.URI;
-
-/**
- * 字符串源码
- * @author: aoshiguchen
- * @date: 2022/8/25
- */
-public class StringSource extends SimpleJavaFileObject {
- private final String contents;
-
- public StringSource(String className, String contents) {
- super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
- this.contents = contents;
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
- return contents;
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/SpringBootJarClassLoader.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/SpringBootJarClassLoader.java
deleted file mode 100644
index b4ab6421..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/SpringBootJarClassLoader.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal;
-
-
-import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
-import fun.asgc.neutrino.core.aop.compiler.internal.archive.JarFileArchive;
-
-import java.io.File;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * {@link ClassLoader} used by the {@link Launcher}.
- *
- * @author Phillip Webb
- * @author Dave Syer
- * @author Andy Wilkinson
- * @since 1.0.0
- */
-public class SpringBootJarClassLoader extends URLClassLoader {
- protected static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = "Spring-Boot-Classpath-Index";
- protected static final String DEFAULT_CLASSPATH_INDEX_FILE_NAME = "classpath.idx";
-
- static {
- ClassLoader.registerAsParallelCapable();
- }
-
- /**
- * Create a new {@link SpringBootJarClassLoader} instance.
- * @param parent the parent class loader for delegation
- */
- public SpringBootJarClassLoader(ClassLoader parent) {
- super(new URL[0], parent);
- }
-
- /**
- * Create a new {@link SpringBootJarClassLoader} instance.
- */
- public SpringBootJarClassLoader() {
- super(new URL[0], ClassLoader.getSystemClassLoader());
- }
-
- public void addJar(String path) throws Exception {
- Archive archive = createArchive(path);
- Iterator archives = getClassPathArchivesIterator(archive);
- List urls = new ArrayList<>(50);
- while (archives.hasNext()) {
- urls.add(archives.next().getUrl());
- }
- urls.forEach(url -> addURL(url));
- }
-
- private Archive createArchive(String path) throws Exception {
- if (path == null) {
- throw new IllegalStateException("Unable to determine code source archive");
- }
- File root = new File(path);
- if (!root.exists()) {
- throw new IllegalStateException("Unable to determine code source archive from " + root);
- }
- return new JarFileArchive(root);
- }
-
- protected Iterator getClassPathArchivesIterator(Archive archive) throws Exception {
- Archive.EntryFilter searchFilter = this::isSearchCandidate;
- Iterator archives = archive.getNestedArchives(searchFilter,
- (entry) -> isNestedArchive(entry));
- archives = applyClassPathArchivePostProcessing(archives);
- return archives;
- }
-
- private Iterator applyClassPathArchivePostProcessing(Iterator archives) throws Exception {
- List list = new ArrayList<>();
- while (archives.hasNext()) {
- list.add(archives.next());
- }
- return list.iterator();
- }
-
- static final Archive.EntryFilter NESTED_ARCHIVE_ENTRY_FILTER = (entry) -> {
- if (entry.isDirectory()) {
- return entry.getName().equals("BOOT-INF/classes/");
- }
- return entry.getName().startsWith("BOOT-INF/lib/");
- };
-
- protected boolean isNestedArchive(Archive.Entry entry) {
- return NESTED_ARCHIVE_ENTRY_FILTER.matches(entry);
- }
-
- /**
- * Determine if the specified entry is a candidate for further searching.
- * @param entry the entry to check
- * @return {@code true} if the entry is a candidate for further searching
- * @since 2.3.0
- */
- protected boolean isSearchCandidate(Archive.Entry entry) {
- if (getArchiveEntryPathPrefix() == null) {
- return true;
- }
- return entry.getName().startsWith(getArchiveEntryPathPrefix());
- }
-
- protected String getArchiveEntryPathPrefix() {
- return "BOOT-INF/";
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/SpringBootJarParser.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/SpringBootJarParser.java
deleted file mode 100644
index 6f0a380a..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/SpringBootJarParser.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.jar.JarFile;
-import fun.asgc.neutrino.core.aop.compiler.internal.jar.JarURLConnection;
-
-import java.io.File;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URL;
-
-/**
- * @author: aoshiguchen
- * @date: 2023/2/23
- */
-public final class SpringBootJarParser {
-
- /**
- * 根据一个URI从SpringBoot jar包中解析出输入流
- * 1、先尝试直接获取流,若能获取则到此结束
- * 2、若不能获取,且URI标识定位的是一个jar包,则进行处理(只处理SpringBoot情况的jar)
- * @param uri
- * @return
- */
- public static InputStream getInputStream(URI uri) {
- try {
- return uri.toURL().openStream();
- } catch (Exception e) {
- try {
- if (uri.getScheme().equals("jar")) {
- URL url = uri.toURL();
- String path = url.getPath();
- int index = path.indexOf("!");
- if (index >= 0) {
- path = path.substring(0, index);
- }
- if (path.startsWith("file:")) {
- path = path.substring(5);
- }
- JarFile jarFile = new JarFile(new File(path));
- return JarURLConnection.get(url, jarFile).getInputStream();
- }
- } catch (Exception e1) {
- // ignore
- }
- }
- return null;
- }
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/Archive.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/Archive.java
deleted file mode 100644
index 9be22c70..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/Archive.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.archive;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Iterator;
-import java.util.jar.Manifest;
-
-/**
- * An archive that can be launched by the {@link Launcher}.
- *
- * @author Phillip Webb
- * @since 1.0.0
- * @see JarFileArchive
- */
-public interface Archive extends Iterable, AutoCloseable {
-
- /**
- * Returns a URL that can be used to load the archive.
- * @return the archive URL
- * @throws MalformedURLException if the URL is malformed
- */
- URL getUrl() throws MalformedURLException;
-
- /**
- * Returns the manifest of the archive.
- * @return the manifest
- * @throws IOException if the manifest cannot be read
- */
- Manifest getManifest() throws IOException;
-
- /**
- * Returns nested {@link Archive}s for entries that match the specified filters.
- * @param searchFilter filter used to limit when additional sub-entry searching is
- * required or {@code null} if all entries should be considered.
- * @param includeFilter filter used to determine which entries should be included in
- * the result or {@code null} if all entries should be included
- * @return the nested archives
- * @throws IOException on IO error
- * @since 2.3.0
- */
- Iterator getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter) throws IOException;
-
- /**
- * Return if the archive is exploded (already unpacked).
- * @return if the archive is exploded
- * @since 2.3.0
- */
- default boolean isExploded() {
- return false;
- }
-
- /**
- * Closes the {@code Archive}, releasing any open resources.
- * @throws Exception if an error occurs during close processing
- * @since 2.2.0
- */
- @Override
- default void close() throws Exception {
-
- }
-
- /**
- * Represents a single entry in the archive.
- */
- interface Entry {
-
- /**
- * Returns {@code true} if the entry represents a directory.
- * @return if the entry is a directory
- */
- boolean isDirectory();
-
- /**
- * Returns the name of the entry.
- * @return the name of the entry
- */
- String getName();
-
- }
-
- /**
- * Strategy interface to filter {@link Entry Entries}.
- */
- @FunctionalInterface
- interface EntryFilter {
-
- /**
- * Apply the jar entry filter.
- * @param entry the entry to filter
- * @return {@code true} if the filter matches
- */
- boolean matches(Entry entry);
-
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/ExplodedArchive.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/ExplodedArchive.java
deleted file mode 100644
index 3377a110..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/ExplodedArchive.java
+++ /dev/null
@@ -1,318 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.archive;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.util.*;
-import java.util.jar.Manifest;
-
-/**
- * {@link Archive} implementation backed by an exploded archive directory.
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @author Madhura Bhave
- * @since 1.0.0
- */
-public class ExplodedArchive implements Archive {
-
- private static final Set SKIPPED_NAMES = new HashSet<>(Arrays.asList(".", ".."));
-
- private final File root;
-
- private final boolean recursive;
-
- private final File manifestFile;
-
- private Manifest manifest;
-
- /**
- * Create a new {@link ExplodedArchive} instance.
- * @param root the root directory
- */
- public ExplodedArchive(File root) {
- this(root, true);
- }
-
- /**
- * Create a new {@link ExplodedArchive} instance.
- * @param root the root directory
- * @param recursive if recursive searching should be used to locate the manifest.
- * Defaults to {@code true}, directories with a large tree might want to set this to
- * {@code false}.
- */
- public ExplodedArchive(File root, boolean recursive) {
- if (!root.exists() || !root.isDirectory()) {
- throw new IllegalArgumentException("Invalid source directory " + root);
- }
- this.root = root;
- this.recursive = recursive;
- this.manifestFile = getManifestFile(root);
- }
-
- private File getManifestFile(File root) {
- File metaInf = new File(root, "META-INF");
- return new File(metaInf, "MANIFEST.MF");
- }
-
- @Override
- public URL getUrl() throws MalformedURLException {
- return this.root.toURI().toURL();
- }
-
- @Override
- public Manifest getManifest() throws IOException {
- if (this.manifest == null && this.manifestFile.exists()) {
- try (FileInputStream inputStream = new FileInputStream(this.manifestFile)) {
- this.manifest = new Manifest(inputStream);
- }
- }
- return this.manifest;
- }
-
- @Override
- public Iterator getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter) throws IOException {
- return new ArchiveIterator(this.root, this.recursive, searchFilter, includeFilter);
- }
-
- @Override
-// @Deprecated(since = "2.3.10", forRemoval = false)
- public Iterator iterator() {
- return new EntryIterator(this.root, this.recursive, null, null);
- }
-
- protected Archive getNestedArchive(Entry entry) {
- File file = ((FileEntry) entry).getFile();
- return (file.isDirectory() ? new ExplodedArchive(file) : new SimpleJarFileArchive((FileEntry) entry));
- }
-
- @Override
- public boolean isExploded() {
- return true;
- }
-
- @Override
- public String toString() {
- try {
- return getUrl().toString();
- }
- catch (Exception ex) {
- return "exploded archive";
- }
- }
-
- /**
- * File based {@link Entry} {@link Iterator}.
- */
- private abstract static class AbstractIterator implements Iterator {
-
- private static final Comparator entryComparator = Comparator.comparing(File::getAbsolutePath);
-
- private final File root;
-
- private final boolean recursive;
-
- private final EntryFilter searchFilter;
-
- private final EntryFilter includeFilter;
-
- private final Deque> stack = new LinkedList<>();
-
- private FileEntry current;
-
- private final String rootUrl;
-
- AbstractIterator(File root, boolean recursive, EntryFilter searchFilter, EntryFilter includeFilter) {
- this.root = root;
- this.rootUrl = this.root.toURI().getPath();
- this.recursive = recursive;
- this.searchFilter = searchFilter;
- this.includeFilter = includeFilter;
- this.stack.add(listFiles(root));
- this.current = poll();
- }
-
- @Override
- public boolean hasNext() {
- return this.current != null;
- }
-
- @Override
- public T next() {
- FileEntry entry = this.current;
- if (entry == null) {
- throw new NoSuchElementException();
- }
- this.current = poll();
- return adapt(entry);
- }
-
- private FileEntry poll() {
- while (!this.stack.isEmpty()) {
- while (this.stack.peek().hasNext()) {
- File file = this.stack.peek().next();
- if (SKIPPED_NAMES.contains(file.getName())) {
- continue;
- }
- FileEntry entry = getFileEntry(file);
- if (isListable(entry)) {
- this.stack.addFirst(listFiles(file));
- }
- if (this.includeFilter == null || this.includeFilter.matches(entry)) {
- return entry;
- }
- }
- this.stack.poll();
- }
- return null;
- }
-
- private FileEntry getFileEntry(File file) {
- URI uri = file.toURI();
- String name = uri.getPath().substring(this.rootUrl.length());
- try {
- return new FileEntry(name, file, uri.toURL());
- }
- catch (MalformedURLException ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- private boolean isListable(FileEntry entry) {
- return entry.isDirectory() && (this.recursive || entry.getFile().getParentFile().equals(this.root))
- && (this.searchFilter == null || this.searchFilter.matches(entry))
- && (this.includeFilter == null || !this.includeFilter.matches(entry));
- }
-
- private Iterator listFiles(File file) {
- File[] files = file.listFiles();
- if (files == null) {
- return Collections.emptyIterator();
- }
- Arrays.sort(files, entryComparator);
- return Arrays.asList(files).iterator();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
-
- protected abstract T adapt(FileEntry entry);
-
- }
-
- private static class EntryIterator extends AbstractIterator {
-
- EntryIterator(File root, boolean recursive, EntryFilter searchFilter, EntryFilter includeFilter) {
- super(root, recursive, searchFilter, includeFilter);
- }
-
- @Override
- protected Entry adapt(FileEntry entry) {
- return entry;
- }
-
- }
-
- private static class ArchiveIterator extends AbstractIterator {
-
- ArchiveIterator(File root, boolean recursive, EntryFilter searchFilter, EntryFilter includeFilter) {
- super(root, recursive, searchFilter, includeFilter);
- }
-
- @Override
- protected Archive adapt(FileEntry entry) {
- File file = entry.getFile();
- return (file.isDirectory() ? new ExplodedArchive(file) : new SimpleJarFileArchive(entry));
- }
-
- }
-
- /**
- * {@link Entry} backed by a File.
- */
- private static class FileEntry implements Entry {
-
- private final String name;
-
- private final File file;
-
- private final URL url;
-
- FileEntry(String name, File file, URL url) {
- this.name = name;
- this.file = file;
- this.url = url;
- }
-
- File getFile() {
- return this.file;
- }
-
- @Override
- public boolean isDirectory() {
- return this.file.isDirectory();
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- URL getUrl() {
- return this.url;
- }
-
- }
-
- /**
- * {@link Archive} implementation backed by a simple JAR file that doesn't itself
- * contain nested archives.
- */
- private static class SimpleJarFileArchive implements Archive {
-
- private final URL url;
-
- SimpleJarFileArchive(FileEntry file) {
- this.url = file.getUrl();
- }
-
- @Override
- public URL getUrl() throws MalformedURLException {
- return this.url;
- }
-
- @Override
- public Manifest getManifest() throws IOException {
- return null;
- }
-
- @Override
- public Iterator getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter)
- throws IOException {
- return Collections.emptyIterator();
- }
-
- @Override
-// @Deprecated(since = "2.3.10", forRemoval = false)
- public Iterator iterator() {
- return Collections.emptyIterator();
- }
-
- @Override
- public String toString() {
- try {
- return getUrl().toString();
- }
- catch (Exception ex) {
- return "jar archive";
- }
- }
-
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/JarFileArchive.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/JarFileArchive.java
deleted file mode 100755
index 327642dd..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/JarFileArchive.java
+++ /dev/null
@@ -1,290 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.archive;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.jar.JarFile;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.*;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.UUID;
-import java.util.jar.JarEntry;
-import java.util.jar.Manifest;
-
-/**
- * {@link Archive} implementation backed by a {@link JarFile}.
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @since 1.0.0
- */
-public class JarFileArchive implements Archive {
-
- private static final String UNPACK_MARKER = "UNPACK:";
-
- private static final int BUFFER_SIZE = 32 * 1024;
-
- private static final FileAttribute>[] NO_FILE_ATTRIBUTES = {};
-
- private static final EnumSet DIRECTORY_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
- PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
-
- private static final EnumSet FILE_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
- PosixFilePermission.OWNER_WRITE);
-
- private final JarFile jarFile;
-
- private URL url;
-
- private Path tempUnpackDirectory;
-
- public JarFileArchive(File file) throws IOException {
- this(file, file.toURI().toURL());
- }
-
- public JarFileArchive(File file, URL url) throws IOException {
- this(new JarFile(file));
- this.url = url;
- }
-
- public JarFileArchive(JarFile jarFile) {
- this.jarFile = jarFile;
- }
-
- @Override
- public URL getUrl() throws MalformedURLException {
- if (this.url != null) {
- return this.url;
- }
- return this.jarFile.getUrl();
- }
-
- @Override
- public Manifest getManifest() throws IOException {
- return this.jarFile.getManifest();
- }
-
- @Override
- public Iterator getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter) throws IOException {
- return new NestedArchiveIterator(this.jarFile.iterator(), searchFilter, includeFilter);
- }
-
- @Override
-// @Deprecated(since = "2.3.10", forRemoval = false)
- public Iterator iterator() {
- return new EntryIterator(this.jarFile.iterator(), null, null);
- }
-
- @Override
- public void close() throws IOException {
- this.jarFile.close();
- }
-
- protected Archive getNestedArchive(Entry entry) throws IOException {
- JarEntry jarEntry = ((JarFileEntry) entry).getJarEntry();
- if (jarEntry.getComment().startsWith(UNPACK_MARKER)) {
- return getUnpackedNestedArchive(jarEntry);
- }
- try {
- JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
- return new JarFileArchive(jarFile);
- }
- catch (Exception ex) {
- throw new IllegalStateException("Failed to get nested archive for entry " + entry.getName(), ex);
- }
- }
-
- private Archive getUnpackedNestedArchive(JarEntry jarEntry) throws IOException {
- String name = jarEntry.getName();
- if (name.lastIndexOf('/') != -1) {
- name = name.substring(name.lastIndexOf('/') + 1);
- }
- Path path = getTempUnpackDirectory().resolve(name);
- if (!Files.exists(path) || Files.size(path) != jarEntry.getSize()) {
- unpack(jarEntry, path);
- }
- return new JarFileArchive(path.toFile(), path.toUri().toURL());
- }
-
- private Path getTempUnpackDirectory() {
- if (this.tempUnpackDirectory == null) {
- Path tempDirectory = Paths.get(System.getProperty("java.io.tmpdir"));
- this.tempUnpackDirectory = createUnpackDirectory(tempDirectory);
- }
- return this.tempUnpackDirectory;
- }
-
- private Path createUnpackDirectory(Path parent) {
- int attempts = 0;
- while (attempts++ < 1000) {
- String fileName = Paths.get(this.jarFile.getName()).getFileName().toString();
- Path unpackDirectory = parent.resolve(fileName + "-spring-boot-libs-" + UUID.randomUUID());
- try {
- createDirectory(unpackDirectory);
- return unpackDirectory;
- }
- catch (IOException ex) {
- }
- }
- throw new IllegalStateException("Failed to create unpack directory in directory '" + parent + "'");
- }
-
- private void unpack(JarEntry entry, Path path) throws IOException {
- createFile(path);
- path.toFile().deleteOnExit();
- try (InputStream inputStream = this.jarFile.getInputStream(entry);
- OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.WRITE,
- StandardOpenOption.TRUNCATE_EXISTING)) {
- byte[] buffer = new byte[BUFFER_SIZE];
- int bytesRead;
- while ((bytesRead = inputStream.read(buffer)) != -1) {
- outputStream.write(buffer, 0, bytesRead);
- }
- outputStream.flush();
- }
- }
-
- private void createDirectory(Path path) throws IOException {
- Files.createDirectory(path, getFileAttributes(path.getFileSystem(), DIRECTORY_PERMISSIONS));
- }
-
- private void createFile(Path path) throws IOException {
- Files.createFile(path, getFileAttributes(path.getFileSystem(), FILE_PERMISSIONS));
- }
-
- private FileAttribute>[] getFileAttributes(FileSystem fileSystem, EnumSet ownerReadWrite) {
- if (!fileSystem.supportedFileAttributeViews().contains("posix")) {
- return NO_FILE_ATTRIBUTES;
- }
- return new FileAttribute>[] { PosixFilePermissions.asFileAttribute(ownerReadWrite) };
- }
-
- @Override
- public String toString() {
- try {
- return getUrl().toString();
- }
- catch (Exception ex) {
- return "jar archive";
- }
- }
-
- /**
- * Abstract base class for iterator implementations.
- */
- private abstract static class AbstractIterator implements Iterator {
-
- private final Iterator iterator;
-
- private final EntryFilter searchFilter;
-
- private final EntryFilter includeFilter;
-
- private Entry current;
-
- AbstractIterator(Iterator iterator, EntryFilter searchFilter, EntryFilter includeFilter) {
- this.iterator = iterator;
- this.searchFilter = searchFilter;
- this.includeFilter = includeFilter;
- this.current = poll();
- }
-
- @Override
- public boolean hasNext() {
- return this.current != null;
- }
-
- @Override
- public T next() {
- T result = adapt(this.current);
- this.current = poll();
- return result;
- }
-
- private Entry poll() {
- while (this.iterator.hasNext()) {
- JarFileEntry candidate = new JarFileEntry(this.iterator.next());
- if ((this.searchFilter == null || this.searchFilter.matches(candidate))
- && (this.includeFilter == null || this.includeFilter.matches(candidate))) {
- return candidate;
- }
- }
- return null;
- }
-
- protected abstract T adapt(Entry entry);
-
- }
-
- /**
- * {@link Entry} iterator implementation backed by {@link JarEntry}.
- */
- private static class EntryIterator extends AbstractIterator {
-
- EntryIterator(Iterator iterator, EntryFilter searchFilter, EntryFilter includeFilter) {
- super(iterator, searchFilter, includeFilter);
- }
-
- @Override
- protected Entry adapt(Entry entry) {
- return entry;
- }
-
- }
-
- /**
- * Nested {@link Archive} iterator implementation backed by {@link JarEntry}.
- */
- private class NestedArchiveIterator extends AbstractIterator {
-
- NestedArchiveIterator(Iterator iterator, EntryFilter searchFilter, EntryFilter includeFilter) {
- super(iterator, searchFilter, includeFilter);
- }
-
- @Override
- protected Archive adapt(Entry entry) {
- try {
- return getNestedArchive(entry);
- }
- catch (IOException ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- }
-
- /**
- * {@link Entry} implementation backed by a {@link JarEntry}.
- */
- private static class JarFileEntry implements Entry {
-
- private final JarEntry jarEntry;
-
- JarFileEntry(JarEntry jarEntry) {
- this.jarEntry = jarEntry;
- }
-
- JarEntry getJarEntry() {
- return this.jarEntry;
- }
-
- @Override
- public boolean isDirectory() {
- return this.jarEntry.isDirectory();
- }
-
- @Override
- public String getName() {
- return this.jarEntry.getName();
- }
-
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/data/RandomAccessData.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/data/RandomAccessData.java
deleted file mode 100644
index b55aef44..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/data/RandomAccessData.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.data;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Interface that provides read-only random access to some underlying data.
- * Implementations must allow concurrent reads in a thread-safe manner.
- *
- * @author Phillip Webb
- * @since 1.0.0
- */
-public interface RandomAccessData {
-
- /**
- * Returns an {@link InputStream} that can be used to read the underlying data. The
- * caller is responsible close the underlying stream.
- * @return a new input stream that can be used to read the underlying data.
- * @throws IOException if the stream cannot be opened
- */
- InputStream getInputStream() throws IOException;
-
- /**
- * Returns a new {@link RandomAccessData} for a specific subsection of this data.
- * @param offset the offset of the subsection
- * @param length the length of the subsection
- * @return the subsection data
- */
- RandomAccessData getSubsection(long offset, long length);
-
- /**
- * Reads all the data and returns it as a byte array.
- * @return the data
- * @throws IOException if the data cannot be read
- */
- byte[] read() throws IOException;
-
- /**
- * Reads the {@code length} bytes of data starting at the given {@code offset}.
- * @param offset the offset from which data should be read
- * @param length the number of bytes to be read
- * @return the data
- * @throws IOException if the data cannot be read
- * @throws IndexOutOfBoundsException if offset is beyond the end of the file or
- * subsection
- * @throws EOFException if offset plus length is greater than the length of the file
- * or subsection
- */
- byte[] read(long offset, long length) throws IOException;
-
- /**
- * Returns the size of the data.
- * @return the size
- */
- long getSize();
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/data/RandomAccessDataFile.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/data/RandomAccessDataFile.java
deleted file mode 100644
index a77ce34d..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/data/RandomAccessDataFile.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.data;
-
-import java.io.*;
-
-/**
- * {@link RandomAccessData} implementation backed by a {@link RandomAccessFile}.
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @since 1.0.0
- */
-public class RandomAccessDataFile implements RandomAccessData {
-
- private final FileAccess fileAccess;
-
- private final long offset;
-
- private final long length;
-
- /**
- * Create a new {@link RandomAccessDataFile} backed by the specified file.
- * @param file the underlying file
- * @throws IllegalArgumentException if the file is null or does not exist
- */
- public RandomAccessDataFile(File file) {
- if (file == null) {
- throw new IllegalArgumentException("File must not be null");
- }
- this.fileAccess = new FileAccess(file);
- this.offset = 0L;
- this.length = file.length();
- }
-
- /**
- * Private constructor used to create a {@link #getSubsection(long, long) subsection}.
- * @param fileAccess provides access to the underlying file
- * @param offset the offset of the section
- * @param length the length of the section
- */
- private RandomAccessDataFile(FileAccess fileAccess, long offset, long length) {
- this.fileAccess = fileAccess;
- this.offset = offset;
- this.length = length;
- }
-
- /**
- * Returns the underlying File.
- * @return the underlying file
- */
- public File getFile() {
- return this.fileAccess.file;
- }
-
- @Override
- public InputStream getInputStream() throws IOException {
- return new DataInputStream();
- }
-
- @Override
- public RandomAccessData getSubsection(long offset, long length) {
- if (offset < 0 || length < 0 || offset + length > this.length) {
- throw new IndexOutOfBoundsException();
- }
- return new RandomAccessDataFile(this.fileAccess, this.offset + offset, length);
- }
-
- @Override
- public byte[] read() throws IOException {
- return read(0, this.length);
- }
-
- @Override
- public byte[] read(long offset, long length) throws IOException {
- if (offset > this.length) {
- throw new IndexOutOfBoundsException();
- }
- if (offset + length > this.length) {
- throw new EOFException();
- }
- byte[] bytes = new byte[(int) length];
- read(bytes, offset, 0, bytes.length);
- return bytes;
- }
-
- private int readByte(long position) throws IOException {
- if (position >= this.length) {
- return -1;
- }
- return this.fileAccess.readByte(this.offset + position);
- }
-
- private int read(byte[] bytes, long position, int offset, int length) throws IOException {
- if (position > this.length) {
- return -1;
- }
- return this.fileAccess.read(bytes, this.offset + position, offset, length);
- }
-
- @Override
- public long getSize() {
- return this.length;
- }
-
- public void close() throws IOException {
- this.fileAccess.close();
- }
-
- /**
- * {@link InputStream} implementation for the {@link RandomAccessDataFile}.
- */
- private class DataInputStream extends InputStream {
-
- private int position;
-
- @Override
- public int read() throws IOException {
- int read = RandomAccessDataFile.this.readByte(this.position);
- if (read > -1) {
- moveOn(1);
- }
- return read;
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return read(b, 0, (b != null) ? b.length : 0);
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- if (b == null) {
- throw new NullPointerException("Bytes must not be null");
- }
- return doRead(b, off, len);
- }
-
- /**
- * Perform the actual read.
- * @param b the bytes to read or {@code null} when reading a single byte
- * @param off the offset of the byte array
- * @param len the length of data to read
- * @return the number of bytes read into {@code b} or the actual read byte if
- * {@code b} is {@code null}. Returns -1 when the end of the stream is reached
- * @throws IOException in case of I/O errors
- */
- int doRead(byte[] b, int off, int len) throws IOException {
- if (len == 0) {
- return 0;
- }
- int cappedLen = cap(len);
- if (cappedLen <= 0) {
- return -1;
- }
- return (int) moveOn(RandomAccessDataFile.this.read(b, this.position, off, cappedLen));
- }
-
- @Override
- public long skip(long n) throws IOException {
- return (n <= 0) ? 0 : moveOn(cap(n));
- }
-
- @Override
- public int available() throws IOException {
- return (int) RandomAccessDataFile.this.length - this.position;
- }
-
- /**
- * Cap the specified value such that it cannot exceed the number of bytes
- * remaining.
- * @param n the value to cap
- * @return the capped value
- */
- private int cap(long n) {
- return (int) Math.min(RandomAccessDataFile.this.length - this.position, n);
- }
-
- /**
- * Move the stream position forwards the specified amount.
- * @param amount the amount to move
- * @return the amount moved
- */
- private long moveOn(int amount) {
- this.position += amount;
- return amount;
- }
-
- }
-
- private static final class FileAccess {
-
- private final Object monitor = new Object();
-
- private final File file;
-
- private RandomAccessFile randomAccessFile;
-
- private FileAccess(File file) {
- this.file = file;
- openIfNecessary();
- }
-
- private int read(byte[] bytes, long position, int offset, int length) throws IOException {
- synchronized (this.monitor) {
- openIfNecessary();
- this.randomAccessFile.seek(position);
- return this.randomAccessFile.read(bytes, offset, length);
- }
- }
-
- private void openIfNecessary() {
- if (this.randomAccessFile == null) {
- try {
- this.randomAccessFile = new RandomAccessFile(this.file, "r");
- }
- catch (FileNotFoundException ex) {
- throw new IllegalArgumentException(
- String.format("File %s must exist", this.file.getAbsolutePath()));
- }
- }
- }
-
- private void close() throws IOException {
- synchronized (this.monitor) {
- if (this.randomAccessFile != null) {
- this.randomAccessFile.close();
- this.randomAccessFile = null;
- }
- }
- }
-
- private int readByte(long position) throws IOException {
- synchronized (this.monitor) {
- openIfNecessary();
- this.randomAccessFile.seek(position);
- return this.randomAccessFile.read();
- }
- }
-
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/AbstractJarFile.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/AbstractJarFile.java
deleted file mode 100644
index eed7b062..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/AbstractJarFile.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.Permission;
-
-/**
- * Base class for extended variants of {@link java.util.jar.JarFile}.
- *
- * @author Phillip Webb
- */
-abstract class AbstractJarFile extends java.util.jar.JarFile {
-
- /**
- * Create a new {@link AbstractJarFile}.
- * @param file the root jar file.
- * @throws IOException on IO error
- */
- AbstractJarFile(File file) throws IOException {
- super(file);
- }
-
- /**
- * Return a URL that can be used to access this JAR file. NOTE: the specified URL
- * cannot be serialized and or cloned.
- * @return the URL
- * @throws MalformedURLException if the URL is malformed
- */
- abstract URL getUrl() throws MalformedURLException;
-
- /**
- * Return the {@link JarFileType} of this instance.
- * @return the jar file type
- */
- abstract JarFileType getType();
-
- /**
- * Return the security permission for this JAR.
- * @return the security permission.
- */
- abstract Permission getPermission();
-
- /**
- * Return an {@link InputStream} for the entire jar contents.
- * @return the contents input stream
- * @throws IOException on IO error
- */
- abstract InputStream getInputStream() throws IOException;
-
- /**
- * The type of a {@link JarFile}.
- */
- enum JarFileType {
-
- DIRECT, NESTED_DIRECTORY, NESTED_JAR
-
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/AsciiBytes.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/AsciiBytes.java
deleted file mode 100644
index 06caea44..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/AsciiBytes.java
+++ /dev/null
@@ -1,239 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import java.nio.charset.StandardCharsets;
-
-/**
- * Simple wrapper around a byte array that represents an ASCII. Used for performance
- * reasons to save constructing Strings for ZIP data.
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- */
-final class AsciiBytes {
-
- private static final String EMPTY_STRING = "";
-
- private static final int[] INITIAL_BYTE_BITMASK = { 0x7F, 0x1F, 0x0F, 0x07 };
-
- private static final int SUBSEQUENT_BYTE_BITMASK = 0x3F;
-
- private final byte[] bytes;
-
- private final int offset;
-
- private final int length;
-
- private String string;
-
- private int hash;
-
- /**
- * Create a new {@link AsciiBytes} from the specified String.
- * @param string the source string
- */
- AsciiBytes(String string) {
- this(string.getBytes(StandardCharsets.UTF_8));
- this.string = string;
- }
-
- /**
- * Create a new {@link AsciiBytes} from the specified bytes. NOTE: underlying bytes
- * are not expected to change.
- * @param bytes the source bytes
- */
- AsciiBytes(byte[] bytes) {
- this(bytes, 0, bytes.length);
- }
-
- /**
- * Create a new {@link AsciiBytes} from the specified bytes. NOTE: underlying bytes
- * are not expected to change.
- * @param bytes the source bytes
- * @param offset the offset
- * @param length the length
- */
- AsciiBytes(byte[] bytes, int offset, int length) {
- if (offset < 0 || length < 0 || (offset + length) > bytes.length) {
- throw new IndexOutOfBoundsException();
- }
- this.bytes = bytes;
- this.offset = offset;
- this.length = length;
- }
-
- int length() {
- return this.length;
- }
-
- boolean startsWith(AsciiBytes prefix) {
- if (this == prefix) {
- return true;
- }
- if (prefix.length > this.length) {
- return false;
- }
- for (int i = 0; i < prefix.length; i++) {
- if (this.bytes[i + this.offset] != prefix.bytes[i + prefix.offset]) {
- return false;
- }
- }
- return true;
- }
-
- boolean endsWith(AsciiBytes postfix) {
- if (this == postfix) {
- return true;
- }
- if (postfix.length > this.length) {
- return false;
- }
- for (int i = 0; i < postfix.length; i++) {
- if (this.bytes[this.offset + (this.length - 1) - i] != postfix.bytes[postfix.offset + (postfix.length - 1)
- - i]) {
- return false;
- }
- }
- return true;
- }
-
- AsciiBytes substring(int beginIndex) {
- return substring(beginIndex, this.length);
- }
-
- AsciiBytes substring(int beginIndex, int endIndex) {
- int length = endIndex - beginIndex;
- if (this.offset + length > this.bytes.length) {
- throw new IndexOutOfBoundsException();
- }
- return new AsciiBytes(this.bytes, this.offset + beginIndex, length);
- }
-
- boolean matches(CharSequence name, char suffix) {
- int charIndex = 0;
- int nameLen = name.length();
- int totalLen = nameLen + ((suffix != 0) ? 1 : 0);
- for (int i = this.offset; i < this.offset + this.length; i++) {
- int b = this.bytes[i];
- int remainingUtfBytes = getNumberOfUtfBytes(b) - 1;
- b &= INITIAL_BYTE_BITMASK[remainingUtfBytes];
- for (int j = 0; j < remainingUtfBytes; j++) {
- b = (b << 6) + (this.bytes[++i] & SUBSEQUENT_BYTE_BITMASK);
- }
- char c = getChar(name, suffix, charIndex++);
- if (b <= 0xFFFF) {
- if (c != b) {
- return false;
- }
- }
- else {
- if (c != ((b >> 0xA) + 0xD7C0)) {
- return false;
- }
- c = getChar(name, suffix, charIndex++);
- if (c != ((b & 0x3FF) + 0xDC00)) {
- return false;
- }
- }
- }
- return charIndex == totalLen;
- }
-
- private char getChar(CharSequence name, char suffix, int index) {
- if (index < name.length()) {
- return name.charAt(index);
- }
- if (index == name.length()) {
- return suffix;
- }
- return 0;
- }
-
- private int getNumberOfUtfBytes(int b) {
- if ((b & 0x80) == 0) {
- return 1;
- }
- int numberOfUtfBytes = 0;
- while ((b & 0x80) != 0) {
- b <<= 1;
- numberOfUtfBytes++;
- }
- return numberOfUtfBytes;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj.getClass() == AsciiBytes.class) {
- AsciiBytes other = (AsciiBytes) obj;
- if (this.length == other.length) {
- for (int i = 0; i < this.length; i++) {
- if (this.bytes[this.offset + i] != other.bytes[other.offset + i]) {
- return false;
- }
- }
- return true;
- }
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int hash = this.hash;
- if (hash == 0 && this.bytes.length > 0) {
- for (int i = this.offset; i < this.offset + this.length; i++) {
- int b = this.bytes[i];
- int remainingUtfBytes = getNumberOfUtfBytes(b) - 1;
- b &= INITIAL_BYTE_BITMASK[remainingUtfBytes];
- for (int j = 0; j < remainingUtfBytes; j++) {
- b = (b << 6) + (this.bytes[++i] & SUBSEQUENT_BYTE_BITMASK);
- }
- if (b <= 0xFFFF) {
- hash = 31 * hash + b;
- }
- else {
- hash = 31 * hash + ((b >> 0xA) + 0xD7C0);
- hash = 31 * hash + ((b & 0x3FF) + 0xDC00);
- }
- }
- this.hash = hash;
- }
- return hash;
- }
-
- @Override
- public String toString() {
- if (this.string == null) {
- if (this.length == 0) {
- this.string = EMPTY_STRING;
- }
- else {
- this.string = new String(this.bytes, this.offset, this.length, StandardCharsets.UTF_8);
- }
- }
- return this.string;
- }
-
- static String toString(byte[] bytes) {
- return new String(bytes, StandardCharsets.UTF_8);
- }
-
- static int hashCode(CharSequence charSequence) {
- // We're compatible with String's hashCode()
- if (charSequence instanceof StringSequence) {
- // ... but save making an unnecessary String for StringSequence
- return charSequence.hashCode();
- }
- return charSequence.toString().hashCode();
- }
-
- static int hashCode(int hash, char suffix) {
- return (suffix != 0) ? (31 * hash + suffix) : hash;
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/Bytes.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/Bytes.java
deleted file mode 100644
index 99fabb53..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/Bytes.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-/**
- * Utilities for dealing with bytes from ZIP files.
- *
- * @author Phillip Webb
- */
-final class Bytes {
-
- private Bytes() {
- }
-
- static long littleEndianValue(byte[] bytes, int offset, int length) {
- long value = 0;
- for (int i = length - 1; i >= 0; i--) {
- value = ((value << 8) | (bytes[offset + i] & 0xFF));
- }
- return value;
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryEndRecord.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryEndRecord.java
deleted file mode 100644
index 75fa2761..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryEndRecord.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
-
-import java.io.IOException;
-
-/**
- * A ZIP File "End of central directory record" (EOCD).
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @author Camille Vienot
- * @see Zip File Format
- */
-class CentralDirectoryEndRecord {
-
- private static final int MINIMUM_SIZE = 22;
-
- private static final int MAXIMUM_COMMENT_LENGTH = 0xFFFF;
-
- private static final int MAXIMUM_SIZE = MINIMUM_SIZE + MAXIMUM_COMMENT_LENGTH;
-
- private static final int SIGNATURE = 0x06054b50;
-
- private static final int COMMENT_LENGTH_OFFSET = 20;
-
- private static final int READ_BLOCK_SIZE = 256;
-
- private final Zip64End zip64End;
-
- private byte[] block;
-
- private int offset;
-
- private int size;
-
- /**
- * Create a new {@link CentralDirectoryEndRecord} instance from the specified
- * {@link RandomAccessData}, searching backwards from the end until a valid block is
- * located.
- * @param data the source data
- * @throws IOException in case of I/O errors
- */
- CentralDirectoryEndRecord(RandomAccessData data) throws IOException {
- this.block = createBlockFromEndOfData(data, READ_BLOCK_SIZE);
- this.size = MINIMUM_SIZE;
- this.offset = this.block.length - this.size;
- while (!isValid()) {
- this.size++;
- if (this.size > this.block.length) {
- if (this.size >= MAXIMUM_SIZE || this.size > data.getSize()) {
- throw new IOException(
- "Unable to find ZIP central directory records after reading " + this.size + " bytes");
- }
- this.block = createBlockFromEndOfData(data, this.size + READ_BLOCK_SIZE);
- }
- this.offset = this.block.length - this.size;
- }
- long startOfCentralDirectoryEndRecord = data.getSize() - this.size;
- Zip64Locator zip64Locator = Zip64Locator.find(data, startOfCentralDirectoryEndRecord);
- this.zip64End = (zip64Locator != null) ? new Zip64End(data, zip64Locator) : null;
- }
-
- private byte[] createBlockFromEndOfData(RandomAccessData data, int size) throws IOException {
- int length = (int) Math.min(data.getSize(), size);
- return data.read(data.getSize() - length, length);
- }
-
- private boolean isValid() {
- if (this.block.length < MINIMUM_SIZE || Bytes.littleEndianValue(this.block, this.offset + 0, 4) != SIGNATURE) {
- return false;
- }
- // Total size must be the structure size + comment
- long commentLength = Bytes.littleEndianValue(this.block, this.offset + COMMENT_LENGTH_OFFSET, 2);
- return this.size == MINIMUM_SIZE + commentLength;
- }
-
- /**
- * Returns the location in the data that the archive actually starts. For most files
- * the archive data will start at 0, however, it is possible to have prefixed bytes
- * (often used for startup scripts) at the beginning of the data.
- * @param data the source data
- * @return the offset within the data where the archive begins
- */
- long getStartOfArchive(RandomAccessData data) {
- long length = Bytes.littleEndianValue(this.block, this.offset + 12, 4);
- long specifiedOffset = (this.zip64End != null) ? this.zip64End.centralDirectoryOffset
- : Bytes.littleEndianValue(this.block, this.offset + 16, 4);
- long zip64EndSize = (this.zip64End != null) ? this.zip64End.getSize() : 0L;
- int zip64LocSize = (this.zip64End != null) ? Zip64Locator.ZIP64_LOCSIZE : 0;
- long actualOffset = data.getSize() - this.size - length - zip64EndSize - zip64LocSize;
- return actualOffset - specifiedOffset;
- }
-
- /**
- * Return the bytes of the "Central directory" based on the offset indicated in this
- * record.
- * @param data the source data
- * @return the central directory data
- */
- RandomAccessData getCentralDirectory(RandomAccessData data) {
- if (this.zip64End != null) {
- return this.zip64End.getCentralDirectory(data);
- }
- long offset = Bytes.littleEndianValue(this.block, this.offset + 16, 4);
- long length = Bytes.littleEndianValue(this.block, this.offset + 12, 4);
- return data.getSubsection(offset, length);
- }
-
- /**
- * Return the number of ZIP entries in the file.
- * @return the number of records in the zip
- */
- int getNumberOfRecords() {
- if (this.zip64End != null) {
- return this.zip64End.getNumberOfRecords();
- }
- long numberOfRecords = Bytes.littleEndianValue(this.block, this.offset + 10, 2);
- return (int) numberOfRecords;
- }
-
- String getComment() {
- int commentLength = (int) Bytes.littleEndianValue(this.block, this.offset + COMMENT_LENGTH_OFFSET, 2);
- AsciiBytes comment = new AsciiBytes(this.block, this.offset + COMMENT_LENGTH_OFFSET + 2, commentLength);
- return comment.toString();
- }
-
- boolean isZip64() {
- return this.zip64End != null;
- }
-
- /**
- * A Zip64 end of central directory record.
- *
- * @see Chapter
- * 4.3.14 of Zip64 specification
- */
- private static final class Zip64End {
-
- private static final int ZIP64_ENDTOT = 32; // total number of entries
-
- private static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
-
- private static final int ZIP64_ENDOFF = 48; // offset of first CEN header
-
- private final Zip64Locator locator;
-
- private final long centralDirectoryOffset;
-
- private final long centralDirectoryLength;
-
- private final int numberOfRecords;
-
- private Zip64End(RandomAccessData data, Zip64Locator locator) throws IOException {
- this.locator = locator;
- byte[] block = data.read(locator.getZip64EndOffset(), 56);
- this.centralDirectoryOffset = Bytes.littleEndianValue(block, ZIP64_ENDOFF, 8);
- this.centralDirectoryLength = Bytes.littleEndianValue(block, ZIP64_ENDSIZ, 8);
- this.numberOfRecords = (int) Bytes.littleEndianValue(block, ZIP64_ENDTOT, 8);
- }
-
- /**
- * Return the size of this zip 64 end of central directory record.
- * @return size of this zip 64 end of central directory record
- */
- private long getSize() {
- return this.locator.getZip64EndSize();
- }
-
- /**
- * Return the bytes of the "Central directory" based on the offset indicated in
- * this record.
- * @param data the source data
- * @return the central directory data
- */
- private RandomAccessData getCentralDirectory(RandomAccessData data) {
- return data.getSubsection(this.centralDirectoryOffset, this.centralDirectoryLength);
- }
-
- /**
- * Return the number of entries in the zip64 archive.
- * @return the number of records in the zip
- */
- private int getNumberOfRecords() {
- return this.numberOfRecords;
- }
-
- }
-
- /**
- * A Zip64 end of central directory locator.
- *
- * @see Chapter
- * 4.3.15 of Zip64 specification
- */
- private static final class Zip64Locator {
-
- static final int SIGNATURE = 0x07064b50;
-
- static final int ZIP64_LOCSIZE = 20; // locator size
-
- static final int ZIP64_LOCOFF = 8; // offset of zip64 end
-
- private final long zip64EndOffset;
-
- private final long offset;
-
- private Zip64Locator(long offset, byte[] block) {
- this.offset = offset;
- this.zip64EndOffset = Bytes.littleEndianValue(block, ZIP64_LOCOFF, 8);
- }
-
- /**
- * Return the size of the zip 64 end record located by this zip64 end locator.
- * @return size of the zip 64 end record located by this zip64 end locator
- */
- private long getZip64EndSize() {
- return this.offset - this.zip64EndOffset;
- }
-
- /**
- * Return the offset to locate {@link Zip64End}.
- * @return offset of the Zip64 end of central directory record
- */
- private long getZip64EndOffset() {
- return this.zip64EndOffset;
- }
-
- private static Zip64Locator find(RandomAccessData data, long centralDirectoryEndOffset) throws IOException {
- long offset = centralDirectoryEndOffset - ZIP64_LOCSIZE;
- if (offset >= 0) {
- byte[] block = data.read(offset, ZIP64_LOCSIZE);
- if (Bytes.littleEndianValue(block, 0, 4) == SIGNATURE) {
- return new Zip64Locator(offset, block);
- }
- }
- return null;
- }
-
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryFileHeader.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryFileHeader.java
deleted file mode 100644
index 340289c2..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryFileHeader.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
-
-import java.io.IOException;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoField;
-import java.time.temporal.ChronoUnit;
-import java.time.temporal.ValueRange;
-
-/**
- * A ZIP File "Central directory file header record" (CDFH).
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @author Dmytro Nosan
- * @see Zip File Format
- */
-
-final class CentralDirectoryFileHeader implements FileHeader {
-
- private static final AsciiBytes SLASH = new AsciiBytes("/");
-
- private static final byte[] NO_EXTRA = {};
-
- private static final AsciiBytes NO_COMMENT = new AsciiBytes("");
-
- private byte[] header;
-
- private int headerOffset;
-
- private AsciiBytes name;
-
- private byte[] extra;
-
- private AsciiBytes comment;
-
- private long localHeaderOffset;
-
- CentralDirectoryFileHeader() {
- }
-
- CentralDirectoryFileHeader(byte[] header, int headerOffset, AsciiBytes name, byte[] extra, AsciiBytes comment,
- long localHeaderOffset) {
- this.header = header;
- this.headerOffset = headerOffset;
- this.name = name;
- this.extra = extra;
- this.comment = comment;
- this.localHeaderOffset = localHeaderOffset;
- }
-
- void load(byte[] data, int dataOffset, RandomAccessData variableData, long variableOffset, JarEntryFilter filter)
- throws IOException {
- // Load fixed part
- this.header = data;
- this.headerOffset = dataOffset;
- long compressedSize = Bytes.littleEndianValue(data, dataOffset + 20, 4);
- long uncompressedSize = Bytes.littleEndianValue(data, dataOffset + 24, 4);
- long nameLength = Bytes.littleEndianValue(data, dataOffset + 28, 2);
- long extraLength = Bytes.littleEndianValue(data, dataOffset + 30, 2);
- long commentLength = Bytes.littleEndianValue(data, dataOffset + 32, 2);
- long localHeaderOffset = Bytes.littleEndianValue(data, dataOffset + 42, 4);
- // Load variable part
- dataOffset += 46;
- if (variableData != null) {
- data = variableData.read(variableOffset + 46, nameLength + extraLength + commentLength);
- dataOffset = 0;
- }
- this.name = new AsciiBytes(data, dataOffset, (int) nameLength);
- if (filter != null) {
- this.name = filter.apply(this.name);
- }
- this.extra = NO_EXTRA;
- this.comment = NO_COMMENT;
- if (extraLength > 0) {
- this.extra = new byte[(int) extraLength];
- System.arraycopy(data, (int) (dataOffset + nameLength), this.extra, 0, this.extra.length);
- }
- this.localHeaderOffset = getLocalHeaderOffset(compressedSize, uncompressedSize, localHeaderOffset, this.extra);
- if (commentLength > 0) {
- this.comment = new AsciiBytes(data, (int) (dataOffset + nameLength + extraLength), (int) commentLength);
- }
- }
-
- private long getLocalHeaderOffset(long compressedSize, long uncompressedSize, long localHeaderOffset, byte[] extra)
- throws IOException {
- if (localHeaderOffset != 0xFFFFFFFFL) {
- return localHeaderOffset;
- }
- int extraOffset = 0;
- while (extraOffset < extra.length - 2) {
- int id = (int) Bytes.littleEndianValue(extra, extraOffset, 2);
- int length = (int) Bytes.littleEndianValue(extra, extraOffset, 2);
- extraOffset += 4;
- if (id == 1) {
- int localHeaderExtraOffset = 0;
- if (compressedSize == 0xFFFFFFFFL) {
- localHeaderExtraOffset += 4;
- }
- if (uncompressedSize == 0xFFFFFFFFL) {
- localHeaderExtraOffset += 4;
- }
- return Bytes.littleEndianValue(extra, extraOffset + localHeaderExtraOffset, 8);
- }
- extraOffset += length;
- }
- throw new IOException("Zip64 Extended Information Extra Field not found");
- }
-
- AsciiBytes getName() {
- return this.name;
- }
-
- @Override
- public boolean hasName(CharSequence name, char suffix) {
- return this.name.matches(name, suffix);
- }
-
- boolean isDirectory() {
- return this.name.endsWith(SLASH);
- }
-
- @Override
- public int getMethod() {
- return (int) Bytes.littleEndianValue(this.header, this.headerOffset + 10, 2);
- }
-
- long getTime() {
- long datetime = Bytes.littleEndianValue(this.header, this.headerOffset + 12, 4);
- return decodeMsDosFormatDateTime(datetime);
- }
-
- /**
- * Decode MS-DOS Date Time details. See
- * Microsoft's documentation for more details of the format.
- * @param datetime the date and time
- * @return the date and time as milliseconds since the epoch
- */
- private long decodeMsDosFormatDateTime(long datetime) {
- int year = getChronoValue(((datetime >> 25) & 0x7f) + 1980, ChronoField.YEAR);
- int month = getChronoValue((datetime >> 21) & 0x0f, ChronoField.MONTH_OF_YEAR);
- int day = getChronoValue((datetime >> 16) & 0x1f, ChronoField.DAY_OF_MONTH);
- int hour = getChronoValue((datetime >> 11) & 0x1f, ChronoField.HOUR_OF_DAY);
- int minute = getChronoValue((datetime >> 5) & 0x3f, ChronoField.MINUTE_OF_HOUR);
- int second = getChronoValue((datetime << 1) & 0x3e, ChronoField.SECOND_OF_MINUTE);
- return ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.systemDefault())
- .toInstant()
- .truncatedTo(ChronoUnit.SECONDS)
- .toEpochMilli();
- }
-
- long getCrc() {
- return Bytes.littleEndianValue(this.header, this.headerOffset + 16, 4);
- }
-
- @Override
- public long getCompressedSize() {
- return Bytes.littleEndianValue(this.header, this.headerOffset + 20, 4);
- }
-
- @Override
- public long getSize() {
- return Bytes.littleEndianValue(this.header, this.headerOffset + 24, 4);
- }
-
- byte[] getExtra() {
- return this.extra;
- }
-
- boolean hasExtra() {
- return this.extra.length > 0;
- }
-
- AsciiBytes getComment() {
- return this.comment;
- }
-
- @Override
- public long getLocalHeaderOffset() {
- return this.localHeaderOffset;
- }
-
- @Override
- public CentralDirectoryFileHeader clone() {
- byte[] header = new byte[46];
- System.arraycopy(this.header, this.headerOffset, header, 0, header.length);
- return new CentralDirectoryFileHeader(header, 0, this.name, header, this.comment, this.localHeaderOffset);
- }
-
- static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data, long offset, JarEntryFilter filter)
- throws IOException {
- CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
- byte[] bytes = data.read(offset, 46);
- fileHeader.load(bytes, 0, data, offset, filter);
- return fileHeader;
- }
-
- private static int getChronoValue(long value, ChronoField field) {
- ValueRange range = field.range();
- return Math.toIntExact(Math.min(Math.max(value, range.getMinimum()), range.getMaximum()));
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryParser.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryParser.java
deleted file mode 100644
index 3e81183b..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryParser.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Parses the central directory from a JAR file.
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @see CentralDirectoryVisitor
- */
-class CentralDirectoryParser {
-
- private static final int CENTRAL_DIRECTORY_HEADER_BASE_SIZE = 46;
-
- private final List visitors = new ArrayList<>();
-
- T addVisitor(T visitor) {
- this.visitors.add(visitor);
- return visitor;
- }
-
- /**
- * Parse the source data, triggering {@link CentralDirectoryVisitor visitors}.
- * @param data the source data
- * @param skipPrefixBytes if prefix bytes should be skipped
- * @return the actual archive data without any prefix bytes
- * @throws IOException on error
- */
- RandomAccessData parse(RandomAccessData data, boolean skipPrefixBytes) throws IOException {
- CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(data);
- if (skipPrefixBytes) {
- data = getArchiveData(endRecord, data);
- }
- RandomAccessData centralDirectoryData = endRecord.getCentralDirectory(data);
- visitStart(endRecord, centralDirectoryData);
- parseEntries(endRecord, centralDirectoryData);
- visitEnd();
- return data;
- }
-
- private void parseEntries(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData)
- throws IOException {
- byte[] bytes = centralDirectoryData.read(0, centralDirectoryData.getSize());
- CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
- int dataOffset = 0;
- for (int i = 0; i < endRecord.getNumberOfRecords(); i++) {
- fileHeader.load(bytes, dataOffset, null, 0, null);
- visitFileHeader(dataOffset, fileHeader);
- dataOffset += CENTRAL_DIRECTORY_HEADER_BASE_SIZE + fileHeader.getName().length()
- + fileHeader.getComment().length() + fileHeader.getExtra().length;
- }
- }
-
- private RandomAccessData getArchiveData(CentralDirectoryEndRecord endRecord, RandomAccessData data) {
- long offset = endRecord.getStartOfArchive(data);
- if (offset == 0) {
- return data;
- }
- return data.getSubsection(offset, data.getSize() - offset);
- }
-
- private void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData) {
- for (CentralDirectoryVisitor visitor : this.visitors) {
- visitor.visitStart(endRecord, centralDirectoryData);
- }
- }
-
- private void visitFileHeader(long dataOffset, CentralDirectoryFileHeader fileHeader) {
- for (CentralDirectoryVisitor visitor : this.visitors) {
- visitor.visitFileHeader(fileHeader, dataOffset);
- }
- }
-
- private void visitEnd() {
- for (CentralDirectoryVisitor visitor : this.visitors) {
- visitor.visitEnd();
- }
- }
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryVisitor.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryVisitor.java
deleted file mode 100644
index af1e84ed..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/CentralDirectoryVisitor.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
-
-/**
- * Callback visitor triggered by {@link CentralDirectoryParser}.
- *
- * @author Phillip Webb
- */
-interface CentralDirectoryVisitor {
-
- void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData);
-
- void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset);
-
- void visitEnd();
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/FileHeader.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/FileHeader.java
deleted file mode 100644
index 9180d093..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/FileHeader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import java.util.zip.ZipEntry;
-
-/**
- * A file header record that has been loaded from a Jar file.
- *
- * @author Phillip Webb
- * @see JarEntry
- * @see CentralDirectoryFileHeader
- */
-interface FileHeader {
-
- /**
- * Returns {@code true} if the header has the given name.
- * @param name the name to test
- * @param suffix an additional suffix (or {@code 0})
- * @return {@code true} if the header has the given name
- */
- boolean hasName(CharSequence name, char suffix);
-
- /**
- * Return the offset of the load file header within the archive data.
- * @return the local header offset
- */
- long getLocalHeaderOffset();
-
- /**
- * Return the compressed size of the entry.
- * @return the compressed size.
- */
- long getCompressedSize();
-
- /**
- * Return the uncompressed size of the entry.
- * @return the uncompressed size.
- */
- long getSize();
-
- /**
- * Return the method used to compress the data.
- * @return the zip compression method
- * @see ZipEntry#STORED
- * @see ZipEntry#DEFLATED
- */
- int getMethod();
-
-}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/Handler.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/Handler.java
deleted file mode 100644
index 44b60ebd..00000000
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/jar/Handler.java
+++ /dev/null
@@ -1,448 +0,0 @@
-package fun.asgc.neutrino.core.aop.compiler.internal.jar;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-import java.net.*;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.regex.Pattern;
-
-/**
- * {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s.
- *
- * @author Phillip Webb
- * @author Andy Wilkinson
- * @since 1.0.0
- * @see JarFile#registerUrlProtocolHandler()
- */
-public class Handler extends URLStreamHandler {
-
- // NOTE: in order to be found as a URL protocol handler, this class must be public,
- // must be named Handler and must be in a package ending '.jar'
-
- private static final String JAR_PROTOCOL = "jar:";
-
- private static final String FILE_PROTOCOL = "file:";
-
- private static final String TOMCAT_WARFILE_PROTOCOL = "war:file:";
-
- private static final String SEPARATOR = "!/";
-
- private static final Pattern SEPARATOR_PATTERN = Pattern.compile(SEPARATOR, Pattern.LITERAL);
-
- private static final String CURRENT_DIR = "/./";
-
- private static final Pattern CURRENT_DIR_PATTERN = Pattern.compile(CURRENT_DIR, Pattern.LITERAL);
-
- private static final String PARENT_DIR = "/../";
-
- private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs";
-
- private static final String[] FALLBACK_HANDLERS = { "sun.net.www.protocol.jar.Handler" };
-
- private static URL jarContextUrl;
-
- private static SoftReference