You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2021/08/20 17:45:39 UTC

[wicket] 01/01: WICKET-6913 replace proxies with StandardMBean

This is an automated email from the ASF dual-hosted git repository.

svenmeier pushed a commit to branch jmx-standardmbean-instead-proxy
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit c776f4d922b6ecd704f846748d488942d5b87ec2
Author: Sven Meier <sv...@apache.org>
AuthorDate: Fri Aug 20 19:34:33 2021 +0200

    WICKET-6913 replace proxies with StandardMBean
---
 .../java/org/apache/wicket/jmx/Initializer.java    | 160 +++++++--------------
 1 file changed, 54 insertions(+), 106 deletions(-)

diff --git a/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java b/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
index 181f293..bb89f78 100644
--- a/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
+++ b/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
@@ -17,11 +17,11 @@
 package org.apache.wicket.jmx;
 
 import java.lang.management.ManagementFactory;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.management.Attribute;
+import javax.management.AttributeList;
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanRegistrationException;
@@ -30,17 +30,7 @@ import javax.management.MBeanServerFactory;
 import javax.management.MalformedObjectNameException;
 import javax.management.NotCompliantMBeanException;
 import javax.management.ObjectName;
-
-import net.bytebuddy.ByteBuddy;
-import net.bytebuddy.NamingStrategy;
-import net.bytebuddy.TypeCache;
-import net.bytebuddy.description.type.TypeDescription;
-import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
-import net.bytebuddy.implementation.MethodDelegation;
-import net.bytebuddy.implementation.bind.annotation.AllArguments;
-import net.bytebuddy.implementation.bind.annotation.Origin;
-import net.bytebuddy.implementation.bind.annotation.RuntimeType;
-import net.bytebuddy.matcher.ElementMatchers;
+import javax.management.StandardMBean;
 
 import org.apache.wicket.IInitializer;
 import org.apache.wicket.ThreadContext;
@@ -78,15 +68,6 @@ public class Initializer implements IInitializer
 {
 	private static final Logger LOG = LoggerFactory.getLogger(Initializer.class);
 
-	/**
-	 * A cache used to store the dynamically generated classes by ByteBuddy.
-	 * Without this cache a new class will be generated for each proxy creation
-	 * and this will fill up the metaspace
-	 */
-	private static final TypeCache<TypeCache.SimpleKey> DYNAMIC_CLASS_CACHE = new TypeCache.WithInlineExpunction<>(TypeCache.Sort.SOFT);
-
-	private static final ByteBuddy BYTE_BUDDY = new ByteBuddy();
-	
 	// It's best to store a reference to the MBeanServer rather than getting it
 	// over and over
 	private MBeanServer mbeanServer = null;
@@ -246,102 +227,69 @@ public class Initializer implements IInitializer
 	 * @throws MBeanRegistrationException
 	 * @throws InstanceAlreadyExistsException
 	 */
-	private void register(final org.apache.wicket.Application application, final Object o,
+	private <T> void register(final org.apache.wicket.Application application, final T o,
 		final ObjectName objectName) throws InstanceAlreadyExistsException,
 		MBeanRegistrationException, NotCompliantMBeanException
 	{
-		Object proxy = createProxy(application, o);
-		mbeanServer.registerMBean(proxy, objectName);
-		registered.add(objectName);
-	}
-
-	// must be public to prevent JMX Server throwing:
-	// failed to access class org.apache.wicket.jmx.Initializer$Interceptor from class org.apache.wicket.jmx.Application
-	public static class Interceptor
-	{
-		private final org.apache.wicket.Application application;
-		private final Object object;
-
-		private Interceptor(org.apache.wicket.Application application, Object object) {
-			this.application = application;
-			this.object = object;
-		}
-
-		@RuntimeType
-		public Object intercept(final @Origin Method method,
-								final @AllArguments Object[] args)
-				throws Throwable
-		{
-			boolean existed = ThreadContext.exists();
-
-			if (existed == false)
+		StandardMBean bean = new StandardMBean(o, (Class<T>)o.getClass().getInterfaces()[0]) {
+			@Override
+			public Object getAttribute(String attribute)
 			{
-				ThreadContext.setApplication(application);
+				return withApplication(() -> super.getAttribute(attribute));
 			}
-
-			try
+			
+			@Override
+			public void setAttribute(Attribute attribute)
+			{
+				withApplication(() -> {
+					super.setAttribute(attribute);
+					return null;
+				});
+			}
+			
+			@Override
+			public AttributeList setAttributes(AttributeList attributes)
 			{
-				return method.invoke(object, args);
+				return withApplication(() -> super.setAttributes(attributes));
 			}
-			finally
+			
+			@Override
+			public Object invoke(String actionName, Object[] params, String[] signature)
 			{
+				return withApplication(() -> super.invoke(actionName, params, signature));
+			}
+			
+			private <R> R withApplication(Invocation<R> invocation)
+			{
+				boolean existed = ThreadContext.exists();
+
 				if (existed == false)
 				{
-					ThreadContext.detach();
+					ThreadContext.setApplication(application);
 				}
-			}
-		}
-	}
-
-	private Object createProxy(final org.apache.wicket.Application application, final Object o)
-	{
-		final Class<?> type = o.getClass();
-		final ClassLoader classLoader = resolveClassLoader();
-
-		Class<?> proxyClass = DYNAMIC_CLASS_CACHE.findOrInsert(classLoader,
-				new TypeCache.SimpleKey(type),
-				() -> BYTE_BUDDY
-						.with(new NamingStrategy.AbstractBase()
-						{
-							@Override
-							protected String name(TypeDescription superClass)
-							{
-								return type.getName().replace(".wrapper", "");
-							}
-						})
-						.subclass(Object.class)
-						.implement(type.getInterfaces())
-						.method(ElementMatchers.any())
-						.intercept(MethodDelegation.to(new Interceptor(application, o)))
-						.make()
-						.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
-						.getLoaded());
 
-
-		try
-		{
-			return proxyClass.getDeclaredConstructor().newInstance();
-		}
-		catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e)
-		{
-			throw new WicketRuntimeException(e);
-		}
+				try
+				{
+					return invocation.invoke();
+				}
+				catch (Exception ex)
+				{
+					throw new WicketRuntimeException(ex);
+				}
+				finally
+				{
+					if (existed == false)
+					{
+						ThreadContext.detach();
+					}
+				}
+			}
+		};
+		mbeanServer.registerMBean(bean, objectName);
+		registered.add(objectName);
 	}
 
-	private static ClassLoader resolveClassLoader()
-	{
-		ClassLoader classLoader = null;
-		if (org.apache.wicket.Application.exists())
-		{
-			classLoader = org.apache.wicket.Application.get().getApplicationSettings()
-					.getClassResolver().getClassLoader();
-		}
-
-		if (classLoader == null) {
-			classLoader = Thread.currentThread().getContextClassLoader();
-		}
-
-		return classLoader;
+	private static interface Invocation<R> {
+		R invoke() throws Exception;
 	}
-
-}
+}
\ No newline at end of file