From e59a5db5b70f06212b18401b997632468e08647b Mon Sep 17 00:00:00 2001 From: Andrew Pielage Date: Tue, 2 Nov 2021 11:40:01 +0000 Subject: [PATCH 1/2] FISH-5832 FISH-5833 Weld 3.1.8 and API 3.1.SP4 Signed-off-by: Andrew Pielage --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 379f2a61533..045671cb6cd 100644 --- a/pom.xml +++ b/pom.xml @@ -174,8 +174,8 @@ 1.2.5 1.0 2.0.2 - 3.1.4.Final - 3.1.Final + 3.1.8.Final + 3.1.SP4 1.0.2 1.1-b01.payara-p4 1.6.1 From 3541b2d40f1b11e4ea7946e8b6d04693828286db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mat=C4=9Bj=C4=8Dek?= Date: Wed, 19 May 2021 22:55:39 +0200 Subject: [PATCH 2/2] FISH-5832 ProxyServicesImpl Cherry-pick - reimplemented ProxyServicesImpl, because Weld changed behavior and added methods to the interface and previous implementation caused failure of cdi_all tests Signed-off-by: Andrew Pielage --- .../weld/services/ProxyServicesImpl.java | 258 +++++++++++------- .../weld/services/WeldProxyException.java | 37 +++ 2 files changed, 200 insertions(+), 95 deletions(-) create mode 100644 appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/WeldProxyException.java diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/ProxyServicesImpl.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/ProxyServicesImpl.java index 60f887fcc02..673dd8cb0b3 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/ProxyServicesImpl.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/ProxyServicesImpl.java @@ -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 @@ -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 ProxyServices 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}. + *

+ * 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} + *

+ * Context: Weld generates proxies for beans from an application and for certain API artifacts + * such as UserTransaction. + * * @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() { - public ClassLoader run() { - return getClassLoaderforBean(proxiedBeanType); - } - }); - } else { + if (System.getSecurityManager() == null) { return getClassLoaderforBean(proxiedBeanType); } + final PrivilegedAction 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> 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 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 - * UserTransaction. - * - * @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() { - 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); + } + } } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/WeldProxyException.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/WeldProxyException.java new file mode 100644 index 00000000000..d3beaba7c1e --- /dev/null +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/WeldProxyException.java @@ -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); + } +}