DynamicClassLoader.java

package coneforest.psylla.runtime;

import coneforest.psylla.core.*;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Hashtable;
import java.util.jar.JarFile;

public abstract class DynamicClassLoader
	extends ClassLoader
{
	private final Hashtable<String, Class<?>> classes=new Hashtable<>();

	public DynamicClassLoader()
	{
	}

	public void psyExternal(final PsyTextual oClassName)
		throws PsyInvalidExternalException
	{
		try
		{
			loadClass(oClassName.stringValue());
		}
		catch(final ClassNotFoundException ex)
		{
			throw new PsyInvalidExternalException();
		}
	}

	@Override
	public Class<?> findClass(final String className)
		throws ClassNotFoundException
	{
		try
		{
			return findSystemClass(className);
		}
		catch(final ClassNotFoundException ex)
		{
			// NOP
		}
		var result=classes.get(className);
		if(result!=null)
			return result;

		try
		{
			final var url=findResource(className.replace('.', '/')+".class");
			if(url==null)
				throw new ClassNotFoundException();

			final var classBytes=url.openStream().readAllBytes();
			result=defineClass(className, classBytes, 0, classBytes.length, null);
			classes.put(className, result);
			return result;
		}
		catch(final IOException ex)
		{
			throw new ClassNotFoundException();
		}
	}

	protected abstract Iterable<String> getClassPath()
		throws Exception;

	@Override
	protected URL findResource(final String name)
	{
		try
		{
			final var cp=getClassPath();
			for(final String item: cp)
			{
				//final String item=oItem.stringValue();
				final var itemPath=Path.of(item);
				try
				{
					if(Files.isRegularFile(itemPath))
					{
						try(final var jar=new JarFile(itemPath.toFile()))
						{
							final var entry=jar.getJarEntry(name);
							if(entry==null)
								return null;
							return new URI("jar:"+itemPath.toUri().toURL()+"!/"+entry).toURL();
						}
					}
					else if(Files.isDirectory(itemPath))
					{
						// TODO: if directory does not exist
						return Path.of(itemPath.toString(), name).toUri().toURL();
					}
				}
				catch(final IOException ex)
				{
					return null;
				}
			}
		}
		catch(Exception ex)
		{
			return null;
		}
		return null;
	}
}