Skip to content

Commit

Permalink
LDEV-5040 - completely reorganise how javasettings are loaded
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeloffner committed Aug 16, 2024
1 parent 93cfb65 commit 4300d16
Show file tree
Hide file tree
Showing 23 changed files with 317 additions and 389 deletions.
62 changes: 22 additions & 40 deletions core/src/main/java/lucee/commons/io/res/util/MavenClassLoader.java
Original file line number Diff line number Diff line change
@@ -1,43 +1,25 @@
package lucee.commons.io.res.util;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import lucee.runtime.mvn.POM;

public class MavenClassLoader extends ResourceClassLoader {

private static Map<String, MavenClassLoader> instances = new ConcurrentHashMap<>();
private POM pom;

public MavenClassLoader(POM pom, ClassLoader parent) throws IOException {
super(pom.getJars(), parent);
this.pom = pom;
}

public static MavenClassLoader getInstance(POM pom, ClassLoader parent) throws IOException {
MavenClassLoader mcl = instances.get(pom.hash());
if (mcl == null) {
mcl = new MavenClassLoader(pom, parent);
instances.put(pom.hash(), mcl);
}
return mcl;
}

public static MavenClassLoader getInstance(POM[] poms, ClassLoader parent) throws IOException {
if (poms == null || poms.length == 0) throw new IOException("you need to define at least one POM.");

Arrays.sort(poms, (pom1, pom2) -> pom1.id().compareTo(pom2.id()));

for (POM pom: poms) {
parent = getInstance(pom, parent);
}
return (MavenClassLoader) parent;
}

public POM getPOM() {
return pom;
}
public class MavenClassLoader {// extends ResourceClassLoader {
/*
* private static Map<String, MavenClassLoader> instances = new ConcurrentHashMap<>(); private POM
* pom;
*
* public MavenClassLoader(POM pom, ClassLoader parent) throws IOException { super(pom.getJars(),
* parent); this.pom = pom; }
*
* public static MavenClassLoader getInstance(POM pom, ClassLoader parent) throws IOException {
* MavenClassLoader mcl = instances.get(pom.hash()); if (mcl == null) { mcl = new
* MavenClassLoader(pom, parent); instances.put(pom.hash(), mcl); } return mcl; }
*
* public static MavenClassLoader getInstance(POM[] poms, ClassLoader parent) throws IOException {
* if (poms == null || poms.length == 0) throw new
* IOException("you need to define at least one POM.");
*
* Arrays.sort(poms, (pom1, pom2) -> pom1.id().compareTo(pom2.id()));
*
* for (POM pom: poms) { parent = getInstance(pom, parent); } return (MavenClassLoader) parent; }
*
* public POM getPOM() { return pom; }
*/
}
106 changes: 42 additions & 64 deletions core/src/main/java/lucee/commons/io/res/util/ResourceClassLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@

import java.io.Closeable;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
Expand All @@ -35,46 +33,63 @@
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.type.file.FileResource;
import lucee.runtime.exp.PageException;
import lucee.runtime.type.util.ArrayUtil;

/**
* Classloader that load classes from resources
*/
public class ResourceClassLoader extends URLClassLoader implements Closeable {
private static Map<String, ResourceClassLoader> classloaders = new ConcurrentHashMap<>();

private final List<Resource> resources = new ArrayList<Resource>();
private Map<String, SoftReference<ResourceClassLoader>> customCLs;
private Integer hc = null;
private final Collection<Resource> resources;

private final String id;
private static RC rc = new RC();
static {
boolean res = registerAsParallelCapable();
}

/**
* Constructor of the class
*
* @param reses
* @param parent
* @throws PageException
*/
public ResourceClassLoader(Resource[] resources, ClassLoader parent) throws IOException {
super(doURLs(resources), parent);
public static ResourceClassLoader getInstance(Resource[] resources, ClassLoader parent) throws IOException {
List<Resource> list = new ArrayList<Resource>();
for (Resource r: resources) {
if (r != null) this.resources.add(r);
if (r != null) list.add(r);
}
java.util.Collections.sort(this.resources, rc);
java.util.Collections.sort(list, rc);
return getInstance(list, parent);
}

public ResourceClassLoader(Collection<Resource> resources, ClassLoader parent) throws IOException {
super(doURLs(resources), parent);
public static ResourceClassLoader getInstance(Collection<Resource> resources, ClassLoader parent) throws IOException {
List<Resource> list = new ArrayList<Resource>();
for (Resource r: resources) {
if (r != null) this.resources.add(r);
if (r != null) list.add(r);
}
java.util.Collections.sort(this.resources, rc);
java.util.Collections.sort(list, rc);
return getInstance(list, parent);
}

private static ResourceClassLoader getInstance(List<Resource> resourcesSorted, ClassLoader parent) throws IOException {
StringBuilder sb = new StringBuilder();
for (Resource r: resourcesSorted) {
if (r != null) sb.append(r.getAbsolutePath()).append(';');
}
String id = HashUtil.create64BitHashAsString(sb);
ResourceClassLoader rcl = classloaders.get(id);
if (rcl == null) {
rcl = new ResourceClassLoader(resourcesSorted, parent, id);
classloaders.put(id, rcl);
}
return rcl;
}

private ResourceClassLoader(List<Resource> resources, ClassLoader parent, String id) throws IOException {
super(doURLs(resources), parent);
this.resources = resources;
this.id = id;
}

public ResourceClassLoader(ClassLoader parent) {
private ResourceClassLoader(ClassLoader parent) {
super(new URL[0], parent);
this.resources = new ArrayList<Resource>();
this.id = "orphan";
}

/**
Expand Down Expand Up @@ -113,60 +128,23 @@ public static URL[] doURLs(Resource[] reses) throws IOException {
}

private static URL doURL(Resource res) throws IOException {
if (!(res instanceof FileResource)) throw new IOException("resource [" + res.getPath() + "] must be a local file");
if (!(res instanceof FileResource)) {
return ResourceUtil.toFile(res).toURL();
}
return ((FileResource) res).toURL();
}

@Override
public void close() {
}

public ResourceClassLoader getCustomResourceClassLoader(Resource[] resources) throws IOException {

if (ArrayUtil.isEmpty(resources)) return this;
Arrays.sort(resources);
String key = hash(resources);
SoftReference<ResourceClassLoader> tmp = customCLs == null ? null : customCLs.get(key);
ResourceClassLoader rcl = tmp == null ? null : tmp.get();

if (rcl != null) return rcl;

resources = ResourceUtil.merge(this.getResources(), resources);
rcl = new ResourceClassLoader(resources, getParent());

if (customCLs == null) customCLs = new ConcurrentHashMap<String, SoftReference<ResourceClassLoader>>();

customCLs.put(key, new SoftReference<ResourceClassLoader>(rcl));
return rcl;
}

@Override
public int hashCode() {
if (hc == null) {
synchronized (resources) {
if (hc == null) {
hc = _hashStr(getResources()).hashCode();
}
}
}
return hc.intValue();
}

private String _hashStr(Resource[] resources) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < resources.length; i++) {
sb.append(ResourceUtil.getCanonicalPathEL(resources[i]));
sb.append(';');
}
return sb.toString();
return id.hashCode();
}

public String hash() {
return hash(getResources());
}

private String hash(Resource[] resources) {
return HashUtil.create64BitHashAsString(_hashStr(resources));
return id;
}

private static class RC implements Comparator<Resource> {
Expand Down
11 changes: 8 additions & 3 deletions core/src/main/java/lucee/commons/lang/ClassUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import lucee.runtime.config.Identification;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.PageException;
import lucee.runtime.listener.JavaSettingsImpl;
import lucee.runtime.op.Caster;
import lucee.runtime.osgi.OSGiUtil;
import lucee.runtime.osgi.OSGiUtil.BundleDefinition;
Expand Down Expand Up @@ -255,7 +256,7 @@ public static Class loadClass(PageContext pc, String className) throws ClassExce
if (pc instanceof PageContextImpl) {
ClassLoader cl;
try {
cl = ((PageContextImpl) pc).getClassLoader();
cl = ((PageContextImpl) pc).getClassLoader(null);
}
catch (IOException e) {
ClassException ce = new ClassException("cannot load class through its string name");
Expand Down Expand Up @@ -1027,13 +1028,17 @@ public Class<?> loadClass(String className, Class defaultValue, Set<Throwable> e
}
}

public static ClassLoader getClassLoader(Class clazz) {
public static ClassLoader getClassLoader(PageContext pc, Class clazz) throws IOException {
ClassLoader cl = clazz.getClassLoader();
if (cl != null) return cl;

if (pc instanceof PageContextImpl) {
return ((PageContextImpl) pc).getClassLoader();
}
// NEXT this is wrong
Config config = ThreadLocalPageContext.getConfig();
if (config instanceof ConfigPro) {
return ((ConfigPro) config).getClassLoaderCore();
return ((JavaSettingsImpl) ((ConfigPro) config).getJavaSettings()).getClassLoader(false);
}
return new lucee.commons.lang.ClassLoaderHelper().getClass().getClassLoader();
}
Expand Down
29 changes: 0 additions & 29 deletions core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,19 @@
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import lucee.commons.digest.HashUtil;
import lucee.commons.io.IOUtil;
import lucee.commons.io.SystemUtil;
import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.util.ResourceClassLoader;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.runtime.PageSourcePool;
import lucee.runtime.config.Config;
import lucee.runtime.config.ConfigPro;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.type.util.ArrayUtil;
import lucee.transformer.bytecode.util.ClassRenamer;

/**
Expand Down Expand Up @@ -267,31 +263,6 @@ public Resource getDirectory() {
return directory;
}

public PhysicalClassLoader getCustomClassLoader(Resource[] resources, boolean reload) throws IOException {
if (ArrayUtil.isEmpty(resources)) return this;
String key = hash(resources);

if (reload && customCLs != null) customCLs.remove(key);

SoftReference<PhysicalClassLoader> tmp = customCLs == null ? null : customCLs.get(key);
PhysicalClassLoader pcl = tmp == null ? null : tmp.get();
if (pcl != null) return pcl;
pcl = new PhysicalClassLoader(config, getDirectory(), new ResourceClassLoader(resources, getParent()), true, pageSourcePool);
if (customCLs == null) customCLs = new ConcurrentHashMap<String, SoftReference<PhysicalClassLoader>>();
customCLs.put(key, new SoftReference<PhysicalClassLoader>(pcl));
return pcl;
}

private String hash(Resource[] resources) {
Arrays.sort(resources);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < resources.length; i++) {
sb.append(ResourceUtil.getCanonicalPathEL(resources[i]));
sb.append(';');
}
return HashUtil.create64BitHashAsString(sb.toString(), Character.MAX_RADIX);
}

public void clear() {
clear(true);
}
Expand Down
42 changes: 16 additions & 26 deletions core/src/main/java/lucee/runtime/PageContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@
import lucee.commons.io.log.Log;
import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.util.ResourceClassLoader;
import lucee.commons.lang.ClassException;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.HTMLEntities;
import lucee.commons.lang.PhysicalClassLoader;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.mimetype.MimeType;
import lucee.commons.lang.types.RefBoolean;
Expand Down Expand Up @@ -3846,39 +3846,29 @@ public JavaSettings getJavaSettings() {
}

public ClassLoader getClassLoader() throws IOException {
JavaSettingsImpl js = (JavaSettingsImpl) getJavaSettings();
if (js != null) {
// TODO FUTURE 7 we do this to avoid any kind of regression, in Lucee 7 remove this
if (JAVA_SETTING_CLASSIC_MODE && !js.hasPoms() && !js.hasOSGis()) {
Resource[] jars = js.getResourcesTranslated();
if (jars.length > 0) return config.getResourceClassLoader().getCustomResourceClassLoader(jars);
}
return js.getClassLoader(null, false);
return getClassLoader(null);
}

public ClassLoader getClassLoader(JavaSettings customJS) throws IOException {
JavaSettings js = getJavaSettings();
if (customJS != null) {
js = JavaSettingsImpl.merge(config, js, customJS);
}
return config.getResourceClassLoader();
return ((JavaSettingsImpl) js).getClassLoader(false);
}

public ClassLoader getRPCClassLoader(boolean reload) throws IOException {
return getRPCClassLoader(reload, null);
return getRPCClassLoader(reload, (JavaSettings) null);
}

public ClassLoader getRPCClassLoader(boolean reload, ClassLoader parent) throws IOException {
ClassLoader cl = ((ConfigPro) config).getRPCClassLoader(reload, parent);
JavaSettingsImpl js = (JavaSettingsImpl) getJavaSettings();
if (js != null) {
// TODO FUTURE 7 we do this to avoid any kind of regression, in Lucee 7 remove this
if (JAVA_SETTING_CLASSIC_MODE && !js.hasPoms() && !js.hasOSGis()) {
Resource[] jars = js.getResourcesTranslated();
if (jars.length > 0) return ((PhysicalClassLoader) cl).getCustomClassLoader(jars, reload);
}
else {
java.util.Collection<Resource> jars = js.getAllResources(cl);
if (jars.size() > 0) return ((PhysicalClassLoader) cl).getCustomClassLoader(jars.toArray(new Resource[jars.size()]), reload);
}
public ClassLoader getRPCClassLoader(boolean reload, JavaSettings customJS) throws IOException {
return ((ConfigPro) config).getRPCClassLoader(reload, (ResourceClassLoader) getClassLoader(customJS));

}

public ClassLoader getRPCClassLoader(boolean reload, ResourceClassLoader parent) throws IOException {
return ((ConfigPro) config).getRPCClassLoader(reload, parent);

}
return cl;
}

public void resetSession() {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/lucee/runtime/config/ConfigAdmin.java
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ public static void updateJar(Config config, Resource resJar, boolean reloadWhenC
if (fileLib.length() != resJar.length()) {
IOUtil.closeEL(config.getClassLoader());
ResourceUtil.copy(resJar, fileLib);
if (reloadWhenClassicJar) ConfigWebUtil.reloadLib(config);
// NEXT if (reloadWhenClassicJar) ConfigWebUtil.reloadLib(config);
}
}

Expand Down
Loading

0 comments on commit 4300d16

Please sign in to comment.