make gauge injection working
diff --git a/pom.xml b/pom.xml
index 6bb13ee..0f3cefc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -168,6 +168,10 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
+ <!-- current setup has some leakage it seems
+ <forkCount>1</forkCount>
+ <reuseForks>false</reuseForks>
+ -->
<dependenciesToScan>
<dependency>org.eclipse.microprofile.metrics:microprofile-metrics-api-tck</dependency>
<dependency>org.eclipse.microprofile.metrics:microprofile-metrics-rest-tck</dependency>
diff --git a/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java b/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
index f5d0fee..87fbb43 100644
--- a/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
+++ b/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
@@ -13,6 +13,8 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -38,6 +40,7 @@
import javax.enterprise.util.AnnotationLiteral;
import javax.enterprise.util.Nonbinding;
+import org.apache.geronimo.microprofile.metrics.impl.GaugeImpl;
import org.apache.geronimo.microprofile.metrics.impl.RegistryImpl;
import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.Gauge;
@@ -58,17 +61,17 @@
private final MetricRegistry vendorRegistry = new RegistryImpl();
private final Map<String, Metadata> registrations = new HashMap<>();
- private final Map<String, Function<BeanManager, Gauge<?>>> gauges = new HashMap<>();
+ private final Map<String, Function<BeanManager, Gauge<?>>> gaugeFactories = new HashMap<>();
private final Collection<CreationalContext<?>> creationalContexts = new ArrayList<>();
- void letOtherExtensionUseRegistries(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager beanManager) {
+ void letOtherExtensionsUseRegistries(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager beanManager) {
beforeBeanDiscovery.addQualifier(RegistryType.class);
beanManager.fireEvent(applicationRegistry);
beanManager.fireEvent(applicationRegistry, new RegistryTypeImpl(MetricRegistry.Type.APPLICATION));
beanManager.fireEvent(baseRegistry, new RegistryTypeImpl(MetricRegistry.Type.BASE));
beanManager.fireEvent(vendorRegistry, new RegistryTypeImpl(MetricRegistry.Type.VENDOR));
- // we make @Metric(name) binding
+ // we make @Metric.name binding (to avoid to write producers relying on injection point)
beforeBeanDiscovery.configureQualifier(org.eclipse.microprofile.metrics.annotation.Metric.class)
.methods().stream().filter(method -> method.getAnnotated().getJavaMember().getName().equals("name"))
.forEach(method -> method.remove(a -> a.annotationType() == Nonbinding.class));
@@ -181,19 +184,12 @@
final Metadata metadata = new Metadata(name, gauge.displayName(), gauge.description(), MetricType.GAUGE, gauge.unit());
Stream.of(gauge.tags()).forEach(metadata::addTag);
addRegistration(method, name, metadata, false, gauge.tags());
- gauges.put(name, beanManager -> {
+ gaugeFactories.put(name, beanManager -> {
final CreationalContext<Object> creationalContext = beanManager.createCreationalContext(null);
final Bean<?> bean = beanManager.resolve(beanManager.getBeans(javaClass, Default.Literal.INSTANCE));
final Object reference = beanManager.getReference(bean, javaClass, creationalContext);
- final Gauge<?> instance = () -> {
- try {
- return Method.class.cast(javaMember).invoke(reference);
- } catch (final IllegalAccessException e) {
- throw new IllegalStateException(e);
- } catch (final InvocationTargetException e) {
- throw new IllegalStateException(e.getCause());
- }
- };
+ final Method mtd = Method.class.cast(javaMember);
+ final Gauge<?> instance = new GaugeImpl<>(reference, mtd);
if (!beanManager.isNormalScope(bean.getScope())) {
creationalContexts.add(creationalContext);
}
@@ -203,7 +199,7 @@
});
}
- void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
+ void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery, final BeanManager beanManager) {
addBean(afterBeanDiscovery, MetricRegistry.Type.APPLICATION.name() + "_@Default", MetricRegistry.class, Default.Literal.INSTANCE, applicationRegistry);
addBean(afterBeanDiscovery, MetricRegistry.Type.APPLICATION.name(), MetricRegistry.class, new RegistryTypeImpl(MetricRegistry.Type.APPLICATION), applicationRegistry);
addBean(afterBeanDiscovery, MetricRegistry.Type.BASE.name(), MetricRegistry.class, new RegistryTypeImpl(MetricRegistry.Type.BASE), baseRegistry);
@@ -212,6 +208,20 @@
// metrics
registrations.forEach((name, registration) -> {
switch (registration.getTypeRaw()) {
+ case GAUGE:
+ addBean(afterBeanDiscovery, name, Gauge.class, new MetricImpl(registration), new Gauge<Object>() {
+ private final AtomicReference<Gauge<?>> ref = new AtomicReference<>();
+ @Override
+ public Object getValue() {
+ Gauge<?> gauge = ref.get();
+ if (gauge == null) { // getGauges() is expensive in current form, avoid it
+ gauge = applicationRegistry.getGauges().get(name);
+ ref.compareAndSet(null, gauge);
+ }
+ return gauge.getValue();
+ }
+ });
+ break;
case TIMER:
addBean(afterBeanDiscovery, name, Timer.class, new MetricImpl(registration), applicationRegistry.timer(registration));
break;
@@ -232,9 +242,12 @@
void afterDeploymentValidation(@Observes final AfterDeploymentValidation afterDeploymentValidation,
final BeanManager beanManager) {
registrations.values().stream().filter(m -> m.getTypeRaw() == MetricType.GAUGE)
- .forEach(registration -> applicationRegistry.register(registration, gauges.get(registration.getName()).apply(beanManager)));
+ .forEach(registration -> {
+ final Gauge<?> gauge = gaugeFactories.get(registration.getName()).apply(beanManager);
+ applicationRegistry.register(registration, gauge);
+ });
- gauges.clear();
+ gaugeFactories.clear();
registrations.clear();
}
diff --git a/src/main/java/org/apache/geronimo/microprofile/metrics/impl/GaugeImpl.java b/src/main/java/org/apache/geronimo/microprofile/metrics/impl/GaugeImpl.java
new file mode 100644
index 0000000..f6f31a6
--- /dev/null
+++ b/src/main/java/org/apache/geronimo/microprofile/metrics/impl/GaugeImpl.java
@@ -0,0 +1,27 @@
+package org.apache.geronimo.microprofile.metrics.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.eclipse.microprofile.metrics.Gauge;
+
+public class GaugeImpl<T> implements Gauge<T> {
+ private final Method method;
+ private final Object reference;
+
+ public GaugeImpl(final Object reference, final Method method) {
+ this.method = method;
+ this.reference = reference;
+ }
+
+ @Override
+ public T getValue() {
+ try {
+ return (T) method.invoke(reference);
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (final InvocationTargetException e) {
+ throw new IllegalStateException(e.getCause());
+ }
+ }
+}
diff --git a/src/test/java/org/apache/geronimo/microprofile/metrics/test/ArquillianSetup.java b/src/test/java/org/apache/geronimo/microprofile/metrics/test/ArquillianSetup.java
index e8ccd1f..d11893f 100644
--- a/src/test/java/org/apache/geronimo/microprofile/metrics/test/ArquillianSetup.java
+++ b/src/test/java/org/apache/geronimo/microprofile/metrics/test/ArquillianSetup.java
@@ -2,18 +2,17 @@
import java.lang.reflect.Field;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
-import javax.enterprise.inject.spi.InjectionTarget;
import org.apache.catalina.Context;
import org.apache.meecrowave.Meecrowave;
import org.apache.meecrowave.arquillian.MeecrowaveContainer;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.spi.context.annotation.ContainerScoped;
import org.jboss.arquillian.container.spi.context.annotation.DeploymentScoped;
import org.jboss.arquillian.container.spi.event.container.AfterDeploy;
+import org.jboss.arquillian.container.spi.event.container.AfterStart;
import org.jboss.arquillian.container.spi.event.container.BeforeUnDeploy;
import org.jboss.arquillian.container.test.impl.client.protocol.local.LocalProtocol;
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
@@ -49,43 +48,38 @@
private InstanceProducer<ClassLoader> appClassLoaderInstanceProducer;
@Inject
- @DeploymentScoped
- private InstanceProducer<ClassLoader> testClassLoaderInstanceProducer;
+ @ContainerScoped
+ private InstanceProducer<Meecrowave> container;
+
+ public void onDeploy(@Observes final AfterStart afterStart) throws Exception {
+ final DeployableContainer<?> deployableContainer = afterStart.getDeployableContainer();
+ final Field container = MeecrowaveContainer.class.getDeclaredField("container");
+ container.setAccessible(true);
+ final Meecrowave meecrowave = Meecrowave.class.cast(container.get(deployableContainer));
+ this.container.set(meecrowave);
+ }
public void onDeploy(@Observes final AfterDeploy afterDeploy) {
- final DeployableContainer<?> deployableContainer = afterDeploy.getDeployableContainer();
- try {
- final Field container = MeecrowaveContainer.class.getDeclaredField("container");
- container.setAccessible(true);
- final Meecrowave meecrowave = Meecrowave.class.cast(container.get(deployableContainer));
- final ClassLoader appLoader = Context.class.cast(meecrowave.getTomcat().getHost().findChildren()[0]).getLoader().getClassLoader();
- final Thread thread = Thread.currentThread();
- appClassLoaderInstanceProducer.set(appLoader);
- testClassLoaderInstanceProducer.set(meecrowave.getTomcat().getServer().getParentClassLoader());
- thread.setContextClassLoader(appLoader);
- beanManagerInstanceProducer.set(CDI.current().getBeanManager());
- } catch (final Exception e) {
- // no-op, will not happen and if so it is another container
- }
+ final Meecrowave meecrowave = container.get();
+ final ClassLoader appLoader = Context.class.cast(meecrowave.getTomcat().getHost().findChildren()[0]).getLoader().getClassLoader();
+ appClassLoaderInstanceProducer.set(appLoader);
+
+ final Thread thread = Thread.currentThread();
+ thread.setContextClassLoader(appLoader);
+ beanManagerInstanceProducer.set(CDI.current().getBeanManager());
}
public void onUndeploy(@Observes final BeforeUnDeploy beforeUnDeploy) {
- final ClassLoader cl = testClassLoaderInstanceProducer.get();
+ final ClassLoader cl = container.get().getTomcat().getServer().getParentClassLoader();
Thread.currentThread().setContextClassLoader(cl);
}
- public void enrich(@Observes final Before before) {
+ public void enrich(@Observes final Before before) throws Exception {
final Thread thread = Thread.currentThread();
final ClassLoader classLoader = thread.getContextClassLoader();
thread.setContextClassLoader(appClassLoaderInstanceProducer.get());
try {
- final BeanManager beanManager = beanManagerInstanceProducer.get();
- final Object testInstance = before.getTestInstance();
- final AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(before.getTestClass().getJavaClass());
- final InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotatedType);
- final CreationalContext<?> creationalContext = beanManager.createCreationalContext(null);
- injectionTarget.inject(testInstance, creationalContext);
- creationalContext.release();
+ container.get().inject(before.getTestInstance()).close();
} finally {
thread.setContextClassLoader(classLoader);
}