Skip to content

Commit

Permalink
Merge pull request #5484 from Pandrex247/FISH-5832
Browse files Browse the repository at this point in the history
FISH-5832 FISH-5833 Weld 3.1.8 and Weld SPI 3.1.SP4
  • Loading branch information
breakponchito authored Nov 4, 2021
2 parents d355323 + 3541b2d commit 643f4a3
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2010-2012 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010-2021 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -37,138 +36,207 @@
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright 2021 Payara Foundation and/or its affiliates.

package org.glassfish.weld.services;

import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.concurrent.atomic.AtomicBoolean;

import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.jboss.weld.serialization.spi.ProxyServices;
import org.glassfish.hk2.api.ServiceLocator;

/**
* An implementation of the <code>ProxyServices</code> Service.
*
* This implementation uses the thread context classloader (the application
* classloader) as the classloader for loading the bean proxies. The classloader
* that loaded the Bean must be used to load and define the bean proxy to handle
* Beans with package-private constructor as discussed in WELD-737.
*
* Weld proxies today have references to some internal weld implementation classes
* such as javassist and org.jboss.weld.proxy.* packages. These classes are
* temporarily re-exported through the weld-integration-fragment bundle so that
* when the bean proxies when loaded using the application classloader will have
* visibility to these internal implementation classes.
*
* As a fix for WELD-737, Weld may use the Bean's classloader rather than asking
* the ProxyServices service implementation. Weld also plans to remove the
* dependencies of the bean proxy on internal implementation classes. When that
* happens we can remove the weld-integration-fragment workaround and the
* ProxyServices implementation
*
* An implementation of the {@link ProxyServices}.
* <p>
* This implementation respects the classloader hierarchy used to load original beans.
* If it is not an application classloader, uses the current thread classloader.
* If it wasn't possible to detect any usable classloader, throws a {@link WeldProxyException}
* <p>
* Context: Weld generates proxies for beans from an application and for certain API artifacts
* such as <code>UserTransaction</code>.
*
* @author Sivakumar Thyagarajan
* @author David Matějček
*/
public class ProxyServicesImpl implements ProxyServices {

ClassLoaderHierarchy clh;

public ProxyServicesImpl(ServiceLocator services) {
clh = services.getService(ClassLoaderHierarchy.class);

private static Method defineClassMethod;
private static Method defineClassMethodSM;
private static final AtomicBoolean CL_METHODS_INITIALIZATION_FINISHED = new AtomicBoolean(false);

private final ClassLoaderHierarchy classLoaderHierarchy;


/**
* @param services immediately used to find a {@link ClassLoaderHierarchy} service
*/
public ProxyServicesImpl(final ServiceLocator services) {
classLoaderHierarchy = services.getService(ClassLoaderHierarchy.class);
}



@Deprecated
@Override
public boolean supportsClassDefining() {
// true is mandatory since Weld 4.0.1.SP1, because default method impl returns false
// and cdi_all tests then fail
return true;
}


@Deprecated
@Override
public ClassLoader getClassLoader(final Class<?> proxiedBeanType) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return AccessController
.doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return getClassLoaderforBean(proxiedBeanType);
}
});
} else {
if (System.getSecurityManager() == null) {
return getClassLoaderforBean(proxiedBeanType);
}
final PrivilegedAction<ClassLoader> action = () -> getClassLoaderforBean(proxiedBeanType);
return AccessController.doPrivileged(action);
}


@Deprecated
@Override
public Class<?> loadBeanClass(final String className) {
try {
if (System.getSecurityManager() == null) {
return loadClassByThreadCL(className);
}
final PrivilegedExceptionAction<Class<?>> action = () -> loadClassByThreadCL(className);
return AccessController.doPrivileged(action);
} catch (final Exception ex) {
throw new WeldProxyException("Failed to load the bean class: " + className, ex);
}
}


@Override
public Class<?> defineClass(final Class<?> originalClass, final String className, final byte[] classBytes,
final int off, final int len) throws ClassFormatError {
return defineClass(originalClass, className, classBytes, off, len, null);
}


@Override
public Class<?> defineClass(final Class<?> originalClass, final String className, final byte[] classBytes,
final int off, final int len, final ProtectionDomain protectionDomain) throws ClassFormatError {
checkClassDefinitionFeature();
final ClassLoader loader = getClassLoaderforBean(originalClass);
if (protectionDomain == null) {
return defineClass(loader, className, classBytes, off, len);
}
return defineClass(loader, className, classBytes, off, len, protectionDomain);
}


@Override
public Class<?> loadClass(final Class<?> originalClass, final String classBinaryName)
throws ClassNotFoundException {
return getClassLoaderforBean(originalClass).loadClass(classBinaryName);
}


@Override
public void cleanup() {
// nothing to cleanup in this implementation.
}


/**
* Initialization of access to protected methods of the {@link ClassLoader} class.
*/
private static void checkClassDefinitionFeature() {
if (CL_METHODS_INITIALIZATION_FINISHED.compareAndSet(false, true)) {
try {
final PrivilegedExceptionAction<Void> action = () -> {
final Class<?> cl = Class.forName("java.lang.ClassLoader");
final String name = "defineClass";
defineClassMethod = cl.getDeclaredMethod(name, String.class, byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
defineClassMethodSM = cl.getDeclaredMethod(
name, String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
defineClassMethodSM.setAccessible(true);
return null;
};
AccessController.doPrivileged(action);
} catch (final Exception e) {
throw new WeldProxyException("Could not initialize access to ClassLoader.defineClass method.", e);
}
}
}



/**
* Gets the ClassLoader associated with the Bean. Weld generates Proxies
* for Beans from an application/BDA and for certain API artifacts such as
* <code>UserTransaction</code>.
*
* @param proxiedBeanType
* @return
* @param originalClass
* @return ClassLoader probably usable with the bean.
*/
private ClassLoader getClassLoaderforBean(Class<?> proxiedBeanType) {
//Get the ClassLoader that loaded the Bean. For Beans in an application,
//this would be the application/module classloader. For other API
//Bean classes, such as UserTransaction, this would be a non-application
//classloader
ClassLoader prxCL = proxiedBeanType.getClassLoader();
//Check if this is an application classloader
boolean isAppCL = isApplicationClassLoader(prxCL);
if (!isAppCL) {
prxCL = _getClassLoader();
//fall back to the old behaviour of using TCL to get the application
//or module classloader. We return this classloader for non-application
//Beans, as Weld Proxies requires other Weld support classes (such as
//JBoss Reflection API) that is exported through the weld-osgi-bundle.
private ClassLoader getClassLoaderforBean(final Class<?> originalClass) {
// Get the ClassLoader that loaded the Bean. For Beans in an application,
// this would be the application/module classloader. For other API
// Bean classes, such as UserTransaction, this would be a non-application
// classloader
final ClassLoader originalClassLoader = originalClass.getClassLoader();
if (isApplicationClassLoader(originalClassLoader)) {
return originalClassLoader;
}
return prxCL;
// fall back to the old behaviour of using thread class loader to get the application
// or module classloader. We return this classloader for non-application
// Beans, as Weld Proxies requires other Weld support classes (such as
// JBoss Reflection API) that is exported through the weld-osgi-bundle.
final ClassLoader threadCL = Thread.currentThread().getContextClassLoader();
if (threadCL != null) {
return threadCL;
}
throw new WeldProxyException("Could not determine classloader for " + originalClass);
}


/**
* Check if the ClassLoader of the Bean type being proxied is a
* GlassFish application ClassLoader. The current logic checks if
* the common classloader appears as a parent in the classloader hierarchy
* of the Bean's classloader.
* Check if the ClassLoader of the Bean type being proxied is a GlassFish application
* ClassLoader. The current logic checks if the common classloader appears as a parent in
* the classloader hierarchy of the Bean's classloader.
*/
private boolean isApplicationClassLoader(ClassLoader prxCL) {
boolean isAppCL = false;
while (prxCL != null) {
if (prxCL.equals(clh.getCommonClassLoader())) {
isAppCL = true;
break;
private boolean isApplicationClassLoader(ClassLoader classLoader) {
while (classLoader != null) {
if (classLoader.equals(classLoaderHierarchy.getCommonClassLoader())) {
return true;
}
prxCL = prxCL.getParent();
classLoader = classLoader.getParent();
}
return isAppCL;
return false;
}


private ClassLoader _getClassLoader() {
ClassLoader tcl = Thread.currentThread().getContextClassLoader();
return tcl;
private Class<?> loadClassByThreadCL(final String className) throws ClassNotFoundException {
return Class.forName(className, true, Thread.currentThread().getContextClassLoader());
}

@Override
public Class<?> loadBeanClass(final String className) {

private Class<?> defineClass(
final ClassLoader loader, final String className,
final byte[] b, final int off, final int len,
final ProtectionDomain protectionDomain) {
try {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return (Class<?>) AccessController
.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
ClassLoader cl = _getClassLoader();
return Class.forName(className, true, cl);
}
});
} else {
ClassLoader cl = _getClassLoader();
return Class.forName(className, true, cl);
}
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
return (Class<?>) defineClassMethodSM.invoke(loader, className, b, 0, len, protectionDomain);
} catch (final Exception e) {
throw new WeldProxyException("Could not define class " + className, e);
}
}

@Override
public void cleanup() {
// nothing to cleanup in this implementation.
}

private Class<?> defineClass(
final ClassLoader loader, final String className,
final byte[] b, final int off, final int len) {
try {
return (Class<?>) defineClassMethod.invoke(loader, className, b, 0, len);
} catch (final Exception e) {
throw new WeldProxyException("Could not define class " + className, e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2021 Eclipse Foundation and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.weld.services;


/**
* Runtime exception meaning that the operation failed to finish the desired operation.
*
* @author David Matějček
*/
public class WeldProxyException extends RuntimeException {

private static final long serialVersionUID = 1L;

public WeldProxyException(final String message, final Exception cause) {
super(message, cause);
}


public WeldProxyException(final String message) {
super(message);
}
}
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@
<jakarta.interceptor-api.version>1.2.5</jakarta.interceptor-api.version>
<jakarta.inject.version>1.0</jakarta.inject.version>
<cdi-api.version>2.0.2</cdi-api.version>
<weld.version>3.1.4.Final</weld.version>
<weld-api.version>3.1.Final</weld-api.version>
<weld.version>3.1.8.Final</weld.version>
<weld-api.version>3.1.SP4</weld-api.version>
<jakarta.security.enterprise-api.version>1.0.2</jakarta.security.enterprise-api.version>
<jakarta.security.enterprise.version>1.1-b01.payara-p4</jakarta.security.enterprise.version>
<jakarta.security.jacc-api.version>1.6.1</jakarta.security.jacc-api.version>
Expand Down

0 comments on commit 643f4a3

Please sign in to comment.