Author: rmannibucau Date: Wed Jun 12 07:20:08 2019 New Revision: 1861090 URL: http://svn.apache.org/viewvc?rev=1861090&view=rev Log: OWB-1289 add DefiningClassService
Added: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/service/ClassLoaderProxyService.java openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/service/ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/service/ClassLoaderProxyServiceTest.java openwebbeans/trunk/webbeans-spi/src/main/java/org/apache/webbeans/spi/DefiningClassService.java Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java?rev=1861090&r1=1861089&r2=1861090&view=diff ============================================================================== --- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java (original) +++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java Wed Jun 12 07:20:08 2019 @@ -211,7 +211,10 @@ public class WebBeansContext public <T> void registerService(Class<T> clazz, T t) { - serviceMap.put(clazz, t); + if (t != null) + { + serviceMap.put(clazz, t); + } } private <T> T doServiceLoader(Class<T> serviceInterface) Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java?rev=1861090&r1=1861089&r2=1861090&view=diff ============================================================================== --- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java (original) +++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java Wed Jun 12 07:20:08 2019 @@ -32,6 +32,7 @@ import java.util.Arrays; import org.apache.webbeans.config.WebBeansContext; import org.apache.webbeans.exception.ProxyGenerationException; import org.apache.webbeans.exception.WebBeansException; +import org.apache.webbeans.spi.DefiningClassService; import org.apache.xbean.asm7.ClassReader; import org.apache.xbean.asm7.ClassWriter; import org.apache.xbean.asm7.MethodVisitor; @@ -55,6 +56,8 @@ public abstract class AbstractProxyFacto protected final Unsafe unsafe; + private final DefiningClassService definingService; + protected WebBeansContext webBeansContext; private final int javaVersion; @@ -73,6 +76,7 @@ public abstract class AbstractProxyFacto this.webBeansContext = webBeansContext; javaVersion = determineDefaultJavaVersion(); unsafe = new Unsafe(); + definingService = webBeansContext.getService(DefiningClassService.class); } private int determineDefaultJavaVersion() @@ -104,6 +108,25 @@ public abstract class AbstractProxyFacto { return Opcodes.V12; } + else if (javaVersionProp.startsWith("13")) + { + return Opcodes.V13; + } + else + { + try + { + final int i = Integer.parseInt(javaVersionProp); + if (i > 13) + { + return Opcodes.V13 + (i - 13); + } + } + catch (final NumberFormatException nfe) + { + // let's default + } + } } // the fallback is the lowest one to ensure it supports all possible classes of current environments @@ -113,6 +136,10 @@ public abstract class AbstractProxyFacto protected ClassLoader getProxyClassLoader(Class<?> beanClass) { + if (definingService != null) + { + return definingService.getProxyClassLoader(beanClass); + } return webBeansContext.getApplicationBoundaryService().getBoundaryClassLoader(beanClass); } @@ -246,6 +273,10 @@ public abstract class AbstractProxyFacto sortOutDuplicateMethods(nonInterceptedMethods), constructor); + if (definingService != null) + { + return definingService.defineAndLoad(proxyClassName, proxyBytes, classToProxy); + } return unsafe.defineAndLoadClass(classLoader, proxyClassName, proxyBytes); } Added: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/service/ClassLoaderProxyService.java URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/service/ClassLoaderProxyService.java?rev=1861090&view=auto ============================================================================== --- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/service/ClassLoaderProxyService.java (added) +++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/service/ClassLoaderProxyService.java Wed Jun 12 07:20:08 2019 @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.webbeans.service; + +import java.security.ProtectionDomain; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.webbeans.config.WebBeansContext; +import org.apache.webbeans.spi.DefiningClassService; + +public class ClassLoaderProxyService implements DefiningClassService +{ + private final ProxiesClassLoader loader; + + public ClassLoaderProxyService(final WebBeansContext context) + { + this.loader = new ProxiesClassLoader(context.getApplicationBoundaryService().getApplicationClassLoader()); + } + + @Override + public ClassLoader getProxyClassLoader(final Class<?> forClass) + { + return loader; + } + + @Override + public <T> Class<T> defineAndLoad(final String name, final byte[] bytecode, final Class<T> proxiedClass) + { + return (Class<T>) loader.getOrRegister( + name, bytecode, proxiedClass.getPackage(), proxiedClass.getProtectionDomain()); + } + + private static class ProxiesClassLoader extends ClassLoader + { + private final ConcurrentMap<String, Class<?>> classes = new ConcurrentHashMap<>(); + + private ProxiesClassLoader(final ClassLoader applicationClassLoader) + { + super(applicationClassLoader); + } + + + @Override + protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException + { + final Class<?> clazz = classes.get(name); + if (clazz == null) + { + return getParent().loadClass(name); + } + return clazz; + } + + private Class<?> getOrRegister(final String proxyClassName, final byte[] proxyBytes, + final Package pck, final ProtectionDomain protectionDomain) + { + final String key = proxyClassName.replace('/', '.'); + Class<?> existing = classes.get(key); + if (existing == null) + { + synchronized (this) + { + existing = classes.get(key); + if (existing == null) + { + definePackageFor(pck, protectionDomain); + existing = super.defineClass(proxyClassName, proxyBytes, 0, proxyBytes.length); + resolveClass(existing); + classes.put(key, existing); + } + } + } + return existing; + } + + private void definePackageFor(final Package model, final ProtectionDomain protectionDomain) + { + if (model == null) + { + return; + } + if (getPackage(model.getName()) == null) + { + if (model.isSealed() && protectionDomain != null && + protectionDomain.getCodeSource() != null && + protectionDomain.getCodeSource().getLocation() != null) + { + definePackage( + model.getName(), + model.getSpecificationTitle(), + model.getSpecificationVersion(), + model.getSpecificationVendor(), + model.getImplementationTitle(), + model.getImplementationVersion(), + model.getImplementationVendor(), + protectionDomain.getCodeSource().getLocation()); + } + else + { + definePackage( + model.getName(), + model.getSpecificationTitle(), + model.getSpecificationVersion(), + model.getSpecificationVendor(), + model.getImplementationTitle(), + model.getImplementationVersion(), + model.getImplementationVendor(), + null); + } + } + } + } +} Added: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/service/ClassLoaderProxyServiceTest.java URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/service/ClassLoaderProxyServiceTest.java?rev=1861090&view=auto ============================================================================== --- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/service/ClassLoaderProxyServiceTest.java (added) +++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/service/ClassLoaderProxyServiceTest.java Wed Jun 12 07:20:08 2019 @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.webbeans.service; + +import static java.util.Collections.emptyMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.util.Properties; + +import org.apache.webbeans.config.WebBeansContext; +import org.apache.webbeans.proxy.NormalScopeProxyFactory; +import org.apache.webbeans.spi.DefiningClassService; +import org.junit.Test; + +public class ClassLoaderProxyServiceTest +{ + @Test + public void defineInProxy() throws NoSuchMethodException + { + final Properties config = new Properties(); + config.setProperty(DefiningClassService.class.getName(), ClassLoaderProxyService.class.getName()); + final WebBeansContext context = new WebBeansContext(emptyMap(), config); + final NormalScopeProxyFactory factory = new NormalScopeProxyFactory(context); + final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + final Class<MyBean> proxyClass = factory.createProxyClass(contextClassLoader, MyBean.class); + assertNotEquals(contextClassLoader, proxyClass.getClassLoader()); + final ClassLoader proxyLoader = context.getService(DefiningClassService.class).getProxyClassLoader(proxyClass); + assertEquals(proxyLoader, proxyClass.getClassLoader()); + proxyClass.getMethod("ok", String.class); // this line would fail if not here, no assert needed + } + + public static class MyBean + { + public String ok(final String value) + { + return ">" + value + "<"; + } + } +} Added: openwebbeans/trunk/webbeans-spi/src/main/java/org/apache/webbeans/spi/DefiningClassService.java URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-spi/src/main/java/org/apache/webbeans/spi/DefiningClassService.java?rev=1861090&view=auto ============================================================================== --- openwebbeans/trunk/webbeans-spi/src/main/java/org/apache/webbeans/spi/DefiningClassService.java (added) +++ openwebbeans/trunk/webbeans-spi/src/main/java/org/apache/webbeans/spi/DefiningClassService.java Wed Jun 12 07:20:08 2019 @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.webbeans.spi; + +/** + * a SPI implementing the proxy defining logic. + * It enables to switch from unsafe to classloader logic for instance for java >= 9. + */ +public interface DefiningClassService +{ + /** + * @param forClass the proxied class. + * @return the classloader to use to define the class. + */ + ClassLoader getProxyClassLoader(Class<?> forClass); + + /** + * Register the proxy class from its bytecode. + * @param name the proxy name. + * @param bytecode the bytecode to "define". + * @param proxiedClass the original class. + * @param <T> type of the class to proxy. + * @return the proxy class. + */ + <T> Class<T> defineAndLoad(String name, byte[] bytecode, Class<T> proxiedClass); +}