diff --git a/build.gradle b/build.gradle index 15464723..ef55852d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ rootProject.version = "9.10.0" -group = 'javasabr' +group = 'javasabr.rlib' subprojects { diff --git a/rlib-classpath/build.gradle b/rlib-classpath/build.gradle new file mode 100644 index 00000000..f8325ab9 --- /dev/null +++ b/rlib-classpath/build.gradle @@ -0,0 +1,5 @@ + +dependencies { + api projects.rlibCommon + testImplementation projects.rlibLoggerImpl +} \ No newline at end of file diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java new file mode 100644 index 00000000..135b2e12 --- /dev/null +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java @@ -0,0 +1,89 @@ +package javasabr.rlib.common.classpath; + +import java.lang.annotation.Annotation; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.function.Predicate; +import javasabr.rlib.common.classpath.impl.ClassPathScannerImpl; +import javasabr.rlib.common.util.array.Array; +import org.jspecify.annotations.Nullable; + +/** + * @author JavaSaBr + */ +public interface ClassPathScanner { + + String JAR_EXTENSION = ".jar"; + + @Nullable ClassPathScanner NULL_SCANNER = null; + + ClassPathScanner EMPTY_SCANNER = new ClassPathScannerImpl(ClassPathScanner.class.getClassLoader()) { + + @Override + public void addClasses(Array> classes) {} + + @Override + public void addAdditionalPath(String path) {} + + @Override + public void addAdditionalPaths(String[] paths) {} + + @Override + public void addResources(Array resources) {} + + @Override + public void scan(Predicate filter) {} + }; + + URLClassLoader EMPTY_CLASS_LOADER = new URLClassLoader(new URL[0], ClassPathScanner.class.getClassLoader()); + + @Nullable URLClassLoader NULL_CLASS_LOADER = null; + + void addClasses(Array> classes); + + void addResources(Array resources); + + void useSystemClassPath(boolean useSystemClasspath); + + default Array> findImplementations(Class interfaceClass) { + Array> result = Array.ofType(Class.class); + findImplementationsTo(result, interfaceClass); + return result; + } + + void findImplementationsTo(Array> container, Class interfaceClass); + + default Array> findInherited(Class parentClass) { + Array> result = Array.ofType(Class.class); + findInheritedTo(result, parentClass); + return result; + } + + void findInheritedTo(Array> container, Class parentClass); + + default Array> findAnnotated(Class annotationClass) { + Array> result = Array.ofType(Class.class); + findAnnotatedTo(result, annotationClass); + return result; + } + + void findAnnotatedTo(Array> container, Class annotationClass); + + void foundClassesTo(Array> container); + + void foundResourcesTo(Array container); + + Array> foundClasses(); + + Array foundResources(); + + default void scan() { + scan(null); + } + + void scan(@Nullable Predicate filter); + + void addAdditionalPath(String path); + + void addAdditionalPaths(String[] paths); +} diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java new file mode 100644 index 00000000..ae863e39 --- /dev/null +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java @@ -0,0 +1,44 @@ +package javasabr.rlib.common.classpath; + +import javasabr.rlib.common.classpath.impl.ClassPathScannerImpl; +import javasabr.rlib.common.classpath.impl.ManifestClassPathScannerImpl; + +/** + * @author JavaSaBr + */ +public final class ClassPathScannerFactory { + + public static ClassPathScanner newDefaultScanner() { + return new ClassPathScannerImpl(ClassPathScannerFactory.class.getClassLoader()); + } + + public static ClassPathScanner newDefaultScanner(ClassLoader classLoader) { + return new ClassPathScannerImpl(classLoader); + } + + public static ClassPathScanner newDefaultScanner( + ClassLoader classLoader, + String[] additionalPaths) { + var scanner = new ClassPathScannerImpl(classLoader); + scanner.addAdditionalPaths(additionalPaths); + return scanner; + } + + public static ClassPathScanner newManifestScanner(Class rootClass) { + return new ManifestClassPathScannerImpl( + ClassPathScannerFactory.class.getClassLoader(), + rootClass, + "Class-Path"); + } + + public static ClassPathScanner newManifestScanner(Class rootClass, String classPathKey) { + return new ManifestClassPathScannerImpl( + ClassPathScannerFactory.class.getClassLoader(), + rootClass, + classPathKey); + } + + private ClassPathScannerFactory() { + throw new RuntimeException(); + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java similarity index 62% rename from rlib-common/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java rename to rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java index 3a1de57c..7a0f8934 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ClassPathScannerImpl.java @@ -8,9 +8,9 @@ import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.function.Predicate; import java.util.jar.JarInputStream; import java.util.zip.ZipException; @@ -26,16 +26,16 @@ import javasabr.rlib.logger.api.LoggerManager; import lombok.AccessLevel; import lombok.Getter; -import org.jspecify.annotations.NullMarked; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * The base implementation of the {@link ClassPathScanner}. - * * @author JavaSaBr */ -@NullMarked -@Getter(AccessLevel.PRIVATE) +@Accessors(fluent = true) +@Getter(AccessLevel.PROTECTED) +@FieldDefaults(level = AccessLevel.PROTECTED) public class ClassPathScannerImpl implements ClassPathScanner { protected static final Logger LOGGER = LoggerManager.getLogger(ClassPathScanner.class); @@ -43,31 +43,17 @@ public class ClassPathScannerImpl implements ClassPathScanner { private static final String CLASS_PATH = System.getProperty("java.class.path"); private static final String PATH_SEPARATOR = File.pathSeparator; private static final String CLASS_EXTENSION = ".class"; + private static final String MODULE_INFO_CLASS = "module-info.class"; + private static final String META_INF_PREFIX = "META-INF"; - /** - * The list of additional paths to scan. - */ - private final Array additionalPaths; + final Array additionalPaths; + final ClassLoader loader; - /** - * The class loader. - */ - private final ClassLoader loader; + Class[] classes; + String[] resources; - /** - * The found classes. - */ - private Class[] classes; - - /** - * The found resources. - */ - private String[] resources; - - /** - * The flag of using system classpath. - */ - private boolean useSystemClassPath; + @Getter + boolean useSystemClassPath; public ClassPathScannerImpl(ClassLoader classLoader) { this.additionalPaths = ArrayFactory.newArray(String.class); @@ -76,91 +62,98 @@ public ClassPathScannerImpl(ClassLoader classLoader) { this.resources = new String[0]; } + @Override + public void useSystemClassPath(boolean useSystemClassPath) { + this.useSystemClassPath = useSystemClassPath; + } + @Override public void addClasses(Array> classes) { - this.classes = ArrayUtils.combine(this.classes, classes.toArray(ArrayUtils.EMPTY_CLASS_ARRAY), Class.class); + this.classes = ArrayUtils.combine( + this.classes, + classes.toArray(ArrayUtils.EMPTY_CLASS_ARRAY), + Class.class); } @Override public void addResources(Array resources) { - this.resources = ArrayUtils.combine(this.resources, resources.toArray(ArrayUtils.EMPTY_STRING_ARRAY), String.class); + this.resources = ArrayUtils.combine( + this.resources, + resources.toArray(ArrayUtils.EMPTY_STRING_ARRAY), + String.class); } @Override - public void findImplements(Array> container, Class interfaceClass) { + public void findImplementationsTo(Array> container, Class interfaceClass) { if (!interfaceClass.isInterface()) { throw new IllegalArgumentException("Class " + interfaceClass + " is not interface."); } - for (var cs : getClasses()) { - - if (cs.isInterface() || !interfaceClass.isAssignableFrom(cs) || isAbstract(cs.getModifiers())) { + for (Class klass : classes) { + if (klass.isInterface() || + !interfaceClass.isAssignableFrom(klass) || + isAbstract(klass.getModifiers())) { continue; } - - container.add(unsafeNNCast(cs)); + container.add(unsafeNNCast(klass)); } } @Override - public void findInherited(Array> container, Class parentClass) { + public void findInheritedTo(Array> container, Class parentClass) { if (Modifier.isFinal(parentClass.getModifiers())) { throw new IllegalArgumentException("Class " + parentClass + " is final class."); } - for (var cs : getClasses()) { - - if (cs.isInterface() || cs == parentClass || !parentClass.isAssignableFrom(cs) || isAbstract(cs.getModifiers())) { + for (Class klass : classes) { + if (klass.isInterface() || + klass == parentClass || + !parentClass.isAssignableFrom(klass) || + isAbstract(klass.getModifiers())) { continue; } - - container.add(unsafeNNCast(cs)); + container.add(unsafeNNCast(klass)); } } @Override - public void findAnnotated(Array> container, Class annotationClass) { - for (var cs : getClasses()) { - - if (cs.isInterface() || isAbstract(cs.getModifiers()) || cs.isAnnotation() || !cs.isAnnotationPresent( - annotationClass)) { + public void findAnnotatedTo(Array> container, Class annotationClass) { + for (Class klass : classes) { + if (klass.isInterface() || + isAbstract(klass.getModifiers()) || + klass.isAnnotation() || + !klass.isAnnotationPresent(annotationClass)) { continue; } - - container.add(cs); + container.add(klass); } } @Override - public void getFoundClasses(Array> container) { - container.addAll(getClasses()); + public void foundClassesTo(Array> container) { + container.addAll(classes); } @Override - public void getFoundResources(Array container) { - container.addAll(getResources()); + public void foundResourcesTo(Array container) { + container.addAll(resources); } @Override - public Array> getFoundClasses() { - return Array.of(getClasses()); + public Array> foundClasses() { + return Array.of(classes); } @Override - public Array getFoundResources() { - return Array.of(getResources()); + public Array foundResources() { + return Array.of(resources); } - /** - * Get a list of paths to scan. - * - * @return the list of paths. - */ - protected String[] getPathsToScan() { + protected String[] calculatePathsToScan() { - var systemClasspath = useSystemClasspath() ? getClasspathPaths() : ArrayUtils.EMPTY_STRING_ARRAY; + var systemClasspath = useSystemClassPath() ? classpathPaths() : ArrayUtils.EMPTY_STRING_ARRAY; var capacity = additionalPaths.size() + systemClasspath.length; var result = Array.ofType(String.class, capacity); @@ -170,37 +163,10 @@ protected String[] getPathsToScan() { return result.toArray(String.class); } - /** - * Return true if need to scan the system classpath. - * - * @return true if need to scan the system classpath. - */ - protected boolean useSystemClasspath() { - return useSystemClassPath; - } - - @Override - public void setUseSystemClasspath(boolean useSystemClasspath) { - this.useSystemClassPath = useSystemClasspath; - } - - /** - * Get the list of paths of system classpath. - * - * @return the list of paths of system classpath. - */ - protected String[] getClasspathPaths() { + protected String[] classpathPaths() { return CLASS_PATH.split(PATH_SEPARATOR); } - /** - * Load a class by its name to container. - * - * @param rootPath the root folder. - * @param file the class file. - * @param name the name. - * @param container the container. - */ private void loadClass( @Nullable Path rootPath, @Nullable Path file, @@ -209,6 +175,12 @@ private void loadClass( if (!name.endsWith(CLASS_EXTENSION)) { return; + } else if(MODULE_INFO_CLASS.equals(name)) { + LOGGER.debug("Skip loading module-info..."); + return; + } else if(name.startsWith(META_INF_PREFIX)) { + LOGGER.debug("Skip loading META-INF class..."); + return; } String className; @@ -217,50 +189,40 @@ private void loadClass( StringBuilder result = new StringBuilder(name.length() - CLASS_EXTENSION.length()); for (int i = 0, length = name.length() - CLASS_EXTENSION.length(); i < length; i++) { - char ch = name.charAt(i); - if (ch == '/' || ch == '\\') { ch = '.'; } - result.append(ch); } className = result.toString(); } catch (Exception e) { - LOGGER.warning(name, arg -> "Incorrect replaced " + arg + " to java path, used separator " + File.separator); + LOGGER.warning(name, File.separator, "Incorrect replaced class name:[%s] to java path, used separator:[%s]"::formatted); return; } + LOGGER.debug(className, "Try to load class:[%s]"::formatted); try { - container.add(getLoader().loadClass(className)); + container.add(loader().loadClass(className)); } catch (NoClassDefFoundError error) { - LOGGER.warning( - "Can't load class: " + className + "\n" + "Original name:" + name + "\n" + "Root folder: " + rootPath + "\n" - + "Class file: " + file); + LOGGER.warning(className, name, rootPath, file, + "Can't load class:[%s] with original name:[%s], root folder:[%s] and class file:[%s]"::formatted); LOGGER.warning(error); } catch (Throwable e) { LOGGER.warning(e); } } - /** - * Scan a directory and find here classes, resources or jars. - * - * @param classes the classes container. - * @param resources the resources container. - * @param directory the directory. - */ private void scanDirectory( Path rootPath, Array> classes, Array resources, Path directory) { - - try (var stream = Files.newDirectoryStream(directory)) { - for (var file : stream) { + LOGGER.debug(directory, "Scanning directory:[%s]"::formatted); + try (DirectoryStream stream = Files.newDirectoryStream(directory)) { + for (Path file : stream) { if (Files.isDirectory(file)) { scanDirectory(rootPath, classes, resources, file); @@ -280,11 +242,10 @@ private void scanDirectory( .toString(); if (path.startsWith(File.separator)) { - path = path.substring(1, path.length()); + path = path.substring(1); } loadClass(rootPath, file, path, classes); - } else if (!filename.endsWith(Compiler.SOURCE_EXTENSION)) { String path = file @@ -292,7 +253,7 @@ private void scanDirectory( .toString(); if (path.startsWith(File.separator)) { - path = path.substring(1, path.length()); + path = path.substring(1); } resources.add(path); @@ -304,29 +265,22 @@ private void scanDirectory( } } - /** - * Scan a .jar to load classes. - * - * @param classes the classes container. - * @param resources the resources container. - * @param jarFile the .jar file. - */ private void scanJar(Array> classes, Array resources, Path jarFile) { + LOGGER.debug(jarFile, "Scanning jar:[%s]"::formatted); if (!Files.exists(jarFile)) { - LOGGER.warning(jarFile, arg -> "Not exists " + arg); + LOGGER.warning(jarFile, "Jar file:[%s] does not exists"::formatted); return; } var rout = new ReuseBytesOutputStream(); var rin = new ReuseBytesInputStream(); - var buffer = new byte[128]; try (var jin = new JarInputStream(Files.newInputStream(jarFile))) { scanJarInputStream(classes, resources, rout, rin, buffer, jin); } catch (ZipException e) { - LOGGER.warning(jarFile, arg -> "Can't open zip file " + arg); + LOGGER.warning(jarFile, "Can't open zip file:[%s]"::formatted); LOGGER.warning(e); } catch (IOException e) { LOGGER.warning(e); @@ -362,18 +316,11 @@ private void scanJarInputStream( } } - /** - * Scan a .jar to load classes. - * - * @param classes the classes container. - * @param resources the resources container. - * @param jarFile the input stream of a .jar. - */ private void scanJar(Array> classes, Array resources, InputStream jarFile) { + LOGGER.debug(jarFile, "Scanning jar:[%s]"::formatted); var rout = new ReuseBytesOutputStream(); var rin = new ReuseBytesInputStream(); - var buffer = new byte[128]; try (var jin = new JarInputStream(jarFile)) { @@ -389,20 +336,18 @@ private void scanJar(Array> classes, Array resources, InputStre @Override public void scan(@Nullable Predicate filter) { - var paths = getPathsToScan(); + var paths = calculatePathsToScan(); Array> classes = Array.ofType(Class.class); Array resources = Array.ofType(String.class); - for (var path : paths) { - - var file = Paths.get(path); - + for (String path : paths) { + var file = Path.of(path); if (!Files.exists(file) || (filter != null && !filter.test(path))) { continue; } - LOGGER.debug(file, arg -> "Scan " + arg); + LOGGER.debug(file, "Scanning file:[%s]"::formatted); var filename = file .getFileName() @@ -419,9 +364,9 @@ public void scan(@Nullable Predicate filter) { this.resources = resources.toArray(ArrayUtils.EMPTY_STRING_ARRAY); LOGGER.debug( - getClasses(), - getResources(), - (arg1, arg2) -> "Scanned " + arg1.length + " classes and " + arg2.length + " resources."); + classes().length, + resources().length, + "Scanned [%s] classes and [%s] resources"::formatted); } @Override diff --git a/rlib-common/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java similarity index 54% rename from rlib-common/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java rename to rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java index e145be7e..4ddcc931 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/ManifestClassPathScannerImpl.java @@ -1,31 +1,27 @@ package javasabr.rlib.common.classpath.impl; +import java.io.InputStream; +import java.net.URL; import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; -import javasabr.rlib.common.classpath.ClassPathScanner; import javasabr.rlib.common.util.Utils; import javasabr.rlib.common.util.array.Array; import javasabr.rlib.common.util.array.ArrayFactory; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** - * The implementation of the {@link ClassPathScanner} with parsing manifest file. - * * @author JavaSaBr */ -@NullMarked +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class ManifestClassPathScannerImpl extends ClassPathScannerImpl { - /** - * The roo class. - */ - private final Class rootClass; - - /** - * The classpath key. - */ - private final String classPathKey; + Class rootClass; + String classPathKey; public ManifestClassPathScannerImpl( ClassLoader classLoader, @@ -36,47 +32,38 @@ public ManifestClassPathScannerImpl( this.classPathKey = classPathKey; } - /** - * Get manifest class path. - * - * @return the class paths. - */ - protected String[] getManifestClassPath() { + protected String[] calculateManifestClassPath() { - var root = Utils.getRootFolderFromClass(rootClass); var result = Array.ofType(String.class); - var currentThread = Thread.currentThread(); - var loader = currentThread.getContextClassLoader(); - var urls = Utils.uncheckedGet(loader, arg -> arg.getResources(JarFile.MANIFEST_NAME)); + + Path root = Utils.getRootFolderFromClass(rootClass); + ClassLoader loader = currentThread.getContextClassLoader(); + Enumeration urls = Utils.uncheckedGet(loader, arg -> arg.getResources(JarFile.MANIFEST_NAME)); while (urls.hasMoreElements()) { try { - var url = urls.nextElement(); - var is = url.openStream(); - + URL url = urls.nextElement(); + InputStream is = url.openStream(); if (is == null) { LOGGER.warning(url, arg -> "not found input stream for the url " + arg); continue; } var manifest = new Manifest(is); - var attributes = manifest.getMainAttributes(); - - var value = attributes.getValue(classPathKey); + Attributes attributes = manifest.getMainAttributes(); + String value = attributes.getValue(classPathKey); if (value == null) { continue; } - var classpath = value.split(" "); - - for (var path : classpath) { - - var file = root.resolve(path); + String[] classpath = value.split(" "); + for (String path : classpath) { + Path file = root.resolve(path); if (Files.exists(file)) { result.add(file.toString()); } @@ -91,11 +78,11 @@ protected String[] getManifestClassPath() { } @Override - protected String[] getPathsToScan() { + protected String[] calculatePathsToScan() { var result = ArrayFactory.newArraySet(String.class); - result.addAll(super.getPathsToScan()); - result.addAll(getManifestClassPath()); + result.addAll(super.calculatePathsToScan()); + result.addAll(calculateManifestClassPath()); return result.toArray(String.class); } diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/package-info.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/package-info.java new file mode 100644 index 00000000..ce23c2a1 --- /dev/null +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.common.classpath.impl; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/package-info.java b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/package-info.java new file mode 100644 index 00000000..7b11faaf --- /dev/null +++ b/rlib-classpath/src/main/java/javasabr/rlib/common/classpath/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.common.classpath; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-classpath/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java b/rlib-classpath/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java new file mode 100644 index 00000000..4130ef73 --- /dev/null +++ b/rlib-classpath/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java @@ -0,0 +1,35 @@ +package javasabr.rlib.common.classpath; + +import java.util.Collection; +import javasabr.rlib.common.util.array.Array; +import javasabr.rlib.common.util.array.impl.AbstractArray; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author JavaSaBr + */ +public class ClasspathScannerTests { + + static { + LoggerManager.enable(ClassPathScanner.class, LoggerLevel.DEBUG); + } + + @Test + void testSystemClasspathScanner() { + + ClassPathScanner scanner = ClassPathScannerFactory.newDefaultScanner(); + scanner.useSystemClassPath(true); + scanner.scan(); + + Array> implementations = scanner.findImplementations(Collection.class); + + Assertions.assertFalse(implementations.isEmpty()); + + Array> inherited = scanner.findInherited(AbstractArray.class); + + Assertions.assertFalse(inherited.isEmpty()); + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java b/rlib-common/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java deleted file mode 100644 index 0844c296..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/classpath/ClassPathScanner.java +++ /dev/null @@ -1,200 +0,0 @@ -package javasabr.rlib.common.classpath; - -import java.lang.annotation.Annotation; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.function.Predicate; -import javasabr.rlib.common.classpath.impl.ClassPathScannerImpl; -import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayFactory; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * THe interface to implement a classpath scanner. - * - * @author JavaSaBr - */ -@NullMarked -public interface ClassPathScanner { - - String JAR_EXTENSION = ".jar"; - - ClassPathScanner NULL_SCANNER = null; - - ClassPathScanner EMPTY_SCANNER = new ClassPathScannerImpl(ClassPathScanner.class.getClassLoader()) { - - @Override - public void addClasses(Array> classes) { - } - - @Override - public void addAdditionalPath(String path) { - } - - @Override - public void addAdditionalPaths(String[] paths) { - } - - @Override - public void addResources(Array resources) { - } - - @Override - public void scan(Predicate filter) { - } - }; - - URLClassLoader EMPTY_CLASS_LOADER = new URLClassLoader(new URL[0], ClassPathScanner.class.getClassLoader()); - - @Nullable URLClassLoader NULL_CLASS_LOADER = null; - - /** - * Add some classes to this scanner. - * - * @param classes the classes. - */ - void addClasses(Array> classes); - - /** - * Add some resources to this scanner. - * - * @param resources the resources. - */ - void addResources(Array resources); - - /** - * Sets the flat of using system classpath. - * - * @param useSystemClasspath true if need to use system classpath. - */ - void setUseSystemClasspath(boolean useSystemClasspath); - - /** - * Find all implementations of the interface class. - * - * @param interfaceClass the interface class. - * @param the first argument's type. - * @return the list of found implementations. - */ - default Array> findImplements(Class interfaceClass) { - Array> result = ArrayFactory.newArray(Class.class); - findImplements(result, interfaceClass); - return result; - } - - /** - * Find all implementations of the interface class. - * - * @param container the container. - * @param interfaceClass the interface class. - * @param the interface's type. - */ - void findImplements(Array> container, Class interfaceClass); - - /** - * Find all inheriting classes of the parent class. - * - * @param parentClass the parent class. - * @param the classes type. - * @return the list of found inherited classes. - */ - default Array> findInherited(Class parentClass) { - Array> result = ArrayFactory.newArray(Class.class); - findInherited(result, parentClass); - return result; - } - - /** - * Find all inheriting classes of the parent class. - * - * @param container the container. - * @param parentClass the parent class. - * @param the parent classes type. - */ - void findInherited(Array> container, Class parentClass); - - /** - * Find all classes annotated via specified annotation.
Exclude class types:
    - *
  • Interfaces
  • - *
  • Abstract classes
  • - *
  • Annotations
  • - *
- * - * @param annotationClass the annotation class. - * @return the list of found annotated classes. - */ - default Array> findAnnotated(Class annotationClass) { - Array> result = ArrayFactory.newArray(Class.class); - findAnnotated(result, annotationClass); - return result; - } - - /** - * Find all classes annotated via specified annotation.
Exclude class types:
    - *
  • Interfaces
  • - *
  • Abstract classes
  • - *
  • Annotations
  • - *
- * - * @param container the container. - * @param annotationClass the annotation class. - */ - void findAnnotated(Array> container, Class annotationClass); - - /** - * Get all found classes. - * - * @param container the container. - */ - void getFoundClasses(Array> container); - - /** - * Get all found resources. - * - * @param container the container. - */ - void getFoundResources(Array container); - - /** - * Get all found classes. - * - * @return the array of all found classes. - */ - Array> getFoundClasses(); - - /** - * Get all found resources. - * - * @return the array of all found resources. - */ - Array getFoundResources(); - - /** - * Start scanning classpath. - */ - default void scan() { - scan(null); - } - - /** - * Start scanning classpath. - * - * @param filter the filter. - */ - void scan(@Nullable Predicate filter); - - /** - * Add the additional path to scan. - * - * @param path the additional path. - */ - void addAdditionalPath(String path); - - /** - * Add the additional paths to scan. - * - * @param paths the additional paths. - */ - void addAdditionalPaths(String[] paths); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java deleted file mode 100644 index d7fc3634..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/classpath/ClassPathScannerFactory.java +++ /dev/null @@ -1,71 +0,0 @@ -package javasabr.rlib.common.classpath; - -import javasabr.rlib.common.classpath.impl.ClassPathScannerImpl; -import javasabr.rlib.common.classpath.impl.ManifestClassPathScannerImpl; -import org.jspecify.annotations.NullMarked; - -/** - * The factory of classpath scanners. - * - * @author JavaSaBr - */ -@NullMarked -public final class ClassPathScannerFactory { - - /** - * Create a new default class path scanner. - * - * @return the new class path scanner. - */ - public static ClassPathScanner newDefaultScanner() { - return new ClassPathScannerImpl(ClassPathScannerFactory.class.getClassLoader()); - } - - /** - * Create a new default class path scanner. - * - * @param classLoader the class loader. - * @return the new class path scanner. - */ - public static ClassPathScanner newDefaultScanner(ClassLoader classLoader) { - return new ClassPathScannerImpl(classLoader); - } - - /** - * Create a new default class path scanner with additional class paths. - * - * @param classLoader the class loader. - * @param additionalPaths the additional class paths. - * @return the new class path scanner. - */ - public static ClassPathScanner newDefaultScanner(ClassLoader classLoader, String[] additionalPaths) { - var scanner = new ClassPathScannerImpl(classLoader); - scanner.addAdditionalPaths(additionalPaths); - return scanner; - } - - /** - * Create a new manifest class path scanner. - * - * @param rootClass the root class. - * @return the new class path scanner. - */ - public static ClassPathScanner newManifestScanner(Class rootClass) { - return new ManifestClassPathScannerImpl(ClassPathScannerFactory.class.getClassLoader(), rootClass, "Class-Path"); - } - - /** - * Create a new manifest class path scanner. - * - * @param rootClass the root class. - * @param classPathKey the class path key. - * @return the new class path scanner. - */ - public static ClassPathScanner newManifestScanner(Class rootClass, String classPathKey) { - return new ManifestClassPathScannerImpl(ClassPathScannerFactory.class.getClassLoader(), rootClass, classPathKey); - } - - private ClassPathScannerFactory() { - throw new RuntimeException(); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java b/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java index ef962c50..01edb66a 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java @@ -2,14 +2,6 @@ import org.jspecify.annotations.NullUnmarked; -/** - * The function. - * - * @param the type parameter - * @param the type parameter - * @param the type parameter - * @author JavaSaBr - */ @NullUnmarked @FunctionalInterface public interface TriplePredicate { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/DirectionType.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/DirectionType.java deleted file mode 100644 index 076be43d..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/DirectionType.java +++ /dev/null @@ -1,33 +0,0 @@ -package javasabr.rlib.common.geom; - -/** - * The list od direction types. - * - * @author JavaSaBr - */ -public enum DirectionType { - /** - * Left direction type. - */ - LEFT, - /** - * Up direction type. - */ - UP, - /** - * Front direction type. - */ - FRONT, - /** - * Right direction type. - */ - RIGHT, - /** - * Down direction type. - */ - DOWN, - /** - * Behind direction type. - */ - BEHIND -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Ray3f.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/Ray3f.java deleted file mode 100644 index aad31a67..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Ray3f.java +++ /dev/null @@ -1,82 +0,0 @@ -package javasabr.rlib.common.geom; - -import javasabr.rlib.common.util.pools.Reusable; -import org.jspecify.annotations.NullMarked; - -/** - * The implementation of a ray. - * - * @author JavaSaBr - */ -@NullMarked -public class Ray3f implements Reusable { - - /** - * The start point of this ray. - */ - private final Vector3f start; - - /** - * The direction of this ray. - */ - private final Vector3f direction; - - /** - * Construct new ray in start point and specified direction. - * - * @param origin start point - * @param direction direction - */ - public Ray3f(Vector3f origin, Vector3f direction) { - this.start = origin; - this.direction = direction; - } - - /** - * Construct empty ray in zero point and zero direction. - */ - public Ray3f() { - this(new Vector3f(), new Vector3f()); - } - - /** - * Get the direction. - * - * @return the direction. - */ - public final Vector3f getDirection() { - return direction; - } - - /** - * Set the direction. - * - * @param direction the direction. - */ - public final void setDirection(Vector3f direction) { - this.direction.set(direction); - } - - /** - * Get the start point. - * - * @return the start point. - */ - public final Vector3f getStart() { - return start; - } - - /** - * Set the start point. - * - * @param start the start point. - */ - public final void setStart(Vector3f start) { - this.start.set(start); - } - - @Override - public String toString() { - return "Ray3f{" + "start=" + start + ", direction=" + direction + '}'; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/Bounding.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/Bounding.java deleted file mode 100644 index 41872d06..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/Bounding.java +++ /dev/null @@ -1,135 +0,0 @@ -package javasabr.rlib.common.geom.bounding; - -import javasabr.rlib.common.geom.Quaternion4f; -import javasabr.rlib.common.geom.Ray3f; -import javasabr.rlib.common.geom.Vector3f; -import javasabr.rlib.common.geom.Vector3fBuffer; -import org.jspecify.annotations.NullMarked; - -/** - * The interface to implement a bounding of objects. - * - * @author JavaSaBr - */ -@NullMarked -public interface Bounding { - - /** - * Return true if this bounding contains the point. - * - * @param x the X coordinate. - * @param y the Y coordinate. - * @param z the X coordinate. - * @return true if this bounding contains the point. - */ - boolean contains(float x, float y, float z); - - /** - * Return true if this bounding contains the point. - * - * @param point the point. - * @return true if this bounding contains the point. - */ - boolean contains(Vector3f point); - - /** - * Get a distance from a center of a bounding to a point. - * - * @param point the point. - * @return the distance. - */ - float distanceTo(Vector3f point); - - /** - * Get a type of a bounding. - * - * @return the type. - */ - BoundingType getBoundingType(); - - /** - * Get a center of a bounding. - * - * @return the center. - */ - Vector3f getCenter(); - - /** - * Change a center of a bounding. - * - * @param center the new center. - */ - void setCenter(Vector3f center); - - /** - * Get an offset of a bounding. - * - * @return the offset. - */ - Vector3f getOffset(); - - /** - * Get a result center of this bounding. - * - * @param buffer the vector buffer. - * @return the result center. - */ - Vector3f getResultCenter(Vector3fBuffer buffer); - - /** - * Get a result X coordinate of the center of this bounding. - * - * @return the result X coordinate. - */ - float getResultCenterX(); - - /** - * Get a result Y coordinate of the center of this bounding. - * - * @return the result Y coordinate. - */ - float getResultCenterY(); - - /** - * Get a result Z coordinate of the center of this bounding. - * - * @return the result X coordinate. - */ - float getResultCenterZ(); - - /** - * Check this bounding that it intersects with an other bounding. - * - * @param bounding the other bounding. - * @param buffer the vector buffer. - * @return true if this bounding interests with other bounding. - */ - boolean intersects(Bounding bounding, Vector3fBuffer buffer); - - /** - * Check this bounding that it intersects with a ray. - * - * @param ray the ray. - * @param buffer the vector buffer. - * @return true if this bounding interests with the ray. - */ - boolean intersects(Ray3f ray, Vector3fBuffer buffer); - - /** - * Check this bounding that it intersects with a ray. - * - * @param start the start point of the ray. - * @param direction the direction of the ray. - * @param buffer the vector buffer. - * @return true if this bounding interests with the ray. - */ - boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer); - - /** - * Update a rotation of a bounding. - * - * @param rotation the rotation. - * @param buffer the vector buffer. - */ - void update(Quaternion4f rotation, Vector3fBuffer buffer); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/BoundingFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/BoundingFactory.java deleted file mode 100644 index 22d30738..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/BoundingFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -package javasabr.rlib.common.geom.bounding; - -import javasabr.rlib.common.geom.Vector3f; -import javasabr.rlib.common.geom.bounding.impl.AbstractBounding; -import javasabr.rlib.common.geom.bounding.impl.AxisAlignedBoundingBox; -import javasabr.rlib.common.geom.bounding.impl.BoundingSphere; -import org.jspecify.annotations.NullMarked; - -/** - * The bounding's factory. - * - * @author JavaSaBr - */ -@NullMarked -public final class BoundingFactory { - - /** - * Creates a new bounding box. - * - * @param center the center. - * @param offset the offset. - * @param sizeX the size x. - * @param sizeY the size y. - * @param sizeZ the size z. - * @return the new bounding box. - */ - public static Bounding newBoundingBox( - Vector3f center, - Vector3f offset, - float sizeX, - float sizeY, - float sizeZ) { - return new AxisAlignedBoundingBox(center, offset, sizeX, sizeY, sizeZ); - } - - /** - * Creates a new empty bounding. - * - * @return the new empty bounding. - */ - public static Bounding newBoundingEmpty() { - return new AbstractBounding(new Vector3f(), new Vector3f()) {}; - } - - /** - * Creates a new bounding sphere. - * - * @param center the center. - * @param offset the offset. - * @param radius the radius. - * @return the bounding sphere. - */ - public static Bounding newBoundingSphere(Vector3f center, Vector3f offset, float radius) { - return new BoundingSphere(center, offset, radius); - } - - private BoundingFactory() { - throw new IllegalArgumentException(); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/BoundingType.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/BoundingType.java deleted file mode 100644 index 021fae9a..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/BoundingType.java +++ /dev/null @@ -1,21 +0,0 @@ -package javasabr.rlib.common.geom.bounding; - -/** - * The list of bounding types. - * - * @author JavaSaBr - */ -public enum BoundingType { - /** - * Axis aligned box bounding type. - */ - AXIS_ALIGNED_BOX, - /** - * Sphere bounding type. - */ - SPHERE, - /** - * Empty bounding type. - */ - EMPTY, -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/AbstractBounding.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/AbstractBounding.java deleted file mode 100644 index e64fd3d0..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/AbstractBounding.java +++ /dev/null @@ -1,110 +0,0 @@ -package javasabr.rlib.common.geom.bounding.impl; - -import javasabr.rlib.common.geom.Quaternion4f; -import javasabr.rlib.common.geom.Ray3f; -import javasabr.rlib.common.geom.Vector3f; -import javasabr.rlib.common.geom.Vector3fBuffer; -import javasabr.rlib.common.geom.bounding.Bounding; -import javasabr.rlib.common.geom.bounding.BoundingType; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import org.jspecify.annotations.NullMarked; - -/** - * The base implementation of a bounding. - * - * @author JavaSaBr - */ -@NullMarked -public abstract class AbstractBounding implements Bounding { - - protected static final Logger LOGGER = LoggerManager.getLogger(Bounding.class); - - /** - * The center. - */ - protected Vector3f center; - - /** - * The offset. - */ - protected Vector3f offset; - - protected AbstractBounding(Vector3f center, Vector3f offset) { - this.center = center; - this.offset = offset; - } - - @Override - public boolean contains(float x, float y, float z) { - return false; - } - - @Override - public boolean contains(Vector3f point) { - return contains(point.getX(), point.getY(), point.getZ()); - } - - @Override - public final float distanceTo(Vector3f point) { - return center.distance(point); - } - - @Override - public BoundingType getBoundingType() { - return BoundingType.EMPTY; - } - - @Override - public final Vector3f getCenter() { - return center; - } - - @Override - public void setCenter(Vector3f center) { - this.center = center; - } - - @Override - public Vector3f getOffset() { - return offset; - } - - @Override - public Vector3f getResultCenter(Vector3fBuffer buffer) { - return getCenter(); - } - - @Override - public float getResultCenterX() { - return getCenter().getX(); - } - - @Override - public float getResultCenterY() { - return getCenter().getY(); - } - - @Override - public float getResultCenterZ() { - return getCenter().getZ(); - } - - @Override - public boolean intersects(Bounding bounding, Vector3fBuffer buffer) { - return false; - } - - @Override - public final boolean intersects(Ray3f ray, Vector3fBuffer buffer) { - return intersects(ray.getStart(), ray.getDirection(), buffer); - } - - @Override - public boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer) { - return false; - } - - @Override - public void update(Quaternion4f rotation, Vector3fBuffer buffer) {} -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/AxisAlignedBoundingBox.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/AxisAlignedBoundingBox.java deleted file mode 100644 index 73441844..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/AxisAlignedBoundingBox.java +++ /dev/null @@ -1,278 +0,0 @@ -package javasabr.rlib.common.geom.bounding.impl; - -import javasabr.rlib.common.geom.Matrix3f; -import javasabr.rlib.common.geom.Quaternion4f; -import javasabr.rlib.common.geom.Vector3f; -import javasabr.rlib.common.geom.Vector3fBuffer; -import javasabr.rlib.common.geom.bounding.Bounding; -import javasabr.rlib.common.geom.bounding.BoundingType; -import org.jspecify.annotations.NullMarked; - -/** - * The implementation AxisAlignedBoundingBox. - * - * @author JavaSaBr - */ -@NullMarked -public class AxisAlignedBoundingBox extends AbstractBounding { - - /** - * The matrix. - */ - private final Matrix3f matrix; - - /** - * The vector size. - */ - private final Vector3f size; - - /** - * The size X. - */ - protected float sizeX; - - /** - * The size Y. - */ - protected float sizeY; - - /** - * The size Z. - */ - protected float sizeZ; - - /** - * The offset X. - */ - protected float offsetX; - - /** - * The offset Y. - */ - protected float offsetY; - - /** - * The offset Z. - */ - protected float offsetZ; - - public AxisAlignedBoundingBox(Vector3f center, Vector3f offset, float sizeX, float sizeY, float sizeZ) { - super(center, offset); - this.matrix = new Matrix3f(); - this.size = new Vector3f(sizeX, sizeY, sizeZ); - this.sizeX = sizeX; - this.sizeY = sizeY; - this.sizeZ = sizeZ; - this.offsetX = offset.getX(); - this.offsetY = offset.getY(); - this.offsetZ = offset.getZ(); - } - - @Override - public boolean contains(float x, float y, float z) { - return Math.abs(getResultCenterX() - x) < sizeX && Math.abs(getResultCenterY() - y) < sizeY - && Math.abs(getResultCenterZ() - z) < sizeZ; - } - - @Override - public BoundingType getBoundingType() { - return BoundingType.AXIS_ALIGNED_BOX; - } - - @Override - public Vector3f getResultCenter(Vector3fBuffer buffer) { - - Vector3f vector = buffer - .nextVector() - .set(center); - - if (offset.isZero()) { - return vector; - } - - return vector.addLocal(offsetX, offsetY, offsetZ); - } - - @Override - public float getResultCenterZ() { - return center.getZ() + offsetZ; - } - - @Override - public float getResultCenterY() { - return center.getY() + offsetY; - } - - @Override - public float getResultCenterX() { - return center.getX() + offsetX; - } - - /** - * Get the size by X coordinates. - * - * @return the size. - */ - protected final float getSizeX() { - return sizeX; - } - - /** - * Get the size by Y coordinates. - * - * @return the size. - */ - protected final float getSizeY() { - return sizeY; - } - - /** - * Get the size by Z coordinates. - * - * @return the size. - */ - protected final float getSizeZ() { - return sizeZ; - } - - /** - * Get a copy of the AABB's size vector. - * - * @return AABB's size. - */ - public Vector3f getSize() { - return new Vector3f(size); - } - - /** - * Get AABB's size. - * - * @param buffer the vector buffer. - * @return AABB's size. - */ - public Vector3f getSize(Vector3fBuffer buffer) { - return buffer - .nextVector() - .set(size); - } - - @Override - public boolean intersects(Bounding bounding, Vector3fBuffer buffer) { - switch (bounding.getBoundingType()) { - case EMPTY: { - return false; - } - case AXIS_ALIGNED_BOX: { - - AxisAlignedBoundingBox box = (AxisAlignedBoundingBox) bounding; - - Vector3f target = box.getResultCenter(buffer); - Vector3f center = getResultCenter(buffer); - - float sizeX = getSizeX(); - float sizeY = getSizeY(); - float sizeZ = getSizeZ(); - - if (center.getX() + sizeX < target.getX() - box.getSizeX() - || center.getX() - sizeX > target.getX() + box.getSizeX()) { - return false; - } else if (center.getY() + sizeY < target.getY() - box.getSizeY() - || center.getY() - sizeY > target.getY() + box.getSizeY()) { - return false; - } else if (center.getZ() + sizeZ < target.getZ() - box.getSizeZ() - || center.getZ() - sizeZ > target.getZ() + box.getSizeZ()) { - return false; - } - - return true; - } - case SPHERE: { - - BoundingSphere sphere = (BoundingSphere) bounding; - - Vector3f target = sphere.getResultCenter(buffer); - Vector3f center = getResultCenter(buffer); - - float radius = sphere.getRadius(); - - if (Math.abs(center.getX() - target.getX()) > radius + getSizeX()) { - return false; - } else if (Math.abs(center.getY() - target.getY()) > radius + getSizeY()) { - return false; - } else { - return !(Math.abs(center.getZ() - target.getZ()) > radius + getSizeZ()); - } - - } - default: { - LOGGER.warning(new IllegalArgumentException("incorrect bounding type " + bounding.getBoundingType())); - } - } - - return false; - } - - @Override - public boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer) { - - float divX = 1.0F / (Float.compare(direction.getX(), 0) == 0 ? 0.00001F : direction.getX()); - float divY = 1.0F / (Float.compare(direction.getY(), 0) == 0 ? 0.00001F : direction.getY()); - float divZ = 1.0F / (Float.compare(direction.getZ(), 0) == 0 ? 0.00001F : direction.getZ()); - - float sizeX = getSizeX() * 0.5F; - float sizeY = getSizeY() * 0.5F; - float sizeZ = getSizeZ() * 0.5F; - - Vector3f center = getResultCenter(buffer); - - float minX = center.getX() - sizeX; - float minY = center.getY() - sizeY; - float minZ = center.getZ() - sizeZ; - - float maxX = center.getX() + sizeX; - float maxY = center.getY() + sizeY; - float maxZ = center.getZ() + sizeZ; - - float t1 = (minX - start.getX()) * divX; - float t2 = (maxX - start.getX()) * divX; - float t3 = (minY - start.getY()) * divY; - float t4 = (maxY - start.getY()) * divY; - float t5 = (minZ - start.getZ()) * divZ; - float t6 = (maxZ - start.getZ()) * divZ; - - float tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6)); - float tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6)); - - return tmin <= tmax && tmax > 0.f; - } - - @Override - public void update(Quaternion4f rotation, Vector3fBuffer buffer) { - - matrix.set(rotation); - matrix.absoluteLocal(); - - Vector3f vector = matrix.mult(size, buffer.nextVector()); - - sizeX = Math.abs(vector.getX()); - sizeY = Math.abs(vector.getY()); - sizeZ = Math.abs(vector.getZ()); - - if (offset.isZero()) { - return; - } - - matrix.mult(offset, vector); - - offsetX = vector.getX(); - offsetY = vector.getY(); - offsetZ = vector.getZ(); - } - - @Override - public String toString() { - return getClass().getSimpleName() + " size = " + size + ", sizeX = " + sizeX + ", sizeY = " + sizeY + ", sizeZ = " - + sizeZ + ", center = " + center + ", offset = " + offset; - } - -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/BoundingSphere.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/BoundingSphere.java deleted file mode 100644 index 8807bf6e..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/bounding/impl/BoundingSphere.java +++ /dev/null @@ -1,146 +0,0 @@ -package javasabr.rlib.common.geom.bounding.impl; - -import static java.lang.Math.abs; - -import javasabr.rlib.common.geom.Vector3f; -import javasabr.rlib.common.geom.Vector3fBuffer; -import javasabr.rlib.common.geom.bounding.Bounding; -import javasabr.rlib.common.geom.bounding.BoundingType; -import javasabr.rlib.common.geom.util.GeometryUtils; -import org.jspecify.annotations.NullMarked; - -/** - * The implementation of sphere bounding. - * - * @author JavaSaBr - */ -@NullMarked -public class BoundingSphere extends AbstractBounding { - - /** - * The sphere radius. - */ - protected float radius; - - /** - * The square radius. - */ - protected float squareRadius; - - public BoundingSphere(Vector3f center, Vector3f offset, float radius) { - super(center, offset); - - this.radius = radius; - this.squareRadius = radius * radius; - } - - @Override - public boolean contains(float x, float y, float z) { - - float startX = getResultCenterX(); - float centerY = getResultCenterY(); - float centerZ = getResultCenterZ(); - - return GeometryUtils.getSquareDistance(startX, centerY, centerZ, x, y, z) < squareRadius; - } - - @Override - public float getResultCenterZ() { - return center.getZ() + offset.getZ(); - } - - @Override - public float getResultCenterY() { - return center.getY() + offset.getY(); - } - - @Override - public float getResultCenterX() { - return center.getX() + offset.getX(); - } - - @Override - public BoundingType getBoundingType() { - return BoundingType.SPHERE; - } - - /** - * Get the sphere's radius. - * - * @return the sphere's radius. - */ - public float getRadius() { - return radius; - } - - @Override - public Vector3f getResultCenter(Vector3fBuffer buffer) { - - Vector3f vector = buffer - .nextVector() - .set(center); - - if (offset.isZero()) { - return vector; - } - - return vector.addLocal(offset); - } - - @Override - public boolean intersects(Bounding bounding, Vector3fBuffer buffer) { - switch (bounding.getBoundingType()) { - case EMPTY: { - return false; - } - case SPHERE: { - - BoundingSphere sphere = (BoundingSphere) bounding; - - Vector3f diff = getResultCenter(buffer).subtractLocal(sphere.getResultCenter(buffer)); - - float rsum = getRadius() + sphere.getRadius(); - - return diff.dot(diff) <= rsum * rsum; - } - case AXIS_ALIGNED_BOX: { - - AxisAlignedBoundingBox box = (AxisAlignedBoundingBox) bounding; - - Vector3f center = getResultCenter(buffer); - Vector3f target = box.getResultCenter(buffer); - - return abs(target.getX() - center.getX()) < getRadius() + box.getSizeX() - && abs(target.getY() - center.getY()) < getRadius() + box.getSizeY() - && abs(target.getZ() - center.getZ()) < getRadius() + box.getSizeZ(); - } - } - - return false; - } - - @Override - public boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer) { - - Vector3f diff = buffer - .nextVector() - .set(start) - .subtractLocal(getResultCenter(buffer)); - - float a = start.dot(diff) - squareRadius; - - if (a <= 0.0) { - return true; - } - - float b = direction.dot(diff); - - return b < 0.0 && b * b >= a; - - } - - @Override - public String toString() { - return getClass().getSimpleName() + " [radius=" + radius + ", squareRadius=" + squareRadius + "]"; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/util/AngleUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/util/AngleUtils.java deleted file mode 100644 index 7f97c85b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/util/AngleUtils.java +++ /dev/null @@ -1,176 +0,0 @@ -package javasabr.rlib.common.geom.util; - -import org.jspecify.annotations.NullMarked; - -/** - * Реализация утильного класса с методами по работе с углами. - * - * @author JavaSaBr - */ -@NullMarked -public final class AngleUtils { - - /** - * The constant HEADINGS_IN_PI. - */ - public static final float HEADINGS_IN_PI = 10430.378350470452724949566316381F; - /** - * The constant PI. - */ - public static final float PI = 3.14159265358979323846F; - - /** - * Расчет разворота в указанные координаты. - * - * @param x начальная координата. - * @param y начальная координата. - * @param targetX целевая координата. - * @param targetY целевая координата. - * @return нужный разворот. - */ - public static int calcHeading(float x, float y, float targetX, float targetY) { - return (int) (Math.atan2(y - targetY, x - targetX) * HEADINGS_IN_PI) + 32768; - } - - /** - * Расчет относительного положения. - * - * @param x начальная координата. - * @param y начальная координата. - * @param heading разворот. - * @param targetX целевая координата. - * @param targetY целевая координата. - * @return нужный разворот. - */ - public static int calcHeadingTo(float x, float y, int heading, float targetX, float targetY) { - - int newHeading = calcHeading(x, y, targetX, targetY); - - newHeading = heading - newHeading; - - if (newHeading < 0) { - newHeading = newHeading + 1 + Integer.MAX_VALUE & 0xFFFF; - } else if (newHeading > 0xFFFF) { - newHeading &= 0xFFFF; - } - - return newHeading; - } - - /** - * Конвектирует градус в heading. - * - * @param degree кол-во градусов. - * @return heading направление разворота. - */ - public static int degreeToHeading(float degree) { - if (degree < 0) { - degree += 360f; - } - return (int) (degree * 182.044444444f); - } - - /** - * Конвектирование градусы в радианы. - * - * @param angle кол-во градусов. - * @return кол -во радианов. - */ - public static float degreeToRadians(float angle) { - return angle * PI / 180F; - } - - /** - * Получаем относительный градус между 2 точками. - * - * @param startX х координата первой точки. - * @param startY у координата второй точки. - * @param endX х координата второй точки. - * @param endY у координата второй точки. - * @return кол -во градусов. - */ - public static float getAngleFrom(float startX, float startY, float endX, float endY) { - float angle = (float) Math.toDegrees(Math.atan2(startY - endY, startX - endX)); - if (angle <= 0F) { - angle += 360F; - } - return angle; - } - - /** - * Конвектирование heading в градусы. - * - * @param heading направление разворота. - * @return кол -во градусов. - */ - public static float headingToDegree(int heading) { - float angle = heading / 182.044444444f; - if (angle == 0) { - angle = 360f; - } - return angle; - } - - /** - * Конвектирование heading в радианы. - * - * @param heading направление разворота. - * @return кол -во радианов. - */ - public static float headingToRadians(int heading) { - float angle = heading / 182.044444444f; - if (angle == 0) { - angle = 360f; - } - return angle * 3.141592653f / 180f; - } - - /** - * Рассчет вхождения в относительную область перед точкой точки. - * - * @param x координата первой точки. - * @param y координата первой точки. - * @param heading направление области. - * @param targetX координата второй точки. - * @param targetY координата второй точки. - * @param width ширина области. - * @return входит ли. - */ - public static boolean isInDegree(float x, float y, int heading, float targetX, float targetY, int width) { - - int angle = (int) AngleUtils.headingToDegree(calcHeadingTo(x, y, heading, targetX, targetY)); - final int degree = (int) headingToDegree(heading); - - int min = degree - width; - int max = degree + width; - - if (min < 0) { - min += 360; - } - if (max < 0) { - max += 360; - } - - final boolean flag = angle - degree > 180; - if (flag) { - angle -= 360; - } - if (angle > max) { - return false; - } - - angle += 360; - - return angle > min; - } - - /** - * Конвектироввание радианов в градусы. - * - * @param radians угол в радианах. - * @return угол в градусах. - */ - public static float radiansToDegree(float radians) { - return radians * 180F / PI; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/util/CoordsUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/util/CoordsUtils.java deleted file mode 100644 index c2370431..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/util/CoordsUtils.java +++ /dev/null @@ -1,272 +0,0 @@ -package javasabr.rlib.common.geom.util; - -import java.util.concurrent.ThreadLocalRandom; -import javasabr.rlib.common.geom.Vector3f; -import javasabr.rlib.common.util.ExtMath; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import org.jspecify.annotations.NullMarked; - -/** - * Реализация утильного класса с методами для рассчета координат. - * - * @author JavaSaBr - */ -@NullMarked -public final class CoordsUtils { - - private static final Logger LOGGER = LoggerManager.getLogger(CoordsUtils.class); - - /** - * Генерация дуговых позиций. - * - * @param x целевая координата. - * @param y целевая координата. - * @param z целевая координата. - * @param heading разворот. - * @param radius радиус формирования. - * @param count кол-во необходимых позиций. - * @param degree положение на окружности центра дуги. - * @param width ширина дуги. - * @return массив позиций. - */ - public static Vector3f[] arcCoords( - float x, - float y, - float z, - int heading, - int radius, - int count, - int degree, - int width) { - - Vector3f[] vectors = new Vector3f[count]; - float current = AngleUtils.headingToDegree(heading) - degree; - - float min = current - width; - float max = current + width; - - float angle = Math.abs(min - max) / count; - - for (int i = 0; i < count; i++) { - - Vector3f vector = new Vector3f(); - - float radians = AngleUtils.degreeToRadians(min + angle * i); - - float newX = calcX(x, radius, radians); - float newY = calcY(y, radius, radians); - - vector.set(newX, newY, z); - - vectors[i] = vector; - } - - return vectors; - } - - /** - * Рассчет х координаты с учетом дистанции и разворота. - * - * @param x стартовая х координата. - * @param distance дистанция сдвига. - * @param radians направление сдвига. - * @return новая х координата. - */ - public static float calcX(float x, int distance, float radians) { - return x + distance * (float) Math.cos(radians); - } - - /** - * Рассчет х координаты с учетом дистанции и разворота. - * - * @param x стартовая х координата. - * @param distance дистанция сдвига. - * @param heading направление сдвига. - * @return новая х координата. - */ - public static float calcX(float x, int distance, int heading) { - return x + distance * (float) Math.cos(AngleUtils.headingToRadians(heading)); - } - - /** - * Рассчет х координаты с учетом дистанции и разворота. - * - * @param x стартовая х координата. - * @param distance дистанция сдвига. - * @param heading направление сдвига. - * @param offset смещение по градусам. - * @return новая х координата. - */ - public static float calcX(float x, int distance, int heading, int offset) { - return x + distance * (float) Math.cos(AngleUtils.headingToRadians(heading + offset)); - } - - /** - * Рассчет у координаты с учетом дистанции и разворота. - * - * @param y стартовая у координата. - * @param distance дистанция сдвига. - * @param radians направление сдвига. - * @return новая у координата. - */ - public static float calcY(float y, int distance, float radians) { - return y + distance * (float) Math.sin(radians); - } - - /** - * Рассчет у координаты с учетом дистанции и разворота. - * - * @param y стартовая у координата. - * @param distance дистанция сдвига. - * @param heading направление сдвига. - * @return новая у координата. - */ - public static float calcY(float y, int distance, int heading) { - return y + distance * (float) Math.sin(AngleUtils.headingToRadians(heading)); - } - - /** - * Рассчет у координаты с учетом дистанции и разворота. - * - * @param y стартовая у координата. - * @param distance дистанция сдвига. - * @param heading направление сдвига. - * @param offset смещение по градусам. - * @return новая у координата. - */ - public static float calcY(float y, int distance, int heading, int offset) { - return y + distance * (float) Math.sin(AngleUtils.headingToRadians(heading + offset)); - } - - /** - * Генерация массива круговых позиций с одинаковым интервлаом. - * - * @param x центральная координата. - * @param y центральная координата. - * @param z центральная координата. - * @param radius радиус разброса. - * @param count кол-во позиций. - * @return массив позиций. - */ - @SuppressWarnings("unchecked") - public static Vector3f[] circularCoords(float x, float y, float z, int radius, int count) { - - Vector3f[] locs = new Vector3f[count]; - float angle = 360F / count; - - for (int i = 1; i <= count; i++) { - - Vector3f loc = new Vector3f(); - float radians = AngleUtils.degreeToRadians(i * angle); - - float newX = calcX(x, radius, radians); - float newY = calcY(y, radius, radians); - - loc.set(newX, newY, z); - - locs[i - 1] = loc; - } - - return locs; - } - - /** - * Получение точек по кругу от указанной точки. - * - * @param source массив исходных точек. - * @param x координата центра. - * @param y координата центра. - * @param z координата центра. - * @param count кол-во точек. - * @param radius радиус от центра. - * @return массив точек. - */ - public static Vector3f[] getCircularPoints( - Vector3f[] source, - float x, - float y, - float z, - int count, - int radius) { - - if (count < 1) { - return source; - } - - float angle = 360F / count; - - for (int i = 1; i <= count; i++) { - - float radians = AngleUtils.degreeToRadians(angle * i); - - float newX = x + radius * (float) Math.cos(radians); - float newY = y + radius * (float) Math.sin(radians); - - Vector3f point = source[i - 1]; - - point.set(newX, newY, z); - } - - return source; - } - - /** - * Рассчет случайной точки. - * - * @param loc the loc - * @param x центральная координата. - * @param y центральная координата. - * @param z центральная координата. - * @param radiusMin минимальный радиус рандома. - * @param radiusMax максимальный радиус рандома. - * @return новая точка. - */ - public static Vector3f randomCoords( - Vector3f loc, - float x, - float y, - float z, - int radiusMin, - int radiusMax) { - - ThreadLocalRandom current = ThreadLocalRandom.current(); - - if (radiusMax == 0 || radiusMax < radiusMin) { - loc.set(x, y, z); - return loc; - } - - int radius = current.nextInt(radiusMin, radiusMax); - float radians = AngleUtils.degreeToRadians(current.nextInt(0, 360)); - - float newX = calcX(x, radius, radians); - float newY = calcY(y, radius, radians); - - loc.set(newX, newY, z); - - return loc; - } - - /** - * Calculates the magnitude of the vector. - * - * @param x the X component. - * @param y the Y component. - * @return the length or magnitude of the vector. - */ - public static float length(float x, float y) { - return ExtMath.sqrt(lengthSquared(x, y)); - } - - /** - * Calculates the squared value of the magnitude of the vector. - * - * @param x the X component. - * @param y the Y component. - * @return the magnitude squared of the vector. - */ - public static float lengthSquared(float x, float y) { - return x * x + y * y; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/util/GeometryUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/geom/util/GeometryUtils.java deleted file mode 100644 index 803d4525..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/util/GeometryUtils.java +++ /dev/null @@ -1,257 +0,0 @@ -package javasabr.rlib.common.geom.util; - -import org.jspecify.annotations.NullMarked; - -/** - * Набор геометрически методов. - * - * @author JavaSaBr - */ -@NullMarked -public final class GeometryUtils { - - /** - * Рассчет расстояния между 2мя точками. - * - * @param startX координата первой точки. - * @param startY координата первой точки. - * @param startZ координата первой точки. - * @param targetX координата второй точки. - * @param targetY координата второй точки. - * @param targetZ координата второй точки. - * @return расстояние между точками. - */ - public static float getDistance( - float startX, - float startY, - float startZ, - float targetX, - float targetY, - float targetZ) { - return (float) Math.sqrt(getSquareDistance(startX, startY, startZ, targetX, targetY, targetZ)); - } - - /** - * Возвращает расстояние от точки до отрезка. - * - * @param startX начальная координата отрезка. - * @param startY начальная координата отрезка. - * @param endX конечная координата отрезка. - * @param endY конечная координата отрезка. - * @param targetX координата точки. - * @param targetY координата точки. - * @return расстояние от точки до отрезка. - */ - public static float getDistanceToLine( - float startX, - float startY, - float endX, - float endY, - float targetX, - float targetY) { - return (float) Math.sqrt(getSquareDistanceToLine(startX, startY, endX, endY, targetX, targetY)); - } - - /** - * Возвращает расстояние от точки до отрезка. - * - * @param startX начальная координата отрезка. - * @param startY начальная координата отрезка. - * @param startZ начальная координата отрезка. - * @param endX конечная координата отрезка. - * @param endY конечная координата отрезка. - * @param endZ конечная координата отрезка. - * @param targetX координата точки. - * @param targetY координата точки. - * @param targetZ координата точки. - * @return расстояние от точки до отрезка. - */ - public static float getDistanceToLine( - float startX, - float startY, - float startZ, - float endX, - float endY, - float endZ, - float targetX, - float targetY, - float targetZ) { - return (float) Math.sqrt(getSquareDistanceToLine( - startX, - startY, - startZ, - endX, - endY, - endZ, - targetX, - targetY, - targetZ)); - } - - /** - * Get squared distance distance between two points. - * - * @param startX the start X coordinate. - * @param startY the start Y coordinate. - * @param startZ the start Z coordinate. - * @param targetX the end X coordinate. - * @param targetY the end Y coordinate. - * @param targetZ the end Z coordinate. - * @return the squared distance. - */ - public static float getSquareDistance( - float startX, - float startY, - float startZ, - float targetX, - float targetY, - float targetZ) { - - float dx = targetX - startX; - float dy = targetY - startY; - float dz = targetZ - startZ; - - return dx * dx + dy * dy + dz * dz; - } - - /** - * Возвращает квадрат расстояния от точки до отрезка. - * - * @param startX начальная координата отрезка. - * @param startY начальная координата отрезка. - * @param endX конечная координата отрезка. - * @param endY конечная координата отрезка. - * @param targetX координата точки. - * @param targetY координата точки. - * @return квадрат расстояния от точки до отрезка. - */ - public static float getSquareDistanceToLine( - final float startX, - final float startY, - float endX, - float endY, - float targetX, - float targetY) { - - endX -= startX; - endY -= startY; - - targetX -= startX; - targetY -= startY; - - float dotprod = targetX * endX + targetY * endY; - - float projlenSq; - - if (dotprod <= 0.0F) { - projlenSq = 0.0F; - } else { - - targetX = endX - targetX; - targetY = endY - targetY; - - dotprod = targetX * endX + targetY * endY; - - if (dotprod <= 0.0F) { - projlenSq = 0.0F; - } else { - projlenSq = dotprod * dotprod / (endX * endX + endY * endY); - } - } - - float lenSq = targetX * targetX + targetY * targetY - projlenSq; - - if (lenSq < 0F) { - lenSq = 0F; - } - - return lenSq; - } - - /** - * Возвращает квадрат расстояния от точки до отрезка. - * - * @param startX начальная координата отрезка. - * @param startY начальная координата отрезка. - * @param startZ начальная координата отрезка. - * @param endX конечная координата отрезка. - * @param endY конечная координата отрезка. - * @param endZ конечная координата отрезка. - * @param targetX координата точки. - * @param targetY координата точки. - * @param targetZ координата точки. - * @return квадрат расстояния от точки до отрезка. - */ - public static float getSquareDistanceToLine( - float startX, - float startY, - float startZ, - float endX, - float endY, - float endZ, - float targetX, - float targetY, - float targetZ) { - - float lineX = endX - startX; - float lineY = endY - startY; - float lineZ = endZ - startZ; - - float pointX = targetX - startX; - float pointY = targetY - startY; - float pointZ = targetZ - startZ; - - float c1 = scalar(pointX, pointY, pointZ, lineX, lineY, lineZ); - - if (c1 < 0F) { - return squareLength(targetX, targetY, targetZ, startX, startY, startZ); - } - - float c2 = scalar(lineX, lineY, lineZ, lineX, lineY, lineZ); - - if (c2 <= c1) { - return squareLength(targetX, targetY, targetZ, endX, endY, endZ); - } - - float b = c1 / c2; - - pointX = startX + lineX * b; - pointY = startY + lineY * b; - pointZ = startZ + lineZ * b; - - return squareLength(targetX, targetY, targetZ, pointX, pointY, pointZ); - } - - /** - * Производит скалярное произведение двух точек. - * - * @param x1 координата первой точки. - * @param y1 координата первой точки. - * @param z1 координата первой точки. - * @param x2 координата второй точки. - * @param y2 координата второй точки. - * @param z2 координата второй точки. - * @return произведение двух точек. - */ - public static float scalar(float x1, float y1, float z1, float x2, float y2, float z2) { - return x1 * x2 + y1 * y2 + z1 * z2; - } - - /** - * Находит квадрат длинны между двумя точками. - * - * @param x1 координата первой точки. - * @param y1 координата первой точки. - * @param z1 координата первой точки. - * @param x2 координата второй точки. - * @param y2 координата второй точки. - * @param z2 координата второй точки. - * @return квадрат длинны между точками. - */ - public static float squareLength(float x1, float y1, float z1, float x2, float y2, float z2) { - float dx = x1 - x2; - float dy = y1 - y2; - float dz = z1 - z2; - return dx * dx + dy * dy + dz * dz; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/ConfigurablePluginSystem.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/ConfigurablePluginSystem.java deleted file mode 100644 index b661f9d0..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/ConfigurablePluginSystem.java +++ /dev/null @@ -1,83 +0,0 @@ -package javasabr.rlib.common.plugin; - -import java.nio.file.Path; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * The interface to implement configurable plugin system. - * - * @author JavaSaBr - */ -@NullMarked -public interface ConfigurablePluginSystem extends PluginSystem { - - /** - * Configure the path to installed plugins. - * - * @param installationPluginsPath the path. - */ - void configureInstallationPluginsPath(Path installationPluginsPath); - - /** - * Configure the path to embedded plugins. - * - * @param embeddedPluginPath the path. - */ - void configureEmbeddedPluginPath(Path embeddedPluginPath); - - /** - * Set the app version. - * - * @param version the app version. - */ - void setAppVersion(@Nullable Version version); - - /** - * Preload all plugins. - * - * @return the async result of pre-loaded plugin system. - */ - CompletableFuture preLoad(); - - /** - * Preload all plugins. - * - * @param executor the executor. - * @return the async result of pre-loaded plugin system. - */ - CompletableFuture preLoad(Executor executor); - - /** - * Initialize all plugins. - * - * @return the async result of initialized plugin system. - */ - CompletableFuture initialize(); - - /** - * Initialize all plugins. - * - * @param executor the executor. - * @return the async result of initialized plugin system. - */ - CompletableFuture initialize(Executor executor); - - /** - * Install a new plugin. - * - * @param file the path to the plugin. - * @param needInitialize true if need to initialize the plugin. - * @return the installed plugin or null. - */ - @Nullable Plugin installPlugin(Path file, boolean needInitialize); - - /** - * Remove the plugin. - * - * @param plugin the plugin. - */ - void removePlugin(Plugin plugin); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/Plugin.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/Plugin.java deleted file mode 100644 index 1df8cf44..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/Plugin.java +++ /dev/null @@ -1,78 +0,0 @@ -package javasabr.rlib.common.plugin; - -import javasabr.rlib.common.plugin.annotation.PluginDescription; -import org.jspecify.annotations.NullMarked; - -/** - * The interface to implement a plugin. - * - * @author JavaSaBr - */ -@NullMarked -public interface Plugin { - - /** - * Get a class loader of this plugin. - * - * @return the class loader. - */ - ClassLoader getClassLoader(); - - /** - * Get the ID of this plugin. - * - * @return the plugin id. - */ - default String getId() { - return getClass() - .getAnnotation(PluginDescription.class) - .id(); - } - - /** - * Get the version of this plugin. - * - * @return the plugin version. - */ - default Version getVersion() { - return new Version(getClass() - .getAnnotation(PluginDescription.class) - .version()); - } - - /** - * Gets a name of this plugin. - * - * @return the name of this plugin. - */ - default String getName() { - return getClass() - .getAnnotation(PluginDescription.class) - .name(); - } - - /** - * Gets a description of this plugin. - * - * @return the description of this plugin. - */ - default String getDescription() { - return getClass() - .getAnnotation(PluginDescription.class) - .description(); - } - - /** - * Return true if this plugin is embedded. - * - * @return true if this plugin is embedded. - */ - boolean isEmbedded(); - - /** - * Initialize this plugin. - * - * @param pluginSystem the plugin system. - */ - void initialize(PluginSystem pluginSystem); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/PluginContainer.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/PluginContainer.java deleted file mode 100644 index 7e1086a1..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/PluginContainer.java +++ /dev/null @@ -1,153 +0,0 @@ -package javasabr.rlib.common.plugin; - -import java.net.URLClassLoader; -import java.nio.file.Path; -import javasabr.rlib.common.classpath.ClassPathScanner; -import javasabr.rlib.common.plugin.annotation.PluginDescription; -import org.jspecify.annotations.NullMarked; - -/** - * The implementation of a plugin container. - * - * @author JavaSaBr - */ -@NullMarked -public class PluginContainer { - - /** - * The plugin class. - */ - private final Class pluginClass; - - /** - * The class loader of this class. - */ - private final URLClassLoader classLoader; - - /** - * The classpath scanner of this plugin. - */ - private final ClassPathScanner scanner; - - /** - * The path to a plugin folder. - */ - private final Path path; - - /** - * The plugin id. - */ - private final String id; - - /** - * The name. - */ - private final String name; - - /** - * The description. - */ - private final String description; - - /** - * The version. - */ - private final Version version; - - /** - * The flag of that this container is of an embedded plugin. - */ - private final boolean embedded; - - public PluginContainer( - Class pluginClass, - URLClassLoader classLoader, - ClassPathScanner scanner, - Path path, - boolean embedded) { - PluginDescription description = pluginClass.getAnnotation(PluginDescription.class); - this.pluginClass = pluginClass; - this.classLoader = classLoader; - this.scanner = scanner; - this.path = path; - this.embedded = embedded; - this.id = description.id(); - this.name = description.name(); - this.version = new Version(description.version()); - this.description = description.description(); - } - - public Class getPluginClass() { - return pluginClass; - } - - /** - * Gets the ID of this plugin. - * - * @return the ID. - */ - public String getId() { - return id; - } - - /** - * Get the version of this plugin. - * - * @return the plugin version. - */ - public Version getVersion() { - return version; - } - - /** - * Gets a name of this plugin. - * - * @return the name of this plugin. - */ - public String getName() { - return name; - } - - /** - * Gets a description of this plugin. - * - * @return the description of this plugin. - */ - public String getDescription() { - return description; - } - - /** - * @return true if this container is of an embedded plugin. - */ - public boolean isEmbedded() { - return embedded; - } - - /** - * Get the scanner of this plugin. - * - * @return the scanner. - */ - public ClassPathScanner getScanner() { - return scanner; - } - - /** - * Get the class loader of this plugin. - * - * @return the class loader. - */ - public URLClassLoader getClassLoader() { - return classLoader; - } - - public Path getPath() { - return path; - } - - @Override - public String toString() { - return "PluginContainer{" + "pluginClass=" + pluginClass + ", path=" + path + '}'; - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/PluginSystem.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/PluginSystem.java deleted file mode 100644 index 8c20b009..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/PluginSystem.java +++ /dev/null @@ -1,66 +0,0 @@ -package javasabr.rlib.common.plugin; - -import java.util.Optional; -import javasabr.rlib.common.util.array.Array; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * The interface to implement a plugin system. - * - * @author JavaSaBr - */ -@NullMarked -public interface PluginSystem { - - /** - * Get all available plugin containers. - * - * @return the list of all available plugin containers. - */ - Array getPluginContainers(); - - /** - * Get a plugin container by the plugin id. - * - * @param id the plugin id. - * @return the container or null. - */ - @Nullable - PluginContainer getPluginContainer(String id); - - /** - * Get a plugin container by the plugin id. - * - * @param id the plugin id. - * @return the optional value of container. - */ - default Optional getPluginContainerOpt(String id) { - return Optional.ofNullable(getPluginContainer(id)); - } - - /** - * Get all available plugins. - * - * @return the list of all available plugins. - */ - Array getPlugins(); - - /** - * Get a plugin by the plugin id. - * - * @param id the plugin id. - * @return the plugin or null. - */ - @Nullable Plugin getPlugin(String id); - - /** - * Get a plugin by the plugin id. - * - * @param id the plugin id. - * @return the optional value of a plugin. - */ - default Optional getPluginOpt(String id) { - return Optional.ofNullable(getPlugin(id)); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/extension/ExtensionPoint.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/extension/ExtensionPoint.java deleted file mode 100644 index 167fc150..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/extension/ExtensionPoint.java +++ /dev/null @@ -1,390 +0,0 @@ -package javasabr.rlib.common.plugin.extension; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import javasabr.rlib.common.function.TriplePredicate; -import javasabr.rlib.common.util.ArrayUtils; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * The class to present an extension point. - * - * @author JavaSaBr - */ -@NullMarked -public class ExtensionPoint implements Iterable { - - @NullMarked - private static class State { - - /** - * The read only list of extensions. - */ - private final List extensions; - - /** - * The array for fast access. - */ - private final Object[] array; - - public State() { - this.extensions = Collections.emptyList(); - this.array = ArrayUtils.EMPTY_OBJECT_ARRAY; - } - - public State(List extensions, Object[] array) { - this.extensions = extensions; - this.array = array; - } - - /** - * Append the extension to the current state as new state. - * - * @param extension the extension. - * @return the new state. - */ - public State append(T extension) { - - List result = new ArrayList<>(extensions); - result.add(extension); - - boolean canBeSorted = result - .stream() - .allMatch(Comparable.class::isInstance); - - if (canBeSorted) { - result.sort((first, second) -> ((Comparable) first).compareTo(second)); - } - - List extensions = Collections.unmodifiableList(result); - Object[] array = result.toArray(); - - return new State<>(extensions, array); - } - - /** - * Append the additional extensions to the current state as new state. - * - * @param additionalExtensions the additional extension. - * @return the new state. - */ - public State append(T[] additionalExtensions) { - - List result = new ArrayList<>(extensions); - result.addAll(Arrays.asList(additionalExtensions)); - - boolean canBeSorted = result - .stream() - .allMatch(Comparable.class::isInstance); - - if (canBeSorted) { - result.sort((first, second) -> ((Comparable) first).compareTo(second)); - } - - List extensions = Collections.unmodifiableList(result); - Object[] array = result.toArray(); - - return new State<>(extensions, array); - } - } - - /** - * The reference to the current state. - */ - private final AtomicReference> state; - - public ExtensionPoint() { - this.state = new AtomicReference<>(new State<>()); - } - - /** - * Register a new extension. - * - * @param extension the new extension. - * @return this point. - */ - public ExtensionPoint register(T extension) { - - State currentState = state.get(); - State newState = currentState.append(extension); - - while (!state.compareAndSet(currentState, newState)) { - currentState = state.get(); - newState = currentState.append(extension); - } - - return this; - } - - /** - * Register the new extensions. - * - * @param extensions the new extensions. - * @return this point. - */ - @SafeVarargs - public final ExtensionPoint register(T... extensions) { - - State currentState = state.get(); - State newState = currentState.append(extensions); - - while (!state.compareAndSet(currentState, newState)) { - currentState = state.get(); - newState = currentState.append(extensions); - } - - return this; - } - - /** - * Get all registered extensions. - * - * @return the all registered extensions. - */ - public List getExtensions() { - return state.get().extensions; - } - - /** - * Handle each extension. - * - * @param consumer the consumer. - */ - @Override - public void forEach(Consumer consumer) { - - Object[] array = state.get().array; - - for (Object obj : array) { - consumer.accept((T) obj); - } - } - - /** - * Handle each extension. - * - * @param first the first argument. - * @param consumer the consumer. - * @param the argument's type. - */ - public void forEach(F first, BiConsumer consumer) { - - Object[] array = state.get().array; - - for (Object obj : array) { - consumer.accept((T) obj, first); - } - } - - /** - * Find an extension using the condition. - * - * @param predicate the condition. - * @return the found extension or null. - */ - public @Nullable T findAny(Predicate predicate) { - - for (Object element : state.get().array) { - if (predicate.test((T) element)) { - return (T) element; - } - } - - return null; - } - - /** - * Find an extension using the condition. - * - * @param the argument's type. - * @param argument the argument. - * @param predicate the condition. - * @return the found extension or null. - */ - public @Nullable T findAny(@Nullable F argument, BiPredicate predicate) { - - for (Object element : state.get().array) { - if (predicate.test((T) element, argument)) { - return (T) element; - } - } - - return null; - } - - /** - * Return true if there is at least an extension for the condition. - * - * @param the argument's type. - * @param argument the argument. - * @param predicate the condition. - * @return true if there is at least an extension for the condition. - */ - public boolean anyMatch(@Nullable F argument, BiPredicate predicate) { - return findAny(argument, predicate) != null; - } - - /** - * Find an extension using the inverted condition. - * - * @param the argument's type. - * @param argument the argument. - * @param predicate the condition. - * @return the found extension or null. - */ - public @Nullable T findAnyNot(@Nullable F argument, BiPredicate predicate) { - - for (Object element : state.get().array) { - if (!predicate.test((T) element, argument)) { - return (T) element; - } - } - - return null; - } - - /** - * Return true if there is at least an extension for the inverted condition. - * - * @param the argument's type. - * @param argument the argument. - * @param predicate the condition. - * @return true if there is at least an extension for the inverted condition. - */ - public boolean anyMatchNot(@Nullable F argument, BiPredicate predicate) { - return findAnyNot(argument, predicate) != null; - } - - /** - * Find an extension using the condition. - * - * @param the first argument's type. - * @param the second argument's type. - * @param first the first argument. - * @param second the second argument. - * @param predicate the condition. - * @return the found extension or null. - */ - public @Nullable T findAny( - @Nullable F first, - @Nullable S second, - TriplePredicate predicate) { - - for (Object element : state.get().array) { - if (predicate.test((T) element, first, second)) { - return (T) element; - } - } - - return null; - } - - /** - * Return true if there is at least an extension for the condition. - * - * @param the first argument's type. - * @param the second argument's type. - * @param first the first argument. - * @param second the second argument. - * @param predicate the condition. - * @return true if there is at least an extension for the condition. - */ - public boolean anyMatch( - @Nullable F first, - @Nullable S second, - TriplePredicate predicate) { - return findAny(first, second, predicate) != null; - } - - /** - * Find an extension using the inverted condition. - * - * @param the first argument's type. - * @param the second argument's type. - * @param first the first argument. - * @param second the second argument. - * @param predicate the condition. - * @return the found extension or null. - */ - public @Nullable T findAnyNot( - @Nullable F first, - @Nullable S second, - TriplePredicate predicate) { - - for (Object element : state.get().array) { - if (!predicate.test((T) element, first, second)) { - return (T) element; - } - } - - return null; - } - - /** - * Return true if there is at least an extension for the inverted condition. - * - * @param the first argument's type. - * @param the second argument's type. - * @param first the first argument. - * @param second the second argument. - * @param predicate the condition. - * @return the found extension or null. - */ - public boolean anyMatchNot( - @Nullable F first, - @Nullable S second, - TriplePredicate predicate) { - return findAnyNot(first, second, predicate) != null; - } - - /** - * Search an extension using the condition. - * - * @param the argument's type. - * @param argument the argument. - * @param predicate the condition. - * @return the found extension or null. - */ - public @Nullable T anyMatchR(@Nullable F argument, BiPredicate predicate) { - - for (Object element : state.get().array) { - if (predicate.test(argument, (T) element)) { - return (T) element; - } - } - - return null; - } - - @Override - public Iterator iterator() { - return state.get().extensions.iterator(); - } - - /** - * Get a stream of extensions. - * - * @return the stream of extensions. - */ - public Stream stream() { - return StreamSupport.stream(spliterator(), false); - } - - @Override - public Spliterator spliterator() { - return Spliterators.spliterator(state.get().array, 0); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/extension/ExtensionPointManager.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/extension/ExtensionPointManager.java deleted file mode 100644 index 8be10915..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/extension/ExtensionPointManager.java +++ /dev/null @@ -1,144 +0,0 @@ -package javasabr.rlib.common.plugin.extension; - -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.common.util.dictionary.ConcurrentObjectDictionary; -import javasabr.rlib.common.util.dictionary.DictionaryFactory; -import javasabr.rlib.common.util.dictionary.ObjectDictionary; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import org.jspecify.annotations.NullMarked; - -/** - * The manager to manage all extension points. - * - * @author JavaSaBr - */ -@NullMarked -public class ExtensionPointManager { - - private static final Logger LOGGER = LoggerManager.getLogger(ExtensionPointManager.class); - - /** - * Register a new extension point. - * - * @param id the extension id. - * @param the extension's type. - * @return the new extension point. - * @throws IllegalArgumentException if an extension with the id is already exists. - */ - public static ExtensionPoint register(String id) { - return getInstance().create(id); - } - - private static final ExtensionPointManager INSTANCE = new ExtensionPointManager(); - - public static ExtensionPointManager getInstance() { - return INSTANCE; - } - - /** - * All created extension points. - */ - private final ConcurrentObjectDictionary> extensionPoints; - - private ExtensionPointManager() { - this.extensionPoints = DictionaryFactory.newConcurrentAtomicObjectDictionary(); - } - - private ExtensionPoint create(String id) { - - long stamp = extensionPoints.writeLock(); - try { - - var exists = extensionPoints.get(id); - - if (exists != null) { - LOGGER.warning("The extension point with the id " + id + " is already registered."); - return ClassUtils.unsafeNNCast(exists); - } - - var extensionPoint = new ExtensionPoint(); - - extensionPoints.put(id, extensionPoint); - - return extensionPoint; - - } finally { - extensionPoints.writeUnlock(stamp); - } - } - - /** - * Add the new extension to the extension point. - * - * @param id the extension point's id. - * @param type the extension's type. - * @param extension the new extension. - * @param the extension's type. - * @return this manager. - */ - public ExtensionPointManager addExtension(String id, Class type, T extension) { - getExtensionPoint(id).register(extension); - return this; - } - - /** - * Add the new extension to the extension point. - * - * @param id the extension point's id. - * @param extension the new extension. - * @param the extension's type. - * @return this manager. - */ - public ExtensionPointManager addExtension(String id, T extension) { - getExtensionPoint(id).register(extension); - return this; - } - - /** - * Add the new extensions to the extension point. - * - * @param id the extension point's id. - * @param extensions the new extensions. - * @param the extension's type. - * @return this manager. - */ - public ExtensionPointManager addExtension(String id, T... extensions) { - getExtensionPoint(id).register(extensions); - return this; - } - - /** - * Get or create an extension point. - * - * @param id the id. - * @param type the extension's type. - * @param the extension's type. - * @return the extension point. - */ - public ExtensionPoint getExtensionPoint(String id, Class type) { - return getExtensionPoint(id); - } - - /** - * Get or create an extension point. - * - * @param id the id. - * @param the extension's type. - * @return the extension point. - */ - public ExtensionPoint getExtensionPoint(String id) { - - var extensionPoint = extensionPoints.getInReadLock(id, ObjectDictionary::get); - - if (extensionPoint != null) { - return ClassUtils.unsafeNNCast(extensionPoint); - } - - try { - return create(id); - } catch (IllegalArgumentException e) { - return getExtensionPoint(id); - } - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/BasePlugin.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/BasePlugin.java deleted file mode 100644 index 280927cc..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/BasePlugin.java +++ /dev/null @@ -1,68 +0,0 @@ -package javasabr.rlib.common.plugin.impl; - -import javasabr.rlib.common.plugin.Plugin; -import javasabr.rlib.common.plugin.PluginContainer; -import javasabr.rlib.common.plugin.PluginSystem; -import javasabr.rlib.common.plugin.Version; -import org.jspecify.annotations.NullMarked; - -/** - * The base implementation of the {@link Plugin}. - * - * @author JavaSaBr - */ -@NullMarked -public class BasePlugin implements Plugin { - - /** - * The plugin container. - */ - private final PluginContainer container; - - public BasePlugin(PluginContainer container) { - this.container = container; - } - - @Override - public ClassLoader getClassLoader() { - return container.getClassLoader(); - } - - @Override - public boolean isEmbedded() { - return container.isEmbedded(); - } - - @Override - public String getId() { - return container.getId(); - } - - @Override - public Version getVersion() { - return container.getVersion(); - } - - @Override - public String getDescription() { - return container.getDescription(); - } - - @Override - public String getName() { - return container.getName(); - } - - /** - * The container of this plugin. - * - * @return the container. - */ - protected PluginContainer getContainer() { - return container; - } - - @Override - public void initialize(PluginSystem pluginSystem) { - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/BasePluginSystem.java b/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/BasePluginSystem.java deleted file mode 100644 index f0976d85..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/BasePluginSystem.java +++ /dev/null @@ -1,596 +0,0 @@ -package javasabr.rlib.common.plugin.impl; - -import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; -import static java.util.concurrent.CompletableFuture.supplyAsync; -import static javasabr.rlib.common.util.ObjectUtils.notNull; -import static javasabr.rlib.common.util.array.ArrayCollectors.toArray; -import static javasabr.rlib.common.util.dictionary.DictionaryCollectors.toObjectDictionary; - -import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import javasabr.rlib.common.classpath.ClassPathScannerFactory; -import javasabr.rlib.common.plugin.ConfigurablePluginSystem; -import javasabr.rlib.common.plugin.Plugin; -import javasabr.rlib.common.plugin.PluginContainer; -import javasabr.rlib.common.plugin.PluginSystem; -import javasabr.rlib.common.plugin.Version; -import javasabr.rlib.common.plugin.annotation.PluginDescription; -import javasabr.rlib.common.plugin.exception.InitializePluginException; -import javasabr.rlib.common.plugin.exception.PluginException; -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.common.util.FileUtils; -import javasabr.rlib.common.util.Utils; -import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ArrayFactory; -import javasabr.rlib.common.util.dictionary.ObjectDictionary; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * The base implementation of the {@link PluginSystem}. - * - * @author JavaSaBr - */ -@NullMarked -public class BasePluginSystem implements ConfigurablePluginSystem { - - protected static final Logger LOGGER = LoggerManager.getLogger(BasePluginSystem.class); - - @NullMarked - private static class State { - - static final State EMPTY = new State(Array.empty(), ObjectDictionary.empty(), ObjectDictionary.empty()); - - /** - * The list of preload plugin containers. - */ - private final Array containers; - - /** - * The result map of plugin containers. - */ - private final ObjectDictionary idToContainer; - - /** - * The result map of plugins. - */ - private final ObjectDictionary idToPlugin; - - private State( - Array containers, - ObjectDictionary idToContainer, - ObjectDictionary idToPlugin) { - this.containers = containers; - this.idToContainer = idToContainer; - this.idToPlugin = idToPlugin; - } - } - - /** - * The base classloader. - */ - private final ClassLoader baseLoader; - - /** - * The app version. - */ - private volatile @Nullable Version appVersion; - - /** - * The path to folder with embedded plugins. - */ - private volatile @Nullable Path embeddedPluginsPath; - - /** - * The path to folder with installed plugins. - */ - private volatile @Nullable Path installationPluginsPath; - - /** - * The flag of this plugin system was pre-loaded. - */ - private final AtomicBoolean preLoaded; - - /** - * The flag of this plugin system was initialized. - */ - private final AtomicBoolean initialized; - - /** - * The system's state. - */ - private final AtomicReference state; - - public BasePluginSystem() { - this(StackWalker - .getInstance(RETAIN_CLASS_REFERENCE) - .getCallerClass() - .getClassLoader()); - } - - public BasePluginSystem(ClassLoader baseLoader) { - this.baseLoader = baseLoader; - this.state = new AtomicReference<>(State.EMPTY); - this.preLoaded = new AtomicBoolean(false); - this.initialized = new AtomicBoolean(false); - } - - @Override - public void setAppVersion(@Nullable Version appVersion) { - this.appVersion = appVersion; - } - - @Override - public CompletableFuture preLoad() { - return preLoad(ForkJoinPool.commonPool()); - } - - @Override - public CompletableFuture preLoad(Executor executor) { - - if (!preLoaded.compareAndSet(false, true)) { - throw new PluginException("This system was already pre-loaded."); - } - - return supplyAsync( - () -> { - - var current = state.get(); - - LOGGER.debug("Start to pre-load all plugins."); - - var futures = Array.optionals( - CompletableFuture.class, - getEmbeddedPluginsPath().map(path -> loadPlugins(path, executor, true)), - getInstallationPluginsPath().map(path -> loadPlugins(path, executor, false))); - - var containers = futures - .stream() - .map(CompletableFuture::join) - .flatMap(Array::stream) - .collect(toArray(PluginContainer.class)); - - var idToContainer = containers - .stream() - .collect(toObjectDictionary(PluginContainer::getId, container -> container)); - - if (state.compareAndSet(current, new State(containers, idToContainer, ObjectDictionary.empty()))) { - LOGGER.debug(containers, arg -> "Pre-loaded: " + arg); - LOGGER.debug("All plugins were pre-loaded."); - return this; - } - - return null; - - }, executor); - } - - @Override - public CompletableFuture initialize() { - return initialize(ForkJoinPool.commonPool()); - } - - @Override - public CompletableFuture initialize(Executor executor) { - - if (!initialized.compareAndSet(false, true)) { - throw new PluginException("This system was already initialized."); - } - - LOGGER.debug("Start to load all plugins."); - - return supplyAsync( - () -> { - - var current = state.get(); - var plugins = current.containers - .stream() - .map(pluginContainer -> createPluginClass(pluginContainer, executor)) - .map(future -> future.thenApply(this::initializePlugin)) - .map(CompletableFuture::join) - .collect(toObjectDictionary(Plugin::getId, plugin -> plugin)); - - if (state.compareAndSet(current, new State(current.containers, current.idToContainer, plugins))) { - LOGGER.debug("All plugins were initialized."); - return this; - } - - return null; - - }, executor); - } - - /** - * Create a plugin's class. - * - * @param container the plugin's container. - * @param executor the executor. - * @return the plugin's class. - */ - private CompletableFuture createPluginClass(PluginContainer container, Executor executor) { - - return supplyAsync( - () -> { - - var pluginClass = container.getPluginClass(); - - LOGGER.debug(pluginClass, arg -> "Start to create a plugin " + arg); - - var constructor = ClassUtils.tryGetConstructor(pluginClass, PluginContainer.class); - - if (constructor == null) { - throw new InitializePluginException( - "Not found base constructor in the class " + pluginClass, - container.getPath()); - } - - Plugin plugin; - try { - plugin = ClassUtils.newInstance(constructor, container); - } catch (Throwable exc) { - throw new InitializePluginException( - "Found a problem with creating a plugin " + pluginClass, - container.getPath(), - exc); - } - - return plugin; - - }, executor); - } - - /** - * Initialize the plugin. - * - * @param plugin the plugin. - * @return the initialized plugin. - */ - private Plugin initializePlugin(Plugin plugin) { - - try { - plugin.initialize(this); - } catch (Throwable exc) { - var container = notNull(getPluginContainer(plugin.getId())); - throw new InitializePluginException( - "Found a problem with initializing a plugin " + plugin, - container.getPath(), - exc); - } - - return plugin; - } - - /** - * Load plugins from the directory. - * - * @param path the path to the directory. - * @param executor the executor. - * @param embedded true if this directory with embedded plugins. - * @return the future of the loading plugins. - */ - protected CompletableFuture> loadPlugins(Path path, Executor executor, boolean embedded) { - LOGGER.debug(path, arg -> "Try to pre-load plugins from the folder " + arg); - return supplyAsync( - () -> FileUtils - .stream(path) - .filter(Files::isDirectory) - .map(directory -> loadPlugin(directory, baseLoader, executor, embedded)) - .map(CompletableFuture::join) - .filter(Objects::nonNull) - .collect(toArray(PluginContainer.class)), executor); - } - - /** - * Load a plugin from the directory. - * - * @param directory the plugin directory. - * @param parentLoader the parent class loader. - * @param executor the executor. - * @param embedded the embedded flag. - * @return the future of loaded plugin container. - */ - protected CompletableFuture<@Nullable PluginContainer> loadPlugin( - Path directory, - ClassLoader parentLoader, - Executor executor, - boolean embedded) { - return loadPlugin(directory, parentLoader, null, executor, embedded); - } - - /** - * Load a plugin from the directory. - * - * @param directory the plugin directory. - * @param parentLoader the parent class loader. - * @param parents the parent plugins. - * @param executor the executor. - * @param embedded the embedded flag. - * @return the future of loading plugin container. - */ - protected CompletableFuture<@Nullable PluginContainer> loadPlugin( - Path directory, - ClassLoader parentLoader, - PluginContainer @Nullable [] parents, - Executor executor, - boolean embedded) { - return supplyAsync( - () -> { - - var files = FileUtils.getFiles(directory, ".jar"); - - var urls = files - .stream() - .map(path -> Utils.uncheckedGet(path, Path::toUri)) - .map(uri -> Utils.uncheckedGet(uri, URI::toURL)) - .toArray(URL[]::new); - - var additionalPaths = files - .stream() - .map(Path::toAbsolutePath) - .map(Path::toString) - .toArray(String[]::new); - - var classLoader = new URLClassLoader(urls); - - var scanner = ClassPathScannerFactory.newDefaultScanner(classLoader, additionalPaths); - scanner.setUseSystemClasspath(false); - - try { - scanner.scan(); - } catch (Throwable exc) { - LOGGER.warning(exc); - return null; - } - - var pluginImplementations = ArrayFactory.>newArray(Class.class); - scanner.findImplements(pluginImplementations, Plugin.class); - - if (pluginImplementations.isEmpty()) { - LOGGER.warning( - directory, - arg -> "Can't load the plugin from the directory" + arg - + " because can't find any implementation of the plugin interface."); - return null; - } else if (pluginImplementations.size() > 1) { - LOGGER.warning( - directory, - arg -> "Can't load the plugin from the directory" + arg - + " because found more than 1 implementation of the plugin interfaces."); - return null; - } - - var pluginClass = notNull(pluginImplementations.first()); - var description = pluginClass.getAnnotation(PluginDescription.class); - - if (description == null) { - LOGGER.warning( - directory, - arg -> "Can't load the plugin from the directory" + arg - + " because can't find any plugin class with description."); - return null; - } - - var appVersion = getAppVersion(); - - if (appVersion != null) { - - var minVersion = new Version(description.minAppVersion()); - - if (minVersion.compareTo(appVersion) > 0) { - LOGGER.warning( - description, - arg -> "Can't load the plugin " + arg.id() + ", it requires the app version " + arg.minAppVersion() - + " or higher."); - return null; - } - } - - return new PluginContainer(pluginClass, classLoader, scanner, directory, embedded); - - }, executor); - } - - /** - * Get the application version. - * - * @return the application version or null. - */ - private @Nullable Version getAppVersion() { - return appVersion; - } - - /** - * Get the path to folder with embedded plugins. - * - * @return the path to folder with embedded plugins. - */ - protected Optional getEmbeddedPluginsPath() { - return Optional.ofNullable(embeddedPluginsPath); - } - - /** - * Get the path to folder with installed plugins. - * - * @return the path to folder with installed plugins. - */ - protected Optional getInstallationPluginsPath() { - return Optional.ofNullable(installationPluginsPath); - } - - @Override - public void configureEmbeddedPluginPath(Path embeddedPluginPath) { - if (isInitialized()) { - throw new RuntimeException("The plugin system is already initialized."); - } - this.embeddedPluginsPath = embeddedPluginPath; - } - - @Override - public void configureInstallationPluginsPath(Path installationPluginsPath) { - if (isInitialized()) { - throw new RuntimeException("The plugin system is already initialized."); - } - this.installationPluginsPath = installationPluginsPath; - } - - /** - * Return true if this system was pre-loaded. - * - * @return true if this system was pre-loaded. - */ - protected boolean isPreLoaded() { - return preLoaded.get(); - } - - /** - * Return true if this system was initialized. - * - * @return true if this system was initialized. - */ - protected boolean isInitialized() { - return initialized.get(); - } - - @Override - public Array getPluginContainers() { - return state.get().idToContainer.values(PluginContainer.class); - } - - @Override - public @Nullable PluginContainer getPluginContainer(String id) { - return state.get().idToContainer.get(id); - } - - @Override - public Array getPlugins() { - return state.get().idToPlugin.values(Plugin.class); - } - - @Override - public @Nullable Plugin getPlugin(String id) { - return state.get().idToPlugin.get(id); - } - - @Override - public @Nullable Plugin installPlugin(Path file, boolean needInitialize) { - - var installPath = getInstallationPluginsPath() - .filter(path -> Files.exists(path)) - .orElse(null); - - if (installPath == null) { - throw new PluginException("The installation folder " + getInstallationPluginsPath() + " doesn't exists."); - } - - var current = state.get(); - var folderName = FileUtils.getNameWithoutExtension(file); - var pluginFolder = installPath.resolve(folderName); - - if (Files.exists(pluginFolder)) { - FileUtils.delete(pluginFolder); - } - - FileUtils.createDirectories(pluginFolder); - FileUtils.unzip(pluginFolder, file); - - var container = loadPlugin(pluginFolder, baseLoader, ForkJoinPool.commonPool(), false).join(); - - if (container == null) { - return null; - } - - var existsContainer = getPluginContainer(container.getId()); - - if (existsContainer != null && !pluginFolder.equals(existsContainer.getPath())) { - FileUtils.delete(existsContainer.getPath()); - } - - var pluginClass = container.getPluginClass(); - var constructor = ClassUtils.tryGetConstructor(pluginClass, PluginContainer.class); - - if (constructor == null) { - throw new InitializePluginException( - "Not found base constructor in the class " + pluginClass, - container.getPath()); - } - - Plugin plugin; - try { - plugin = ClassUtils.newInstance(constructor, container); - } catch (Exception exc) { - throw new InitializePluginException( - "Found a problem with creating a plugin " + pluginClass, - container.getPath(), - exc); - } - - if (needInitialize) { - try { - plugin.initialize(this); - } catch (Exception exc) { - throw new InitializePluginException( - "Found a problem with initializing a plugin " + plugin, - container.getPath(), - exc); - } - } - - var idToContainer = ObjectDictionary.ofType(String.class, PluginContainer.class); - idToContainer.put(current.idToContainer); - idToContainer.put(existsContainer.getId(), existsContainer); - - var idToPlugin = ObjectDictionary.ofType(String.class, Plugin.class); - idToPlugin.put(current.idToPlugin); - idToPlugin.put(plugin.getId(), plugin); - - var containers = Array.ofType(PluginContainer.class); - containers.addAll(current.containers); - containers.add(existsContainer); - - if (state.compareAndSet(current, new State(containers, idToContainer, idToPlugin))) { - return plugin; - } - - return installPlugin(file, needInitialize); - } - - @Override - public void removePlugin(Plugin plugin) { - - var current = state.get(); - - var pluginId = plugin.getId(); - var pluginContainer = notNull(current.idToContainer.get(pluginId)); - - var containers = Array.ofType(PluginContainer.class); - containers.addAll(current.containers); - containers.fastRemove(pluginContainer); - - var idToContainer = ObjectDictionary.ofType(String.class, PluginContainer.class); - idToContainer.put(current.idToContainer); - idToContainer.remove(pluginId); - - var idToPlugin = ObjectDictionary.ofType(String.class, Plugin.class); - idToPlugin.put(current.idToPlugin); - idToPlugin.remove(pluginId); - - containers.addAll(current.containers); - containers.fastRemove(pluginContainer); - - if (state.compareAndSet(current, new State(containers, idToContainer, idToPlugin))) { - FileUtils.delete(pluginContainer.getPath()); - } - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java index 628849b2..b8ffb6c9 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java @@ -1,6 +1,5 @@ package javasabr.rlib.common.util; -import javasabr.rlib.common.geom.Vector3f; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -346,21 +345,6 @@ public static float lerpUnnormal(float min, float max, float time) { return (1.f - time) * min + time * max; } - /** - * Return true if these vectors are equals. - * - * @param first the first vector. - * @param second the second vector. - * @param epsilon the epsilon. - * @return true if these vectors are equals. - */ - public boolean isEquals(@Nullable Vector3f first, @Nullable Vector3f second, float epsilon) { - if (first == null || second == null) { - return false; - } else { - return first.equals(second, epsilon); - } - } private ExtMath() { throw new RuntimeException(); diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java b/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java index 0e4d2633..7eb1daea 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/VarTable.java @@ -3,8 +3,6 @@ import static java.lang.Float.parseFloat; import static javasabr.rlib.common.util.ObjectUtils.notNull; -import javasabr.rlib.common.geom.Quaternion4f; -import javasabr.rlib.common.geom.Vector3f; import javasabr.rlib.common.util.dictionary.DictionaryFactory; import javasabr.rlib.common.util.dictionary.ObjectDictionary; import org.jspecify.annotations.NullMarked; @@ -976,59 +974,6 @@ public long[] getLongArray( throw new IllegalArgumentException("Not found " + key); } - /** - * Get a rotation by the key. - * - * @param key the key. - * @return the rotation. - */ - public Quaternion4f getRotation(final String key) { - - var object = values.get(key); - - if (object == null) { - throw new IllegalArgumentException("Not found " + key); - } else if (object instanceof Quaternion4f) { - return (Quaternion4f) object; - } else if (object instanceof String) { - return parseRotation((String) object); - } - - throw new IllegalArgumentException("Not found " + key); - } - - private Quaternion4f parseRotation(String object) { - - var values = object.split(","); - - var rotation = new Quaternion4f(); - rotation.setXYZW(parseFloat(values[0]), parseFloat(values[1]), parseFloat(values[2]), parseFloat(values[3])); - - return rotation; - } - - /** - * Get a rotation by the key. - * - * @param key the key. - * @param def the default value. - * @return the rotation. - */ - public Quaternion4f getRotation(final String key, final Quaternion4f def) { - - final Object object = values.get(key); - - if (object == null) { - throw new IllegalArgumentException("Not found " + key); - } else if (object instanceof Quaternion4f) { - return (Quaternion4f) object; - } else if (object instanceof String) { - return parseRotation((String) object); - } - - return def; - } - /** * Get a short value by the key. * @@ -1253,54 +1198,6 @@ public ObjectDictionary getValues() { return values; } - /** - * Get a vector by the key. - * - * @param key the key. - * @return the vector. - */ - public Vector3f getVector(String key) { - - Object object = values.get(key); - - if (object == null) { - throw new IllegalArgumentException("Not found " + key); - } else if (object instanceof Vector3f) { - return (Vector3f) object; - } else if (object instanceof String) { - return parseVector((String) object); - } - - throw new IllegalArgumentException("Not found " + key); - } - - private Vector3f parseVector(String object) { - String[] values = object.split(","); - return new Vector3f(parseFloat(values[0]), parseFloat(values[1]), parseFloat(values[2])); - } - - /** - * Get a vector by the key. - * - * @param key the key. - * @param def the default vector. - * @return the vector. - */ - public Vector3f getVector(final String key, final Vector3f def) { - - final Object object = values.get(key); - - if (object == null) { - return def; - } else if (object instanceof Vector3f) { - return (Vector3f) object; - } else if (object instanceof String) { - return parseVector((String) object); - } - - return def; - } - /** * Put the value by the key to this vars table. * diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ReadOnlyArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ReadOnlyArray.java index 7baea642..26c7d7ed 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ReadOnlyArray.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ReadOnlyArray.java @@ -3,6 +3,7 @@ import java.util.Collection; import java.util.function.Function; import java.util.function.Predicate; +import javasabr.rlib.common.util.array.impl.ReadOnlyFastArray; import org.jspecify.annotations.NullMarked; /** @@ -14,6 +15,10 @@ @NullMarked public interface ReadOnlyArray extends Array { + static ReadOnlyArray wrap(Array array) { + return new ReadOnlyFastArray<>(array.toArray()); + } + @Override @Deprecated void apply(Function function); diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/AbstractArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/AbstractArray.java index 1188e570..aac5f22e 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/AbstractArray.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/AbstractArray.java @@ -71,12 +71,12 @@ public AbstractArray clone() throws CloneNotSupportedException { @Override public String toString() { - return getClass().getSimpleName() + " size = " + size() + " :\n " + ArrayUtils.toString(this); + return ArrayUtils.toString(this); } @Override public String toString(Function toString) { - return getClass().getSimpleName() + " size = " + size() + " :\n " + ArrayUtils.toString(this, toString); + return ArrayUtils.toString(this, toString); } @Override diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionary.java b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionary.java index f5d09356..96c0ea84 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionary.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionary.java @@ -1,10 +1,12 @@ package javasabr.rlib.common.util.dictionary; +import java.util.function.BiFunction; import javasabr.rlib.common.function.NotNullBiConsumer; import javasabr.rlib.common.function.NotNullConsumer; import javasabr.rlib.common.function.NotNullNullableBiFunction; import javasabr.rlib.common.function.NotNullNullableTripleFunction; import javasabr.rlib.common.function.NotNullTripleConsumer; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -132,21 +134,12 @@ default ConcurrentObjectDictionary runInWriteLock( return this; } - /** - * Get the value from a function for this dictionary under block {@link ConcurrentObjectDictionary#readLock()}. - * - * @param argument the argument. - * @param function the function. - * @param the argument's type. - * @param the result's type. - * @return the result of the function. - */ - default @Nullable R getInReadLock( - A argument, - NotNullNullableBiFunction, A, R> function) { + default @Nullable R getFromReadLock( + A arg1, + BiFunction<@NonNull ConcurrentObjectDictionary, A, R> function) { var stamp = readLock(); try { - return function.apply(this, argument); + return function.apply(this, arg1); } finally { readUnlock(stamp); } diff --git a/rlib-common/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java b/rlib-common/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java deleted file mode 100644 index 5feba7f3..00000000 --- a/rlib-common/src/test/java/javasabr/rlib/common/classpath/ClasspathScannerTests.java +++ /dev/null @@ -1,28 +0,0 @@ -package javasabr.rlib.common.classpath; - -import java.util.Collection; -import javasabr.rlib.common.util.array.impl.AbstractArray; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author JavaSaBr - */ -public class ClasspathScannerTests { - - @Test - void testSystemClasspathScanner() { - - var scanner = ClassPathScannerFactory.newDefaultScanner(); - scanner.setUseSystemClasspath(true); - scanner.scan(); - - var implementations = scanner.findImplements(Collection.class); - - Assertions.assertFalse(implementations.isEmpty()); - - var inherited = scanner.findInherited(AbstractArray.class); - - Assertions.assertFalse(inherited.isEmpty()); - } -} diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionaryTest.java b/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionaryTest.java index b5324a3c..781d510f 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionaryTest.java +++ b/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentObjectDictionaryTest.java @@ -97,7 +97,7 @@ void getInReadLockTest() { dic.put("3", 3); }); - Integer val1 = dictionary.getInReadLock( + Integer val1 = dictionary.getFromReadLock( "1", (dic, arg) -> { assertType(dic, ConcurrentObjectDictionary.class); assertType(arg, String.class); diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentStampedLockObjectDictionaryTest.java b/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentStampedLockObjectDictionaryTest.java index 06ee1fcf..353dafa7 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentStampedLockObjectDictionaryTest.java +++ b/rlib-common/src/test/java/javasabr/rlib/common/util/dictionary/ConcurrentStampedLockObjectDictionaryTest.java @@ -70,7 +70,7 @@ void writeReadLockTest() { Assertions.assertNotEquals(0, stamp); - var asyncRead = CompletableFuture.supplyAsync(() -> dictionary.getInReadLock("Key1", ObjectDictionary::get)); + var asyncRead = CompletableFuture.supplyAsync(() -> dictionary.getFromReadLock("Key1", ObjectDictionary::get)); var result = Utils.uncheckedGet(() -> asyncRead.get(100, TimeUnit.MILLISECONDS)); Assertions.assertEquals(dictionary.get("Key1"), result); diff --git a/rlib-fx/src/main/java/javasabr/rlib/fx/handler/ControlDragHandler.java b/rlib-fx/src/main/java/javasabr/rlib/fx/handler/ControlDragHandler.java index 63e05838..76fca69b 100644 --- a/rlib-fx/src/main/java/javasabr/rlib/fx/handler/ControlDragHandler.java +++ b/rlib-fx/src/main/java/javasabr/rlib/fx/handler/ControlDragHandler.java @@ -73,7 +73,7 @@ protected void processMove(MouseEvent event) { LOGGER.debug(event, ev -> "processMove -> " + ev); - if (LOGGER.isEnabled(LoggerLevel.DEBUG)) { + if (LOGGER.enabled(LoggerLevel.DEBUG)) { LOGGER.debug("processMove -> dragOffset -> " + offsetX + "," + offsetY); } @@ -84,14 +84,14 @@ protected void processMove(MouseEvent event) { var dragX = dragPosition.getX() - offsetX; var dragY = dragPosition.getY() - offsetY; - if (LOGGER.isEnabled(LoggerLevel.DEBUG)) { + if (LOGGER.enabled(LoggerLevel.DEBUG)) { LOGGER.debug("processMove -> dragXY -> " + (dragX - offsetX) + "-" + (dragY - offsetY)); } var newXPos = startX + dragX; var newYPos = startY + dragY; - if (LOGGER.isEnabled(LoggerLevel.DEBUG)) { + if (LOGGER.enabled(LoggerLevel.DEBUG)) { LOGGER.debug("processMove -> newXY -> " + newXPos + ", " + newYPos); } diff --git a/rlib-fx/src/main/java/javasabr/rlib/fx/handler/WindowDragHandler.java b/rlib-fx/src/main/java/javasabr/rlib/fx/handler/WindowDragHandler.java index 325c7c74..eb55cc55 100644 --- a/rlib-fx/src/main/java/javasabr/rlib/fx/handler/WindowDragHandler.java +++ b/rlib-fx/src/main/java/javasabr/rlib/fx/handler/WindowDragHandler.java @@ -151,7 +151,7 @@ protected void processMove(MouseEvent event) { var newXPos = startX + dragX; var newYPos = startY + dragY; - if (LOGGER.isEnabled(LoggerLevel.DEBUG)) { + if (LOGGER.enabled(LoggerLevel.DEBUG)) { LOGGER.debug("processMove -> newXY -> " + newXPos + ", " + newYPos); } diff --git a/rlib-geometry/build.gradle b/rlib-geometry/build.gradle new file mode 100644 index 00000000..f6679eef --- /dev/null +++ b/rlib-geometry/build.gradle @@ -0,0 +1,4 @@ + +dependencies { + api projects.rlibCommon +} \ No newline at end of file diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/DirectionType.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/DirectionType.java new file mode 100644 index 00000000..f6c91624 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/DirectionType.java @@ -0,0 +1,13 @@ +package javasabr.rlib.geometry; + +/** + * @author JavaSaBr + */ +public enum DirectionType { + LEFT, + UP, + FRONT, + RIGHT, + DOWN, + BEHIND +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Matrix3f.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Matrix3f.java similarity index 66% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Matrix3f.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Matrix3f.java index 8a876261..d4866054 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Matrix3f.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Matrix3f.java @@ -1,26 +1,32 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; import javasabr.rlib.common.util.pools.Reusable; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** - * The implementation of float matrix 3x3. - * * @author JavaSaBr */ -@NullMarked +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public final class Matrix3f implements Reusable { - public static final Matrix3f ZERO = new Matrix3f(0, 0, 0, 0, 0, 0, 0, 0, 0); + public static final Matrix3f ZERO = new Matrix3f( + 0, 0, 0, + 0, 0, 0, + 0, 0, 0); public static final Matrix3f IDENTITY = new Matrix3f(); /** * Values. */ - protected float val_0_0, val_0_1, val_0_2; - protected float val_1_0, val_1_1, val_1_2; - protected float val_2_0, val_2_1, val_2_2; + float val_0_0, val_0_1, val_0_2; + float val_1_0, val_1_1, val_1_2; + float val_2_0, val_2_1, val_2_2; public Matrix3f() { val_0_1 = val_0_2 = val_1_0 = val_1_2 = val_2_0 = val_2_1 = 0; @@ -61,9 +67,6 @@ public Matrix3f( this.val_2_2 = val_2_2; } - /** - * Change all values to absolute. - */ public void absoluteLocal() { val_0_0 = Math.abs(val_0_0); val_0_1 = Math.abs(val_0_1); @@ -76,13 +79,6 @@ public void absoluteLocal() { val_2_2 = Math.abs(val_2_2); } - /** - * Multiply the vector by this matrix. - * - * @param vector the source vector. - * @param result the result vector. - * @return the result. - */ public Vector3f mult(Vector3f vector, Vector3f result) { float x = vector.x; @@ -96,19 +92,6 @@ public Vector3f mult(Vector3f vector, Vector3f result) { return result; } - /** - * Set the matrix values. - * - * @param val_0_0 the val 0 0 - * @param val_0_1 the val 0 1 - * @param val_0_2 the val 0 2 - * @param val_1_0 the val 1 0 - * @param val_1_1 the val 1 1 - * @param val_1_2 the val 1 2 - * @param val_2_0 the val 2 0 - * @param val_2_1 the val 2 1 - * @param val_2_2 the val 2 2 - */ public void set( float val_0_0, float val_0_1, @@ -130,19 +113,14 @@ public void set( this.val_2_2 = val_2_2; } - /** - * Set values from the rotation. - * - * @param rotation the rotation. - * @return this updated matrix. - */ public Matrix3f set(Quaternion4f rotation) { return rotation.toRotationMatrix(this); } @Override public String toString() { - return val_0_0 + ", " + val_0_1 + ", " + val_0_2 + "\n" + val_1_0 + ", " + val_1_1 + ", " + val_1_2 + "\n" + val_2_0 - + ", " + val_2_1 + ", " + val_2_2 + "\n"; + return val_0_0 + ", " + val_0_1 + ", " + val_0_2 + "\n" + + val_1_0 + ", " + val_1_1 + ", " + val_1_2 + "\n" + + val_2_0 + ", " + val_2_1 + ", " + val_2_2 + "\n"; } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Plane.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Plane.java similarity index 65% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Plane.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Plane.java index a2c695fc..09b308d5 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Plane.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Plane.java @@ -1,27 +1,31 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; -import static javasabr.rlib.common.geom.Vector3f.substract; +import static javasabr.rlib.geometry.Vector3f.substract; import javasabr.rlib.common.util.ExtMath; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** * Geometry 3D plane.
Follow to the formula:
Ax + By + Cz + D = 0
* * @author zcxv */ -@NullMarked +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public class Plane { /** * The plane normal */ - private final Vector3f normal; - + final Vector3f normal; /** * The D component, inverted by sign. */ - private float d; + float dot; public Plane(Vector3f first, Vector3f second, Vector3f third) { @@ -31,205 +35,92 @@ public Plane(Vector3f first, Vector3f second, Vector3f third) { normal = ba .cross(ca) .normalizeLocal(); - - this.d = first.dot(normal); + dot = first.dot(normal); } public Plane(Vector3f planePoint, Vector3f normal) { this.normal = normal.clone(); - this.d = planePoint.dot(normal); - } - - /** - * Return a plane normal. - * - * @return normal. - */ - public Vector3f getNormal() { - return normal; + this.dot = planePoint.dot(normal); } - /** - * Return a D component inverted by sign. - * - * @return the D component. - */ - public float getD() { - return d; - } - - /** - * Multiply plane by scalar. - * - * @param scalar scalar. - * @return this plane. - */ public Plane multLocal(float scalar) { normal.multLocal(scalar); - d *= scalar; + dot *= scalar; return this; } - /** - * Divide plane by scalar. - * - * @param scalar scalar. - * @return this plane . - */ public Plane divideLocal(float scalar) { normal.divideLocal(scalar); - d /= scalar; + dot /= scalar; return this; } - /** - * Add values to plane. - * - * @param x the X axis value. - * @param y the Y axis value. - * @param z the Z axis value. - * @param d the D component. - * @return this plane . - */ - public Plane addLocal(float x, float y, float z, float d) { + public Plane addLocal(float x, float y, float z, float dot) { normal.addLocal(x, y, z); - this.d += d; + this.dot += dot; return this; } - /** - * Subtract values to plane. - * - * @param x the X axis value. - * @param y the Y axis value. - * @param z the Z axis value. - * @param d the D component. - * @return this plane. - */ - public Plane subtractLocal(float x, float y, float z, float d) { + public Plane subtractLocal(float x, float y, float z, float dot) { normal.subtractLocal(x, y, z); - this.d -= d; + this.dot -= dot; return this; } - /** - * Multiply plane by other plane. - * - * @param plane the other plane. - * @return this plane . - */ public Plane multLocal(Plane plane) { normal.multLocal(plane.normal); - d *= plane.d; + dot *= plane.dot; return this; } - /** - * Divide plane by other plane. - * - * @param plane the other plane. - * @return this plane . - */ public Plane divideLocal(Plane plane) { normal.divideLocal(plane.normal); - d /= plane.d; + dot /= plane.dot; return this; } - /** - * Add plane by other plane. - * - * @param plane the other plane. - * @return this plane - */ public Plane addLocal(Plane plane) { normal.addLocal(plane.normal); - d += plane.d; + dot += plane.dot; return this; } - /** - * Subtract plane by other plane. - * - * @param plane the other plane - * @return this plane - */ public Plane subtractLocal(Plane plane) { normal.subtractLocal(plane.normal); - d -= plane.d; + dot -= plane.dot; return this; } - /** - * Multiply plane by vector.
Its operation is equals to multiply plane normal vector with vector. - * - * @param vector the vector. - * @return this plane. - */ public Plane multLocal(Vector3f vector) { normal.multLocal(vector); return this; } - /** - * Divide plane by vector.
Its operation is equals to divide plane normal vector with vector. - * - * @param vector the vector. - * @return this plane . - */ public Plane divideLocal(Vector3f vector) { normal.divideLocal(vector); return this; } - /** - * Add plane by vector.
Its operation is equals to: plane normal plus vector. - * - * @param vector the vector. - * @return this plane. - */ public Plane addLocal(Vector3f vector) { normal.addLocal(vector); return this; } - /** - * Subtract plane by vector.
Its operation is equals to: plane normal minus vector. - * - * @param vector the vector. - * @return this plane. - */ public Plane subtractLocal(Vector3f vector) { normal.subtractLocal(vector); return this; } - /** - * Dot product plane with vector. - * - * @param point vector - * @return dot product - */ public float dot(Vector3f point) { - return normal.dot(point) - d; + return normal.dot(point) - dot; } - /** - * Dot product plane with plane. - * - * @param plane plane - * @return dot product - */ public float dot(Plane plane) { - return normal.dot(plane.normal) - d * plane.d; + return normal.dot(plane.normal) - dot * plane.dot; } /** * Distance between the point and the plane. - * - * @param point the point. - * @param planePoint the plane point. - * @return the distance. */ public float distance(Vector3f point, Vector3f planePoint) { return distance(point, planePoint, Vector3fBuffer.NO_REUSE); @@ -237,11 +128,6 @@ public float distance(Vector3f point, Vector3f planePoint) { /** * Distance between the point and the plane. - * - * @param point the point. - * @param planePoint the plane point. - * @param buffer the vector's buffer. - * @return the distance. */ public float distance(Vector3f point, Vector3f planePoint, Vector3fBuffer buffer) { return buffer @@ -252,47 +138,34 @@ public float distance(Vector3f point, Vector3f planePoint, Vector3fBuffer buffer /** * Distance between point and plane. - * - * @param point point - * @return distance */ public float distance(Vector3f point) { - return -d + point.dot(normal); + return -dot + point.dot(normal); } /** * Angle between planes. - * - * @param plane plane - * @return angle in radians */ public float angle(Plane plane) { - return ExtMath.cos(normal.dot(plane.normal) / ExtMath.sqrt(normal.sqrLength() * plane.normal.sqrLength())); + return ExtMath.cos(normal.dot(plane.normal) / + ExtMath.sqrt(normal.sqrLength() * plane.normal.sqrLength())); } /** * Return true if the planes are parallel. - * - * @param plane the plane. - * @param epsilon the epsilon. - * @return true if the planes are parallel. */ public boolean isParallel(Plane plane, float epsilon) { // check plane normals to collinearity - var fA = plane.normal.getX() / normal.getX(); - var fB = plane.normal.getY() / normal.getY(); - var fC = plane.normal.getZ() / normal.getZ(); + var fA = plane.normal.x() / normal.x(); + var fB = plane.normal.y() / normal.y(); + var fC = plane.normal.z() / normal.z(); return Math.abs(fA - fB) < epsilon && Math.abs(fA - fC) < epsilon; } /** * Return true if the planes are perpendicular. - * - * @param plane the plane. - * @param epsilon the epsilon. - * @return true if the planes are perpendicular. */ public boolean isPerpendicular(Plane plane, float epsilon) { return Math.abs(normal.dot(plane.normal)) < epsilon; @@ -325,11 +198,13 @@ public Vector3f rayIntersection(Vector3f startPoint, Vector3f endPoint, Vector3f direction.subtractLocal(startPoint); var denominator = direction.dot(normal); - var distance = (d - startPoint.dot(normal)) / denominator; + var distance = (dot - startPoint.dot(normal)) / denominator; direction.multLocal(distance); - return new Vector3f(startPoint).addLocal(direction); + return buffer + .next(startPoint) + .addLocal(direction); } /** @@ -371,7 +246,9 @@ public Vector3f rayIntersection( direction.multLocal(distance); - return new Vector3f(startPoint).addLocal(direction); + return buffer + .next(startPoint) + .addLocal(direction); } /** @@ -395,16 +272,18 @@ public Vector3f rayIntersection(Ray3f ray) { */ public Vector3f rayIntersection(Ray3f ray, Vector3fBuffer buffer) { - var direction = ray.getDirection(); - var start = ray.getStart(); + var direction = ray.direction(); + var start = ray.start(); var denominator = direction.dot(normal); - var distance = (d - start.dot(normal)) / denominator; + var distance = (dot - start.dot(normal)) / denominator; var add = buffer.next(direction); add.multLocal(distance); - return new Vector3f(start).addLocal(add); + return buffer + .next(start) + .addLocal(add); } /** @@ -436,13 +315,15 @@ public Vector3f lineIntersection( var ab = buffer.next(secondPoint); ab.subtractLocal(startPoint); - var t = (d - normal.dot(startPoint)) / normal.dot(ab); + var t = (dot - normal.dot(startPoint)) / normal.dot(ab); if (t < 0 || t > 1.f) { return Vector3f.POSITIVE_INFINITY; } - return new Vector3f(startPoint).addLocal(ab.multLocal(t)); + return buffer + .next(startPoint) + .addLocal(ab.multLocal(t)); } /** @@ -468,7 +349,7 @@ public Vector3f planeIntersection(Plane plane, float epsilon) { */ public Vector3f planeIntersection(Plane plane, float epsilon, Vector3fBuffer buffer) { - var direction = normal.cross(plane.normal, buffer.nextVector()); + var direction = normal.cross(plane.normal, buffer.next()); var denominator = direction.dot(direction); if (denominator < epsilon) { @@ -476,32 +357,27 @@ public Vector3f planeIntersection(Plane plane, float epsilon, Vector3fBuffer buf return Vector3f.POSITIVE_INFINITY; } - return new Vector3f(plane.normal) - .multLocal(d) + return buffer + .next(plane.normal) + .multLocal(dot) .subtractLocal(buffer .next(normal) - .multLocal(plane.d)) + .multLocal(plane.dot)) .crossLocal(direction) .divideLocal(denominator); } - /** - * {@inheritDoc} - */ @Override public int hashCode() { int prime = 31; int result = 1; result = prime * result + normal.hashCode(); - result = prime * result + Float.floatToIntBits(d); + result = prime * result + Float.floatToIntBits(dot); return result; } - /** - * {@inheritDoc} - */ @Override public String toString() { - return "Plane{normal=" + normal + ", d=" + d + "}"; + return "Plane{normal=" + normal + ", d=" + dot + "}"; } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Polygon.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Polygon.java similarity index 69% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Polygon.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Polygon.java index 214b60a0..03675169 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Polygon.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Polygon.java @@ -1,36 +1,29 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; import static javasabr.rlib.common.util.array.ArrayFactory.toArray; import java.util.Arrays; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * Geometry 3D polygon. - * * @author zcxv */ -@NullMarked +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public class Polygon { private final static float EPSILON_ON_PLANE = 0.1f; private final static float EPSILON_CWW = 0.01f; - /** - * The polygon vertices. - */ - private final Vector3f[] vertices; + final Vector3f[] vertices; + final Plane plane; - /** - * The polygon plane. - */ - private final Plane plane; - - /** - * Custom flags. - */ - private int flags; + int flags; /** * Construct polygon from the vertices. @@ -59,7 +52,7 @@ public Polygon(Vector3f[] vertices, Vector3fBuffer buffer) throws IllegalArgumen this.vertices = vertices; - var normal = buffer.nextVector(); + var normal = buffer.next(); for (int i = 2; i < vertices.length; i++) { var ab = buffer @@ -71,7 +64,7 @@ public Polygon(Vector3f[] vertices, Vector3fBuffer buffer) throws IllegalArgumen normal.addLocal(ab.crossLocal(ac)); } - this.plane = new Plane(getPlanePoint(), normal.normalizeLocal()); + this.plane = new Plane(planePoint(), normal.normalizeLocal()); } /** @@ -91,14 +84,6 @@ public Polygon( this(toArray(first, second, third), buffer); } - /** - * Construct polygon from the 3 vertices. - * - * @param first the first vertex. - * @param second the second vertex. - * @param third the third vertex. - * @see Polygon#Polygon(Vector3f[]) - */ public Polygon(Vector3f first, Vector3f second, Vector3f third) { this(toArray(first, second, third), Vector3fBuffer.NO_REUSE); } @@ -108,103 +93,38 @@ public Polygon(Vector3f first, Vector3f second, Vector3f third) { * * @return the plane point. */ - public Vector3f getPlanePoint() { + public Vector3f planePoint() { return vertices[0]; } - /** - * Return polygon vertices. - * - * @return vertices - */ - public Vector3f[] getVertices() { - return vertices; - } - - /** - * Return polygon plane. - * - * @return plane - */ - public Plane getPlane() { - return plane; - } - - /** - * Return polygon custom flags.
By default it is zero. - * - * @return flags - */ - public int getFlags() { - return flags; - } - - /** - * Set polygon custom flags. - * - * @param flags flags - */ - public void setFlags(int flags) { + public void flags(int flags) { this.flags = flags; } - /** - * Toggle flag bit. - * - * @param flag flag - * @return flag status - */ public boolean toggleFlag(int flag) { flags ^= flag; return isFlagSet(flag); } - /** - * Return flag status. - * - * @param flag - * @return true if flag is set - */ public boolean isFlagSet(int flag) { return (flags & flag) != 0; } - /** - * Set flag bit. - * - * @param flag - */ public void setFlag(int flag) { flags |= flag; } - /** - * Unset flag bit. - * - * @param flag flag - */ public void unsetFlag(int flag) { flags &= ~flag; } - /** - * Return mid-point of this polygon. - * - * @return mid-point - */ - public Vector3f getMidPoint() { - return getMidPoint(Vector3fBuffer.NO_REUSE); + public Vector3f calculateMidPoint() { + return calculateMidPoint(Vector3fBuffer.NO_REUSE); } - /** - * Return mid-point of this polygon. - * - * @param buffer vector's buffer - * @return mid-point - */ - public Vector3f getMidPoint(Vector3fBuffer buffer) { + public Vector3f calculateMidPoint(Vector3fBuffer buffer) { - var point = buffer.nextVector(); + var point = buffer.next(); for (var vertice : vertices) { point.addLocal(vertice); @@ -213,25 +133,14 @@ public Vector3f getMidPoint(Vector3fBuffer buffer) { return point.divideLocal(vertices.length); } - /** - * Check polygon vertices to coplanar. - * - * @return true if polygon vertices is coplanar - */ - public boolean isCoplanar() { - return isCoplanar(Vector3fBuffer.NO_REUSE); + public boolean calculateIsCoplanar() { + return calculateIsCoplanar(Vector3fBuffer.NO_REUSE); } - /** - * Check polygon vertices to coplanar. - * - * @param buffer vector's buffer - * @return true if polygon vertices is coplanar - */ - public boolean isCoplanar(Vector3fBuffer buffer) { + public boolean calculateIsCoplanar(Vector3fBuffer buffer) { for (var vertice : vertices) { - if (!isOnPlane(vertice, buffer)) { + if (!isOnPlane(vertice)) { return false; } } @@ -239,24 +148,7 @@ public boolean isCoplanar(Vector3fBuffer buffer) { return true; } - /** - * Determines if point on polygon plane. - * - * @param point point - * @return true if point on plane - */ public boolean isOnPlane(Vector3f point) { - return isOnPlane(point, Vector3fBuffer.NO_REUSE); - } - - /** - * Determines if point on polygon plane. - * - * @param point point - * @param buffer vector's buffer - * @return true if point on plane - */ - public boolean isOnPlane(Vector3f point, Vector3fBuffer buffer) { var distance = plane.distance(point); return distance > -EPSILON_ON_PLANE && distance < EPSILON_ON_PLANE; } @@ -377,13 +269,10 @@ private boolean isTriangleCCW( ab.crossLocal(ac); return plane - .getNormal() + .normal() .dot(ab) > EPSILON_CWW; } - /** - * {@inheritDoc} - */ @Override public String toString() { return "Polygon{vertices=" + Arrays.toString(vertices) + ", plane=" + plane + ", flags=" + flags + "}"; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Quaternion4f.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Quaternion4f.java similarity index 52% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Quaternion4f.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Quaternion4f.java index 578826ac..44bef689 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Quaternion4f.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Quaternion4f.java @@ -1,18 +1,25 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; -import javasabr.rlib.common.geom.util.AngleUtils; import javasabr.rlib.common.util.ExtMath; import javasabr.rlib.common.util.random.Random; import javasabr.rlib.common.util.random.RandomFactory; -import org.jspecify.annotations.NullMarked; +import javasabr.rlib.geometry.util.AngleUtils; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * The implementation of rotation in 3D world based on Quaternion. - * * @author JavaSaBr */ -@NullMarked +@Getter +@Setter +@AllArgsConstructor +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PRIVATE) public class Quaternion4f { public static final Quaternion4f IDENTITY = new Quaternion4f(0, 0, 0, 1); @@ -21,34 +28,11 @@ public class Quaternion4f { private static final ThreadLocal ROTATION_LOCAL = ThreadLocal.withInitial(Quaternion4f::new); - /** - * Get the thread local instance. - * - * @return the thread local instance. - */ - public static Quaternion4f get() { + public static Quaternion4f threadLocal() { return ROTATION_LOCAL.get(); } - /** - * The X component. - */ - private float x; - - /** - * The Y component. - */ - private float y; - - /** - * The Z component. - */ - private float z; - - /** - * The W component. - */ - private float w; + float x, y, z, w; public Quaternion4f() { w = 1; @@ -62,19 +46,6 @@ public Quaternion4f(float angleX, float angleY, float angleZ) { fromAngles(angleX, angleY, angleZ); } - public Quaternion4f(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - /** - * Add local quaternion 4 f. - * - * @param rotation the rotation - * @return the quaternion 4 f - */ public Quaternion4f addLocal(Quaternion4f rotation) { this.x += rotation.x; this.y += rotation.y; @@ -83,51 +54,10 @@ public Quaternion4f addLocal(Quaternion4f rotation) { return this; } - /** - * Рассчет косинуса угла между текущим и указанным разворотом. - * - * @param rotation сверяемый разворот. - * @return косинус угла между 2мя разворотами. - */ public float dot(Quaternion4f rotation) { return w * rotation.w + x * rotation.x + y * rotation.y + z * rotation.z; } - @Override - public final boolean equals(Object obj) { - - if (this == obj) { - return true; - } else if (obj == null) { - return false; - } else if (getClass() != obj.getClass()) { - return false; - } - - Quaternion4f other = (Quaternion4f) obj; - - if (Float.floatToIntBits(w) != Float.floatToIntBits(other.w)) { - return false; - } else if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x)) { - return false; - } else if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y)) { - return false; - } else if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z)) { - return false; - } - - return true; - } - - /** - * Расчет разворота по углам в 3х осях. - * - * @param angleX угол по оси X. - * @param yAngle угол по оси Y. - * @param zAngle угол по оси Z. - * @return the quaternion 4 f - */ - public final Quaternion4f fromAngles(float angleX, float yAngle, float zAngle) { float angle = zAngle * 0.5f; @@ -158,53 +88,23 @@ public final Quaternion4f fromAngles(float angleX, float yAngle, float zAngle) { return normalizeLocal(); } - /** - * Calculate a rotation from angles. - * - * @param angles the angles. - * @return the quaternion 4 f - */ public final Quaternion4f fromAngles(float[] angles) { return fromAngles(angles[0], angles[1], angles[2]); } - /** - * fromAxes creates a Quaternion that represents the coordinate system defined by three - * axes. These axes are assumed to be orthogonal and no error checking is applied. Thus, the user must insure that the - * three axes being provided indeed represents a proper right handed coordinate system. - * - * @param axisX vector representing the x-axis of the coordinate system. - * @param axisY vector representing the y-axis of the coordinate system. - * @param axisZ vector representing the z-axis of the coordinate system. - * @return the quaternion 4 f - */ public Quaternion4f fromAxes(Vector3f axisX, Vector3f axisY, Vector3f axisZ) { return fromRotationMatrix( - axisX.getX(), - axisY.getX(), - axisZ.getX(), - axisX.getY(), - axisY.getY(), - axisZ.getY(), - axisX.getZ(), - axisY.getZ(), - axisZ.getZ()); + axisX.x(), + axisY.x(), + axisZ.x(), + axisX.y(), + axisY.y(), + axisZ.y(), + axisX.z(), + axisY.z(), + axisZ.z()); } - /** - * From rotation matrix quaternion 4 f. - * - * @param val_0_0 the val 0 0 - * @param val_0_1 the val 0 1 - * @param val_0_2 the val 0 2 - * @param val_1_0 the val 1 0 - * @param val_1_1 the val 1 1 - * @param val_1_2 the val 1 2 - * @param val_2_0 the val 2 0 - * @param val_2_1 the val 2 1 - * @param val_2_2 the val 2 2 - * @return the quaternion 4 f - */ public Quaternion4f fromRotationMatrix( float val_0_0, float val_0_1, @@ -252,23 +152,10 @@ public Quaternion4f fromRotationMatrix( return this; } - /** - * Calculate a vector for the direction type. - * - * @param type the direction type. - * @return the calculated vector. - */ public Vector3f getDirection(DirectionType type) { return getDirection(type, null); } - /** - * Calculate a vector for the direction type. - * - * @param type the direction type. - * @param store the vector to store result. - * @return the calculated vector. - */ public Vector3f getDirection(DirectionType type, @Nullable Vector3f store) { if (store == null) { @@ -293,41 +180,41 @@ public Vector3f getDirection(DirectionType type, @Nullable Vector3f store) { switch (type) { case RIGHT: { - store.setX(1 - 2 * (yy + zz)); - store.setY(2 * (xy + zw)); - store.setZ(2 * (xz - yw)); + store.x(1 - 2 * (yy + zz)); + store.y(2 * (xy + zw)); + store.z(2 * (xz - yw)); break; } case LEFT: { - store.setX(1 - 2 * (yy + zz)); - store.setY(2 * (xy + zw)); - store.setZ(2 * (xz - yw)); + store.x(1 - 2 * (yy + zz)); + store.y(2 * (xy + zw)); + store.z(2 * (xz - yw)); store.negateLocal(); break; } case UP: { - store.setX(2 * (xy - zw)); - store.setY(1 - 2 * (xx + zz)); - store.setZ(2 * (yz + xw)); + store.x(2 * (xy - zw)); + store.y(1 - 2 * (xx + zz)); + store.z(2 * (yz + xw)); break; } case DOWN: { - store.setX(2 * (xy - zw)); - store.setY(1 - 2 * (xx + zz)); - store.setZ(2 * (yz + xw)); + store.x(2 * (xy - zw)); + store.y(1 - 2 * (xx + zz)); + store.z(2 * (yz + xw)); store.negateLocal(); break; } case FRONT: { - store.setX(2 * (xz + yw)); - store.setY(2 * (yz - xw)); - store.setZ(1 - 2 * (xx + yy)); + store.x(2 * (xz + yw)); + store.y(2 * (yz - xw)); + store.z(1 - 2 * (xx + yy)); break; } case BEHIND: { - store.setX(2 * (xz + yw)); - store.setY(2 * (yz - xw)); - store.setZ(1 - 2 * (xx + yy)); + store.x(2 * (xz + yw)); + store.y(2 * (yz - xw)); + store.z(1 - 2 * (xx + yy)); store.negateLocal(); break; } @@ -336,76 +223,30 @@ public Vector3f getDirection(DirectionType type, @Nullable Vector3f store) { return store; } - /** - * Gets w. - * - * @return степень разворота по оси w. - */ - public final float getW() { - return w; - } - - /** - * Sets w. - * - * @param w степень разворота по оси w. - */ - public final void setW(float w) { - this.w = w; - } - - /** - * Gets x. - * - * @return степень разворота по оси х. - */ - public final float getX() { - return x; - } - - /** - * Sets x. - * - * @param x степень разворота по оси х. - */ - public final void setX(float x) { - this.x = x; - } + @Override + public final boolean equals(Object obj) { - /** - * Gets y. - * - * @return степень разворота по оси y. - */ - public final float getY() { - return y; - } + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } else if (getClass() != obj.getClass()) { + return false; + } - /** - * Sets y. - * - * @param y степень разворота по оси y. - */ - public final void setY(float y) { - this.y = y; - } + Quaternion4f other = (Quaternion4f) obj; - /** - * Gets z. - * - * @return степень разворота по оси z. - */ - public final float getZ() { - return z; - } + if (Float.floatToIntBits(w) != Float.floatToIntBits(other.w)) { + return false; + } else if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x)) { + return false; + } else if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y)) { + return false; + } else if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z)) { + return false; + } - /** - * Sets z. - * - * @param z степень разворота по оси z. - */ - public final void setZ(float z) { - this.z = z; + return true; } @Override @@ -422,23 +263,10 @@ public final int hashCode() { return result; } - /** - * Calculate the value of the quaternion, which will look in the specified direction. - * - * @param direction the direction. - * @param up the vector of orientation where is top. - */ public void lookAt(Vector3f direction, Vector3f up) { lookAt(direction, up, Vector3fBuffer.NO_REUSE); } - /** - * Calculate the value of the quaternion, which will look in the specified direction. - * - * @param direction the direction. - * @param up the vector of orientation where is top. - * @param buffer the vector's buffer. - */ public void lookAt(Vector3f direction, Vector3f up, Vector3fBuffer buffer) { var axisZ = buffer @@ -456,42 +284,30 @@ public void lookAt(Vector3f direction, Vector3f up, Vector3fBuffer buffer) { .normalizeLocal(); fromAxes(axisX, axisY, axisZ); - normalizeLocal(); } - /** - * Приминение разворота на вектор. - * - * @param vector вектор, который надо развернуть. - * @return полученный вектор. - */ public final Vector3f multLocal(Vector3f vector) { - final float vectorX = vector.getX(); - final float vectorY = vector.getY(); - final float vectorZ = vector.getZ(); + float vectorX = vector.x(); + float vectorY = vector.y(); + float vectorZ = vector.z(); - final float x = getX(); - final float y = getY(); - final float z = getZ(); - final float w = getW(); + float x = x(); + float y = y(); + float z = z(); + float w = w(); - vector.setX(w * w * vectorX + 2 * y * w * vectorZ - 2 * z * w * vectorY + x * x * vectorX + 2 * y * x * vectorY + vector.x(w * w * vectorX + 2 * y * w * vectorZ - 2 * z * w * vectorY + x * x * vectorX + 2 * y * x * vectorY + 2 * z * x * vectorZ - z * z * vectorX - y * y * vectorX); - vector.setY(2 * x * y * vectorX + y * y * vectorY + 2 * z * y * vectorZ + 2 * w * z * vectorX - z * z * vectorY + vector.y(2 * x * y * vectorX + y * y * vectorY + 2 * z * y * vectorZ + 2 * w * z * vectorX - z * z * vectorY + w * w * vectorY - 2 * x * w * vectorZ - x * x * vectorY); - vector.setZ(2 * x * z * vectorX + 2 * y * z * vectorY + z * z * vectorZ - 2 * w * y * vectorX - y * y * vectorZ + vector.z(2 * x * z * vectorX + 2 * y * z * vectorY + z * z * vectorZ - 2 * w * y * vectorX - y * y * vectorZ + 2 * w * x * vectorY - x * x * vectorZ + w * w * vectorZ); return vector; } - /** - * Negate local quaternion 4 f. - * - * @return перевернуть значения. - */ public final Quaternion4f negateLocal() { x = -x; y = -y; @@ -500,20 +316,10 @@ public final Quaternion4f negateLocal() { return this; } - /** - * Norm float. - * - * @return норма этого разворота. - */ public float norm() { return w * w + x * x + y * y + z * z; } - /** - * Normalizing of the current quaternion - * - * @return this quaternion. - */ public final Quaternion4f normalizeLocal() { var norm = ExtMath.invSqrt(norm()); @@ -526,18 +332,10 @@ public final Quaternion4f normalizeLocal() { return this; } - /** - * Создание случайного разворота. - */ public void random() { random(RANDOM_LOCAL.get()); } - /** - * Создание случайного разворота. - * - * @param random the random - */ public void random(Random random) { float x = AngleUtils.degreeToRadians(random.nextInt(0, 360)); @@ -547,12 +345,6 @@ public void random(Random random) { fromAngles(x, y, z); } - /** - * Set quaternion 4 f. - * - * @param rotation the rotation - * @return the quaternion 4 f - */ public Quaternion4f set(Quaternion4f rotation) { this.x = rotation.x; this.y = rotation.y; @@ -561,28 +353,16 @@ public Quaternion4f set(Quaternion4f rotation) { return this; } - /** - * Sets xyzw. - * - * @param x the x - * @param y the y - * @param z the z - * @param w the w - */ - public void setXYZW(final float x, final float y, final float z, final float w) { + public void set(float x, float y, float z, float w) { this.x = x; this.y = y; this.z = z; this.w = w; } - /** - * Рассчитывает промежуточный разворот между текуим и указанным в зависимости от указанного %. - * - * @param end конечный разворот. - * @param percent % разворота от текущего к конечному. - */ + public void slerp(Quaternion4f end, float percent) { + if (equals(end)) { return; } @@ -601,10 +381,8 @@ public void slerp(Quaternion4f end, float percent) { float scale1 = percent; if (1 - result > 0.1f) { - - final float theta = ExtMath.acos(result); - final float invSinTheta = 1f / ExtMath.sin(theta); - + float theta = ExtMath.acos(result); + float invSinTheta = 1f / ExtMath.sin(theta); scale0 = ExtMath.sin((1 - percent) * theta) * invSinTheta; scale1 = ExtMath.sin(percent * theta) * invSinTheta; } @@ -615,29 +393,10 @@ public void slerp(Quaternion4f end, float percent) { w = scale0 * w + scale1 * end.w; } - /** - * Рассчитывает промежуточный разворот от указанного стартового, до указанного конечного в зависимости от указанного - * %. - * - * @param start стартовый разворот. - * @param end конечный разворот. - * @param percent % разворота от стартового до конечного. - * @return the quaternion 4 f - */ public Quaternion4f slerp(Quaternion4f start, Quaternion4f end, float percent) { return slerp(start, end, percent, false); } - /** - * Рассчитывает промежуточный разворот от указанного стартового, до указанного конечного в зависимости от указанного - * %. - * - * @param start стартовый разворот. - * @param end конечный разворот. - * @param percent % разворота от стартового до конечного. - * @param forceLinear принудительное использование линейной интерполяции. - * @return the quaternion 4 f - */ public final Quaternion4f slerp(Quaternion4f start, Quaternion4f end, float percent, boolean forceLinear) { if (start.equals(end)) { @@ -656,29 +415,20 @@ public final Quaternion4f slerp(Quaternion4f start, Quaternion4f end, float perc float endScale = percent; if (!forceLinear && 1 - result > 0.1f) { - - final float theta = ExtMath.acos(result); - final float invSinTheta = 1f / ExtMath.sin(theta); - + float theta = ExtMath.acos(result); + float invSinTheta = 1f / ExtMath.sin(theta); startScale = ExtMath.sin((1 - percent) * theta) * invSinTheta; endScale = ExtMath.sin(percent * theta) * invSinTheta; } - this.x = startScale * start.getX() + endScale * end.getX(); - this.y = startScale * start.getY() + endScale * end.getY(); - this.z = startScale * start.getZ() + endScale * end.getZ(); - this.w = startScale * start.getW() + endScale * end.getW(); + this.x = startScale * start.x() + endScale * end.x(); + this.y = startScale * start.y() + endScale * end.y(); + this.z = startScale * start.z() + endScale * end.z(); + this.w = startScale * start.w() + endScale * end.w(); return this; } - /** - * Рассчитывает промежуточный разворот от указанного стартового, до указанного конечного в зависимости от указанного - * %. - * - * @param targetRotation конечный разворот. - * @param percent % разворота от стартового до конечного. - */ public void nlerp(Quaternion4f targetRotation, float percent) { float dot = dot(targetRotation); @@ -699,12 +449,6 @@ public void nlerp(Quaternion4f targetRotation, float percent) { normalizeLocal(); } - /** - * Subtract local quaternion 4 f. - * - * @param rotation the rotation - * @return the quaternion 4 f - */ public Quaternion4f subtractLocal(Quaternion4f rotation) { this.x -= rotation.x; this.y -= rotation.y; @@ -713,38 +457,25 @@ public Quaternion4f subtractLocal(Quaternion4f rotation) { return this; } - /** - * To angle axis float. - * - * @param axisStore the axis store - * @return the float - */ public final float toAngleAxis(@Nullable Vector3f axisStore) { float sqrLength = x * x + y * y + z * z; float angle; if (sqrLength == 0.0f) { - angle = 0.0f; - if (axisStore != null) { - axisStore.setX(1.0F); - axisStore.setY(0.0F); - axisStore.setZ(0.0F); + axisStore.x(1.0F); + axisStore.y(0.0F); + axisStore.z(0.0F); } - } else { - angle = 2.0f * ExtMath.acos(w); - if (axisStore != null) { - float invLength = 1.0f / ExtMath.sqrt(sqrLength); - - axisStore.setX(x * invLength); - axisStore.setY(y * invLength); - axisStore.setZ(z * invLength); + axisStore.x(x * invLength); + axisStore.y(y * invLength); + axisStore.z(z * invLength); } } @@ -797,35 +528,28 @@ public float[] toAngles(float @Nullable [] angles) { return angles; } - /** - * Конвектирование квантерниона в матрицу 3х3 - * - * @param result матрица, в которую занести нужно результат. - * @return результат в виде матрицы. - */ public final Matrix3f toRotationMatrix(Matrix3f result) { - final float norm = norm(); - - final float s = norm == 1f ? 2f : norm > 0f ? 2f / norm : 0; - - final float x = getX(); - final float y = getY(); - final float z = getZ(); - final float w = getW(); + float norm = norm(); + float s = norm == 1f ? 2f : norm > 0f ? 2f / norm : 0; - final float xs = x * s; - final float ys = y * s; - final float zs = z * s; - final float xx = x * xs; - final float xy = x * ys; - final float xz = x * zs; - final float xw = w * xs; - final float yy = y * ys; - final float yz = y * zs; - final float yw = w * ys; - final float zz = z * zs; - final float zw = w * zs; + float x = x(); + float y = y(); + float z = z(); + float w = w(); + + float xs = x * s; + float ys = y * s; + float zs = z * s; + float xx = x * xs; + float xy = x * ys; + float xz = x * zs; + float xw = w * xs; + float yy = y * ys; + float yz = y * zs; + float yw = w * ys; + float zz = z * zs; + float zw = w * zs; result.set( 1 - (yy + zz), @@ -841,12 +565,6 @@ public final Matrix3f toRotationMatrix(Matrix3f result) { return result; } - /** - * Rotate the vector by this quaternion. - * - * @param vector the vector to rotate. - * @return the same vector which was rotated. - */ public Vector3f rotate(Vector3f vector) { float px = vector.x; @@ -856,22 +574,22 @@ public Vector3f rotate(Vector3f vector) { float norm = norm(); float s = norm == 1f ? 2f : norm > 0f ? 2f / norm : 0; - float x = getX() * s; - float y = getY() * s; - float z = getZ() * s; - float xx = getX() * x; - float xy = getX() * y; - float xz = getX() * z; - float xw = getW() * x; - float yy = getY() * y; - float yz = getY() * z; - float yw = getW() * y; - float zz = getZ() * z; - float zw = getW() * z; - - vector.setX((1f - (yy + zz)) * px + (xy - zw) * py + (xz + yw) * pz); - vector.setY((xy + zw) * px + (1f - (xx + zz)) * py + (yz - xw) * pz); - vector.setZ((xz - yw) * px + (yz - xw) * py + (1f - (xx + yy)) * pz); + float x = x() * s; + float y = y() * s; + float z = z() * s; + float xx = x() * x; + float xy = x() * y; + float xz = x() * z; + float xw = w() * x; + float yy = y() * y; + float yz = y() * z; + float yw = w() * y; + float zz = z() * z; + float zw = w() * z; + + vector.x((1f - (yy + zz)) * px + (xy - zw) * py + (xz + yw) * pz); + vector.y((xy + zw) * px + (1f - (xx + zz)) * py + (yz - xw) * pz); + vector.z((xz - yw) * px + (yz - xw) * py + (1f - (xx + yy)) * pz); return vector; } diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/Ray3f.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Ray3f.java new file mode 100644 index 00000000..f8cb3d90 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Ray3f.java @@ -0,0 +1,40 @@ +package javasabr.rlib.geometry; + +import javasabr.rlib.common.util.pools.Reusable; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class Ray3f implements Reusable { + + Vector3f start, direction; + + /** + * Construct empty ray in zero point and zero direction. + */ + public Ray3f() { + this(new Vector3f(), new Vector3f()); + } + + public final void direction(Vector3f direction) { + this.direction.set(direction); + } + + public final void start(Vector3f start) { + this.start.set(start); + } + + @Override + public String toString() { + return "Ray3f{" + "start=" + start + ", direction=" + direction + '}'; + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Vector2f.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector2f.java similarity index 50% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Vector2f.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector2f.java index 6e7f9ecf..41ff7b90 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Vector2f.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector2f.java @@ -1,18 +1,25 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; import static java.lang.Float.floatToIntBits; import static java.lang.Float.isFinite; import javasabr.rlib.common.util.ExtMath; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * Implementation of float vector in 2D space (two coordinates) - * * @author zcxv */ -@NullMarked +@Setter +@Getter +@AllArgsConstructor +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public class Vector2f implements Cloneable { public final static Vector2f ZERO = new Vector2f(0, 0); @@ -32,85 +39,40 @@ public class Vector2f implements Cloneable { /** * Return true if the vector is not null and valid. - * - * @param vector the vector. - * @return true if the vector is not null and valid. */ public static boolean isValid(@Nullable Vector2f vector) { - return vector != null && isFinite(vector.getX()) && isFinite(vector.getY()); + return vector != null && isFinite(vector.x()) && isFinite(vector.y()); } - /** - * The X component. - */ - private float x; - - /** - * The Y component. - */ - private float y; - - public Vector2f() { - } + float x, y; public Vector2f(float value) { this.x = value; this.y = value; } - public Vector2f(float x, float y) { - this.x = x; - this.y = y; - } - public Vector2f(float[] components) { this(components[0], components[1]); } public Vector2f(Vector2f another) { - this(another.getX(), another.getY()); + this(another.x(), another.y()); } - /** - * Add coordinates to this vector. - * - * @param addX x axis value. - * @param addY y axis value. - * @return this vector - */ public Vector2f addLocal(float addX, float addY) { x += addX; y += addY; return this; } - /** - * Add the vector to this vector. - * - * @param vector the vector. - * @return this vector. - */ public Vector2f addLocal(Vector2f vector) { return addLocal(vector.x, vector.y); } - /** - * Calculate distance to the vector. - * - * @param vector the vector. - * @return the distance. - */ public float distance(Vector2f vector) { return ExtMath.sqrt(distanceSquared(vector)); } - /** - * Calculate squared distance to the coordinates. - * - * @param targetX the target x. - * @param targetY the target y. - * @return the squared distance. - */ public float distanceSquared(float targetX, float targetY) { var dx = x - targetX; @@ -119,66 +81,15 @@ public float distanceSquared(float targetX, float targetY) { return dx * dx + dy * dy; } - /** - * Calculate squared distance to the vector. - * - * @param vector the vector. - * @return the squared distance. - */ public float distanceSquared(Vector2f vector) { return distanceSquared(vector.x, vector.y); } - /** - * Calculate dot to the vector. - * - * @param vector the vector. - * @return the dot product. - */ + public float dot(Vector2f vector) { return x * vector.x + y * vector.y; } - /** - * Get the X component. - * - * @return the X component. - */ - public float getX() { - return x; - } - - /** - * Set the X component. - * - * @param x the X component. - * @return this vector. - */ - public Vector2f setX(float x) { - this.x = x; - return this; - } - - /** - * Get the Y component. - * - * @return the Y component. - */ - public float getY() { - return y; - } - - /** - * Set the Y component, - * - * @param y the Y component. - * @return this vector. - */ - public Vector2f setY(float y) { - this.y = y; - return this; - } - @Override public int hashCode() { var prime = 31; @@ -190,71 +101,35 @@ public int hashCode() { /** * Return true if all components are zero. - * - * @return true if all components are zero. */ public boolean isZero() { return ExtMath.isZero(x) && ExtMath.isZero(y); } - /** - * Multiply this vector by the scalar. - * - * @param scalar the scalar. - * @return this vector. - */ public Vector2f multLocal(float scalar) { return multLocal(scalar, scalar); } - /** - * Multiply this vector by the scalar values. - * - * @param x the x scalar. - * @param y the y scalar. - * @return this vector. - */ public Vector2f multLocal(float x, float y) { this.x *= x; this.y *= y; return this; } - /** - * Multiply this vector by the vector. - * - * @param vector the vector. - * @return this vector. - */ public Vector2f multLocal(Vector2f vector) { - return multLocal(vector.getX(), vector.getY()); + return multLocal(vector.x(), vector.y()); } - /** - * Create a new vector as negative version of this vector. - * - * @return the new negative vector. - */ public Vector2f negate() { - return new Vector2f(-getX(), -getY()); + return new Vector2f(-x(), -y()); } - /** - * Invert this vector to get a negative vector. - * - * @return this vector. - */ public Vector2f negateLocal() { x = -x; y = -y; return this; } - /** - * Create a normalized vector from this vector. - * - * @return the new normalized vector. - */ public Vector2f normalize() { float length = x * x + y * y; @@ -267,11 +142,6 @@ public Vector2f normalize() { return new Vector2f(x, y); } - /** - * Normalize this vector. - * - * @return this vector. - */ public Vector2f normalizeLocal() { float length = x * x + y * y; @@ -285,130 +155,63 @@ public Vector2f normalizeLocal() { return this; } - /** - * Set components from the vector to this vector. - * - * @param vector the vector. - * @return this vector. - */ public Vector2f set(Vector2f vector) { return set(vector.x, vector.y); } - /** - * Set the components to this vector. - * - * @param x x component. - * @param y y component. - * @return this vector. - */ public Vector2f set(float x, float y) { this.x = x; this.y = y; return this; } - /** - * Subtract this vector by the vector and store it to the result vector. - * - * @param vector the vector. - * @param result the result. - * @return the result vector. - */ public Vector2f subtract(Vector2f vector, Vector2f result) { result.x = x - vector.x; result.y = y - vector.y; return result; } - /** - * Subtract the components from this vector. - * - * @param subX the sub x. - * @param subY the sub y. - * @return this changed vector. - */ public Vector2f subtractLocal(float subX, float subY) { x -= subX; y -= subY; return this; } - /** - * Subtract the vector from this vector. - * - * @param vector the vector. - * @return this changed vector. - */ public Vector2f subtractLocal(Vector2f vector) { return subtractLocal(vector.x, vector.y); } - /** - * Return vector's length (magnitude). - * - * @return the vector's length. - */ public float length() { return ExtMath.sqrt(x * x + y * y); } - /** - * Return vector's squared length (magnitude). - * - * @return the vector's squared length. - */ public float sqrLength() { return x * x + y * y; } - /** - * Divide this vector by the components. - * - * @param x the divider x. - * @param y the divider y. - * @return this changed vector. - */ public Vector2f divideLocal(float x, float y) { this.x /= x; this.y /= y; return this; } - /** - * Divide this vector by the vector. - * - * @param vector the divider vector. - * @return this changed vector. - */ public Vector2f divideLocal(Vector2f vector) { return divideLocal(vector.x, vector.y); } - /** - * Divide this vector by the scalar. - * - * @param scalar the divider scalar. - * @return this changed vector. - */ public Vector2f divideLocal(float scalar) { return divideLocal(scalar, scalar); } /** * Linear time-based interpolation stored to this vector. - * - * @param min the minimal vector - * @param max the maximal vector - * @param t the time - * @return this vector. */ - public Vector2f lerp(Vector2f min, Vector2f max, float t) { + public Vector2f lerp(Vector2f min, Vector2f max, float time) { - t = ExtMath.clamp(t); + time = ExtMath.clamp(time); - this.x = min.x + (max.x - min.x) * t; - this.y = min.y + (max.y - min.y) * t; + this.x = min.x + (max.x - min.x) * time; + this.y = min.y + (max.y - min.y) * time; return this; } @@ -422,15 +225,12 @@ protected Vector2f clone() { } } - /** - * Check vectors to equals with epsilon. - * - * @param vector vector - * @param epsilon epsilon - * @return true if vectors equals - */ public boolean equals(Vector3f vector, float epsilon) { - return Math.abs(x - vector.getX()) < epsilon && Math.abs(y - vector.getY()) < epsilon; + return Math.abs(x - vector.x()) < epsilon && Math.abs(y - vector.y()) < epsilon; + } + + public boolean equals(Vector2f vector, float epsilon) { + return Math.abs(x - vector.x()) < epsilon && Math.abs(y - vector.y()) < epsilon; } @Override @@ -455,20 +255,8 @@ public boolean equals(@Nullable Object obj) { return true; } - /** - * Return true if these vectors are equal with the epsilon. - * - * @param vector the vector. - * @param epsilon the epsilon. - * @return true if these vectors are equal with the epsilon. - */ - public boolean equals(Vector2f vector, float epsilon) { - return Math.abs(x - vector.getX()) < epsilon && Math.abs(y - vector.getY()) < epsilon; - } - @Override public String toString() { return "Vector2f(" + x + ", " + y + ')'; } - } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Vector3f.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector3f.java similarity index 54% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Vector3f.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector3f.java index a1538631..5c61b6e5 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Vector3f.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector3f.java @@ -1,18 +1,25 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; import static java.lang.Float.floatToIntBits; import static java.lang.Float.isFinite; import javasabr.rlib.common.util.ExtMath; -import org.jspecify.annotations.NullMarked; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * The implementation of vector with 3 float values. - * * @author JavaSaBr */ -@NullMarked +@Setter +@Getter +@AllArgsConstructor +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) public final class Vector3f implements Cloneable { public final static Vector3f ZERO = new Vector3f(0, 0, 0); @@ -40,20 +47,13 @@ public final class Vector3f implements Cloneable { /** * Return true if the vector is not null and valid. - * - * @param vector the vector. - * @return true if the vector is not null and valid. */ public static boolean isValid(@Nullable Vector3f vector) { - return vector != null && isFinite(vector.getX()) && isFinite(vector.getY()) && isFinite(vector.getZ()); + return vector != null && isFinite(vector.x()) && isFinite(vector.y()) && isFinite(vector.z()); } /** - * Get a subtraction result between the two vectors. - * - * @param first the first vector. - * @param second the second vector. - * @return the subtraction result. + * Create a subtraction result between the two vectors. */ public static Vector3f substract(Vector3f first, Vector3f second) { return first @@ -61,20 +61,7 @@ public static Vector3f substract(Vector3f first, Vector3f second) { .subtractLocal(second); } - /** - * The X component. - */ - protected float x; - - /** - * The Y component. - */ - protected float y; - - /** - * The Z component. - */ - protected float z; + float x, y, z; public Vector3f() { super(); @@ -86,28 +73,14 @@ public Vector3f(float value) { this.z = value; } - public Vector3f(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - public Vector3f(float[] components) { this(components[0], components[1], components[2]); } public Vector3f(Vector3f another) { - this(another.getX(), another.getY(), another.getZ()); + this(another.x(), another.y(), another.z()); } - /** - * Add the values to this vector. - * - * @param addX x axis value. - * @param addY y axis value. - * @param addZ z axis value. - * @return this vector. - */ public Vector3f addLocal(float addX, float addY, float addZ) { x += addX; y += addY; @@ -115,25 +88,10 @@ public Vector3f addLocal(float addX, float addY, float addZ) { return this; } - /** - * Add the vector to this vector. - * - * @param vector the vector. - * @return this vector. - */ public Vector3f addLocal(Vector3f vector) { return addLocal(vector.x, vector.y, vector.z); } - /** - * Calculate a cross vector between this vector and the coordinates. - * - * @param otherX the other x - * @param otherY the other y - * @param otherZ the other z - * @param result the result vector. - * @return the result vector. - */ public Vector3f cross(float otherX, float otherY, float otherZ, Vector3f result) { var resX = y * otherZ - z * otherY; @@ -145,35 +103,14 @@ public Vector3f cross(float otherX, float otherY, float otherZ, Vector3f result) return result; } - /** - * Calculate a cross vector between this vector and the vector. - * - * @param vector the vector. - * @return the result vector. - */ public Vector3f cross(Vector3f vector) { return cross(vector, new Vector3f()); } - /** - * Calculate a cross vector between this vector and the vector. - * - * @param vector the vector. - * @param result the result vector to store result. - * @return the result vector. - */ public Vector3f cross(Vector3f vector, Vector3f result) { return cross(vector.x, vector.y, vector.z, result); } - /** - * Calculate a cross vector between this vector and the coordinates and store the result to this vector. - * - * @param otherX the other x. - * @param otherY the other y. - * @param otherZ the other z. - * @return this changed vector. - */ public Vector3f crossLocal(float otherX, float otherY, float otherZ) { var tempx = y * otherZ - z * otherY; @@ -186,34 +123,14 @@ public Vector3f crossLocal(float otherX, float otherY, float otherZ) { return this; } - /** - * Calculate a cross vector between this vector and the coordinates and store the result to this vector. - * - * @param vector the vector. - * @return this changed vector. - */ public Vector3f crossLocal(Vector3f vector) { return crossLocal(vector.x, vector.y, vector.z); } - /** - * Calculate distance to the vector. - * - * @param vector the vector. - * @return the distance. - */ public float distance(Vector3f vector) { return ExtMath.sqrt(distanceSquared(vector)); } - /** - * Calculate squared distance to the coordinates. - * - * @param targetX the target x. - * @param targetY the target y. - * @param targetZ the target z. - * @return the squared distance. - */ public float distanceSquared(float targetX, float targetY, float targetZ) { var dx = x - targetX; @@ -223,86 +140,14 @@ public float distanceSquared(float targetX, float targetY, float targetZ) { return dx * dx + dy * dy + dz * dz; } - /** - * Calculate squared distance to the vector. - * - * @param vector the vector. - * @return the squared distance. - */ public float distanceSquared(Vector3f vector) { return distanceSquared(vector.x, vector.y, vector.z); } - /** - * Calculate dot to the vector. - * - * @param vector the vector. - * @return the dot product. - */ public float dot(Vector3f vector) { return x * vector.x + y * vector.y + z * vector.z; } - /** - * Get the X component. - * - * @return the X component. - */ - public float getX() { - return x; - } - - /** - * Set the X component. - * - * @param x the X component. - * @return this vector. - */ - public Vector3f setX(float x) { - this.x = x; - return this; - } - - /** - * Get the Y component. - * - * @return the Y component. - */ - public float getY() { - return y; - } - - /** - * Set the Y component, - * - * @param y the Y component. - * @return this vector. - */ - public Vector3f setY(float y) { - this.y = y; - return this; - } - - /** - * Get the Z component. - * - * @return the Z component. - */ - public float getZ() { - return z; - } - - /** - * Set the Z component, - * - * @param z the Z component. - * @return this vector. - */ - public Vector3f setZ(float z) { - this.z = z; - return this; - } - @Override public int hashCode() { var prime = 31; @@ -315,31 +160,15 @@ public int hashCode() { /** * Return true if all components are zero. - * - * @return true if all components are zero. */ public boolean isZero() { return this == ZERO || ExtMath.isZero(x) && ExtMath.isZero(y) && ExtMath.isZero(z); } - /** - * Multiply this vector by the scalar. - * - * @param scalar the scalar. - * @return this vector. - */ public Vector3f multLocal(float scalar) { return multLocal(scalar, scalar, scalar); } - /** - * Multiply this vector by the scalar values. - * - * @param x the x scalar. - * @param y the y scalar. - * @param z the z scalar. - * @return this vector. - */ public Vector3f multLocal(float x, float y, float z) { this.x *= x; this.y *= y; @@ -347,30 +176,14 @@ public Vector3f multLocal(float x, float y, float z) { return this; } - /** - * Multiply this vector by the vector. - * - * @param vector the vector. - * @return this vector. - */ public Vector3f multLocal(Vector3f vector) { - return multLocal(vector.getX(), vector.getY(), vector.getZ()); + return multLocal(vector.x(), vector.y(), vector.z()); } - /** - * Create a new vector as negative version of this vector. - * - * @return the new negative vector. - */ public Vector3f negate() { - return new Vector3f(-getX(), -getY(), -getZ()); + return new Vector3f(-x(), -y(), -z()); } - /** - * Invert this vector to get a negative vector. - * - * @return this vector. - */ public Vector3f negateLocal() { x = -x; y = -y; @@ -378,11 +191,6 @@ public Vector3f negateLocal() { return this; } - /** - * Create a normalized vector from this vector. - * - * @return the new normalized vector. - */ public Vector3f normalize() { var length = x * x + y * y + z * z; @@ -395,11 +203,6 @@ public Vector3f normalize() { return new Vector3f(x, y, z); } - /** - * Normalize this vector. - * - * @return this vector. - */ public Vector3f normalizeLocal() { var length = x * x + y * y + z * z; @@ -414,24 +217,10 @@ public Vector3f normalizeLocal() { return this; } - /** - * Set components from the vector to this vector. - * - * @param vector the vector. - * @return this vector. - */ public Vector3f set(Vector3f vector) { return set(vector.x, vector.y, vector.z); } - /** - * Set the components to this vector. - * - * @param x x component. - * @param y y component. - * @param z z component. - * @return this vector. - */ public Vector3f set(float x, float y, float z) { this.x = x; this.y = y; @@ -439,13 +228,6 @@ public Vector3f set(float x, float y, float z) { return this; } - /** - * Subtract the vector from this vector and store the result to the result vector. - * - * @param vector the vector. - * @param result the result. - * @return the result vector. - */ public Vector3f subtract(Vector3f vector, Vector3f result) { result.x = x - vector.x; result.y = y - vector.y; @@ -453,14 +235,6 @@ public Vector3f subtract(Vector3f vector, Vector3f result) { return result; } - /** - * Subtract the components from this vector. - * - * @param subX the sub x. - * @param subY the sub y. - * @param subZ the sub z. - * @return this changed vector. - */ public Vector3f subtractLocal(float subX, float subY, float subZ) { x -= subX; y -= subY; @@ -468,42 +242,18 @@ public Vector3f subtractLocal(float subX, float subY, float subZ) { return this; } - /** - * Subtract the vector from this vector. - * - * @param vector the vector. - * @return this changed vector. - */ public Vector3f subtractLocal(Vector3f vector) { return subtractLocal(vector.x, vector.y, vector.z); } - /** - * Return vector's length (magnitude). - * - * @return the vector's length. - */ public float length() { return ExtMath.sqrt(x * x + y * y + z * z); } - /** - * Return vector's squared length (magnitude). - * - * @return the vector's squared length. - */ public float sqrLength() { return x * x + y * y + z * z; } - /** - * Divide this vector by the components. - * - * @param x the divider x. - * @param y the divider y. - * @param z the divider z. - * @return this changed vector. - */ public Vector3f divideLocal(float x, float y, float z) { this.x /= x; this.y /= y; @@ -511,35 +261,19 @@ public Vector3f divideLocal(float x, float y, float z) { return this; } - /** - * Divide this vector by the vector. - * - * @param vector the divider vector. - * @return this changed vector. - */ public Vector3f divideLocal(Vector3f vector) { return divideLocal(vector.x, vector.y, vector.z); } - /** - * Divide this vector by the scalar. - * - * @param scalar the divider scalar. - * @return this changed vector. - */ public Vector3f divideLocal(float scalar) { return divideLocal(scalar, scalar, scalar); } /** * Move this vector to a new point by specified direction. - * - * @param direction move direction. - * @param distance move distance. - * @return this changed vector. */ public Vector3f moveToDirection(Vector3f direction, float distance) { - return addLocal(direction.getX() * distance, direction.getY() * distance, direction.getZ() * distance); + return addLocal(direction.x() * distance, direction.y() * distance, direction.z() * distance); } /** @@ -554,8 +288,10 @@ public Vector3f moveToPoint(Vector3f destination, float distance) { Vector3f direction = new Vector3f(destination).subtractLocal(this); - double length = Math.sqrt(direction.getX() * direction.getX() + direction.getY() * direction.getY() - + direction.getZ() * direction.getZ()); + double length = Math.sqrt( + direction.x() * direction.x() + + direction.y() * direction.y() + + direction.z() * direction.z()); if (length <= distance || length < ExtMath.EPSILON) { set(destination); @@ -571,19 +307,14 @@ public Vector3f moveToPoint(Vector3f destination, float distance) { /** * Linear time-based interpolation stored to this vector. - * - * @param min the minimal vector. - * @param max the maximal vector. - * @param t the time. - * @return this vector. */ - public Vector3f lerp(Vector3f min, Vector3f max, float t) { + public Vector3f lerp(Vector3f min, Vector3f max, float time) { - t = ExtMath.clamp(t); + time = ExtMath.clamp(time); - this.x = min.x + (max.x - min.x) * t; - this.y = min.y + (max.y - min.y) * t; - this.z = min.z + (max.z - min.z) * t; + this.x = min.x + (max.x - min.x) * time; + this.y = min.y + (max.y - min.y) * time; + this.z = min.z + (max.z - min.z) * time; return this; } @@ -629,8 +360,10 @@ public boolean equals(@Nullable Object obj) { * @return true if these vectors are equal with the epsilon. */ public boolean equals(Vector3f vector, float epsilon) { - return Math.abs(x - vector.getX()) < epsilon && Math.abs(y - vector.getY()) < epsilon - && Math.abs(z - vector.getZ()) < epsilon; + return + Math.abs(x - vector.x()) < epsilon && + Math.abs(y - vector.y()) < epsilon && + Math.abs(z - vector.z()) < epsilon; } @Override diff --git a/rlib-common/src/main/java/javasabr/rlib/common/geom/Vector3fBuffer.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector3fBuffer.java similarity index 54% rename from rlib-common/src/main/java/javasabr/rlib/common/geom/Vector3fBuffer.java rename to rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector3fBuffer.java index 0454bfa6..660e90d7 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/geom/Vector3fBuffer.java +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/Vector3fBuffer.java @@ -1,19 +1,14 @@ -package javasabr.rlib.common.geom; - -import org.jspecify.annotations.NullMarked; +package javasabr.rlib.geometry; /** - * The interface to implement a buffer of vectors. - * * @author JavaSaBr */ -@NullMarked public interface Vector3fBuffer { Vector3fBuffer NO_REUSE = new Vector3fBuffer() { @Override - public Vector3f nextVector() { + public Vector3f next() { return new Vector3f(); } @@ -30,30 +25,20 @@ public Vector3f next(float x, float y, float z) { /** * Take a next free vector. - * - * @return the next vector. */ - Vector3f nextVector(); + Vector3f next(); /** * Take a next free vector with copied values from the source vector. - * - * @param source the source vector. - * @return the next free vector with copied values. */ default Vector3f next(Vector3f source) { - return nextVector().set(source); + return next().set(source); } /** * Take a next free vector with copied values. - * - * @param x the X component. - * @param y the Y component. - * @param z the Z component. - * @return the next free vector with copied values. */ default Vector3f next(float x, float y, float z) { - return nextVector().set(x, y, z); + return next().set(x, y, z); } } diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/Bounding.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/Bounding.java new file mode 100644 index 00000000..22e07514 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/Bounding.java @@ -0,0 +1,75 @@ +package javasabr.rlib.geometry.bounding; + +import javasabr.rlib.geometry.Quaternion4f; +import javasabr.rlib.geometry.Ray3f; +import javasabr.rlib.geometry.Vector3f; +import javasabr.rlib.geometry.Vector3fBuffer; + +/** + * @author JavaSaBr + */ +public interface Bounding { + + /** + * Return true if this bounding contains the point. + */ + boolean contains(float x, float y, float z); + + /** + * Return true if this bounding contains the point. + */ + boolean contains(Vector3f point); + + /** + * Get a distance from a center of a bounding to a point. + */ + float distanceTo(Vector3f point); + + BoundingType boundingType(); + + Vector3f center(); + + void center(Vector3f center); + + Vector3f offset(); + + /** + * Get a result center of this bounding. + */ + Vector3f calculateResultCenter(Vector3fBuffer buffer); + + /** + * Get a result X coordinate of the center of this bounding. + */ + float calculateResultCenterX(); + + /** + * Get a result Y coordinate of the center of this bounding. + */ + float calculateResultCenterY(); + + /** + * Get a result Z coordinate of the center of this bounding. + */ + float calculateResultCenterZ(); + + /** + * Check this bounding that it intersects with other bounding. + */ + boolean intersects(Bounding bounding, Vector3fBuffer buffer); + + /** + * Check this bounding that it intersects with a ray. + */ + boolean intersects(Ray3f ray, Vector3fBuffer buffer); + + /** + * Check this bounding that it intersects with a ray. + */ + boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer); + + /** + * Update a rotation of a bounding. + */ + void update(Quaternion4f rotation, Vector3fBuffer buffer); +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/BoundingFactory.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/BoundingFactory.java new file mode 100644 index 00000000..05f2a221 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/BoundingFactory.java @@ -0,0 +1,35 @@ +package javasabr.rlib.geometry.bounding; + +import javasabr.rlib.geometry.Vector3f; +import javasabr.rlib.geometry.bounding.impl.AbstractBounding; +import javasabr.rlib.geometry.bounding.impl.AxisAlignedBoundingBox; +import javasabr.rlib.geometry.bounding.impl.BoundingSphere; +import org.jspecify.annotations.NullMarked; + +/** + * @author JavaSaBr + */ +@NullMarked +public final class BoundingFactory { + + public static Bounding newBoundingBox( + Vector3f center, + Vector3f offset, + float sizeX, + float sizeY, + float sizeZ) { + return new AxisAlignedBoundingBox(center, offset, sizeX, sizeY, sizeZ); + } + + public static Bounding newBoundingEmpty() { + return new AbstractBounding(new Vector3f(), new Vector3f()) {}; + } + + public static Bounding newBoundingSphere(Vector3f center, Vector3f offset, float radius) { + return new BoundingSphere(center, offset, radius); + } + + private BoundingFactory() { + throw new IllegalArgumentException(); + } +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/BoundingType.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/BoundingType.java new file mode 100644 index 00000000..cea1e88b --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/BoundingType.java @@ -0,0 +1,10 @@ +package javasabr.rlib.geometry.bounding; + +/** + * @author JavaSaBr + */ +public enum BoundingType { + AXIS_ALIGNED_BOX, + SPHERE, + EMPTY +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/AbstractBounding.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/AbstractBounding.java new file mode 100644 index 00000000..401f8806 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/AbstractBounding.java @@ -0,0 +1,94 @@ +package javasabr.rlib.geometry.bounding.impl; + +import javasabr.rlib.geometry.Quaternion4f; +import javasabr.rlib.geometry.Ray3f; +import javasabr.rlib.geometry.Vector3f; +import javasabr.rlib.geometry.Vector3fBuffer; +import javasabr.rlib.geometry.bounding.Bounding; +import javasabr.rlib.geometry.bounding.BoundingType; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerManager; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public abstract class AbstractBounding implements Bounding { + + protected static final Logger LOGGER = LoggerManager.getLogger(Bounding.class); + + Vector3f center, offset; + + protected AbstractBounding(Vector3f center, Vector3f offset) { + this.center = new Vector3f(center); + this.offset = new Vector3f(offset); + } + + @Override + public boolean contains(float x, float y, float z) { + return false; + } + + @Override + public boolean contains(Vector3f point) { + return contains(point.x(), point.y(), point.z()); + } + + @Override + public final float distanceTo(Vector3f point) { + return center.distance(point); + } + + @Override + public BoundingType boundingType() { + return BoundingType.EMPTY; + } + + @Override + public void center(Vector3f center) { + this.center.set(center); + } + @Override + public Vector3f calculateResultCenter(Vector3fBuffer buffer) { + return center(); + } + + @Override + public float calculateResultCenterX() { + return center().x(); + } + + @Override + public float calculateResultCenterY() { + return center().y(); + } + + @Override + public float calculateResultCenterZ() { + return center().z(); + } + + @Override + public boolean intersects(Bounding bounding, Vector3fBuffer buffer) { + return false; + } + + @Override + public final boolean intersects(Ray3f ray, Vector3fBuffer buffer) { + return intersects(ray.start(), ray.direction(), buffer); + } + + @Override + public boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer) { + return false; + } + + @Override + public void update(Quaternion4f rotation, Vector3fBuffer buffer) {} +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/AxisAlignedBoundingBox.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/AxisAlignedBoundingBox.java new file mode 100644 index 00000000..61ea07c4 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/AxisAlignedBoundingBox.java @@ -0,0 +1,198 @@ +package javasabr.rlib.geometry.bounding.impl; + +import javasabr.rlib.geometry.Matrix3f; +import javasabr.rlib.geometry.Quaternion4f; +import javasabr.rlib.geometry.Vector3f; +import javasabr.rlib.geometry.Vector3fBuffer; +import javasabr.rlib.geometry.bounding.Bounding; +import javasabr.rlib.geometry.bounding.BoundingType; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class AxisAlignedBoundingBox extends AbstractBounding { + + final Matrix3f matrix; + final Vector3f size; + + float sizeX, sizeY, sizeZ; + float offsetX, offsetY, offsetZ; + + public AxisAlignedBoundingBox(Vector3f center, Vector3f offset, float sizeX, float sizeY, float sizeZ) { + super(center, offset); + this.matrix = new Matrix3f(); + this.size = new Vector3f(sizeX, sizeY, sizeZ); + this.sizeX = sizeX; + this.sizeY = sizeY; + this.sizeZ = sizeZ; + this.offsetX = offset.x(); + this.offsetY = offset.y(); + this.offsetZ = offset.z(); + } + + @Override + public boolean contains(float x, float y, float z) { + return Math.abs(calculateResultCenterX() - x) < sizeX && Math.abs(calculateResultCenterY() - y) < sizeY + && Math.abs(this.calculateResultCenterZ() - z) < sizeZ; + } + + @Override + public BoundingType boundingType() { + return BoundingType.AXIS_ALIGNED_BOX; + } + + @Override + public Vector3f calculateResultCenter(Vector3fBuffer buffer) { + + Vector3f vector = buffer + .next() + .set(center); + + if (offset.isZero()) { + return vector; + } + + return vector.addLocal(offsetX, offsetY, offsetZ); + } + + @Override + public float calculateResultCenterZ() { + return center.z() + offsetZ; + } + + @Override + public float calculateResultCenterY() { + return center.y() + offsetY; + } + + @Override + public float calculateResultCenterX() { + return center.x() + offsetX; + } + + @Override + public boolean intersects(Bounding bounding, Vector3fBuffer buffer) { + switch (bounding.boundingType()) { + case EMPTY: { + return false; + } + case AXIS_ALIGNED_BOX: { + + AxisAlignedBoundingBox box = (AxisAlignedBoundingBox) bounding; + + Vector3f target = box.calculateResultCenter(buffer); + Vector3f center = calculateResultCenter(buffer); + + float sizeX = sizeX(); + float sizeY = sizeY(); + float sizeZ = sizeZ(); + + if (center.x() + sizeX < target.x() - box.sizeX() + || center.x() - sizeX > target.x() + box.sizeX()) { + return false; + } else if (center.y() + sizeY < target.y() - box.sizeY() + || center.y() - sizeY > target.y() + box.sizeY()) { + return false; + } else if (center.z() + sizeZ < target.z() - box.sizeZ() + || center.z() - sizeZ > target.z() + box.sizeZ()) { + return false; + } + + return true; + } + case SPHERE: { + + BoundingSphere sphere = (BoundingSphere) bounding; + + Vector3f target = sphere.calculateResultCenter(buffer); + Vector3f center = calculateResultCenter(buffer); + + float radius = sphere.radius(); + + if (Math.abs(center.x() - target.x()) > radius + sizeX()) { + return false; + } else if (Math.abs(center.y() - target.y()) > radius + sizeY()) { + return false; + } else { + return !(Math.abs(center.z() - target.z()) > radius + sizeZ()); + } + + } + default: { + LOGGER.warning(new IllegalArgumentException("incorrect bounding type " + bounding.boundingType())); + } + } + + return false; + } + + @Override + public boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer) { + + float divX = 1.0F / (Float.compare(direction.x(), 0) == 0 ? 0.00001F : direction.x()); + float divY = 1.0F / (Float.compare(direction.y(), 0) == 0 ? 0.00001F : direction.y()); + float divZ = 1.0F / (Float.compare(direction.z(), 0) == 0 ? 0.00001F : direction.z()); + + float sizeX = sizeX() * 0.5F; + float sizeY = sizeY() * 0.5F; + float sizeZ = sizeZ() * 0.5F; + + Vector3f center = calculateResultCenter(buffer); + + float minX = center.x() - sizeX; + float minY = center.y() - sizeY; + float minZ = center.z() - sizeZ; + + float maxX = center.x() + sizeX; + float maxY = center.y() + sizeY; + float maxZ = center.z() + sizeZ; + + float t1 = (minX - start.x()) * divX; + float t2 = (maxX - start.x()) * divX; + float t3 = (minY - start.y()) * divY; + float t4 = (maxY - start.y()) * divY; + float t5 = (minZ - start.z()) * divZ; + float t6 = (maxZ - start.z()) * divZ; + + float tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6)); + float tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6)); + + return tmin <= tmax && tmax > 0.f; + } + + @Override + public void update(Quaternion4f rotation, Vector3fBuffer buffer) { + + matrix.set(rotation); + matrix.absoluteLocal(); + + Vector3f vector = matrix.mult(size, buffer.next()); + + sizeX = Math.abs(vector.x()); + sizeY = Math.abs(vector.y()); + sizeZ = Math.abs(vector.z()); + + if (offset.isZero()) { + return; + } + + matrix.mult(offset, vector); + + offsetX = vector.x(); + offsetY = vector.y(); + offsetZ = vector.z(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " size = " + size + ", sizeX = " + sizeX + ", sizeY = " + sizeY + ", sizeZ = " + + sizeZ + ", center = " + center + ", offset = " + offset; + } +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/BoundingSphere.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/BoundingSphere.java new file mode 100644 index 00000000..5c1270b7 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/BoundingSphere.java @@ -0,0 +1,131 @@ +package javasabr.rlib.geometry.bounding.impl; + +import static java.lang.Math.abs; + +import javasabr.rlib.geometry.Vector3f; +import javasabr.rlib.geometry.Vector3fBuffer; +import javasabr.rlib.geometry.bounding.Bounding; +import javasabr.rlib.geometry.bounding.BoundingType; +import javasabr.rlib.geometry.util.GeometryUtils; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class BoundingSphere extends AbstractBounding { + + float radius, squareRadius; + + public BoundingSphere(Vector3f center, Vector3f offset, float radius) { + super(center, offset); + this.radius = radius; + this.squareRadius = radius * radius; + } + + @Override + public boolean contains(float x, float y, float z) { + + float startX = calculateResultCenterX(); + float centerY = this.calculateResultCenterY(); + float centerZ = this.calculateResultCenterZ(); + + return GeometryUtils.getSquareDistance(startX, centerY, centerZ, x, y, z) < squareRadius; + } + + @Override + public float calculateResultCenterZ() { + return center.z() + offset.z(); + } + + @Override + public float calculateResultCenterY() { + return center.y() + offset.y(); + } + + @Override + public float calculateResultCenterX() { + return center.x() + offset.x(); + } + + @Override + public BoundingType boundingType() { + return BoundingType.SPHERE; + } + + @Override + public Vector3f calculateResultCenter(Vector3fBuffer buffer) { + + Vector3f vector = buffer + .next() + .set(center); + + if (offset.isZero()) { + return vector; + } + + return vector.addLocal(offset); + } + + @Override + public boolean intersects(Bounding bounding, Vector3fBuffer buffer) { + switch (bounding.boundingType()) { + case EMPTY: { + return false; + } + case SPHERE: { + + BoundingSphere sphere = (BoundingSphere) bounding; + Vector3f diff = this + .calculateResultCenter(buffer).subtractLocal(sphere.calculateResultCenter(buffer)); + + float rsum = radius() + sphere.radius(); + + return diff.dot(diff) <= rsum * rsum; + } + case AXIS_ALIGNED_BOX: { + + AxisAlignedBoundingBox box = (AxisAlignedBoundingBox) bounding; + + Vector3f center = this.calculateResultCenter(buffer); + Vector3f target = box.calculateResultCenter(buffer); + + return abs(target.x() - center.x()) < radius() + box.sizeX() + && abs(target.y() - center.y()) < radius() + box.sizeY() + && abs(target.z() - center.z()) < radius() + box.sizeZ(); + } + } + + return false; + } + + @Override + public boolean intersects(Vector3f start, Vector3f direction, Vector3fBuffer buffer) { + + Vector3f diff = buffer + .next() + .set(start) + .subtractLocal(this.calculateResultCenter(buffer)); + + float a = start.dot(diff) - squareRadius; + + if (a <= 0.0) { + return true; + } + + float b = direction.dot(diff); + + return b < 0.0 && b * b >= a; + + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [radius=" + radius + ", squareRadius=" + squareRadius + "]"; + } +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/package-info.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/package-info.java new file mode 100644 index 00000000..ec6ef21a --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.geometry.bounding.impl; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/package-info.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/package-info.java new file mode 100644 index 00000000..fffaee25 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/bounding/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.geometry.bounding; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/package-info.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/package-info.java new file mode 100644 index 00000000..68dc865d --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.geometry; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/AngleUtils.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/AngleUtils.java new file mode 100644 index 00000000..6aedd6f2 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/AngleUtils.java @@ -0,0 +1,104 @@ +package javasabr.rlib.geometry.util; + +import org.jspecify.annotations.NullMarked; + +/** + * @author JavaSaBr + */ +@NullMarked +public final class AngleUtils { + + /** + * The constant HEADINGS_IN_PI. + */ + public static final float HEADINGS_IN_PI = 10430.378350470452724949566316381F; + /** + * The constant PI. + */ + public static final float PI = 3.14159265358979323846F; + + public static int calcHeading(float x, float y, float targetX, float targetY) { + return (int) (Math.atan2(y - targetY, x - targetX) * HEADINGS_IN_PI) + 32768; + } + + public static int calcHeadingTo(float x, float y, int heading, float targetX, float targetY) { + + int newHeading = calcHeading(x, y, targetX, targetY); + newHeading = heading - newHeading; + + if (newHeading < 0) { + newHeading = newHeading + 1 + Integer.MAX_VALUE & 0xFFFF; + } else if (newHeading > 0xFFFF) { + newHeading &= 0xFFFF; + } + + return newHeading; + } + + public static int degreeToHeading(float degree) { + if (degree < 0) { + degree += 360f; + } + return (int) (degree * 182.044444444f); + } + + public static float degreeToRadians(float angle) { + return angle * PI / 180F; + } + + public static float getAngleFrom(float startX, float startY, float endX, float endY) { + float angle = (float) Math.toDegrees(Math.atan2(startY - endY, startX - endX)); + if (angle <= 0F) { + angle += 360F; + } + return angle; + } + + public static float headingToDegree(int heading) { + float angle = heading / 182.044444444f; + if (angle == 0) { + angle = 360f; + } + return angle; + } + + public static float headingToRadians(int heading) { + float angle = heading / 182.044444444f; + if (angle == 0) { + angle = 360f; + } + return angle * 3.141592653f / 180f; + } + + public static boolean isInDegree(float x, float y, int heading, float targetX, float targetY, int width) { + + int angle = (int) AngleUtils.headingToDegree(calcHeadingTo(x, y, heading, targetX, targetY)); + final int degree = (int) headingToDegree(heading); + + int min = degree - width; + int max = degree + width; + + if (min < 0) { + min += 360; + } + if (max < 0) { + max += 360; + } + + final boolean flag = angle - degree > 180; + if (flag) { + angle -= 360; + } + if (angle > max) { + return false; + } + + angle += 360; + + return angle > min; + } + + public static float radiansToDegree(float radians) { + return radians * 180F / PI; + } +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/CoordsUtils.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/CoordsUtils.java new file mode 100644 index 00000000..935cecb6 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/CoordsUtils.java @@ -0,0 +1,159 @@ +package javasabr.rlib.geometry.util; + +import java.util.concurrent.ThreadLocalRandom; +import javasabr.rlib.common.util.ExtMath; +import javasabr.rlib.geometry.Vector3f; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerManager; + +/** + * @author JavaSaBr + */ +public final class CoordsUtils { + + private static final Logger LOGGER = LoggerManager.getLogger(CoordsUtils.class); + + public static Vector3f[] arcCoords( + float x, + float y, + float z, + int heading, + int radius, + int count, + int degree, + int width) { + + Vector3f[] vectors = new Vector3f[count]; + float current = AngleUtils.headingToDegree(heading) - degree; + + float min = current - width; + float max = current + width; + + float angle = Math.abs(min - max) / count; + + for (int i = 0; i < count; i++) { + + Vector3f vector = new Vector3f(); + + float radians = AngleUtils.degreeToRadians(min + angle * i); + + float newX = calcX(x, radius, radians); + float newY = calcY(y, radius, radians); + + vector.set(newX, newY, z); + + vectors[i] = vector; + } + + return vectors; + } + + public static float calcX(float x, int distance, float radians) { + return x + distance * (float) Math.cos(radians); + } + + public static float calcX(float x, int distance, int heading) { + return x + distance * (float) Math.cos(AngleUtils.headingToRadians(heading)); + } + + public static float calcX(float x, int distance, int heading, int offset) { + return x + distance * (float) Math.cos(AngleUtils.headingToRadians(heading + offset)); + } + + public static float calcY(float y, int distance, float radians) { + return y + distance * (float) Math.sin(radians); + } + + public static float calcY(float y, int distance, int heading) { + return y + distance * (float) Math.sin(AngleUtils.headingToRadians(heading)); + } + + public static float calcY(float y, int distance, int heading, int offset) { + return y + distance * (float) Math.sin(AngleUtils.headingToRadians(heading + offset)); + } + + @SuppressWarnings("unchecked") + public static Vector3f[] circularCoords(float x, float y, float z, int radius, int count) { + + Vector3f[] locs = new Vector3f[count]; + float angle = 360F / count; + + for (int i = 1; i <= count; i++) { + + Vector3f loc = new Vector3f(); + float radians = AngleUtils.degreeToRadians(i * angle); + + float newX = calcX(x, radius, radians); + float newY = calcY(y, radius, radians); + + loc.set(newX, newY, z); + + locs[i - 1] = loc; + } + + return locs; + } + + public static Vector3f[] getCircularPoints( + Vector3f[] source, + float x, + float y, + float z, + int count, + int radius) { + + if (count < 1) { + return source; + } + + float angle = 360F / count; + + for (int i = 1; i <= count; i++) { + + float radians = AngleUtils.degreeToRadians(angle * i); + + float newX = x + radius * (float) Math.cos(radians); + float newY = y + radius * (float) Math.sin(radians); + + Vector3f point = source[i - 1]; + + point.set(newX, newY, z); + } + + return source; + } + + public static Vector3f randomCoords( + Vector3f loc, + float x, + float y, + float z, + int radiusMin, + int radiusMax) { + + ThreadLocalRandom current = ThreadLocalRandom.current(); + + if (radiusMax == 0 || radiusMax < radiusMin) { + loc.set(x, y, z); + return loc; + } + + int radius = current.nextInt(radiusMin, radiusMax); + float radians = AngleUtils.degreeToRadians(current.nextInt(0, 360)); + + float newX = calcX(x, radius, radians); + float newY = calcY(y, radius, radians); + + loc.set(newX, newY, z); + + return loc; + } + + public static float length(float x, float y) { + return ExtMath.sqrt(lengthSquared(x, y)); + } + + public static float lengthSquared(float x, float y) { + return x * x + y * y; + } +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/GeometryUtils.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/GeometryUtils.java new file mode 100644 index 00000000..d7cd7ed4 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/GeometryUtils.java @@ -0,0 +1,172 @@ +package javasabr.rlib.geometry.util; + +import javasabr.rlib.geometry.Vector3f; +import org.jspecify.annotations.Nullable; + +/** + * @author JavaSaBr + */ +public final class GeometryUtils { + + public static float getDistance( + float startX, + float startY, + float startZ, + float targetX, + float targetY, + float targetZ) { + return (float) Math.sqrt(getSquareDistance(startX, startY, startZ, targetX, targetY, targetZ)); + } + + public static float getDistanceToLine( + float startX, + float startY, + float endX, + float endY, + float targetX, + float targetY) { + return (float) Math.sqrt(getSquareDistanceToLine(startX, startY, endX, endY, targetX, targetY)); + } + + public static float getDistanceToLine( + float startX, + float startY, + float startZ, + float endX, + float endY, + float endZ, + float targetX, + float targetY, + float targetZ) { + return (float) Math.sqrt(getSquareDistanceToLine( + startX, + startY, + startZ, + endX, + endY, + endZ, + targetX, + targetY, + targetZ)); + } + + public static float getSquareDistance( + float startX, + float startY, + float startZ, + float targetX, + float targetY, + float targetZ) { + + float dx = targetX - startX; + float dy = targetY - startY; + float dz = targetZ - startZ; + + return dx * dx + dy * dy + dz * dz; + } + + public static float getSquareDistanceToLine( + final float startX, + final float startY, + float endX, + float endY, + float targetX, + float targetY) { + + endX -= startX; + endY -= startY; + + targetX -= startX; + targetY -= startY; + + float dotprod = targetX * endX + targetY * endY; + + float projlenSq; + + if (dotprod <= 0.0F) { + projlenSq = 0.0F; + } else { + + targetX = endX - targetX; + targetY = endY - targetY; + + dotprod = targetX * endX + targetY * endY; + + if (dotprod <= 0.0F) { + projlenSq = 0.0F; + } else { + projlenSq = dotprod * dotprod / (endX * endX + endY * endY); + } + } + + float lenSq = targetX * targetX + targetY * targetY - projlenSq; + + if (lenSq < 0F) { + lenSq = 0F; + } + + return lenSq; + } + + public static float getSquareDistanceToLine( + float startX, + float startY, + float startZ, + float endX, + float endY, + float endZ, + float targetX, + float targetY, + float targetZ) { + + float lineX = endX - startX; + float lineY = endY - startY; + float lineZ = endZ - startZ; + + float pointX = targetX - startX; + float pointY = targetY - startY; + float pointZ = targetZ - startZ; + + float c1 = scalar(pointX, pointY, pointZ, lineX, lineY, lineZ); + + if (c1 < 0F) { + return squareLength(targetX, targetY, targetZ, startX, startY, startZ); + } + + float c2 = scalar(lineX, lineY, lineZ, lineX, lineY, lineZ); + + if (c2 <= c1) { + return squareLength(targetX, targetY, targetZ, endX, endY, endZ); + } + + float b = c1 / c2; + + pointX = startX + lineX * b; + pointY = startY + lineY * b; + pointZ = startZ + lineZ * b; + + return squareLength(targetX, targetY, targetZ, pointX, pointY, pointZ); + } + + public static float scalar(float x1, float y1, float z1, float x2, float y2, float z2) { + return x1 * x2 + y1 * y2 + z1 * z2; + } + + public static float squareLength(float x1, float y1, float z1, float x2, float y2, float z2) { + float dx = x1 - x2; + float dy = y1 - y2; + float dz = z1 - z2; + return dx * dx + dy * dy + dz * dz; + } + + /** + * Return true if these vectors are equals. + */ + public boolean isEquals(@Nullable Vector3f first, @Nullable Vector3f second, float epsilon) { + if (first == null || second == null) { + return false; + } else { + return first.equals(second, epsilon); + } + } +} diff --git a/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/package-info.java b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/package-info.java new file mode 100644 index 00000000..e2dbdb44 --- /dev/null +++ b/rlib-geometry/src/main/java/javasabr/rlib/geometry/util/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.geometry.util; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-common/src/test/java/javasabr/rlib/common/geom/QuaternionTests.java b/rlib-geometry/src/test/java/javasabr/rlib/geometry/QuaternionTests.java similarity index 97% rename from rlib-common/src/test/java/javasabr/rlib/common/geom/QuaternionTests.java rename to rlib-geometry/src/test/java/javasabr/rlib/geometry/QuaternionTests.java index 5d050c72..f10ffc63 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/geom/QuaternionTests.java +++ b/rlib-geometry/src/test/java/javasabr/rlib/geometry/QuaternionTests.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.geom; +package javasabr.rlib.geometry; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java index 8de421e5..3264d670 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java @@ -1,60 +1,68 @@ package javasabr.rlib.logger.api; -import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullUnmarked; /** - * The interface to implement a logger. - * * @author JavaSaBr */ +@NullUnmarked public interface Logger { @FunctionalInterface interface Factory { + @NonNull String make(); } @FunctionalInterface - interface SinFactory { + interface N1Factory { - String make(F first); + @NonNull + String make(F arg1); } @FunctionalInterface - interface IntSinFactory { + interface IntN1Factory { - String make(int val); + @NonNull + String make(int arg1); } @FunctionalInterface - interface BiFactory { + interface N2Factory { - String make(F first, S second); + @NonNull + String make(F arg1, S arg2); } @FunctionalInterface - interface NullableBiFactory { + interface N1IntFactory { - String make(@Nullable F first, @Nullable S second); + @NonNull + String make(F arg1, int arg2); } @FunctionalInterface - interface ObjIntFactory { + interface Int2Factory { - String make(F first, int second); + @NonNull + String make(int arg1, int arg2); } @FunctionalInterface - interface IntBiFactory { + interface N3Factory { - String make(int first, int second); + @NonNull + String make(F arg1, S arg2, T arg3); } @FunctionalInterface - interface TriFactory { + interface N4Factory { - String make(F first, S second, T third); + @NonNull + String make(F arg1, S arg2, T arg3, FO arg4); } /** @@ -62,382 +70,170 @@ interface TriFactory { * * @param message the message. */ - default void debug(String message) { + default void debug(@NonNull String message) { print(LoggerLevel.DEBUG, message); } - /** - * Print a build debug message. - * - * @param arg the arg for the message factory. - * @param messageFactory the message factory. - */ - default void debug(int arg, Logger.IntSinFactory messageFactory) { - print(LoggerLevel.DEBUG, arg, messageFactory); - } - - /** - * Print a build debug message. - * - * @param arg the arg for the message factory. - * @param messageFactory the message factory. - * @param the argument's type. - */ - default void debug(T arg, Logger.SinFactory messageFactory) { - print(LoggerLevel.DEBUG, arg, messageFactory); + default void debug(int arg1, @NonNull IntN1Factory factory) { + print(LoggerLevel.DEBUG, arg1, factory); } - /** - * Print a build debug message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - */ - default void debug(F first, S second, Logger.BiFactory messageFactory) { - print(LoggerLevel.DEBUG, first, second, messageFactory); + default void debug(T arg1, @NonNull N1Factory factory) { + print(LoggerLevel.DEBUG, arg1, factory); } - /** - * Print a build debug message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - */ - default void debugNullable( - @Nullable F first, - @Nullable S second, - Logger.NullableBiFactory messageFactory) { - print(LoggerLevel.DEBUG, first, second, messageFactory); + default void debug(F arg1, S arg2, @NonNull N2Factory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, factory); } - /** - * Print a build debug message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - */ - default void debug(F first, int second, Logger.ObjIntFactory messageFactory) { - print(LoggerLevel.DEBUG, first, second, messageFactory); + default void debug(F arg1, int arg2, @NonNull N1IntFactory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, factory); } - /** - * Print a build debug message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - */ - default void debug(int first, int second, Logger.IntBiFactory messageFactory) { - print(LoggerLevel.DEBUG, first, second, messageFactory); + default void debug(int arg1, int arg2, @NonNull Int2Factory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, factory); } - /** - * Print a build debug message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param third the third arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - * @param the third argument's type. - */ - default void debug( - F first, - S second, - T third, - Logger.TriFactory messageFactory) { - print(LoggerLevel.DEBUG, first, second, third, messageFactory); + default void debug(F arg1, S arg2, T arg3, @NonNull N3Factory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, arg3, factory); } - /** - * Print a build error message. - * - * @param message the message. - */ - default void error(String message) { + default void error(@NonNull String message) { print(LoggerLevel.ERROR, message); } - /** - * Print a build error message. - * - * @param exception the exception. - */ - default void error(Throwable exception) { + default void error(@NonNull Throwable exception) { print(LoggerLevel.ERROR, exception); } - /** - * Print a build information message. - * - * @param message the message. - */ - default void info(String message) { + default void info(@NonNull String message) { print(LoggerLevel.INFO, message); } - /** - * Print a build information message. - * - * @param arg the arg for the message factory. - * @param messageFactory the message factory. - * @param the argument's type. - */ - default void info(T arg, Logger.SinFactory messageFactory) { - print(LoggerLevel.INFO, arg, messageFactory); + default void info(T arg1, @NonNull N1Factory factory) { + print(LoggerLevel.INFO, arg1, factory); } - /** - * Print a build information message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - */ - default void info(F first, S second, Logger.BiFactory messageFactory) { - print(LoggerLevel.INFO, first, second, messageFactory); + default void info(F arg1, S arg2, @NonNull N2Factory factory) { + print(LoggerLevel.INFO, arg1, arg2, factory); } - /** - * Print a build information message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param third the third arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - * @param the third argument's type. - */ - default void info( - F first, - S second, - T third, - Logger.TriFactory messageFactory) { - print(LoggerLevel.INFO, first, second, third, messageFactory); + default void info(F arg1, S arg2, T arg3, @NonNull N3Factory factory) { + print(LoggerLevel.INFO, arg1, arg2, arg3, factory); } /** * Check of enabling the logger level. - * - * @param level the logger level. - * @return true if the level is enabled. */ - default boolean isEnabled(LoggerLevel level) { - return level.isEnabled(); + default boolean enabled(@NonNull LoggerLevel level) { + return level.enabled(); } /** * Override the enabling status of the logger level. - * - * @param level the logger level. - * @param enabled true if need to be enabled. - * @return true if the status was changed. */ - default boolean setEnabled(LoggerLevel level, boolean enabled) { + default boolean overrideEnabled(@NonNull LoggerLevel level, boolean enabled) { return false; } /** * Remove overriding of enabling status if the logger level. - * - * @param level the logger level. - * @return true if the status was changed. */ - default boolean applyDefault(LoggerLevel level) { + default boolean resetToDefault(@NonNull LoggerLevel level) { return false; } - /** - * Print the warning message. - * - * @param message the message. - */ - default void warning(String message) { + default void warning(@NonNull String message) { print(LoggerLevel.WARNING, message); } - /** - * Print the warning message. - * - * @param exception the exception. - */ - default void warning(Throwable exception) { + default void warning(@NonNull Throwable exception) { print(LoggerLevel.WARNING, exception); } - /** - * Print a warning debug message. - * - * @param arg the arg for the message factory. - * @param messageFactory the message factory. - * @param
the argument's type. - */ - default void warning(A arg, Logger.SinFactory messageFactory) { - print(LoggerLevel.WARNING, arg, messageFactory); + default void warning(A arg1, @NonNull N1Factory factory) { + print(LoggerLevel.WARNING, arg1, factory); } - /** - * Print a warning debug message. - * - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - */ - default void warning(F first, S second, Logger.BiFactory messageFactory) { - print(LoggerLevel.WARNING, first, second, messageFactory); + default void warning(F arg1, S arg2, @NonNull N2Factory factory) { + print(LoggerLevel.WARNING, arg1, arg2, factory); } - /** - * Print the message. - * - * @param level the level of the message. - * @param message the message. - */ - void print(LoggerLevel level, String message); + default void warning( + F arg1, + S arg2, + T arg3, + FO arg4, + @NonNull N4Factory factory) { + print(LoggerLevel.WARNING, arg1, arg2, arg3, arg4, factory); + } - /** - * Print the message. - * - * @param level the level of the message. - * @param exception the exception. - */ - void print(LoggerLevel level, Throwable exception); + void print(@NonNull LoggerLevel level, @NonNull String message); - /** - * Print a build message. - * - * @param level the level of the message. - * @param arg the arg for the message factory. - * @param messageFactory the message factory. - * @param the argument's type. - */ - default void print(LoggerLevel level, T arg, Logger.SinFactory messageFactory) { - if (isEnabled(level)) { - print(level, messageFactory.make(arg)); - } - } + void print(@NonNull LoggerLevel level, @NonNull Throwable exception); - /** - * Print a build message. - * - * @param level the level of the message. - * @param arg the arg for the message factory. - * @param messageFactory the message factory. - */ - default void print(LoggerLevel level, int arg, Logger.IntSinFactory messageFactory) { - if (isEnabled(level)) { - print(level, messageFactory.make(arg)); + default void print(@NonNull LoggerLevel level, T arg1, @NonNull N1Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1)); } } - /** - * Print a build message. - * - * @param level the level of the message. - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - */ - default void print( - LoggerLevel level, - F first, - S second, - Logger.BiFactory messageFactory) { - if (isEnabled(level)) { - print(level, messageFactory.make(first, second)); + default void print(@NonNull LoggerLevel level, int arg1, @NonNull IntN1Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1)); } } - /** - * Print a build message. - * - * @param level the level of the message. - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - */ default void print( - LoggerLevel level, - @Nullable F first, - @Nullable S second, - Logger.NullableBiFactory messageFactory) { - if (isEnabled(level)) { - print(level, messageFactory.make(first, second)); + @NonNull LoggerLevel level, + F arg1, + S arg2, + @NonNull N2Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2)); } } - /** - * Print a build message. - * - * @param level the level of the message. - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - */ default void print( - LoggerLevel level, - F first, - int second, - Logger.ObjIntFactory messageFactory) { - if (isEnabled(level)) { - print(level, messageFactory.make(first, second)); + @NonNull LoggerLevel level, + F arg1, + int arg2, + @NonNull N1IntFactory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2)); } } - /** - * Print a build message. - * - * @param level the level of the message. - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param messageFactory the message factory. - */ - default void print(LoggerLevel level, int first, int second, Logger.IntBiFactory messageFactory) { - if (isEnabled(level)) { - print(level, messageFactory.make(first, second)); + default void print( + @NonNull LoggerLevel level, + int arg1, + int arg2, + @NonNull Int2Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2)); } } - /** - * Print a build message. - * - * @param level the level of the message. - * @param first the first arg for the message factory. - * @param second the second arg for the message factory. - * @param third the third arg for the message factory. - * @param messageFactory the message factory. - * @param the first argument's type. - * @param the second argument's type. - * @param the third argument's type. - */ default void print( - LoggerLevel level, - F first, - S second, - T third, - Logger.TriFactory messageFactory) { - - if (isEnabled(level)) { - print(level, messageFactory.make(first, second, third)); + @NonNull LoggerLevel level, + F arg1, + S arg2, + T arg3, + @NonNull N3Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2, arg3)); + } + } + + default void print( + @NonNull LoggerLevel level, + F arg1, + S arg2, + T arg3, + FO arg4, + @NonNull N4Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2, arg3, arg4)); } } } diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerFactory.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerFactory.java index eaac2001..745ca1e4 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerFactory.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerFactory.java @@ -4,54 +4,17 @@ public interface LoggerFactory { - /** - * Make a new logger with the name. - * - * @param name the logger's name. - * @return the new logger. - */ Logger make(String name); - /** - * Make a new logger for the type. - * - * @param type the logger's type. - * @return the new logger. - */ Logger make(Class type); - /** - * Get a default logger. - * - * @return he default logger. - */ Logger getDefault(); - /** - * Add the new listener. - * - * @param listener the new listener. - */ void addListener(LoggerListener listener); - /** - * Add the new writer. - * - * @param writer the new writer. - */ - void addWriter(Writer writer); - - /** - * Remove the listener. - * - * @param listener the listener. - */ void removeListener(LoggerListener listener); - /** - * Remove the writer. - * - * @param writer the writer. - */ + void addWriter(Writer writer); + void removeWriter(Writer writer); } diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerLevel.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerLevel.java index 03c55cb6..6b633358 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerLevel.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerLevel.java @@ -1,56 +1,31 @@ package javasabr.rlib.logger.api; +import lombok.AccessLevel; import lombok.Getter; -import lombok.Setter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** - * The list of logging levels. - * * @author JavaSaBr */ @Getter +@RequiredArgsConstructor +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public enum LoggerLevel { - /** - * Info logger level. - */ - INFO("INFO", false, true), - /** - * Debug logger level. - */ - DEBUG("DEBUG", false, false), - /** - * Warning logger level. - */ - WARNING("WARNING", true, true), - /** - * Error logger level. - */ - ERROR("ERROR", true, true); + INFO("INFO", " ", false, true), + DEBUG("DEBUG", " ", false, false), + WARNING("WARNING", "", true, true), + ERROR("ERROR", " ", true, true); public static final int LENGTH = values().length; - /** - * The level title. - */ - @Setter - private String title; + String title; + String offset; - /** - * The flag of activity. - */ - @Setter - private boolean enabled; - - /** - * The flag of force flushing. - */ - private boolean forceFlush; - - LoggerLevel(String title, boolean forceFlush, boolean enabled) { - this.title = title; - this.forceFlush = forceFlush; - this.enabled = enabled; - } + boolean enabled; + boolean forceFlush; @Override public String toString() { diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerListener.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerListener.java index 26c5ebbd..cb538cb6 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerListener.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerListener.java @@ -1,22 +1,11 @@ package javasabr.rlib.logger.api; /** - * The interface to implement a listener of logger events. - * * @author JavaSaBr */ public interface LoggerListener { - /** - * Print the result logger message. - * - * @param text the text. - */ void println(String text); - /** - * Flush last data. - */ - default void flush() { - } + default void flush() {} } diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java index 293275eb..fa8fd9cc 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java @@ -2,12 +2,11 @@ import java.io.Writer; import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; import java.util.ServiceLoader; import javasabr.rlib.logger.api.impl.NullLoggerFactory; /** - * The class to manage loggers. - * * @author JavaSaBr */ public class LoggerManager { @@ -17,32 +16,27 @@ public class LoggerManager { static { String className = System.getProperty("com.ss.rlib.logger.factory", ""); - Class implementation = null; if (!className.isEmpty()) { try { implementation = (Class) Class.forName(className); - } catch (ClassNotFoundException e) { - e.printStackTrace(); + } catch (ClassNotFoundException exception) { + exception.printStackTrace(); } } if (implementation == null) { - - var impls = ServiceLoader + Iterator impls = ServiceLoader .load(LoggerFactory.class) .iterator(); - if (impls.hasNext()) { - implementation = impls - .next() - .getClass(); + implementation = impls.next().getClass(); } } if (implementation == null) { - System.err.println("ERROR: No any exist implementation of Rlib Logger Factory, will use null logger"); + System.err.printf("ERROR: No any exist implementation of [%s], will be used null logger%n", LoggerFactory.class); LOGGER_FACTORY = new NullLoggerFactory(); } else { try { @@ -55,88 +49,39 @@ public class LoggerManager { } } - /** - * Add the new listener. - * - * @param listener the new listener. - */ - public static void addListener(LoggerListener listener) { - LOGGER_FACTORY.addListener(listener); - } - - /** - * Add the new writer. - * - * @param writer the new writer. - */ - public static void addWriter(Writer writer) { - LOGGER_FACTORY.addWriter(writer); - } - - /** - * Get the main logger. - * - * @return the main logger. - */ public static Logger getDefaultLogger() { return LOGGER_FACTORY.getDefault(); } - /** - * Get or create a logger for the class. - * - * @param cs the class. - * @return the logger for the class. - */ public static Logger getLogger(Class cs) { return LOGGER_FACTORY.make(cs); } - /** - * Get or create a logger for the id. - * - * @param id the id. - * @return the logger for the class. - */ public static Logger getLogger(String id) { return LOGGER_FACTORY.make(id); } - /** - * Remove the listener. - * - * @param listener the listener. - */ + public static void addListener(LoggerListener listener) { + LOGGER_FACTORY.addListener(listener); + } + public static void removeListener(LoggerListener listener) { LOGGER_FACTORY.removeListener(listener); } - /** - * Remove the writer. - * - * @param writer the writer. - */ + public static void addWriter(Writer writer) { + LOGGER_FACTORY.addWriter(writer); + } + public static void removeWriter(Writer writer) { LOGGER_FACTORY.removeWriter(writer); } - /** - * Enable passed logger level for some logger. - * - * @param cs the class which use its own logger. - * @param level the logger level to enable. - */ public static void enable(Class cs, LoggerLevel level) { - getLogger(cs).setEnabled(level, true); + getLogger(cs).overrideEnabled(level, true); } - /** - * Disable passed logger level for some logger. - * - * @param cs the class which use its own logger. - * @param level the logger level to disable. - */ public static void disable(Class cs, LoggerLevel level) { - getLogger(cs).setEnabled(level, false); + getLogger(cs).overrideEnabled(level, false); } } diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLogger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLogger.java index 01361fcf..3e50da07 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLogger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLogger.java @@ -2,9 +2,7 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; -import org.jspecify.annotations.NullMarked; -@NullMarked public final class NullLogger implements Logger { @Override diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLoggerFactory.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLoggerFactory.java index be313870..686665b9 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLoggerFactory.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NullLoggerFactory.java @@ -4,9 +4,7 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerFactory; import javasabr.rlib.logger.api.LoggerListener; -import org.jspecify.annotations.NullMarked; -@NullMarked public class NullLoggerFactory implements LoggerFactory { private static final NullLogger NULL_LOGGER = new NullLogger(); diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/package-info.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/package-info.java new file mode 100644 index 00000000..233f8b90 --- /dev/null +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.logger.api.impl; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java index f79b8d7d..c5d38cec 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLogger.java @@ -4,30 +4,21 @@ import javasabr.rlib.common.util.StringUtils; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; /** - * The base implementation of the logger. - * * @author JavaSaBr */ +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public final class DefaultLogger implements Logger { private static final LoggerLevel[] VALUES = LoggerLevel.values(); - /** - * The table of override enabled statuses. - */ - private final Boolean[] override; - - /** - * The logger name. - */ - private final String name; - - /** - * The default logger factory. - */ - private final DefaultLoggerFactory loggerFactory; + @Nullable Boolean[] override; + String name; + DefaultLoggerFactory loggerFactory; public DefaultLogger(String name, DefaultLoggerFactory loggerFactory) { this.name = name; @@ -36,33 +27,33 @@ public DefaultLogger(String name, DefaultLoggerFactory loggerFactory) { } @Override - public boolean isEnabled(LoggerLevel level) { + public boolean enabled(LoggerLevel level) { var value = override[level.ordinal()]; - return Objects.requireNonNullElse(value, level.isEnabled()); + return Objects.requireNonNullElse(value, level.enabled()); } @Override - public boolean setEnabled(LoggerLevel level, boolean enabled) { + public boolean overrideEnabled(LoggerLevel level, boolean enabled) { override[level.ordinal()] = enabled; return true; } @Override - public boolean applyDefault(LoggerLevel level) { + public boolean resetToDefault(LoggerLevel level) { override[level.ordinal()] = null; return true; } @Override public void print(LoggerLevel level, String message) { - if (isEnabled(level)) { + if (enabled(level)) { loggerFactory.write(level, name, message); } } @Override public void print(LoggerLevel level, Throwable exception) { - if (isEnabled(level)) { + if (enabled(level)) { loggerFactory.write(level, name, StringUtils.toString(exception)); } } diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java index 807249b8..d5fd6ba8 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java @@ -4,65 +4,50 @@ import java.io.IOException; import java.io.Writer; -import java.time.LocalTime; +import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.ConcurrentArray; +import javasabr.rlib.common.util.array.ArrayFactory; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerFactory; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerListener; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** * The class for managing loggers. * * @author JavaSaBr */ +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class DefaultLoggerFactory implements LoggerFactory { - /** - * The dictionary of all created loggers. - */ - private final ConcurrentMap loggers; + ConcurrentMap loggers; + Array listeners; + Array writers; - /** - * The main logger. - */ - private final Logger logger; - - /** - * The list of listeners. - */ - private final ConcurrentArray listeners; - - /** - * The list of writers. - */ - private final ConcurrentArray writers; - - /** - * The date time formatter. - */ - private final DateTimeFormatter timeFormatter; + Logger logger; + DateTimeFormatter timeFormatter; public DefaultLoggerFactory() { this.loggers = new ConcurrentHashMap<>(); this.logger = new DefaultLogger("", this); - this.timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss:SSS"); - this.listeners = ConcurrentArray.ofType(LoggerListener.class); - this.writers = ConcurrentArray.ofType(Writer.class); + this.timeFormatter = DateTimeFormatter.ofPattern("d.MM.yyyy HH:mm:ss:SSS"); + this.listeners = ArrayFactory.newCopyOnModifyArray(LoggerListener.class); + this.writers = ArrayFactory.newCopyOnModifyArray(Writer.class); } @Override public void addListener(LoggerListener listener) { - listeners.runInWriteLock(listener, Array::add); + listeners.add(listener); } @Override public void addWriter(Writer writer) { - writers.runInWriteLock(writer, Array::add); + writers.add(writer); } @Override @@ -72,74 +57,71 @@ public Logger getDefault() { @Override public Logger make(Class type) { - return notNull(loggers.computeIfAbsent(type.getSimpleName(), name -> new DefaultLogger(name, this))); + String simpleName = type.getSimpleName(); + Logger logger = loggers + .computeIfAbsent(simpleName, name -> new DefaultLogger(name, this)); + return notNull(logger); } @Override public Logger make(String name) { - return notNull(loggers.computeIfAbsent(name, str -> new DefaultLogger(str, this))); + Logger logger = loggers + .computeIfAbsent(name, str -> new DefaultLogger(str, this)); + return notNull(logger); } @Override public void removeListener(LoggerListener listener) { - listeners.runInWriteLock(listener, Array::remove); + listeners.remove(listener); } @Override public void removeWriter(Writer writer) { - writers.runInWriteLock(writer, Array::remove); + writers.remove(writer); } - /** - * Process of writing message to a console and writers. - * - * @param level the level of the message. - * @param name the name of owner. - * @param message the message. - */ void write(LoggerLevel level, String name, String message) { - var timeStump = timeFormatter.format(LocalTime.now()); - var result = level.getTitle() + ' ' + timeStump + ' ' + name + ": " + message; + var timeStamp = timeFormatter.format(LocalDateTime.now()); + var result = level.title() + level.offset() + ' ' + timeStamp + ' ' + name + ": " + message; write(level, result); } - /** - * Process of writing the result message. - * - * @param level the level of the result message. - * @param resultMessage the result message. - */ private void write(LoggerLevel level, String resultMessage) { - listeners.forEachInReadLockR(resultMessage, LoggerListener::println); - writers.forEachInReadLockR(resultMessage, DefaultLoggerFactory::append); + listeners.forEachR(resultMessage, LoggerListener::println); + writers.forEachR(resultMessage, DefaultLoggerFactory::append); - System.err.println(resultMessage); + switch (level) { + case INFO, DEBUG -> System.out.println(resultMessage); + case ERROR, WARNING -> System.err.println(resultMessage); + } - if (!level.isForceFlush()) { + if (!level.forceFlush()) { return; } - listeners.forEachInReadLock(LoggerListener::flush); - writers.forEachInReadLock(DefaultLoggerFactory::flush); + listeners.forEach(LoggerListener::flush); + writers.forEach(DefaultLoggerFactory::flush); } private static void append(Writer writer, String toWrite) { try { writer.append(toWrite); writer.append('\n'); - } catch (IOException e) { - e.printStackTrace(); + } catch (IOException exception) { + //noinspection CallToPrintStackTrace + exception.printStackTrace(); } } private static void flush(Writer writer) { try { writer.flush(); - } catch (IOException e) { - e.printStackTrace(); + } catch (IOException exception) { + //noinspection CallToPrintStackTrace + exception.printStackTrace(); } } } diff --git a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/FolderFileListener.java b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/FolderFileListener.java index 3a67f67d..61eb0aad 100644 --- a/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/FolderFileListener.java +++ b/rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/FolderFileListener.java @@ -3,36 +3,30 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.io.Writer; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import javasabr.rlib.logger.api.LoggerListener; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** - * The implementation of a logger listener to save log to files in a directory. - * * @author JavaSaBr */ +@FieldDefaults(level = AccessLevel.PROTECTED) public class FolderFileListener implements LoggerListener { private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyy-MM-dd_HH-mm-ss"); - /** - * The folder with log files. - */ - private final Path folder; - - /** - * The current writer. - */ - private Writer writer; + final Path folder; + Writer writer; public FolderFileListener(Path folder) { if (!Files.isDirectory(folder)) { - throw new IllegalArgumentException("file is not directory."); + throw new IllegalArgumentException("File:[%s] is not directory".formatted(folder)); } if (!Files.exists(folder)) { @@ -44,23 +38,14 @@ public FolderFileListener(Path folder) { } this.folder = folder; - } - /** - * Get or create a writer. - * - * @return the writer. - * @throws IOException the io exception - */ - public Writer getWriter() throws IOException { + public Writer getOrCreateWriter() throws IOException { if (writer == null) { - var dateTime = LocalDateTime.now(); var filename = TIME_FORMATTER.format(dateTime) + ".log"; - - writer = Files.newBufferedWriter(folder.resolve(filename), Charset.forName("UTF-8")); + writer = Files.newBufferedWriter(folder.resolve(filename), StandardCharsets.UTF_8); } return writer; @@ -69,12 +54,13 @@ public Writer getWriter() throws IOException { @Override public void println(String text) { try { - var writer = getWriter(); + var writer = getOrCreateWriter(); writer.append(text); writer.append('\n'); writer.flush(); - } catch (IOException e) { - e.printStackTrace(); + } catch (IOException exception) { + //noinspection CallToPrintStackTrace + exception.printStackTrace(); } } } diff --git a/rlib-logger-slf4j/src/main/java/javasabr/rlib/logger/slf4j/Slf4jLogger.java b/rlib-logger-slf4j/src/main/java/javasabr/rlib/logger/slf4j/Slf4jLogger.java index d9a0b05e..c3729313 100644 --- a/rlib-logger-slf4j/src/main/java/javasabr/rlib/logger/slf4j/Slf4jLogger.java +++ b/rlib-logger-slf4j/src/main/java/javasabr/rlib/logger/slf4j/Slf4jLogger.java @@ -10,55 +10,32 @@ public class Slf4jLogger implements Logger { private final org.slf4j.Logger logger; @Override - public boolean isEnabled(LoggerLevel level) { - - switch (level) { - case INFO: - return logger.isInfoEnabled(); - case DEBUG: - return logger.isDebugEnabled(); - case ERROR: - return logger.isErrorEnabled(); - case WARNING: - return logger.isWarnEnabled(); - } - - return false; + public boolean enabled(LoggerLevel level) { + return switch (level) { + case INFO -> logger.isInfoEnabled(); + case DEBUG -> logger.isDebugEnabled(); + case ERROR -> logger.isErrorEnabled(); + case WARNING -> logger.isWarnEnabled(); + }; } @Override public void print(LoggerLevel level, String message) { - switch (level) { - case INFO: - logger.info(message); - return; - case DEBUG: - logger.debug(message); - return; - case ERROR: - logger.error(message); - return; - case WARNING: - logger.warn(message); + case INFO -> logger.info(message); + case DEBUG -> logger.debug(message); + case ERROR -> logger.error(message); + case WARNING -> logger.warn(message); } } @Override public void print(LoggerLevel level, Throwable exception) { - switch (level) { - case INFO: - logger.info(exception.getMessage(), exception); - return; - case DEBUG: - logger.debug(exception.getMessage(), exception); - return; - case ERROR: - logger.error(exception.getMessage(), exception); - return; - case WARNING: - logger.warn(exception.getMessage(), exception); + case INFO -> logger.info(exception.getMessage(), exception); + case DEBUG -> logger.debug(exception.getMessage(), exception); + case ERROR -> logger.error(exception.getMessage(), exception); + case WARNING -> logger.warn(exception.getMessage(), exception); } } } diff --git a/rlib-network/build.gradle b/rlib-network/build.gradle index bc28de0e..0dd241d5 100644 --- a/rlib-network/build.gradle +++ b/rlib-network/build.gradle @@ -1,5 +1,6 @@ dependencies { api projects.rlibCommon + api projects.rlibClasspath api libs.project.reactor.core testRuntimeOnly projects.rlibLoggerImpl } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java index e70fe770..347d095e 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java @@ -159,7 +159,7 @@ else if (waitedBytes > 0) { tempPendingBuffer = notNull(getTempPendingBuffer()); - LOGGER.debugNullable( + LOGGER.debug( receivedBuffer, tempPendingBuffer, (buf, mappedBuf) -> "Put received buffer: " + buf + " to mapped buffer: " + mappedBuf); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java index f6d74548..9ff97213 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java @@ -43,7 +43,7 @@ static > ReadablePacketRegistry empty(Clas static ReadablePacketRegistry newDefault() { var scanner = ClassPathScannerFactory.newDefaultScanner(); - scanner.setUseSystemClasspath(true); + scanner.useSystemClassPath(true); scanner.scan(); return of(scanner); @@ -58,7 +58,7 @@ static ReadablePacketRegistry newDefault() { static ReadablePacketRegistry newDefault(Class mainClass) { var scanner = ClassPathScannerFactory.newManifestScanner(mainClass); - scanner.setUseSystemClasspath(false); + scanner.useSystemClassPath(false); scanner.scan(); return of(scanner); @@ -73,7 +73,7 @@ static ReadablePacketRegistry newDefault(Class mainClass) { static ReadablePacketRegistry of(ClassPathScanner scanner) { var result = scanner - .findImplements(IdBasedReadablePacket.class) + .findImplementations(IdBasedReadablePacket.class) .stream() .filter(type -> type.getAnnotation(PacketDescription.class) != null) .collect(ArrayCollectors.>toArray(Class.class)); diff --git a/rlib-plugin-system/build.gradle b/rlib-plugin-system/build.gradle new file mode 100644 index 00000000..7169d011 --- /dev/null +++ b/rlib-plugin-system/build.gradle @@ -0,0 +1,6 @@ + +dependencies { + api projects.rlibCommon + api projects.rlibClasspath + testImplementation projects.rlibLoggerImpl +} \ No newline at end of file diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/ConfigurablePluginSystem.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/ConfigurablePluginSystem.java new file mode 100644 index 00000000..9f67db4e --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/ConfigurablePluginSystem.java @@ -0,0 +1,34 @@ +package javasabr.rlib.plugin.system; + +import java.nio.file.Path; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; +import org.jspecify.annotations.Nullable; + +/** + * @author JavaSaBr + */ +public interface ConfigurablePluginSystem extends PluginSystem { + + void configureInstallationPluginsPath(Path installationPluginsPath); + + void configureEmbeddedPluginPath(Path embeddedPluginPath); + + void configureAppVersion(@Nullable Version version); + + CompletionStage preLoad(); + + CompletionStage preLoad(Executor executor); + + CompletionStage initialize(); + + CompletionStage initialize(Executor executor); + + @Nullable + Plugin installPlugin(Path file, boolean needInitialize); + + /** + * @return true if the plugin was removed + */ + boolean removePlugin(Plugin plugin); +} diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/Plugin.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/Plugin.java new file mode 100644 index 00000000..f420579a --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/Plugin.java @@ -0,0 +1,39 @@ +package javasabr.rlib.plugin.system; + +import javasabr.rlib.plugin.system.annotation.PluginDescription; + +/** + * @author JavaSaBr + */ +public interface Plugin { + + ClassLoader classLoader(); + + default String id() { + return getClass() + .getAnnotation(PluginDescription.class) + .id(); + } + + default Version version() { + return new Version(getClass() + .getAnnotation(PluginDescription.class) + .version()); + } + + default String name() { + return getClass() + .getAnnotation(PluginDescription.class) + .name(); + } + + default String description() { + return getClass() + .getAnnotation(PluginDescription.class) + .description(); + } + + boolean isEmbedded(); + + void initialize(PluginSystem pluginSystem); +} diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java new file mode 100644 index 00000000..87df056e --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginContainer.java @@ -0,0 +1,52 @@ +package javasabr.rlib.plugin.system; + +import java.net.URLClassLoader; +import java.nio.file.Path; +import javasabr.rlib.common.classpath.ClassPathScanner; +import javasabr.rlib.plugin.system.annotation.PluginDescription; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@Getter +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class PluginContainer { + + Class pluginClass; + URLClassLoader classLoader; + ClassPathScanner scanner; + Path path; + String id; + String name; + String description; + Version version; + boolean embedded; + + public PluginContainer( + Class pluginClass, + URLClassLoader classLoader, + ClassPathScanner scanner, + Path path, + boolean embedded) { + PluginDescription description = pluginClass.getAnnotation(PluginDescription.class); + this.pluginClass = pluginClass; + this.classLoader = classLoader; + this.scanner = scanner; + this.path = path; + this.embedded = embedded; + this.id = description.id(); + this.name = description.name(); + this.version = new Version(description.version()); + this.description = description.description(); + } + + @Override + public String toString() { + return "PluginContainer{" + "pluginClass=" + pluginClass + ", path=" + path + '}'; + } +} diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginSystem.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginSystem.java new file mode 100644 index 00000000..dccd4c17 --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/PluginSystem.java @@ -0,0 +1,29 @@ +package javasabr.rlib.plugin.system; + +import java.util.Optional; +import javasabr.rlib.common.util.array.Array; +import org.jspecify.annotations.Nullable; + +/** + * @author JavaSaBr + */ +public interface PluginSystem { + + Array pluginContainers(); + + @Nullable + PluginContainer getPluginContainer(String id); + + default Optional getPluginContainerOptional(String id) { + return Optional.ofNullable(getPluginContainer(id)); + } + + Array plugins(); + + @Nullable + Plugin getPlugin(String id); + + default Optional getPluginOptional(String id) { + return Optional.ofNullable(getPlugin(id)); + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/Version.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/Version.java similarity index 89% rename from rlib-common/src/main/java/javasabr/rlib/common/plugin/Version.java rename to rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/Version.java index 6a911846..40978b3e 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/Version.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/Version.java @@ -1,17 +1,13 @@ -package javasabr.rlib.common.plugin; +package javasabr.rlib.plugin.system; import static java.lang.Math.min; import java.util.stream.Stream; import javasabr.rlib.common.util.ArrayUtils; -import org.jspecify.annotations.NullMarked; /** - * The class to present a version. - * * @author JavaSaBr */ -@NullMarked public class Version implements Comparable { /** diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/annotation/PluginDescription.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/annotation/PluginDescription.java similarity index 91% rename from rlib-common/src/main/java/javasabr/rlib/common/plugin/annotation/PluginDescription.java rename to rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/annotation/PluginDescription.java index e9b3af2c..25897be4 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/annotation/PluginDescription.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/annotation/PluginDescription.java @@ -1,18 +1,16 @@ -package javasabr.rlib.common.plugin.annotation; +package javasabr.rlib.plugin.system.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.jspecify.annotations.NullMarked; /** * The annotation to describe a plugin. * * @author JavaSaBr */ -@NullMarked @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/annotation/package-info.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/annotation/package-info.java new file mode 100644 index 00000000..6e27c880 --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/annotation/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.plugin.system.annotation; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/InitializePluginException.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/InitializePluginException.java similarity index 93% rename from rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/InitializePluginException.java rename to rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/InitializePluginException.java index ada8e22d..b8bee9f0 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/InitializePluginException.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/InitializePluginException.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.plugin.exception; +package javasabr.rlib.plugin.system.exception; import java.nio.file.Path; import org.jspecify.annotations.NullMarked; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/PluginException.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/PluginException.java similarity index 88% rename from rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/PluginException.java rename to rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/PluginException.java index ffc9a8b1..00c6df68 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/PluginException.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/PluginException.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.plugin.exception; +package javasabr.rlib.plugin.system.exception; import org.jspecify.annotations.NullMarked; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/PreloadPluginException.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/PreloadPluginException.java similarity index 91% rename from rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/PreloadPluginException.java rename to rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/PreloadPluginException.java index e2e998bc..8a5768c7 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/exception/PreloadPluginException.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/exception/PreloadPluginException.java @@ -1,4 +1,4 @@ -package javasabr.rlib.common.plugin.exception; +package javasabr.rlib.plugin.system.exception; import java.nio.file.Path; import org.jspecify.annotations.NullMarked; diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/ExtensionPoint.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/ExtensionPoint.java new file mode 100644 index 00000000..727ddcd6 --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/ExtensionPoint.java @@ -0,0 +1,110 @@ +package javasabr.rlib.plugin.system.extension; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import javasabr.rlib.common.util.ArrayUtils; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class ExtensionPoint implements Iterable { + + protected record State(List extensions, Object[] array) { + + public static State empty() { + return new State<>(List.of(), ArrayUtils.EMPTY_OBJECT_ARRAY); + } + + /** + * Append the additional extensions to the current state as new state. + * + * @param additionalExtensions the additional extension. + * @return the new state. + */ + @SafeVarargs + public final State append(T... additionalExtensions) { + + List result = new ArrayList<>(extensions); + result.addAll(List.of(additionalExtensions)); + + boolean canBeSorted = result + .stream() + .allMatch(Comparable.class::isInstance); + + if (canBeSorted) { + result.sort((first, second) -> ((Comparable) first).compareTo(second)); + } + + return new State<>(List.copyOf(result), result.toArray()); + } + } + + AtomicReference> state; + + public ExtensionPoint() { + this.state = new AtomicReference<>(State.empty()); + } + + public ExtensionPoint register(T extension) { + + State currentState = state.get(); + State newState = currentState.append(extension); + + while (!state.compareAndSet(currentState, newState)) { + currentState = state.get(); + newState = currentState.append(extension); + } + + return this; + } + + @SafeVarargs + public final ExtensionPoint register(T... extensions) { + + State currentState = state.get(); + State newState = currentState.append(extensions); + + while (!state.compareAndSet(currentState, newState)) { + currentState = state.get(); + newState = currentState.append(extensions); + } + + return this; + } + + public List extensions() { + return state.get().extensions; + } + + @Override + public void forEach(Consumer consumer) { + Object[] array = state.get().array; + for (Object obj : array) { + consumer.accept((T) obj); + } + } + + @Override + public Iterator iterator() { + return state.get().extensions.iterator(); + } + + public Stream stream() { + return StreamSupport.stream(spliterator(), false); + } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(state.get().array, 0); + } +} diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/ExtensionPointManager.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/ExtensionPointManager.java new file mode 100644 index 00000000..5ae155ed --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/ExtensionPointManager.java @@ -0,0 +1,85 @@ +package javasabr.rlib.plugin.system.extension; + +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.common.util.dictionary.ConcurrentObjectDictionary; +import javasabr.rlib.common.util.dictionary.DictionaryFactory; +import javasabr.rlib.common.util.dictionary.ObjectDictionary; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerManager; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class ExtensionPointManager { + + private static final Logger LOGGER = LoggerManager.getLogger(ExtensionPointManager.class); + + private static final ExtensionPointManager INSTANCE = new ExtensionPointManager(); + + public static ExtensionPointManager getInstance() { + return INSTANCE; + } + + public static ExtensionPoint register(String id) { + return getInstance().create(id); + } + + ConcurrentObjectDictionary> extensionPoints; + + public ExtensionPointManager() { + this.extensionPoints = DictionaryFactory.newConcurrentAtomicObjectDictionary(); + } + + public ExtensionPoint create(String id) { + long stamp = extensionPoints.writeLock(); + try { + ExtensionPoint exists = extensionPoints.get(id); + if (exists != null) { + LOGGER.warning(id, "Extension point:[%s] is already registered"::formatted); + return ClassUtils.unsafeNNCast(exists); + } + + var extensionPoint = new ExtensionPoint(); + extensionPoints.put(id, extensionPoint); + return extensionPoint; + } finally { + extensionPoints.writeUnlock(stamp); + } + } + + public ExtensionPointManager addExtension(String id, Class type, T extension) { + getOrCreateExtensionPoint(id).register(extension); + return this; + } + + public ExtensionPointManager addExtension(String id, T extension) { + getOrCreateExtensionPoint(id).register(extension); + return this; + } + + public ExtensionPointManager addExtension(String id, T... extensions) { + getOrCreateExtensionPoint(id).register(extensions); + return this; + } + + public ExtensionPoint getOrCreateExtensionPoint(String id, Class type) { + return getOrCreateExtensionPoint(id); + } + + public ExtensionPoint getOrCreateExtensionPoint(String id) { + + ExtensionPoint extensionPoint = extensionPoints.getFromReadLock(id, ObjectDictionary::get); + if (extensionPoint != null) { + return ClassUtils.unsafeNNCast(extensionPoint); + } + + try { + return create(id); + } catch (IllegalArgumentException e) { + return getOrCreateExtensionPoint(id); + } + } +} diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/package-info.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/package-info.java new file mode 100644 index 00000000..19badc3e --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/extension/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.plugin.system.extension; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePlugin.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePlugin.java new file mode 100644 index 00000000..d95befed --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePlugin.java @@ -0,0 +1,56 @@ +package javasabr.rlib.plugin.system.impl; + +import javasabr.rlib.plugin.system.Plugin; +import javasabr.rlib.plugin.system.PluginContainer; +import javasabr.rlib.plugin.system.PluginSystem; +import javasabr.rlib.plugin.system.Version; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class BasePlugin implements Plugin { + + PluginContainer container; + + @Override + public ClassLoader classLoader() { + return container.classLoader(); + } + + @Override + public boolean isEmbedded() { + return container.embedded(); + } + + @Override + public String id() { + return container.id(); + } + + @Override + public Version version() { + return container.version(); + } + + @Override + public String description() { + return container.description(); + } + + @Override + public String name() { + return container.name(); + } + + protected PluginContainer container() { + return container; + } + + @Override + public void initialize(PluginSystem pluginSystem) {} +} diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java new file mode 100644 index 00000000..6c0bcb38 --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/BasePluginSystem.java @@ -0,0 +1,515 @@ +package javasabr.rlib.plugin.system.impl; + +import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; +import static java.util.concurrent.CompletableFuture.supplyAsync; +import static javasabr.rlib.common.util.ObjectUtils.notNull; +import static javasabr.rlib.common.util.array.ArrayCollectors.toArray; +import static javasabr.rlib.common.util.dictionary.DictionaryCollectors.toObjectDictionary; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.reflect.Constructor; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import javasabr.rlib.common.classpath.ClassPathScannerFactory; +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.common.util.FileUtils; +import javasabr.rlib.common.util.Utils; +import javasabr.rlib.common.util.array.Array; +import javasabr.rlib.common.util.array.ReadOnlyArray; +import javasabr.rlib.common.util.dictionary.ObjectDictionary; +import javasabr.rlib.logger.api.Logger; +import javasabr.rlib.logger.api.LoggerManager; +import javasabr.rlib.plugin.system.ConfigurablePluginSystem; +import javasabr.rlib.plugin.system.Plugin; +import javasabr.rlib.plugin.system.PluginContainer; +import javasabr.rlib.plugin.system.PluginSystem; +import javasabr.rlib.plugin.system.Version; +import javasabr.rlib.plugin.system.annotation.PluginDescription; +import javasabr.rlib.plugin.system.exception.InitializePluginException; +import javasabr.rlib.plugin.system.exception.PluginException; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; + +/** + * @author JavaSaBr + */ +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class BasePluginSystem implements ConfigurablePluginSystem { + + protected static final Logger LOGGER = LoggerManager.getLogger(PluginSystem.class); + + protected record State( + Array containers, + Array plugins, + ObjectDictionary idToContainer, + ObjectDictionary idToPlugin) { + + static final State EMPTY = new State( + Array.empty(), + Array.empty(), + ObjectDictionary.empty(), + ObjectDictionary.empty()); + } + + final ClassLoader baseLoader; + final AtomicBoolean preLoaded; + final AtomicBoolean initialized; + final AtomicReference state; + + @Getter + volatile @Nullable Version appVersion; + volatile @Nullable Path embeddedPluginsPath; + volatile @Nullable Path installationPluginsPath; + + public BasePluginSystem() { + this(StackWalker + .getInstance(RETAIN_CLASS_REFERENCE) + .getCallerClass() + .getClassLoader()); + } + + public BasePluginSystem(ClassLoader baseLoader) { + this.baseLoader = baseLoader; + this.state = new AtomicReference<>(State.EMPTY); + this.preLoaded = new AtomicBoolean(false); + this.initialized = new AtomicBoolean(false); + } + + @Override + public void configureAppVersion(@Nullable Version appVersion) { + this.appVersion = appVersion; + } + + @Override + public CompletionStage preLoad() { + return preLoad(ForkJoinPool.commonPool()); + } + + @Override + public CompletionStage preLoad(Executor executor) { + + if (!preLoaded.compareAndSet(false, true)) { + throw new PluginException("This system was already pre-loaded"); + } + + return supplyAsync(() -> preLoadImpl(executor), executor); + } + + protected BasePluginSystem preLoadImpl(Executor executor) { + LOGGER.debug("Start pre-loading all plugins..."); + + State current = state.get(); + ReadOnlyArray>> futures = Array.optionals( + CompletionStage.class, + embeddedPluginsPathOptional().map(path -> loadPlugins(path, executor, true)), + installationPluginsPathOptional().map(path -> loadPlugins(path, executor, false))); + Array containers = futures + .stream() + .map(CompletionStage::toCompletableFuture) + .map(CompletableFuture::join) + .flatMap(Array::stream) + .collect(toArray(PluginContainer.class)); + + var idToContainer = containers + .stream() + .collect(toObjectDictionary(PluginContainer::id, container -> container)); + + State newState = new State( + ReadOnlyArray.wrap(containers), + Array.empty(), + idToContainer, + ObjectDictionary.empty()); + + if (state.compareAndSet(current, newState)) { + LOGGER.debug(containers, "Pre-loaded:%s"::formatted); + LOGGER.debug("All plugins were pre-loaded"); + return this; + } + + throw new PluginException("This system was already pre-loaded."); + } + + @Override + public CompletionStage initialize() { + return initialize(ForkJoinPool.commonPool()); + } + + @Override + public CompletionStage initialize(Executor executor) { + + if (!initialized.compareAndSet(false, true)) { + throw new PluginException("This system was already initialized."); + } + + return supplyAsync(() -> initializeImpl(executor), executor); + } + + protected BasePluginSystem initializeImpl(Executor executor) { + LOGGER.debug("Start loading all plugins..."); + + var current = state.get(); + var plugins = current.containers + .stream() + .map(pluginContainer -> createPluginClass(pluginContainer, executor)) + .map(future -> future.thenApply(this::initializePlugin)) + .map(CompletionStage::toCompletableFuture) + .map(CompletableFuture::join) + .collect(toObjectDictionary(Plugin::id, plugin -> plugin)); + + State newState = new State( + current.containers, + ReadOnlyArray.wrap(plugins.values(Plugin.class)), + current.idToContainer, + plugins); + + if (state.compareAndSet(current, newState)) { + LOGGER.debug("All plugins were initialized"); + return this; + } + + throw new PluginException("This system was already initialized."); + } + + protected CompletionStage createPluginClass(PluginContainer container, Executor executor) { + return supplyAsync(() -> createPluginClassImpl(container), executor); + } + + protected Plugin createPluginClassImpl(PluginContainer container) { + var pluginClass = container.pluginClass(); + + LOGGER.debug(pluginClass, "Start creating plugin:[%s]"::formatted); + + Constructor constructor = ClassUtils.tryGetConstructor(pluginClass, PluginContainer.class); + if (constructor == null) { + throw new InitializePluginException( + "Not found base constructor in class:[%s]".formatted(pluginClass), + container.path()); + } + + Plugin plugin; + try { + plugin = ClassUtils.newInstance(constructor, container); + } catch (Throwable throwable) { + throw new InitializePluginException( + "Found problem with creating plugin:[%s]".formatted(pluginClass), + container.path(), + throwable); + } + + return plugin; + } + + protected Plugin initializePlugin(Plugin plugin) { + + try { + plugin.initialize(this); + } catch (Throwable throwable) { + var container = notNull(getPluginContainer(plugin.id())); + throw new InitializePluginException( + "Found problem with initializing plugin:[%s]".formatted(plugin.id()), + container.path(), + throwable); + } + + return plugin; + } + + protected CompletionStage> loadPlugins( + Path path, + Executor executor, + boolean embedded) { + + Path realPath; + try { + realPath = path.toRealPath(LinkOption.NOFOLLOW_LINKS); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + LOGGER.debug(realPath, "Try to pre-load plugins from the folder:[%s]"::formatted); + return supplyAsync( + () -> FileUtils + .stream(realPath) + .filter(Files::isDirectory) + .map(directory -> loadPlugin(directory, baseLoader, executor, embedded)) + .map(CompletionStage::toCompletableFuture) + .map(CompletableFuture::join) + .filter(Objects::nonNull) + .collect(toArray(PluginContainer.class)), executor); + } + + protected CompletionStage<@Nullable PluginContainer> loadPlugin( + Path directory, + ClassLoader parentLoader, + Executor executor, + boolean embedded) { + return loadPlugin(directory, parentLoader, null, executor, embedded); + } + + protected CompletionStage<@Nullable PluginContainer> loadPlugin( + Path directory, + ClassLoader parentLoader, + PluginContainer @Nullable [] parents, + Executor executor, + boolean embedded) { + return supplyAsync(() -> loadPluginImpl(directory, parentLoader, parents, embedded), executor); + } + + @Nullable + protected PluginContainer loadPluginImpl( + Path directory, + ClassLoader parentLoader, + PluginContainer @Nullable [] parents, + boolean embedded) { + + Array files = FileUtils.getFiles(directory, ".jar"); + URL[] urls = files + .stream() + .map(path -> Utils.uncheckedGet(path, Path::toUri)) + .map(uri -> Utils.uncheckedGet(uri, URI::toURL)) + .toArray(URL[]::new); + String[] additionalPaths = files + .stream() + .map(Path::toAbsolutePath) + .map(Path::toString) + .toArray(String[]::new); + + var classLoader = new URLClassLoader(urls); + var scanner = ClassPathScannerFactory.newDefaultScanner(classLoader, additionalPaths); + scanner.useSystemClassPath(false); + try { + scanner.scan(); + } catch (Throwable throwable) { + LOGGER.warning(throwable); + return null; + } + + Array> pluginImplementations = scanner.findImplementations(Plugin.class); + if (pluginImplementations.isEmpty()) { + LOGGER.warning( + directory, + "Can't load plugin from directory:[%s] because can't find any implementation of plugin interface"::formatted); + return null; + } else if (pluginImplementations.size() > 1) { + LOGGER.warning( + directory, + "Can't load plugin from directory:[%s] because found more than 1 implementation of plugin interface"::formatted); + return null; + } + + Class pluginClass = notNull(pluginImplementations.first()); + PluginDescription description = pluginClass.getAnnotation(PluginDescription.class); + if (description == null) { + LOGGER.warning( + directory, + pluginClass, + "Can't load plugin from directory:[%s] because can't find description on class:[%s]"::formatted); + return null; + } + + Version appVersion = appVersion(); + if (appVersion != null) { + var minVersion = new Version(description.minAppVersion()); + if (minVersion.compareTo(appVersion) > 0) { + LOGGER.warning( + description.id(), + description.minAppVersion(), + "Can't load plugin:[%s] because it requires minimum app version:[%s]"::formatted); + return null; + } + } + + return new PluginContainer(pluginClass, classLoader, scanner, directory, embedded); + } + + protected Optional embeddedPluginsPathOptional() { + return Optional.ofNullable(embeddedPluginsPath); + } + + protected Optional installationPluginsPathOptional() { + return Optional.ofNullable(installationPluginsPath); + } + + @Override + public void configureEmbeddedPluginPath(Path embeddedPluginPath) { + if (isInitialized()) { + throw new RuntimeException("The plugin system is already initialized."); + } + this.embeddedPluginsPath = embeddedPluginPath; + } + + @Override + public void configureInstallationPluginsPath(Path installationPluginsPath) { + if (isInitialized()) { + throw new RuntimeException("The plugin system is already initialized."); + } + this.installationPluginsPath = installationPluginsPath; + } + + protected boolean isPreLoaded() { + return preLoaded.get(); + } + + protected boolean isInitialized() { + return initialized.get(); + } + + @Override + public Array pluginContainers() { + return state.get().containers; + } + @Nullable + @Override + public PluginContainer getPluginContainer(String id) { + return state.get().idToContainer.get(id); + } + + @Override + public Array plugins() { + return state.get().idToPlugin.values(Plugin.class); + } + + @Nullable + @Override + public Plugin getPlugin(String id) { + return state.get().idToPlugin.get(id); + } + + @Nullable + @Override + public Plugin installPlugin(Path file, boolean needInitialize) { + + var installPath = installationPluginsPathOptional() + .filter(Files::exists) + .orElse(null); + + if (installPath == null) { + throw new PluginException("Installation folder:[%s] doesn't exists".formatted(installationPluginsPathOptional())); + } + + State current = state.get(); + String folderName = FileUtils.getNameWithoutExtension(file); + Path pluginFolder = installPath.resolve(folderName); + + if (Files.exists(pluginFolder)) { + FileUtils.delete(pluginFolder); + } + + FileUtils.createDirectories(pluginFolder); + FileUtils.unzip(pluginFolder, file); + + var container = loadPlugin(pluginFolder, baseLoader, ForkJoinPool.commonPool(), false) + .toCompletableFuture() + .join(); + + if (container == null) { + return null; + } + + var existsContainer = getPluginContainer(container.id()); + if (existsContainer != null && !pluginFolder.equals(existsContainer.path())) { + FileUtils.delete(existsContainer.path()); + } + + Class pluginClass = container.pluginClass(); + Constructor constructor = ClassUtils.tryGetConstructor(pluginClass, PluginContainer.class); + if (constructor == null) { + throw new InitializePluginException( + "Not found base constructor in class:[%s]".formatted(pluginClass), + container.path()); + } + + Plugin plugin; + try { + plugin = ClassUtils.newInstance(constructor, container); + } catch (Exception exception) { + throw new InitializePluginException( + "Found problem with creating plugin:[%s]".formatted(pluginClass), + container.path(), + exception); + } + + if (needInitialize) { + try { + plugin.initialize(this); + } catch (Exception exception) { + throw new InitializePluginException( + "Found problem with initializing plugin:[%s]".formatted(plugin), + container.path(), + exception); + } + } + + var idToContainer = ObjectDictionary.ofType(String.class, PluginContainer.class); + idToContainer.put(current.idToContainer); + idToContainer.put(container.id(), container); + + var idToPlugin = ObjectDictionary.ofType(String.class, Plugin.class); + idToPlugin.put(current.idToPlugin); + idToPlugin.put(plugin.id(), plugin); + + State newState = new State( + ReadOnlyArray.wrap(idToContainer.values(PluginContainer.class)), + ReadOnlyArray.wrap(idToPlugin.values(Plugin.class)), + idToContainer, + idToPlugin); + + if (state.compareAndSet(current, newState)) { + return plugin; + } + + LOGGER.warning("Detected concurrent attempt to install plugin:[%s], trying again...".formatted(pluginClass)); + return installPlugin(file, needInitialize); + } + + @Override + public boolean removePlugin(Plugin plugin) { + + State current = state.get(); + String pluginId = plugin.id(); + PluginContainer pluginContainer = current.idToContainer.get(pluginId); + if (pluginContainer == null) { + LOGGER.warning("Plugin:[%s] is already removed".formatted(plugin.name())); + return false; + } + + var idToContainer = ObjectDictionary.ofType(String.class, PluginContainer.class); + idToContainer.put(current.idToContainer); + idToContainer.remove(pluginId); + + var idToPlugin = ObjectDictionary.ofType(String.class, Plugin.class); + idToPlugin.put(current.idToPlugin); + idToPlugin.remove(pluginId); + + State newState = new State( + ReadOnlyArray.wrap(idToContainer.values(PluginContainer.class)), + ReadOnlyArray.wrap(idToPlugin.values(Plugin.class)), + idToContainer, + idToPlugin); + + if (state.compareAndSet(current, newState)) { + FileUtils.delete(pluginContainer.path()); + return true; + } + + LOGGER.warning("Detected concurrent attempt to remove plugin:[%s], trying again...".formatted(plugin.name())); + return removePlugin(plugin); + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/PluginSystemFactory.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/PluginSystemFactory.java similarity index 60% rename from rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/PluginSystemFactory.java rename to rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/PluginSystemFactory.java index 8db1a59a..de7977ee 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/plugin/impl/PluginSystemFactory.java +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/PluginSystemFactory.java @@ -1,14 +1,10 @@ -package javasabr.rlib.common.plugin.impl; +package javasabr.rlib.plugin.system.impl; -import javasabr.rlib.common.plugin.ConfigurablePluginSystem; -import org.jspecify.annotations.NullMarked; +import javasabr.rlib.plugin.system.ConfigurablePluginSystem; /** - * The factory of different plugin systems. - * * @author JavaSaBr */ -@NullMarked public class PluginSystemFactory { public static ConfigurablePluginSystem newBasePluginSystem() { diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/package-info.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/package-info.java new file mode 100644 index 00000000..3c567c9d --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/impl/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.plugin.system.impl; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/package-info.java b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/package-info.java new file mode 100644 index 00000000..1931cd42 --- /dev/null +++ b/rlib-plugin-system/src/main/java/javasabr/rlib/plugin/system/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.plugin.system; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-common/src/test/java/javasabr/rlib/common/plugin/system/PluginSystemTests.java b/rlib-plugin-system/src/test/java/javasabr/rlib/plugin/system/PluginSystemTests.java similarity index 57% rename from rlib-common/src/test/java/javasabr/rlib/common/plugin/system/PluginSystemTests.java rename to rlib-plugin-system/src/test/java/javasabr/rlib/plugin/system/PluginSystemTests.java index 4096d662..ff121a7d 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/plugin/system/PluginSystemTests.java +++ b/rlib-plugin-system/src/test/java/javasabr/rlib/plugin/system/PluginSystemTests.java @@ -1,9 +1,10 @@ -package javasabr.rlib.common.plugin.system; +package javasabr.rlib.plugin.system; import java.nio.file.Paths; import java.util.concurrent.ForkJoinPool; -import javasabr.rlib.common.plugin.Version; -import javasabr.rlib.common.plugin.impl.PluginSystemFactory; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; +import javasabr.rlib.plugin.system.impl.PluginSystemFactory; import org.junit.jupiter.api.Test; /** @@ -11,16 +12,21 @@ */ public class PluginSystemTests { + static { + LoggerManager.enable(PluginSystem.class, LoggerLevel.DEBUG); + } + @Test public void test() { var pluginSystem = PluginSystemFactory.newBasePluginSystem(); - pluginSystem.setAppVersion(new Version("0.0.1")); + pluginSystem.configureAppVersion(new Version("0.0.1")); pluginSystem.configureEmbeddedPluginPath(Paths.get("../gradle/")); pluginSystem .preLoad(ForkJoinPool.commonPool()) .thenApply(system -> system.initialize(ForkJoinPool.commonPool())) + .toCompletableFuture() .join(); } } diff --git a/rlib-common/src/test/java/javasabr/rlib/common/plugin/extension/ExtensionPointTests.java b/rlib-plugin-system/src/test/java/javasabr/rlib/plugin/system/extension/ExtensionPointTests.java similarity index 62% rename from rlib-common/src/test/java/javasabr/rlib/common/plugin/extension/ExtensionPointTests.java rename to rlib-plugin-system/src/test/java/javasabr/rlib/plugin/system/extension/ExtensionPointTests.java index 8f7afc5a..e922b101 100644 --- a/rlib-common/src/test/java/javasabr/rlib/common/plugin/extension/ExtensionPointTests.java +++ b/rlib-plugin-system/src/test/java/javasabr/rlib/plugin/system/extension/ExtensionPointTests.java @@ -1,12 +1,10 @@ -package javasabr.rlib.common.plugin.extension; +package javasabr.rlib.plugin.system.extension; import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** - * The list of tests {@link ExtensionPoint}. - * * @author JavaSaBr */ public class ExtensionPointTests { @@ -18,24 +16,24 @@ void registerExtensionTest() { point.register("a", "b"); point.register("c"); - Assertions.assertIterableEquals(Arrays.asList("a", "b", "c"), point.getExtensions()); + Assertions.assertIterableEquals(Arrays.asList("a", "b", "c"), point.extensions()); } @Test void registerExtensionPointTest() { - var manager = ExtensionPointManager.getInstance(); + var manager = new ExtensionPointManager(); manager.addExtension("Test1", 5); manager.addExtension("Test1", 6, 7); - var test2 = ExtensionPointManager.register("Test2"); + var test2 = manager.create("Test2"); test2.register(1, 2); test2.register(3); - var forTest1 = manager.getExtensionPoint("Test1"); - var forTest2 = manager.getExtensionPoint("Test2"); + var forTest1 = manager.getOrCreateExtensionPoint("Test1"); + var forTest2 = manager.getOrCreateExtensionPoint("Test2"); - Assertions.assertIterableEquals(Arrays.asList(5, 6, 7), forTest1.getExtensions()); - Assertions.assertIterableEquals(Arrays.asList(1, 2, 3), forTest2.getExtensions()); + Assertions.assertIterableEquals(Arrays.asList(5, 6, 7), forTest1.extensions()); + Assertions.assertIterableEquals(Arrays.asList(1, 2, 3), forTest2.extensions()); } } diff --git a/settings.gradle b/settings.gradle index 849dae0d..21ccd467 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,3 +10,6 @@ include ':rlib-mail' include ':rlib-logger-api' include ':rlib-logger-impl' include ':rlib-logger-slf4j' +include ':rlib-plugin-system' +include ':rlib-geometry' +include ':rlib-classpath' \ No newline at end of file