
org.jboss.weld.probe.ProbeExtension Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2014, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.weld.probe;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.util.Collections;
import java.util.Set;
import java.util.regex.Pattern;
import javax.decorator.Decorator;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.UnproxyableResolutionException;
import javax.enterprise.inject.Vetoed;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.AfterTypeDiscovery;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedMember;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanAttributes;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ObserverMethod;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessBean;
import javax.enterprise.inject.spi.ProcessBeanAttributes;
import javax.enterprise.inject.spi.ProcessInjectionPoint;
import javax.enterprise.inject.spi.ProcessInjectionTarget;
import javax.enterprise.inject.spi.ProcessObserverMethod;
import javax.enterprise.inject.spi.ProcessProducer;
import javax.enterprise.inject.spi.ProcessProducerField;
import javax.enterprise.inject.spi.ProcessProducerMethod;
import javax.interceptor.Interceptor;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.jboss.weld.bean.builtin.BeanManagerProxy;
import org.jboss.weld.bootstrap.api.Environment;
import org.jboss.weld.bootstrap.events.AbstractContainerEvent;
import org.jboss.weld.bootstrap.events.ProcessAnnotatedTypeEventResolvable;
import org.jboss.weld.bootstrap.events.ProcessAnnotatedTypeImpl;
import org.jboss.weld.bootstrap.events.RequiredAnnotationDiscovery;
import org.jboss.weld.config.ConfigurationKey;
import org.jboss.weld.config.WeldConfiguration;
import org.jboss.weld.event.ResolvedObservers;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.manager.api.WeldManager;
import org.jboss.weld.probe.BootstrapStats.EventType;
import org.jboss.weld.util.BiConsumer;
import org.jboss.weld.util.Proxies;
import org.jboss.weld.util.annotated.VetoedSuppressedAnnotatedType;
import org.jboss.weld.util.bean.ForwardingBeanAttributes;
import org.jboss.weld.util.collections.ImmutableSet;
import org.jboss.weld.util.reflection.Formats;
import org.jboss.weld.util.reflection.Reflections;
/**
* This extension adds {@link AnnotatedType}s needed for monitoring. Furthermore, {@link BeanAttributes} of all suitable beans are modified so that a stereotype
* with applied interceptor binding is declared. Finally, an initialization of the {@link Probe} component (mapping data) is triggered.
*
*
* An integrator is required to register this extension for every application which should be a subject of inspection.
*
*
* @author Martin Kouba
*/
@Vetoed
public class ProbeExtension implements Extension {
private final Probe probe;
private volatile JsonDataProvider jsonDataProvider;
private volatile Pattern invocationMonitorExcludePattern;
private volatile boolean eventMonitorContainerLifecycleEvents;
public ProbeExtension() {
this.probe = new Probe();
}
public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event, BeanManager beanManager) {
ProbeLogger.LOG.developmentModeEnabled();
final BeanManagerImpl manager = BeanManagerProxy.unwrap(beanManager);
manager.addValidationFailureCallback(new BiConsumer() {
@Override
public void accept(Exception exception, Environment environment) {
// Note that eventual problems are ignored during callback invocation
probe.init(manager);
Reports.generateValidationReport(probe, exception, environment, manager);
}
});
event.addAnnotatedType(VetoedSuppressedAnnotatedType.from(Monitored.class, beanManager), Monitored.class.getName());
event.addAnnotatedType(VetoedSuppressedAnnotatedType.from(MonitoredComponent.class, beanManager), MonitoredComponent.class.getName());
event.addAnnotatedType(VetoedSuppressedAnnotatedType.from(InvocationMonitor.class, beanManager), InvocationMonitor.class.getName());
WeldConfiguration configuration = manager.getServices().get(WeldConfiguration.class);
String exclude = configuration.getStringProperty(ConfigurationKey.PROBE_INVOCATION_MONITOR_EXCLUDE_TYPE);
this.invocationMonitorExcludePattern = exclude.isEmpty() ? null : Pattern.compile(exclude);
this.jsonDataProvider = new DefaultJsonDataProvider(probe, manager);
this.eventMonitorContainerLifecycleEvents = configuration.getBooleanProperty(ConfigurationKey.PROBE_EVENT_MONITOR_CONTAINER_LIFECYCLE_EVENTS);
addContainerLifecycleEvent(event, null, beanManager);
}
public void processBeanAttributes(@Observes ProcessBeanAttributes event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.PBA);
final BeanAttributes beanAttributes = event.getBeanAttributes();
final WeldManager weldManager = (WeldManager) beanManager;
if (isMonitored(event.getAnnotated(), beanAttributes, weldManager)) {
event.setBeanAttributes(new ForwardingBeanAttributes() {
@Override
public Set> getStereotypes() {
return ImmutableSet.> builder().addAll(attributes().getStereotypes()).add(MonitoredComponent.class).build();
}
@Override
protected BeanAttributes attributes() {
return beanAttributes;
}
@Override
public String toString() {
return beanAttributes.toString();
}
});
ProbeLogger.LOG.monitoringStereotypeAdded(event.getAnnotated());
}
if (eventMonitorContainerLifecycleEvents) {
addContainerLifecycleEvent(event, "Types: [" + Formats.formatTypes(event.getBeanAttributes().getTypes()) + "], qualifiers: ["
+ Formats.formatAnnotations(event.getBeanAttributes().getQualifiers()) + "]", beanManager);
}
}
public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager beanManager) {
BeanManagerImpl weldManager = BeanManagerProxy.unwrap(beanManager);
String exclude = weldManager.getServices().get(WeldConfiguration.class).getStringProperty(ConfigurationKey.PROBE_EVENT_MONITOR_EXCLUDE_TYPE);
event.addObserverMethod(new ProbeObserver(weldManager, exclude.isEmpty() ? null : Pattern.compile(exclude), probe));
addContainerLifecycleEvent(event, null, beanManager);
}
public void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager beanManager) {
BeanManagerImpl manager = BeanManagerProxy.unwrap(beanManager);
probe.init(manager);
if (isJMXSupportEnabled(manager)) {
try {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new ProbeDynamicMBean(jsonDataProvider, JsonDataProvider.class), constructProbeJsonDataMBeanName(manager, probe));
} catch (MalformedObjectNameException | InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
event.addDeploymentProblem(ProbeLogger.LOG.unableToRegisterMBean(JsonDataProvider.class, manager.getContextId(), e));
}
}
addContainerLifecycleEvent(event, null, beanManager);
exportDataIfNeeded(manager);
}
public void beforeShutdown(@Observes BeforeShutdown event, BeanManager beanManager) {
BeanManagerImpl manager = BeanManagerProxy.unwrap(beanManager);
if (isJMXSupportEnabled(manager)) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = constructProbeJsonDataMBeanName(manager, probe);
if (mbs.isRegistered(name)) {
mbs.unregisterMBean(name);
}
} catch (MalformedObjectNameException | MBeanRegistrationException | InstanceNotFoundException e) {
throw ProbeLogger.LOG.unableToUnregisterMBean(JsonDataProvider.class, manager.getContextId(), e);
}
}
}
public void processAnnotatedTypes(@Observes ProcessAnnotatedType> event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.PAT);
addContainerLifecycleEvent(event, null, beanManager);
}
public void processInjectionPoints(@Observes ProcessInjectionPoint, ?> event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.PIP);
if (eventMonitorContainerLifecycleEvents) {
addContainerLifecycleEvent(event, formatMember(event.getInjectionPoint().getMember()), beanManager);
}
}
public void processInjectionTargets(@Observes ProcessInjectionTarget> event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.PIT);
if (eventMonitorContainerLifecycleEvents) {
addContainerLifecycleEvent(event, Formats.formatType(event.getAnnotatedType().getBaseType(), false), beanManager);
}
}
public void afterTypeDiscovery(@Observes AfterTypeDiscovery event, BeanManager beanManager) {
addContainerLifecycleEvent(event, null, beanManager);
}
public void processObserverMethods(@Observes ProcessObserverMethod, ?> event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.POM);
if (eventMonitorContainerLifecycleEvents) {
addContainerLifecycleEvent(event,
event.getAnnotatedMethod() != null ? formatMember(event.getAnnotatedMethod().getJavaMember()) : event.getObserverMethod().toString(),
beanManager);
}
}
public void processProducers(@Observes ProcessProducer, ?> event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.PP);
if (eventMonitorContainerLifecycleEvents) {
addContainerLifecycleEvent(event, formatMember(event.getAnnotatedMember().getJavaMember()), beanManager);
}
}
public void processBeans(@Observes ProcessBean> event, BeanManager beanManager) {
probe.getBootstrapStats().increment(EventType.PB);
if (eventMonitorContainerLifecycleEvents) {
Object info;
if (event instanceof ProcessProducerMethod) {
info = formatMember(((ProcessProducerMethod, ?>) event).getAnnotatedProducerMethod().getJavaMember());
} else if (event instanceof ProcessProducerField) {
info = formatMember(((ProcessProducerField, ?>) event).getAnnotatedProducerField().getJavaMember());
} else {
info = Formats.formatType(event.getBean().getBeanClass(), false);
}
addContainerLifecycleEvent(event, info, beanManager);
}
}
Probe getProbe() {
return probe;
}
JsonDataProvider getJsonDataProvider() {
return jsonDataProvider;
}
private boolean isJMXSupportEnabled(BeanManagerImpl manager) {
return manager.getServices().get(WeldConfiguration.class).getBooleanProperty(ConfigurationKey.PROBE_JMX_SUPPORT);
}
private ObjectName constructProbeJsonDataMBeanName(BeanManagerImpl manager, Probe probe) throws MalformedObjectNameException {
return new ObjectName(
Probe.class.getPackage().getName() + ":type=JsonData,context=" + ObjectName.quote(manager.getContextId() + "_" + probe.getInitTs()));
}
private boolean isMonitored(Annotated annotated, BeanAttributes beanAttributes, WeldManager weldManager) {
if (annotated.isAnnotationPresent(Interceptor.class) || annotated.isAnnotationPresent(Decorator.class)) {
// Omit interceptors and decorators
return false;
}
final Type type;
if (annotated instanceof AnnotatedMember) {
// AnnotatedField or AnnotatedMethod
type = ((AnnotatedMember>) annotated).getDeclaringType().getBaseType();
} else {
type = annotated.getBaseType();
}
UnproxyableResolutionException unproxyableException = Proxies.getUnproxyableTypeException(type, weldManager.getServices());
if (unproxyableException != null) {
// A bean with an interceptor must be a proxyable
ProbeLogger.LOG.invocationMonitorNotAssociatedNonProxyableType(type);
ProbeLogger.LOG.catchingTrace(unproxyableException);
return false;
}
if (type instanceof Class) {
final Class> clazz = (Class>) type;
if (invocationMonitorExcludePattern != null && invocationMonitorExcludePattern.matcher(clazz.getName()).matches()) {
ProbeLogger.LOG.invocationMonitorNotAssociatedExcluded(clazz.getName());
return false;
}
}
return true;
}
private void addContainerLifecycleEvent(T event, Object info, BeanManagerImpl beanManagerImpl) {
ResolvedObservers> resolvedObservers = null;
Type eventType = null;
if (event instanceof AbstractContainerEvent) {
AbstractContainerEvent containerEvent = (AbstractContainerEvent) event;
eventType = containerEvent.getEventType();
resolvedObservers = beanManagerImpl.getGlobalLenientObserverNotifier().resolveObserverMethods(eventType);
} else if (event instanceof ProcessAnnotatedTypeImpl) {
ProcessAnnotatedTypeImpl> processAnnotatedTypeEvent = (ProcessAnnotatedTypeImpl>) event;
eventType = ProcessAnnotatedType.class;
info = Formats.formatType(processAnnotatedTypeEvent.getOriginalAnnotatedType().getBaseType(), false);
resolvedObservers = beanManagerImpl.getGlobalLenientObserverNotifier().resolveObserverMethods(
ProcessAnnotatedTypeEventResolvable.of(processAnnotatedTypeEvent, beanManagerImpl.getServices().get(RequiredAnnotationDiscovery.class)));
}
if (resolvedObservers != null && eventType != null) {
Iterable> observerMethods = Reflections.cast(resolvedObservers.getAllObservers());
probe.addEvent(new EventInfo(eventType, Collections. emptySet(), info, null, observerMethods, true, System.currentTimeMillis(), false));
}
}
private void addContainerLifecycleEvent(T event, Object payloadInfo, BeanManager beanManager) {
if (eventMonitorContainerLifecycleEvents) {
addContainerLifecycleEvent(event, payloadInfo, BeanManagerProxy.unwrap(beanManager));
}
}
private String formatMember(Member member) {
StringBuilder format = new StringBuilder();
format.append(member.getDeclaringClass().getName());
format.append(".");
format.append(member.getName());
if (member instanceof Method) {
format.append("()");
}
return format.toString();
}
private void exportDataIfNeeded(BeanManagerImpl manager) {
String export = manager.getServices().get(WeldConfiguration.class).getStringProperty(ConfigurationKey.PROBE_EXPORT_DATA_AFTER_DEPLOYMENT);
if (!export.isEmpty()) {
File exportPath = new File(export);
if (!exportPath.canWrite()) {
ProbeLogger.LOG.invalidExportPath(exportPath);
return;
}
try {
Files.write(new File(exportPath, "weld-probe-export.zip").toPath(), Exports.exportJsonData(jsonDataProvider));
} catch (IOException e) {
ProbeLogger.LOG.unableToExportData(exportPath, e.getCause() != null ? e.getCause() : e);
ProbeLogger.LOG.catchingTrace(e);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy