All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.qt.internal.RetroHelper Maven / Gradle / Ivy

There is a newer version: 6.8.0
Show newest version
/****************************************************************************
**
** Copyright (C) 2009-2024 Dr. Peter Droste, Omix Visualization GmbH & Co. KG. All rights reserved.
**
** This file is part of Qt Jambi.
**
** $BEGIN_LICENSE$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
** $END_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

package io.qt.internal;

import java.io.File;
import java.lang.invoke.MethodType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.logging.Logger;

import io.qt.InternalAccess.CallerContext;

final class RetroHelper {
	private RetroHelper() {throw new RuntimeException();}
	
	private static interface Implementor{
		Supplier> callerClassProvider();
		IntFunction classAccessChecker();
		String processName();
		boolean isProcessAlive(String pid);
		 T getAnnotatedOwnerType(T actualType);
	}
	
	private static class DefaultImplementor implements Implementor{
		private final StackWalker stackWalker = StackWalker.getInstance(java.util.Collections.singleton(StackWalker.Option.RETAIN_CLASS_REFERENCE));
	    private final Supplier> callerClassProvider = stackWalker::getCallerClass;
	    private final IntFunction classAccessChecker = number->{
	    	if(number>=0) {
		        Optional stackFrame = stackWalker.walk(stream->stream.limit(number+2).skip(number+1).findFirst());
		        if(stackFrame.isPresent() && stackFrame.get().getDeclaringClass()==RetroHelper.class) {
		        	stackFrame = stackWalker.walk(stream->stream.limit(number+3).skip(number+2).findFirst());
		        }
		        if(stackFrame.isPresent()) {
		        	String methodDescriptor = null;
		        	MethodType methodType = null;
		        	try {
						methodDescriptor = stackFrame.get().getDescriptor();
					} catch (UnsupportedOperationException e) {}
		        	try{
		        		methodType = stackFrame.get().getMethodType();
		        	} catch (UnsupportedOperationException e) {}
		            return new io.qt.InternalAccess.CallerContext(
		                stackFrame.get().getDeclaringClass(),
		                stackFrame.get().getMethodName(),
		                methodDescriptor,
		                methodType,
		                stackFrame.get().getLineNumber());
		        }
	        }
	        return null;
	    };
	    private String processName = Long.toUnsignedString(ProcessHandle.current().pid());
	    
	    @Override
	    public Supplier> callerClassProvider(){
	        return callerClassProvider;
	    }
	    
	    @Override
	    public IntFunction classAccessChecker(){
	        return classAccessChecker;
	    }
	    
	    @Override
	    public String processName() {
	    	return processName;
	    }
	    
	    @SuppressWarnings("unchecked")
		@Override
	    public  T getAnnotatedOwnerType(T actualType){
	        try {
	        	if(actualType instanceof java.lang.reflect.AnnotatedType)
	        		return (T)((java.lang.reflect.AnnotatedType)actualType).getAnnotatedOwnerType();
			} catch (Throwable e) {
			}
			return null;
	    }

		@Override
		public boolean isProcessAlive(String pid) {
			ProcessHandle process = ProcessHandle.of(Long.parseUnsignedLong(pid)).orElse(null);
			return process!=null && process.isAlive();
		}
	}
	
	private static class Java8Implementor implements Implementor{
	    Java8Implementor() {
			super();
			Function getAnnotatedOwnerTypeSupplier = null;
	        try {
	        	Method getAnnotatedOwnerType = java.lang.reflect.AnnotatedType.class.getMethod("getAnnotatedOwnerType");
	        	getAnnotatedOwnerTypeSupplier = a->{
					try {
						return (AnnotatedElement)getAnnotatedOwnerType.invoke(a);
					} catch (RuntimeException | Error e) {
						throw e;
					} catch (InvocationTargetException e) {
						try {
							throw e.getTargetException();
						} catch (RuntimeException | Error e2) {
							throw e2;
						}catch(Throwable t) {
							throw new RuntimeException(t);
						}
					}catch(Throwable t) {
						throw new RuntimeException(t);
					}
				};
	        } catch (Throwable e2) {
	        }
	        this.getAnnotatedOwnerTypeSupplier = getAnnotatedOwnerTypeSupplier;
	        
	        this.classAccessChecker = number->{
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                boolean postStackTrace = false;
                for (StackTraceElement element : stackTrace) {
                	if(!postStackTrace) {
                		if(element.getClassName().equals(Thread.class.getName())
                				&& element.getMethodName().equals("getStackTrace")) {
                			postStackTrace = true;
                			--number;
                		}
                	}else {
	                    if(!element.getClassName().startsWith("jdk.internal.reflect")
	                            && !element.getClassName().startsWith("java.lang.reflect")
	                            && !element.getClassName().startsWith("io.qt.internal.RetroHelper")) {
		                    if(number==0){
		                        try {
		                            return new io.qt.InternalAccess.CallerContext(Class.forName(element.getClassName()), element.getMethodName(), null, null, element.getLineNumber());
		                        } catch (ClassNotFoundException e) {
		                            ++number;
		                        }
		                    }
	                        --number;
	                    }
                	}
                }
                return null;
            };
            Supplier> _callerClassProvider;
			try {
				Class reflectionClass = Class.forName("sun.reflect.Reflection");
				Method getCallerClass = reflectionClass.getMethod("getCallerClass", int.class);
				_callerClassProvider = ()->{
					try {
						return (Class)getCallerClass.invoke(null, 4);
					} catch (RuntimeException | Error e) {
						throw e;
					} catch (InvocationTargetException e) {
						try {
							throw e.getTargetException();
						} catch (RuntimeException | Error e2) {
							throw e2;
						}catch(Throwable t) {
							throw new RuntimeException(t);
						}
					}catch(Throwable t) {
						throw new RuntimeException(t);
					}
				};
			} catch (Throwable e) {
				_callerClassProvider = ()->{
	                Class result = Object.class;
	                io.qt.InternalAccess.CallerContext info = classAccessChecker().apply(2);
	                if(info!=null && info.declaringClass!=null) {
	                    result = info.declaringClass;
	                }
	                return result;
	            };
			}
			
			this.callerClassProvider = _callerClassProvider;
			
			String pid = "";
			try {
				Class factoryClass = Class.forName("java.lang.management.ManagementFactory");
				Method getRuntimeMXBean = factoryClass.getMethod("getRuntimeMXBean");
				Object runtimeMXBean = getRuntimeMXBean.invoke(null);
				try {
					Field jvm = runtimeMXBean.getClass().getDeclaredField("jvm");
					jvm.setAccessible(true);
					Object management = jvm.get(runtimeMXBean);
					Method method = management.getClass().getDeclaredMethod("getProcessId");
					method.setAccessible(true);
					pid = ""+method.invoke(management);
				} catch (Throwable e) {
					Method getName = runtimeMXBean.getClass().getMethod("getName");
					getName.setAccessible(true);
					pid = (String)getName.invoke(runtimeMXBean);
			        int index = pid.indexOf('@');
			        if(index>0)
			            pid = pid.substring(0, index);
				}
			} catch (Throwable e) {
				Logger.getLogger("io.qt.internal").throwing("Java8Implementor", "", e);
			}
	        this.processName = pid;
		}

		private final IntFunction classAccessChecker;
	    private final Supplier> callerClassProvider;
	    private final String processName;
	    private final Function getAnnotatedOwnerTypeSupplier;

		@Override
		public Supplier> callerClassProvider() {
			return callerClassProvider;
		}

		@Override
		public IntFunction classAccessChecker() {
			return classAccessChecker;
		}
		
		@Override
		public String processName() {
	    	return processName;
	    }
		
		@SuppressWarnings("unchecked")
		@Override
		public  T getAnnotatedOwnerType(T actualType) {
			if(getAnnotatedOwnerTypeSupplier!=null) {
	            try{
	            	if(actualType instanceof java.lang.reflect.AnnotatedType)
	            		return (T)getAnnotatedOwnerTypeSupplier.apply(actualType);
	            } catch (RuntimeException | Error e) {
	                throw e;
	            } catch (Throwable e) {
	                throw new RuntimeException(e);
	            }
	        }
	        return null;
		}

		@Override
		public boolean isProcessAlive(String pid) {
			switch (LibraryUtility.operatingSystem) {
			case MacOS:
				try {
					Process process = Runtime.getRuntime().exec(new String[]{"ps", "-p", pid});
					return process.waitFor()==0;
				} catch (Throwable e) {
				}
				break;
			case Windows:
				try {
					Process process = Runtime.getRuntime().exec(new String[]{"tasklist", "/FI", "PID eq "+pid});
					return process.waitFor()==0;
				} catch (Throwable e) {
				}
				break;
			default:
				if(LibraryUtility.operatingSystem.isUnixLike())
					return new File("/proc/"+pid+"/exe").exists();
				break;
			}
			return true; //...because unknown
		}
	}
	
    private static final Implementor implementor;
    static{
    	Implementor _implementor;
    	try {
			_implementor = new DefaultImplementor();
		} catch (Throwable e) {
			_implementor = new Java8Implementor();
		}
    	implementor = _implementor;
    }
    
    static Supplier> callerClassProvider(){
        return implementor.callerClassProvider();
    }
    
    static IntFunction classAccessChecker(){
        return implementor.classAccessChecker();
    }
    
    static Supplier callerContextProvider() {
    	return ()->implementor.classAccessChecker().apply(2);
    }
    
    static  T getAnnotatedOwnerType(T actualType) {
		return implementor.getAnnotatedOwnerType(actualType);
    }
    
    static String processName() {
    	return implementor.processName();
    }
    
    static List moduleLocations() {
    	List result = new ArrayList<>();
    	try {
    		ModuleLayer.boot().configuration().modules().forEach(rm->{rm.reference().location().ifPresent(result::add);});
    	} catch (Throwable e2) {
        }
    	return result;
    }
    
    static Set classLoaders(){
    	Set result = new HashSet<>();
    	result.add(Thread.currentThread().getContextClassLoader());
    	result.add(RetroHelper.class.getClassLoader());
    	result.add(ClassLoader.getSystemClassLoader());
    	try {
    		result.add(ClassLoader.getPlatformClassLoader());
		} catch (Throwable e) {}
    	return result;
    }
    
    static void findModules(Set modules) throws MalformedURLException{
    	try {
	    	for(Module module : ModuleLayer.boot().modules()) {
	    		modules.add(CoreUtility.createURL("jrt:/"+module.getName()+"/"));
	    	}
		} catch (Throwable e) {}
    }
    
    static Thread newShutdownThread(Runnable r, String name) {
    	try {
			return new Thread(null, r, name, 0, false);
		} catch (Throwable e) {
			return new Thread(null, r, name, 0);
		}
    }
    
    static Package getDefinedPackage(ClassLoader cl, String pkg) {
        try {
			return cl.getDefinedPackage(pkg);
		} catch (Throwable e) {}
        try {
            return (Package)ReflectionUtility.invokeMethod(ClassLoader.class.getDeclaredMethod("getPackage", String.class), cl, pkg);
		} catch (Throwable e) {}
        try {
        	for(java.lang.Package _pkg : java.lang.Package.getPackages()) {
        		if(_pkg.getName().equals(pkg))
        			return _pkg;
        	}
		} catch (Throwable e) {}
        try {
			return cl.loadClass(pkg.replace("/", ".")+".package-info").getPackage();
		} catch (Throwable e) {}
		return null;
    }

	static boolean isProcessAlive(String pid) {
		return implementor.isProcessAlive(pid);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy