Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArC - new Dev UI - fixes and improvements #32817

Merged
merged 2 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
import java.util.Set;
import java.util.stream.Collectors;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.arc.deployment.ArcConfig;
Expand All @@ -22,7 +19,6 @@
import io.quarkus.arc.deployment.ValidationPhaseBuildItem;
import io.quarkus.arc.deployment.devconsole.DependencyGraph.Link;
import io.quarkus.arc.deployment.devui.ArcBeanInfoBuildItem;
import io.quarkus.arc.processor.AnnotationsTransformer;
import io.quarkus.arc.processor.BeanDeploymentValidator;
import io.quarkus.arc.processor.BeanDeploymentValidator.ValidationContext;
import io.quarkus.arc.processor.BeanInfo;
Expand All @@ -35,10 +31,7 @@
import io.quarkus.arc.runtime.ArcContainerSupplier;
import io.quarkus.arc.runtime.ArcRecorder;
import io.quarkus.arc.runtime.BeanLookupSupplier;
import io.quarkus.arc.runtime.devconsole.InvocationInterceptor;
import io.quarkus.arc.runtime.devconsole.InvocationTree;
import io.quarkus.arc.runtime.devconsole.InvocationsMonitor;
import io.quarkus.arc.runtime.devconsole.Monitored;
import io.quarkus.arc.runtime.devmode.EventsMonitor;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
Expand Down Expand Up @@ -71,37 +64,9 @@ void monitor(ArcConfig config, BuildProducer<DevConsoleRuntimeTemplateInfoBuildI
if (!config.devMode.monitoringEnabled) {
return;
}
if (!config.transformUnproxyableClasses) {
throw new IllegalStateException(
"Dev UI problem: monitoring of CDI business method invocations not possible\n\t- quarkus.arc.transform-unproxyable-classes was set to false and therefore it would not be possible to apply interceptors to unproxyable bean classes\n\t- please disable the monitoring feature via quarkus.arc.dev-mode.monitoring-enabled=false or enable unproxyable classes transformation");
}
// Events
runtimeInfos.produce(
new DevConsoleRuntimeTemplateInfoBuildItem("eventsMonitor",
new BeanLookupSupplier(EventsMonitor.class), this.getClass(), curateOutcomeBuildItem));
beans.produce(AdditionalBeanBuildItem.unremovableOf(EventsMonitor.class));
// Invocations
beans.produce(AdditionalBeanBuildItem.builder().setUnremovable()
.addBeanClasses(InvocationTree.class, InvocationsMonitor.class, InvocationInterceptor.class,
Monitored.class)
.build());
Set<DotName> skipNames = new HashSet<>();
skipNames.add(DotName.createSimple(InvocationTree.class.getName()));
skipNames.add(DotName.createSimple(InvocationsMonitor.class.getName()));
skipNames.add(DotName.createSimple(EventsMonitor.class.getName()));
annotationTransformers.produce(new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {
@Override
public void transform(TransformationContext transformationContext) {
if (transformationContext.isClass()) {
ClassInfo beanClass = transformationContext.getTarget().asClass();
if ((customScopes.isScopeDeclaredOn(beanClass)
|| isAdditionalBeanDefiningAnnotationOn(beanClass, beanDefiningAnnotations))
&& !skipNames.contains(beanClass.name())) {
transformationContext.transform().add(Monitored.class).done();
}
}
}
}));
runtimeInfos.produce(new DevConsoleRuntimeTemplateInfoBuildItem("invocationsMonitor",
new BeanLookupSupplier(InvocationsMonitor.class), this.getClass(), curateOutcomeBuildItem));
}
Expand Down Expand Up @@ -226,16 +191,6 @@ public void handle(Void ignore) {

static final int DEFAULT_MAX_DEPENDENCY_LEVEL = 10;

private boolean isAdditionalBeanDefiningAnnotationOn(ClassInfo beanClass,
List<BeanDefiningAnnotationBuildItem> beanDefiningAnnotations) {
for (BeanDefiningAnnotationBuildItem beanDefiningAnnotation : beanDefiningAnnotations) {
if (beanClass.classAnnotation(beanDefiningAnnotation.getName()) != null) {
return true;
}
}
return false;
}

DependencyGraph buildDependencyGraph(BeanInfo bean, ValidationContext validationContext, BeanResolver resolver,
DevBeanInfos devBeanInfos, List<InjectionPointInfo> allInjectionPoints,
Map<BeanInfo, List<BeanInfo>> declaringToProducers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,30 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.arc.deployment.ArcConfig;
import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem;
import io.quarkus.arc.deployment.CustomScopeAnnotationsBuildItem;
import io.quarkus.arc.deployment.devconsole.DevBeanInfo;
import io.quarkus.arc.deployment.devconsole.DevBeanInfos;
import io.quarkus.arc.deployment.devconsole.DevDecoratorInfo;
import io.quarkus.arc.deployment.devconsole.DevInterceptorInfo;
import io.quarkus.arc.deployment.devconsole.DevObserverInfo;
import io.quarkus.arc.processor.AnnotationsTransformer;
import io.quarkus.arc.runtime.devconsole.InvocationInterceptor;
import io.quarkus.arc.runtime.devconsole.InvocationTree;
import io.quarkus.arc.runtime.devconsole.InvocationsMonitor;
import io.quarkus.arc.runtime.devconsole.Monitored;
import io.quarkus.arc.runtime.devmode.EventsMonitor;
import io.quarkus.arc.runtime.devui.ArcJsonRPCService;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.devui.spi.JsonRPCProvidersBuildItem;
import io.quarkus.devui.spi.page.CardPageBuildItem;
Expand Down Expand Up @@ -94,6 +109,46 @@ JsonRPCProvidersBuildItem createJsonRPCService() {
return new JsonRPCProvidersBuildItem(ArcJsonRPCService.class);
}

@BuildStep(onlyIf = IsDevelopment.class)
void registerMonitoringComponents(ArcConfig config, BuildProducer<AdditionalBeanBuildItem> beans,
BuildProducer<AnnotationsTransformerBuildItem> annotationTransformers,
CustomScopeAnnotationsBuildItem customScopes, List<BeanDefiningAnnotationBuildItem> beanDefiningAnnotations) {
if (!config.devMode.monitoringEnabled) {
return;
}
if (!config.transformUnproxyableClasses) {
throw new IllegalStateException(
"Dev UI problem: monitoring of CDI business method invocations not possible\n\t- quarkus.arc.transform-unproxyable-classes was set to false and therefore it would not be possible to apply interceptors to unproxyable bean classes\n\t- please disable the monitoring feature via quarkus.arc.dev-mode.monitoring-enabled=false or enable unproxyable classes transformation");
}
// Register beans
beans.produce(AdditionalBeanBuildItem.builder().setUnremovable()
.addBeanClasses(EventsMonitor.class, InvocationTree.class, InvocationsMonitor.class,
InvocationInterceptor.class,
Monitored.class)
.build());

// Add @Monitored to all beans
Set<DotName> skipNames = Set.of(DotName.createSimple(InvocationTree.class),
DotName.createSimple(InvocationsMonitor.class), DotName.createSimple(EventsMonitor.class));
annotationTransformers.produce(new AnnotationsTransformerBuildItem(AnnotationsTransformer
.appliedToClass()
.whenClass(c -> (customScopes.isScopeDeclaredOn(c)
|| isAdditionalBeanDefiningAnnotationOn(c, beanDefiningAnnotations))
&& !skipClass(c, skipNames))
.thenTransform(t -> t.add(Monitored.class))));
}

private boolean skipClass(ClassInfo beanClass, Set<DotName> skipNames) {
if (skipNames.contains(beanClass.name())) {
return true;
}
if (beanClass.name().packagePrefix().startsWith("io.quarkus.devui.runtime")) {
// Skip monitoring for internal devui components
return true;
}
return false;
}

private List<DevBeanWithInterceptorInfo> toDevBeanWithInterceptorInfo(List<DevBeanInfo> beans, DevBeanInfos devBeanInfos) {
List<DevBeanWithInterceptorInfo> l = new ArrayList<>();
for (DevBeanInfo dbi : beans) {
Expand All @@ -102,6 +157,16 @@ private List<DevBeanWithInterceptorInfo> toDevBeanWithInterceptorInfo(List<DevBe
return l;
}

private boolean isAdditionalBeanDefiningAnnotationOn(ClassInfo beanClass,
List<BeanDefiningAnnotationBuildItem> beanDefiningAnnotations) {
for (BeanDefiningAnnotationBuildItem beanDefiningAnnotation : beanDefiningAnnotations) {
if (beanClass.hasDeclaredAnnotation(beanDefiningAnnotation.getName())) {
return true;
}
}
return false;
}

private static final String BEANS = "beans";
private static final String OBSERVERS = "observers";
private static final String INTERCEPTORS = "interceptors";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
</tr>
</thead>
<tbody>
{#each info:invocationsMonitor.lastInvocations.orEmpty}
{#each info:invocationsMonitor.filteredLastInvocations.orEmpty}
<tr>
<td>{it.startFormatted}</td>
<td><ul id="tree">{#tree it root=true /}</ul></td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { until } from 'lit/directives/until.js';
import { JsonRpc } from 'jsonrpc';
import '@vaadin/grid';
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
import '@vaadin/details';
import '@vaadin/vertical-layout';
import '@vaadin/button';
import '@vaadin/checkbox';
Expand All @@ -28,27 +27,29 @@ export class QwcArcFiredEvents extends LitElement {
.arctable {
height: 100%;
padding-bottom: 10px;
}
.payload {
color: grey;
font-size: small;
}`;

static properties = {
_firedEvents: {state: true},
_observer: {state:false},
_skipLifecycleEvents: {state: true}
};

connectedCallback() {
super.connectedCallback();
this._refresh();
this._observer = this.jsonRpc.streamEvents().onNext(jsonRpcResponse => {
this._eventsStream = this.jsonRpc.streamEvents().onNext(jsonRpcResponse => {
this._addToEvents(jsonRpcResponse.result);
});
// Context lifecycle events are skipped by default; updates are handled by the stream
this._skipLifecycleEvents = true;
this._skipLifecycleEventsStream = this.jsonRpc.streamSkipContextEvents().onNext(jsonRpcResponse => {
this._skipLifecycleEvents = jsonRpcResponse.result;
});
}

disconnectedCallback() {
this._observer.cancel();
this._eventsStream.cancel();
this._skipLifecycleEventsStream.cancel();
super.disconnectedCallback();
}

Expand All @@ -59,13 +60,13 @@ export class QwcArcFiredEvents extends LitElement {
_renderFiredEvents(){
if(this._firedEvents){
return html`<div class="menubar">
<vaadin-button theme="small" @click=${()=>this._refresh} class="button">
<vaadin-button theme="small" @click=${() => this._refresh()} class="button">
<vaadin-icon icon="font-awesome-solid:rotate"></vaadin-icon> Refresh
</vaadin-button>
<vaadin-button theme="small" @click=${()=>this._clear} class="button">
<vaadin-button theme="small" @click=${() => this._clear()} class="button">
<vaadin-icon icon="font-awesome-solid:trash-can"></vaadin-icon> Clear
</vaadin-button>
<vaadin-checkbox theme="small" label="Skip context lifecycle events" @click=${()=>this._toggleContext}></vaadin-checkbox>
<vaadin-checkbox theme="small" .checked="${this._skipLifecycleEvents}" label="Skip monitoring of context lifecycle events" @change="${() => this._toggleContext()}"></vaadin-checkbox>
</div>
<vaadin-grid .items="${this._firedEvents}" class="arctable" theme="no-border">
<vaadin-grid-column auto-width
Expand All @@ -76,7 +77,7 @@ export class QwcArcFiredEvents extends LitElement {

<vaadin-grid-column auto-width
header="Event Type"
${columnBodyRenderer(this._payloadRenderer, [])}
${columnBodyRenderer(this._eventTypeRenderer, [])}
resizable>
</vaadin-grid-column>

Expand All @@ -90,15 +91,9 @@ export class QwcArcFiredEvents extends LitElement {
}
}

_payloadRenderer(event) {
_eventTypeRenderer(event) {
return html`
<vaadin-details>
<div slot="summary">${event.type}</div>

<vaadin-vertical-layout>
<span><code class="payload">${event.payload}</code></span>
</vaadin-vertical-layout>
</vaadin-details>
<code>${event.type}</code>
`;
}

Expand All @@ -115,13 +110,15 @@ export class QwcArcFiredEvents extends LitElement {
}

_toggleContext(){
// TODO:
this.jsonRpc.toggleSkipContextEvents().then(events => {
this._firedEvents = events.result;
});
}

_addToEvents(event){
this._firedEvents = [
...this._firedEvents,
event,
...this._firedEvents,
];
}
}
Expand Down