Skip to content

Commit

Permalink
enh: loading JARs from <domain_dir>/lib/warlibs if --properies warlib…
Browse files Browse the repository at this point in the history
…s=true is specified
  • Loading branch information
lprimak committed Dec 12, 2024
1 parent a4f4f36 commit 3a59025
Show file tree
Hide file tree
Showing 12 changed files with 341 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,27 @@
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2024] [Payara Foundation and/or its affiliates]

package com.sun.appserv.connectors.internal.api;

import jakarta.inject.Provider;
import org.glassfish.deployment.common.DeploymentUtils;
import org.glassfish.internal.api.*;
import org.glassfish.internal.deployment.Deployment;
import org.jvnet.hk2.annotations.Service;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
import java.util.logging.Logger;
import java.util.logging.Level;

import com.sun.logging.LogDomains;

import jakarta.inject.Inject;
import jakarta.inject.Provider;

/**
* We support two policies:
Expand All @@ -72,13 +77,13 @@ public class ConnectorClassLoaderServiceImpl implements ConnectorClassLoaderServ
* class loader for all applications. In other words, we make every
* standalone RARs available to all applications.
*/
private volatile DelegatingClassLoader globalConnectorCL;
private final AtomicReference<DelegatingClassLoader> globalConnectorCL = new AtomicReference<>();
private final AtomicReference<DelegatingClassLoader> globalConnectorWithWarLibCL = new AtomicReference<>();

@Inject
private AppSpecificConnectorClassLoaderUtil appsSpecificCCLUtil;

@Inject
private Provider<ClassLoaderHierarchy> classLoaderHierarchyProvider;
private Provider<ConnectorsClassLoaderUtil> connectorsClassLoaderUtil;

private Logger logger = LogDomains.getLogger(ConnectorClassLoaderServiceImpl.class, LogDomains.RSR_LOGGER);

Expand All @@ -92,34 +97,8 @@ public class ConnectorClassLoaderServiceImpl implements ConnectorClassLoaderServ
public DelegatingClassLoader getConnectorClassLoader(String appName) {
DelegatingClassLoader loader = null;

// We do not have dependency on common-class-loader explicitly
// and also cannot initialize globalConnectorCL during postConstruct via ClassLoaderHierarchy
// which will result in circular dependency injection between kernel and connector module
// Hence initializing globalConnectorCL lazily
if (globalConnectorCL == null) {
synchronized (ConnectorClassLoaderServiceImpl.class) {
if (globalConnectorCL == null) {
//[parent is assumed to be common-class-loader in ConnectorClassLoaderUtil.createRARClassLoader() also]
final ClassLoader parent = getCommonClassLoader();
globalConnectorCL = AccessController.doPrivileged(new PrivilegedAction<DelegatingClassLoader>() {
public DelegatingClassLoader run() {
DelegatingClassLoader dcl = new DelegatingClassLoader(parent);
for (DelegatingClassLoader.ClassFinder cf : appsSpecificCCLUtil.getSystemRARClassLoaders()) {
dcl.addDelegate(cf);
}
return dcl;
}
});

for (DelegatingClassLoader.ClassFinder cf : appsSpecificCCLUtil.getSystemRARClassLoaders()) {
globalConnectorCL.addDelegate(cf);
}
}
}
}
if (hasGlobalAccessForRARs(appName)) {
assert (globalConnectorCL != null);
loader = globalConnectorCL;
loader = getGlobalConnectorClassLoader();
} else {
appsSpecificCCLUtil.detectReferredRARs(appName);
loader = createConnectorClassLoaderForApplication(appName);
Expand All @@ -133,14 +112,42 @@ private boolean hasGlobalAccessForRARs(String appName) {
(ConnectorConstants.RAR_VISIBILITY_GLOBAL_ACCESS);
}

private ClassLoader getCommonClassLoader(){
return classLoaderHierarchyProvider.get().getCommonClassLoader();
private DelegatingClassLoader getGlobalConnectorClassLoader() {
// We do not have dependency on common-class-loader explicitly
// and also cannot initialize globalConnectorCL during postConstruct via ClassLoaderHierarchy
// which will result in circular dependency injection between kernel and connector module
// Hence initializing globalConnectorCL lazily
UnaryOperator<DelegatingClassLoader> updateOperator = currentValue -> {
if (currentValue == null) {
//[parent is assumed to be common-class-loader in ConnectorClassLoaderUtil.createRARClassLoader() also]
var newValue = AccessController.doPrivileged(new PrivilegedAction<DelegatingClassLoader>() {
public DelegatingClassLoader run() {
DelegatingClassLoader dcl = new DelegatingClassLoader(connectorsClassLoaderUtil.get().getCommonClassLoader());
for (DelegatingClassLoader.ClassFinder cf : appsSpecificCCLUtil.getSystemRARClassLoaders()) {
dcl.addDelegate(cf);
}
return dcl;
}
});

for (DelegatingClassLoader.ClassFinder cf : appsSpecificCCLUtil.getSystemRARClassLoaders()) {
newValue.addDelegate(cf);
}
return newValue;
}
return currentValue;
};
if (DeploymentUtils.useWarLibraries(DeploymentUtils.getCurrentDeploymentContext())) {
return globalConnectorWithWarLibCL.updateAndGet(updateOperator);
} else {
return globalConnectorCL.updateAndGet(updateOperator);
}
}

private DelegatingClassLoader createConnectorClassLoaderForApplication(String appName){

DelegatingClassLoader appSpecificConnectorClassLoader =
new DelegatingClassLoader(getCommonClassLoader());
new DelegatingClassLoader(connectorsClassLoaderUtil.get().getCommonClassLoader());

//add system ra classloaders
for(DelegatingClassLoader.ClassFinder cf : appsSpecificCCLUtil.getSystemRARClassLoaders()){
Expand Down Expand Up @@ -178,7 +185,7 @@ private void addRarClassLoader(String appName, DelegatingClassLoader appSpecific
}

private DelegatingClassLoader.ClassFinder getClassFinder(String raName) {
List<DelegatingClassLoader.ClassFinder> delegates = globalConnectorCL.getDelegates();
List<DelegatingClassLoader.ClassFinder> delegates = getGlobalConnectorClassLoader().getDelegates();
DelegatingClassLoader.ClassFinder classFinder = null;
for(DelegatingClassLoader.ClassFinder cf : delegates){
if(raName.equals(((ConnectorClassFinder)cf).getResourceAdapterName())){
Expand All @@ -188,5 +195,4 @@ private DelegatingClassLoader.ClassFinder getClassFinder(String raName) {
}
return classFinder;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,33 @@
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2024] [Payara Foundation and/or its affiliates]

package com.sun.appserv.connectors.internal.api;

import com.sun.enterprise.loader.CurrentBeforeParentClassLoader;
import org.glassfish.deployment.common.DeploymentUtils;
import org.glassfish.deployment.common.InstalledLibrariesResolver;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.api.DelegatingClassLoader;
import org.glassfish.api.admin.*;
import org.glassfish.api.event.Events;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.EventTypes;
import org.glassfish.internal.api.Globals;
import org.glassfish.internal.deployment.Deployment;
import org.jvnet.hk2.annotations.Service;

import jakarta.inject.Singleton;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Collection;
Expand All @@ -81,7 +89,8 @@ public class ConnectorsClassLoaderUtil {
@Inject
private ClassLoaderHierarchy clh;

//private static List<ConnectorClassFinder> systemRARClassLoaders;
// warLibClassLoader is used to load libraries from the war file
private final AtomicReference<CurrentBeforeParentClassLoader> warLibClassLoader = new AtomicReference<>();

private Logger _logger = LogDomains.getLogger(ConnectorRuntime.class, LogDomains.RSR_LOGGER);

Expand Down Expand Up @@ -209,7 +218,7 @@ public Collection<ConnectorClassFinder> getSystemRARClassLoaders() throws Connec
libraries = ConnectorsUtil.getInstalledLibrariesFromManifest(location, env);
}

ConnectorClassFinder ccf = createRARClassLoader(location, null, rarName, libraries);
ConnectorClassFinder ccf = createRARClassLoader(location, getCommonClassLoader(), rarName, libraries);
classLoaders.add(ccf);
}
// systemRARClassLoaders = classLoaders;
Expand All @@ -218,6 +227,29 @@ public Collection<ConnectorClassFinder> getSystemRARClassLoaders() throws Connec
return classLoaders;
}

public ClassLoader getCommonClassLoader() {
if (DeploymentUtils.useWarLibraries(DeploymentUtils.getCurrentDeploymentContext())) {
return warLibClassLoader.updateAndGet(currentValue -> {
if (currentValue == null) {
var newValue = new CurrentBeforeParentClassLoader(InstalledLibrariesResolver.getWarLibraries()
.stream().map(uri -> {
try {
return uri.toUri().toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
})
.toArray(URL[]::new), clh.getCommonClassLoader());
newValue.enableCurrentBeforeParentUnconditional();
return newValue;
}
return currentValue;
});
} else {
return clh.getCommonClassLoader();
}
}


public ConnectorClassFinder getSystemRARClassLoader(String rarName) throws ConnectorRuntimeException {
if (ConnectorsUtil.belongsToSystemRA(rarName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates]
// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates]

package org.glassfish.weld.connector;

Expand All @@ -48,9 +48,13 @@
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jakarta.decorator.Decorator;
Expand All @@ -60,6 +64,7 @@
import jakarta.enterprise.context.*;
import jakarta.enterprise.inject.Model;
import jakarta.enterprise.inject.Stereotype;
import jakarta.faces.flow.FlowScoped;
import jakarta.inject.Inject;
import jakarta.inject.Scope;
import jakarta.inject.Singleton;
Expand All @@ -68,6 +73,7 @@
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.deployment.common.DeploymentUtils;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.classmodel.reflect.AnnotationModel;
import org.glassfish.hk2.classmodel.reflect.AnnotationType;
Expand All @@ -83,6 +89,7 @@
import org.xml.sax.helpers.DefaultHandler;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.stream.Collectors;

public class WeldUtils {

Expand Down Expand Up @@ -135,6 +142,7 @@ public enum BDAType { WAR, JAR, RAR, UNKNOWN };
cdi.add("jakarta.faces.view.ViewScoped");
cdi.add("jakarta.faces.flow.FlowScoped");
cdi.add(ConversationScoped.class.getName());
cdi.add(FlowScoped.class.getName());
cdi.add(ApplicationScoped.class.getName());
cdi.add(SessionScoped.class.getName());
cdi.add(RequestScoped.class.getName());
Expand Down Expand Up @@ -218,16 +226,13 @@ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, URI p
* @return true, if there is at least one bean annotated with a qualified annotation in the specified paths
*/
public static boolean hasCDIEnablingAnnotations(DeploymentContext context, Collection<URI> paths) {
final Types types = getTypes(context);
if (types != null) {
final Set<String> exclusions = new HashSet<>();
for (final Type type : types.getAllTypes()) {
if (!(type instanceof AnnotationType) && type.wasDefinedIn(paths)) {
for (final AnnotationModel am : type.getAnnotations()) {
final AnnotationType at = am.getType();
if (isCDIEnablingAnnotation(at, exclusions)) {
return true;
}
final Set<String> exclusions = new HashSet<>();
for (final Type type : getAllTypes(context, paths)) {
if (!(type instanceof AnnotationType) && type.wasDefinedIn(paths)) {
for (final AnnotationModel am : type.getAnnotations()) {
final AnnotationType at = am.getType();
if (isCDIEnablingAnnotation(at, exclusions)) {
return true;
}
}
}
Expand All @@ -236,7 +241,6 @@ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, Colle
return false;
}


/**
* Get the names of any annotation types that are applied to beans, which should enable CDI
* processing even in the absence of a beans.xml descriptor.
Expand All @@ -248,16 +252,13 @@ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, Colle
public static String[] getCDIEnablingAnnotations(DeploymentContext context) {
final Set<String> result = new HashSet<>();

final Types types = getTypes(context);
if (types != null) {
final Set<String> exclusions = new HashSet<>();
for (final Type type : types.getAllTypes()) {
if (!(type instanceof AnnotationType)) {
for (final AnnotationModel am : type.getAnnotations()) {
final AnnotationType at = am.getType();
if (isCDIEnablingAnnotation(at, exclusions)) {
result.add(at.getName());
}
final Set<String> exclusions = new HashSet<>();
for (final Type type : getAllTypes(context, List.of())) {
if (!(type instanceof AnnotationType)) {
for (final AnnotationModel am : type.getAnnotations()) {
final AnnotationType at = am.getType();
if (isCDIEnablingAnnotation(at, exclusions)) {
result.add(at.getName());
}
}
}
Expand All @@ -280,16 +281,13 @@ public static Collection<String> getCDIAnnotatedClassNames(DeploymentContext con
final Set<String> cdiEnablingAnnotations = new HashSet<>();
Collections.addAll(cdiEnablingAnnotations, getCDIEnablingAnnotations(context));

final Types types = getTypes(context);
if (types != null) {
for (final Type type : types.getAllTypes()) {
if (!(type instanceof AnnotationType)) {
for (final AnnotationModel am : type.getAnnotations()) {
final AnnotationType at = am.getType();
if (cdiEnablingAnnotations.contains(at.getName())) {
result.add(type.getName());
break;
}
for (final Type type : getAllTypes(context, List.of())) {
if (!(type instanceof AnnotationType)) {
for (final AnnotationModel am : type.getAnnotations()) {
final AnnotationType at = am.getType();
if (cdiEnablingAnnotations.contains(at.getName())) {
result.add(type.getName());
break;
}
}
}
Expand Down Expand Up @@ -704,6 +702,24 @@ public static String getBeanDiscoveryMode(InputStream beansXmlInputStream) {
return beanDiscoveryMode;
}

private static List<Type> getAllTypes(DeploymentContext context, Collection<URI> paths) {
final Types types = getTypes(context);
if (types == null) {
return List.of();
}

List<Type> allTypes = new ArrayList<>(types.getAllTypes());
Map<String, DeploymentUtils.WarLibraryDescriptor> cache = DeploymentUtils.getWarLibraryCache();
for (URI path : paths.isEmpty() ? cache.keySet().stream().map(Path::of).map(Path::toUri)
.collect(Collectors.toList()) : paths) {
var descriptor = cache.get(path.getRawPath());
if (descriptor != null) {
allTypes.addAll(descriptor.getTypes());
}
}
return allTypes;
}

private static class LocalDefaultHandler extends DefaultHandler {
String beanDiscoveryMode = null;

Expand Down
Loading

0 comments on commit 3a59025

Please sign in to comment.