From 6af594ea725d9a5f822c91e213747edad6015d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Mon, 14 Oct 2024 23:31:32 +0200 Subject: [PATCH 01/17] Add Dev-UI --- .../devui/AccessAnnotationInfo.java | 38 ++++ .../deployment/devui/EndpointBuildItem.java | 33 +++ .../hilla/deployment/devui/EndpointInfo.java | 113 ++++++++++ .../deployment/devui/MethodDescriptor.java | 30 +++ .../hilla/deployment/devui/ParameterInfo.java | 25 +++ .../devui/QuarkusHillaDevUIProcessor.java | 63 ++++++ .../hilla/deployment/devui/TypeInfo.java | 41 ++++ .../dev-ui/qwc-quarkus-hilla-endpoints.js | 200 ++++++++++++++++++ .../helloworld/HelloWorldEndpoint.java | 12 ++ 9 files changed, 555 insertions(+) create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/AccessAnnotationInfo.java create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/MethodDescriptor.java create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/ParameterInfo.java create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/TypeInfo.java create mode 100644 commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/AccessAnnotationInfo.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/AccessAnnotationInfo.java new file mode 100644 index 00000000..e1d21509 --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/AccessAnnotationInfo.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import io.quarkus.arc.deployment.devui.Name; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.DotName; + +public record AccessAnnotationInfo(Name name, List roles) { + + public static DotName ROLES_ALLOWED_ANNOTATION = DotName.createSimple("jakarta.annotation.security.RolesAllowed"); + + public static AccessAnnotationInfo from(AnnotationInstance annotation) { + if (annotation.name().equals(ROLES_ALLOWED_ANNOTATION)) { + return new AccessAnnotationInfo( + Name.from(annotation.name()), + Arrays.asList(annotation.value("value").asStringArray())); + } + return new AccessAnnotationInfo(Name.from(annotation.name()), Collections.emptyList()); + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java new file mode 100644 index 00000000..0d29b74a --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import java.util.List; + +import io.quarkus.builder.item.SimpleBuildItem; + +public final class EndpointBuildItem extends SimpleBuildItem { + + private final List endpoints; + + public EndpointBuildItem(List endpoints) { + this.endpoints = endpoints; + } + + public List getEndpoints() { + return endpoints; + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java new file mode 100644 index 00000000..619e6955 --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java @@ -0,0 +1,113 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import jakarta.annotation.Nullable; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import io.quarkus.arc.deployment.devui.Name; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.jandex.MethodInfo; + +public record EndpointInfo( + AnnotationTarget.Kind kind, + Name declaringClass, + @Nullable MethodDescriptor methodDescriptor, + @Nullable String endpointAnnotation, + AccessAnnotationInfo accessAnnotation, + List children) { + + public static DotName ENDPOINT_ANNOTATION = DotName.createSimple("com.vaadin.hilla.Endpoint"); + public static DotName BROWSER_CALLABLE_ANNOTATION = DotName.createSimple("com.vaadin.hilla.BrowserCallable"); + public static DotName DENY_ALL_ANNOTATION = DotName.createSimple("jakarta.annotation.security.DenyAll"); + public static DotName PERMIT_ALL_ANNOTATION = DotName.createSimple("jakarta.annotation.security.PermitAll"); + public static DotName ROLES_ALLOWED_ANNOTATION = DotName.createSimple("jakarta.annotation.security.RolesAllowed"); + public static DotName ANONYMOUS_ALLOWED_ANNOTATION = + DotName.createSimple("com.vaadin.flow.server.auth.AnonymousAllowed"); + private static final AccessAnnotationInfo DENY_ALL_ACCESS_ANNOTATION_INFO = + new AccessAnnotationInfo(Name.from(DENY_ALL_ANNOTATION), Collections.emptyList()); + + public static EndpointInfo from(ClassInfo classInfo) { + final var accessAnnotation = + getEffectiveAccessAnnotation(classInfo.declaredAnnotations()).orElse(DENY_ALL_ACCESS_ANNOTATION_INFO); + return new EndpointInfo( + classInfo.kind(), + Name.from(classInfo.name()), + null, + classInfo.declaredAnnotations().stream() + .map(AnnotationInstance::name) + .filter(a -> a.equals(ENDPOINT_ANNOTATION) || a.equals(BROWSER_CALLABLE_ANNOTATION)) + .findFirst() + .map(DotName::withoutPackagePrefix) + .orElse(null), + accessAnnotation, + classInfo.methods().stream() + .filter(m -> + Modifier.isPublic(m.flags()) && !m.isConstructor() && !Modifier.isStatic(m.flags())) + .map(m -> from(m, accessAnnotation)) + .toList()); + } + + public static EndpointInfo from(MethodInfo methodInfo, AccessAnnotationInfo classAccessAnnotation) { + return new EndpointInfo( + methodInfo.kind(), + Name.from(methodInfo.declaringClass().name()), + MethodDescriptor.from(methodInfo), + null, + getEffectiveAccessAnnotation(methodInfo.declaredAnnotations()).orElse(classAccessAnnotation), + null); + } + + /** + * Returns the effective access annotation. Based on the following rules: + * ... + * @param annotations the annotations + * @return the effective access annotation, if any + */ + private static Optional getEffectiveAccessAnnotation(List annotations) { + return annotations.stream() + .filter(EndpointInfo::isAccessAnnotation) + .reduce((a1, a2) -> { + if (a1.name().equals(DENY_ALL_ANNOTATION)) { + return a1; + } else if (a2.name().equals(DENY_ALL_ANNOTATION)) { + return a2; + } else if (a1.name().equals(ANONYMOUS_ALLOWED_ANNOTATION)) { + return a1; + } else if (a2.name().equals(ANONYMOUS_ALLOWED_ANNOTATION)) { + return a2; + } else if (a1.name().equals(ROLES_ALLOWED_ANNOTATION)) { + return a1; + } else if (a2.name().equals(ROLES_ALLOWED_ANNOTATION)) { + return a2; + } else { + return a1; + } + }) + .map(AccessAnnotationInfo::from); + } + + private static boolean isAccessAnnotation(AnnotationInstance annotation) { + return annotation.name().packagePrefix().equals("jakarta.annotation.security") + || annotation.name().packagePrefix().equals("com.vaadin.flow.server.auth"); + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/MethodDescriptor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/MethodDescriptor.java new file mode 100644 index 00000000..ffb78bf7 --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/MethodDescriptor.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import java.util.List; + +import org.jboss.jandex.MethodInfo; + +public record MethodDescriptor(TypeInfo returnType, String methodName, List parameters) { + + public static MethodDescriptor from(MethodInfo methodInfo) { + return new MethodDescriptor( + TypeInfo.from(methodInfo.returnType()), + methodInfo.name(), + methodInfo.parameters().stream().map(ParameterInfo::from).toList()); + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/ParameterInfo.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/ParameterInfo.java new file mode 100644 index 00000000..0a7f3c40 --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/ParameterInfo.java @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import org.jboss.jandex.MethodParameterInfo; + +public record ParameterInfo(TypeInfo type, String name) { + + public static ParameterInfo from(MethodParameterInfo parameterInfo) { + return new ParameterInfo(TypeInfo.from(parameterInfo.type()), parameterInfo.name()); + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java new file mode 100644 index 00000000..145a6606 --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java @@ -0,0 +1,63 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import java.util.stream.Stream; + +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.CombinedIndexBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.DotName; + +public class QuarkusHillaDevUIProcessor { + + private static final DotName SIGNALS_HANDLER = + DotName.createSimple("com.vaadin.hilla.signals.handler.SignalsHandler"); + + @BuildStep(onlyIf = IsDevelopment.class) + public EndpointBuildItem collectEndpoints(CombinedIndexBuildItem combinedIndexBuildItem) { + final var endpointAnnotated = + combinedIndexBuildItem.getComputingIndex().getAnnotations(EndpointInfo.ENDPOINT_ANNOTATION); + final var browserCallableAnnotated = + combinedIndexBuildItem.getComputingIndex().getAnnotations(EndpointInfo.BROWSER_CALLABLE_ANNOTATION); + final var endpoints = Stream.concat(endpointAnnotated.stream(), browserCallableAnnotated.stream()) + .map(AnnotationInstance::target) + .filter(target -> target.kind().equals(AnnotationTarget.Kind.CLASS)) + .map(AnnotationTarget::asClass) + .filter(c -> !SIGNALS_HANDLER.equals(c.name())) + .map(EndpointInfo::from) + .toList(); + return new EndpointBuildItem(endpoints); + } + + @BuildStep(onlyIf = IsDevelopment.class) + public CardPageBuildItem pages(EndpointBuildItem endpointBuildItems) { + CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); + cardPageBuildItem.addBuildTimeData("hillaEndpoints", endpointBuildItems.getEndpoints()); + cardPageBuildItem.addPage(Page.webComponentPageBuilder() + .title("Endpoints") + .icon("font-awesome-solid:table-list") + .componentLink("qwc-quarkus-hilla-endpoints.js") + .staticLabel(String.valueOf(endpointBuildItems.getEndpoints().stream() + .mapToInt(a -> a.children().size()) + .sum()))); + return cardPageBuildItem; + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/TypeInfo.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/TypeInfo.java new file mode 100644 index 00000000..242a37ec --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/TypeInfo.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import jakarta.annotation.Nullable; +import java.util.List; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.Type; + +public record TypeInfo(List annotations, String type, @Nullable List generics) { + + public static TypeInfo from(Type type) { + if (type.kind() == Type.Kind.PARAMETERIZED_TYPE) { + return new TypeInfo( + annotationsSimple(type.annotations()), + type.name().withoutPackagePrefix(), + type.asParameterizedType().arguments().stream() + .map(TypeInfo::from) + .toList()); + } + return new TypeInfo(annotationsSimple(type.annotations()), type.name().withoutPackagePrefix(), null); + } + + private static List annotationsSimple(List annotations) { + return annotations.stream().map(a -> a.toString(true)).toList(); + } +} diff --git a/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js b/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js new file mode 100644 index 00000000..5e2a0d35 --- /dev/null +++ b/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js @@ -0,0 +1,200 @@ +import {css, html, LitElement} from 'lit'; +import {columnBodyRenderer} from '@vaadin/grid/lit.js'; +import {hillaEndpoints as endpoints} from 'build-time-data'; +import '@vaadin/grid'; +import '@vaadin/grid/vaadin-grid-sort-column.js'; +import '@vaadin/grid/vaadin-grid-tree-column.js'; +import '@vaadin/tooltip/src/vaadin-tooltip.js'; +import '@vaadin/icon'; + +/** + * This component shows the Rest Easy Reactive Parameter Converter Providers + */ +export class QwcQuarkusHillaEndpoints extends LitElement { + + static styles = css` + .datatable { + height: 100%; + padding-bottom: 10px; + border: none; + } + + vaadin-grid-tree-toggle { + width: 100%; + } + + .annotation { + color: var(--lumo-contrast-50pct); + } + + .primary { + color: var(--lumo-primary-text-color); + } + + .parameters { + > ::after { + content: ","; + } + + :last-child::after { + content: ""; + } + } + + .PermitAll { + color: var(--lumo-success-text-color); + } + + .RolesAllowed { + color: var(--lumo-success-text-color); + } + + .AnonymousAllowed { + color: var(--lumo-warning-text-color); + } + + .DenyAll { + color: var(--lumo-error-text-color); + } + `; + + static properties = { + _endpoints: {state: true}, _expandedItems: {state: true} + }; + + constructor() { + super(); + this._endpoints = endpoints; + this._expandedItems = endpoints; + } + + render() { + if (this._endpoints) { + return this._renderEndpointGrid() + } else { + return html`No beans found`; + } + } + + _renderEndpointGrid() { + if (this._endpoints) { + return html` + + + + `; + } + } + + _dataProvider(params, callback) { + if (params.parentItem) { + const children = params.parentItem.children || []; + callback(children, children.length); + } else { + callback(endpoints, endpoints.length); + } + } + + _beanTreeRenderer(bean, model) { + return html` + + ${this._beanRenderer(bean)} + + ` + } + + _beanRenderer(bean) { + return bean.endpointAnnotation ? html` + + @${bean.endpointAnnotation} + + ${bean.declaringClass.simpleName} + + + ` : html` + + ${this._typeRenderer(bean.methodDescriptor.returnType)} + ${bean.methodDescriptor.methodName} + (${bean.methodDescriptor.parameters.map(p => this._parameterRenderer(p))} + ) + `; + } + + _parameterRenderer(parameter) { + return html` + + ${this._typeRenderer(parameter.type)} + ${parameter.name ? html`${parameter.name}` : ''} + + `; + } + + _typeRenderer(type) { + return html` + + ${type.annotations.map(a => html`${a}`)} + ${type.type} + ${type.generics ? html`<${type.generics.map(g => this._typeRenderer(g))}>` : ''} + + `; + } + + _accessAnnotationRenderer(bean) { + return html` + + + ${this._shortenAccessAnnotation(bean.accessAnnotation)} + + `; + } + + _accessAnnotationToIcon(annotation) { + switch (annotation.name.simpleName) { + case "PermitAll": + return "font-awesome-solid:user-check"; + case "RolesAllowed": + return "font-awesome-solid:user-group"; + case "AnonymousAllowed": + return "font-awesome-solid:user-secret"; + case "DenyAll": + return "font-awesome-solid:lock"; + default: + return "font-awesome-solid:person-circle-question"; + } + } + + _shortenAccessAnnotation(annotation) { + switch (annotation.name.simpleName) { + case "PermitAll": + return "Authenticated"; + case "RolesAllowed": + return annotation.roles.join(', '); + case "AnonymousAllowed": + return "Anonymous"; + case "DenyAll": + return "Denied"; + default: + return annotation.name.simpleName; + } + } + +} + +customElements.define('qwc-quarkus-hilla-endpoints', QwcQuarkusHillaEndpoints); diff --git a/integration-tests/smoke-tests/src/main/java/com/example/application/endpoints/helloworld/HelloWorldEndpoint.java b/integration-tests/smoke-tests/src/main/java/com/example/application/endpoints/helloworld/HelloWorldEndpoint.java index 4b3a1d46..6deeaf0c 100644 --- a/integration-tests/smoke-tests/src/main/java/com/example/application/endpoints/helloworld/HelloWorldEndpoint.java +++ b/integration-tests/smoke-tests/src/main/java/com/example/application/endpoints/helloworld/HelloWorldEndpoint.java @@ -15,6 +15,7 @@ */ package com.example.application.endpoints.helloworld; +import jakarta.annotation.security.DenyAll; import jakarta.annotation.security.PermitAll; import jakarta.annotation.security.RolesAllowed; @@ -91,4 +92,15 @@ public String sayHelloProtected() { } return flux.map(msg -> "PUBLIC: " + msg); } + + @AnonymousAllowed + @RolesAllowed("Admin") + public String sayHelloRoles() { + return "Hello Admin"; + } + + @DenyAll + public String sayHelloDenied(@Nonnull String param1, int param2) { + throw new IllegalStateException("This method should not be callable."); + } } From 3862cb2cef51d60f4b3e8000051ccafa4d5d100f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Mon, 14 Oct 2024 23:31:46 +0200 Subject: [PATCH 02/17] Add guide link to quarkus-extension.yaml --- lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml | 1 + react/runtime/src/main/resources/META-INF/quarkus-extension.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 6caa8944..3638bbcd 100644 --- a/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -9,6 +9,7 @@ metadata: - "web" - "reactive" status: "stable" + guide: "https://github.com/mcollovati/quarkus-hilla" icon-url: "https://raw.githubusercontent.com/mcollovati/quarkus-hilla/main/etc/quarkus-hilla-logo.svg" codestart: name: "quarkus-hilla-maven-codestart" diff --git a/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml index ff18c209..87845e32 100644 --- a/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -9,6 +9,7 @@ metadata: - "web" - "reactive" status: "stable" + guide: "https://github.com/mcollovati/quarkus-hilla" icon-url: "https://raw.githubusercontent.com/mcollovati/quarkus-hilla/main/etc/quarkus-hilla-logo.svg" codestart: name: "quarkus-hilla-react-maven-codestart" From 86972bf0a2c8965df8853830ecec5ca31d9c91a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Sun, 3 Nov 2024 17:57:49 +0100 Subject: [PATCH 03/17] Rename endpoints to browser callables --- .../hilla/deployment/devui/QuarkusHillaDevUIProcessor.java | 4 ++-- ...la-endpoints.js => qwc-quarkus-hilla-browser-callables.js} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename commons/deployment/src/main/resources/dev-ui/{qwc-quarkus-hilla-endpoints.js => qwc-quarkus-hilla-browser-callables.js} (97%) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java index 145a6606..f87fcaea 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java @@ -52,9 +52,9 @@ public CardPageBuildItem pages(EndpointBuildItem endpointBuildItems) { CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); cardPageBuildItem.addBuildTimeData("hillaEndpoints", endpointBuildItems.getEndpoints()); cardPageBuildItem.addPage(Page.webComponentPageBuilder() - .title("Endpoints") + .title("Browser callables") .icon("font-awesome-solid:table-list") - .componentLink("qwc-quarkus-hilla-endpoints.js") + .componentLink("qwc-quarkus-hilla-browser-callables.js") .staticLabel(String.valueOf(endpointBuildItems.getEndpoints().stream() .mapToInt(a -> a.children().size()) .sum()))); diff --git a/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js b/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js similarity index 97% rename from commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js rename to commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js index 5e2a0d35..3988c434 100644 --- a/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-endpoints.js +++ b/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js @@ -10,7 +10,7 @@ import '@vaadin/icon'; /** * This component shows the Rest Easy Reactive Parameter Converter Providers */ -export class QwcQuarkusHillaEndpoints extends LitElement { +export class QwcQuarkusHillaBrowserCallables extends LitElement { static styles = css` .datatable { @@ -197,4 +197,4 @@ export class QwcQuarkusHillaEndpoints extends LitElement { } -customElements.define('qwc-quarkus-hilla-endpoints', QwcQuarkusHillaEndpoints); +customElements.define('qwc-quarkus-hilla-browser-callables', QwcQuarkusHillaBrowserCallables); From 9f4c1eec881826f1765a68bea2f612d9859b973b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Tue, 26 Nov 2024 23:01:08 +0100 Subject: [PATCH 04/17] Update extension names --- .../main/resources/META-INF/quarkus-extension.yaml | 11 +++++++++++ .../main/resources/META-INF/quarkus-extension.yaml | 2 +- .../main/resources/META-INF/quarkus-extension.yaml | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 commons/runtime/src/main/resources/META-INF/quarkus-extension.yaml diff --git a/commons/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/commons/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 00000000..728648c3 --- /dev/null +++ b/commons/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,11 @@ +name: Quarkus Hilla Commons +metadata: + keywords: + - "hilla" + - "web" + - "reactive" + categories: + - "web" + - "reactive" + status: "stable" + unlisted: "true" diff --git a/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 3638bbcd..d9359a40 100644 --- a/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/lit/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,4 @@ -name: Quarkus Hilla Extension +name: Quarkus Hilla metadata: keywords: - "hilla" diff --git a/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 87845e32..a1105718 100644 --- a/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/react/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -1,4 +1,4 @@ -name: Quarkus Hilla React Extension +name: Quarkus Hilla React metadata: keywords: - "hilla" From 8f2ed973443e3fa6f1cbbb3a34d5a4803d8dce12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Tue, 26 Nov 2024 23:05:14 +0100 Subject: [PATCH 05/17] Add browser callables to each dev-ui card page --- .../deployment/devui/EndpointBuildItem.java | 6 ++ .../QuarkusHillaDevUICommonsProcessor.java | 90 +++++++++++++++++++ .../devui/QuarkusHillaDevUIProcessor.java | 63 ------------- .../devui/QuarkusHillaDevUIProcessor.java | 25 ++++++ .../resources/dev-ui/qwc-quarkus-hilla.js | 12 +++ .../devui/QuarkusHillaDevUIProcessor.java | 25 ++++++ .../dev-ui/qwc-quarkus-hilla-react.js | 12 +++ 7 files changed, 170 insertions(+), 63 deletions(-) create mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java delete mode 100644 commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java create mode 100644 lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java create mode 100644 lit/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla.js create mode 100644 react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java create mode 100644 react/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-react.js diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java index 0d29b74a..f73f2d18 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java @@ -30,4 +30,10 @@ public EndpointBuildItem(List endpoints) { public List getEndpoints() { return endpoints; } + + public int getEndpointMethodCount() { + return endpoints.stream() + .mapToInt(a -> a.children().size()) + .sum(); + } } diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java new file mode 100644 index 00000000..54f144aa --- /dev/null +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java @@ -0,0 +1,90 @@ +/* + * Copyright 2024 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; + +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.CombinedIndexBuildItem; +import io.quarkus.devui.deployment.BuildTimeConstBuildItem; +import io.quarkus.devui.deployment.DevUIWebJarBuildItem; +import io.quarkus.maven.dependency.GACT; +import io.quarkus.vertx.http.deployment.webjar.WebJarBuildItem; +import io.quarkus.vertx.http.deployment.webjar.WebJarResourcesFilter; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.DotName; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +public class QuarkusHillaDevUICommonsProcessor { + + private static final GACT UI_JAR = new GACT("com.github.mcollovati", "quarkus-hilla-commons-deployment", null, "jar"); + private static final String NAMESPACE = UI_JAR.getGroupId() + "." + UI_JAR.getArtifactId(); + private static final String DEV_UI = "dev-ui"; + + private static final DotName SIGNALS_HANDLER = + DotName.createSimple("com.vaadin.hilla.signals.handler.SignalsHandler"); + + @BuildStep(onlyIf = IsDevelopment.class) + public EndpointBuildItem collectEndpoints(CombinedIndexBuildItem combinedIndexBuildItem) { + final var endpointAnnotated = + combinedIndexBuildItem.getComputingIndex().getAnnotations(EndpointInfo.ENDPOINT_ANNOTATION); + final var browserCallableAnnotated = + combinedIndexBuildItem.getComputingIndex().getAnnotations(EndpointInfo.BROWSER_CALLABLE_ANNOTATION); + final var endpoints = Stream.concat(endpointAnnotated.stream(), browserCallableAnnotated.stream()) + .map(AnnotationInstance::target) + .filter(target -> target.kind().equals(AnnotationTarget.Kind.CLASS)) + .map(AnnotationTarget::asClass) + .filter(c -> !SIGNALS_HANDLER.equals(c.name())) + .map(EndpointInfo::from) + .toList(); + return new EndpointBuildItem(endpoints); + } + + @BuildStep(onlyIf = IsDevelopment.class) + void createShared( + BuildProducer webJarBuildProducer, + BuildProducer devUIWebJarProducer, + BuildProducer buildTimeConstProducer, + EndpointBuildItem endpointBuildItem) { + + final Map buildTimeData = new HashMap<>(); + buildTimeData.put("hillaEndpoints", endpointBuildItem.getEndpoints()); + buildTimeConstProducer.produce(new BuildTimeConstBuildItem(NAMESPACE, buildTimeData)); + + String buildTimeDataImport = NAMESPACE + "-data"; + + webJarBuildProducer.produce(WebJarBuildItem.builder() + .artifactKey(UI_JAR) + .root(DEV_UI + "/") + .filter((fileName, file) -> { + if (fileName.endsWith(".js")) { + String content = new String(file.readAllBytes(), StandardCharsets.UTF_8); + content = content.replaceAll("build-time-data", buildTimeDataImport); + return new WebJarResourcesFilter.FilterResult( + new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)), true); + } + return new WebJarResourcesFilter.FilterResult(file, false); + }) + .build()); + devUIWebJarProducer.produce(new DevUIWebJarBuildItem(UI_JAR, DEV_UI)); + } +} diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java deleted file mode 100644 index f87fcaea..00000000 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUIProcessor.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2024 Marco Collovati, Dario Götze - * - * 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 com.github.mcollovati.quarkus.hilla.deployment.devui; - -import java.util.stream.Stream; - -import io.quarkus.deployment.IsDevelopment; -import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.builditem.CombinedIndexBuildItem; -import io.quarkus.devui.spi.page.CardPageBuildItem; -import io.quarkus.devui.spi.page.Page; -import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.AnnotationTarget; -import org.jboss.jandex.DotName; - -public class QuarkusHillaDevUIProcessor { - - private static final DotName SIGNALS_HANDLER = - DotName.createSimple("com.vaadin.hilla.signals.handler.SignalsHandler"); - - @BuildStep(onlyIf = IsDevelopment.class) - public EndpointBuildItem collectEndpoints(CombinedIndexBuildItem combinedIndexBuildItem) { - final var endpointAnnotated = - combinedIndexBuildItem.getComputingIndex().getAnnotations(EndpointInfo.ENDPOINT_ANNOTATION); - final var browserCallableAnnotated = - combinedIndexBuildItem.getComputingIndex().getAnnotations(EndpointInfo.BROWSER_CALLABLE_ANNOTATION); - final var endpoints = Stream.concat(endpointAnnotated.stream(), browserCallableAnnotated.stream()) - .map(AnnotationInstance::target) - .filter(target -> target.kind().equals(AnnotationTarget.Kind.CLASS)) - .map(AnnotationTarget::asClass) - .filter(c -> !SIGNALS_HANDLER.equals(c.name())) - .map(EndpointInfo::from) - .toList(); - return new EndpointBuildItem(endpoints); - } - - @BuildStep(onlyIf = IsDevelopment.class) - public CardPageBuildItem pages(EndpointBuildItem endpointBuildItems) { - CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); - cardPageBuildItem.addBuildTimeData("hillaEndpoints", endpointBuildItems.getEndpoints()); - cardPageBuildItem.addPage(Page.webComponentPageBuilder() - .title("Browser callables") - .icon("font-awesome-solid:table-list") - .componentLink("qwc-quarkus-hilla-browser-callables.js") - .staticLabel(String.valueOf(endpointBuildItems.getEndpoints().stream() - .mapToInt(a -> a.children().size()) - .sum()))); - return cardPageBuildItem; - } -} diff --git a/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java b/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java new file mode 100644 index 00000000..eded8a03 --- /dev/null +++ b/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java @@ -0,0 +1,25 @@ +package com.github.mcollovati.quarkus.hilla.devui; + +import com.github.mcollovati.quarkus.hilla.deployment.devui.EndpointBuildItem; +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; + +public class QuarkusHillaDevUIProcessor { + + @BuildStep(onlyIf = IsDevelopment.class) + public void pages( + BuildProducer cardPageProducer, + EndpointBuildItem endpointBuildItem) { + CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); + final var page = Page.webComponentPageBuilder() + .title("Browser callables") + .icon("font-awesome-solid:table-list") + .componentLink("qwc-quarkus-hilla.js") + .staticLabel(String.valueOf(endpointBuildItem.getEndpointMethodCount())); + cardPageBuildItem.addPage(page); + cardPageProducer.produce(cardPageBuildItem); + } +} diff --git a/lit/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla.js b/lit/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla.js new file mode 100644 index 00000000..a7b86037 --- /dev/null +++ b/lit/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla.js @@ -0,0 +1,12 @@ +import { LitElement, html} from 'lit'; +import './../com.github.mcollovati.quarkus-hilla-commons/qwc-quarkus-hilla-browser-callables.js'; + +export class QwcQuarkusHilla extends LitElement { + + render() { + return html` + `; + } +} +customElements.define('qwc-quarkus-hilla', QwcQuarkusHilla); diff --git a/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java b/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java new file mode 100644 index 00000000..0db2ae71 --- /dev/null +++ b/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java @@ -0,0 +1,25 @@ +package com.github.mcollovati.quarkus.hilla.devui; + +import com.github.mcollovati.quarkus.hilla.deployment.devui.EndpointBuildItem; +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; + +public class QuarkusHillaDevUIProcessor { + + @BuildStep(onlyIf = IsDevelopment.class) + public void pages( + BuildProducer cardPageProducer, + EndpointBuildItem endpointBuildItem) { + CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); + final var page = Page.webComponentPageBuilder() + .title("Browser callables") + .icon("font-awesome-solid:table-list") + .componentLink("qwc-quarkus-hilla-react.js") + .staticLabel(String.valueOf(endpointBuildItem.getEndpointMethodCount())); + cardPageBuildItem.addPage(page); + cardPageProducer.produce(cardPageBuildItem); + } +} diff --git a/react/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-react.js b/react/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-react.js new file mode 100644 index 00000000..879066d2 --- /dev/null +++ b/react/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-react.js @@ -0,0 +1,12 @@ +import { LitElement, html} from 'lit'; +import './../com.github.mcollovati.quarkus-hilla-commons/qwc-quarkus-hilla-browser-callables.js'; + +export class QwcQuarkusHillaReact extends LitElement { + + render() { + return html` + `; + } +} +customElements.define('qwc-quarkus-hilla-react', QwcQuarkusHillaReact); From ab3e69a0280a426f3ed9b222ac5cc76323f1859e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Mon, 6 Jan 2025 23:18:33 +0100 Subject: [PATCH 06/17] Add EndpointExposed methods --- .../hilla/deployment/devui/EndpointInfo.java | 51 +++++++++++++++---- .../QuarkusHillaDevUICommonsProcessor.java | 17 ++++--- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java index 619e6955..4c5018f5 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointInfo.java @@ -17,16 +17,20 @@ import jakarta.annotation.Nullable; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import io.quarkus.arc.deployment.devui.Name; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; +import org.jboss.jandex.IndexView; import org.jboss.jandex.MethodInfo; +import org.jboss.jandex.Type; public record EndpointInfo( AnnotationTarget.Kind kind, @@ -38,15 +42,22 @@ public record EndpointInfo( public static DotName ENDPOINT_ANNOTATION = DotName.createSimple("com.vaadin.hilla.Endpoint"); public static DotName BROWSER_CALLABLE_ANNOTATION = DotName.createSimple("com.vaadin.hilla.BrowserCallable"); + public static DotName ENDPOINT_EXPOSED_ANNOTATION = DotName.createSimple("com.vaadin.hilla.EndpointExposed"); public static DotName DENY_ALL_ANNOTATION = DotName.createSimple("jakarta.annotation.security.DenyAll"); - public static DotName PERMIT_ALL_ANNOTATION = DotName.createSimple("jakarta.annotation.security.PermitAll"); public static DotName ROLES_ALLOWED_ANNOTATION = DotName.createSimple("jakarta.annotation.security.RolesAllowed"); public static DotName ANONYMOUS_ALLOWED_ANNOTATION = DotName.createSimple("com.vaadin.flow.server.auth.AnonymousAllowed"); private static final AccessAnnotationInfo DENY_ALL_ACCESS_ANNOTATION_INFO = new AccessAnnotationInfo(Name.from(DENY_ALL_ANNOTATION), Collections.emptyList()); - public static EndpointInfo from(ClassInfo classInfo) { + /** + * Creates an {@link EndpointInfo} from the given {@link ClassInfo}. + * + * @param classInfo the class info to create the endpoint info from + * @param computingIndex the computing index, not the normal index + * @return the created endpoint info + */ + public static EndpointInfo from(ClassInfo classInfo, IndexView computingIndex) { final var accessAnnotation = getEffectiveAccessAnnotation(classInfo.declaredAnnotations()).orElse(DENY_ALL_ACCESS_ANNOTATION_INFO); return new EndpointInfo( @@ -60,11 +71,31 @@ public static EndpointInfo from(ClassInfo classInfo) { .map(DotName::withoutPackagePrefix) .orElse(null), accessAnnotation, - classInfo.methods().stream() - .filter(m -> - Modifier.isPublic(m.flags()) && !m.isConstructor() && !Modifier.isStatic(m.flags())) - .map(m -> from(m, accessAnnotation)) - .toList()); + retrieveExposedMethods(computingIndex, classInfo, accessAnnotation)); + } + + private static List retrieveExposedMethods( + IndexView index, ClassInfo classInfo, AccessAnnotationInfo accessAnnotation) { + return Stream.concat(Stream.of(classInfo), getExposedSuperClasses(classInfo, index).stream()) + .flatMap(c -> c.methodsInDeclarationOrder().stream()) + .filter(m -> Modifier.isPublic(m.flags()) && !m.isConstructor() && !Modifier.isStatic(m.flags())) + .map(m -> from(m, accessAnnotation)) + .toList(); + } + + private static List getExposedSuperClasses(ClassInfo classInfo, IndexView index) { + List superClasses = new ArrayList<>(); + Type superClassType = classInfo.superClassType(); + do { + final var superClass = index.getClassByName(superClassType.name()); + if (superClass == null) break; + if (superClass.hasAnnotation(ENDPOINT_EXPOSED_ANNOTATION)) { + superClasses.add(superClass); + } + superClassType = superClass.superClassType(); + } while (superClassType != null); + + return superClasses; } public static EndpointInfo from(MethodInfo methodInfo, AccessAnnotationInfo classAccessAnnotation) { @@ -78,8 +109,9 @@ public static EndpointInfo from(MethodInfo methodInfo, AccessAnnotationInfo clas } /** - * Returns the effective access annotation. Based on the following rules: - * ... + * Returns the effective access annotation. + * Based on the + * security rules. * @param annotations the annotations * @return the effective access annotation, if any */ @@ -100,6 +132,7 @@ private static Optional getEffectiveAccessAnnotation(List< } else if (a2.name().equals(ROLES_ALLOWED_ANNOTATION)) { return a2; } else { + // PermitAll return a1; } }) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java index 54f144aa..19e7f2a7 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java @@ -15,6 +15,12 @@ */ package com.github.mcollovati.quarkus.hilla.deployment.devui; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; @@ -28,15 +34,10 @@ import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.DotName; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; - public class QuarkusHillaDevUICommonsProcessor { - private static final GACT UI_JAR = new GACT("com.github.mcollovati", "quarkus-hilla-commons-deployment", null, "jar"); + private static final GACT UI_JAR = + new GACT("com.github.mcollovati", "quarkus-hilla-commons-deployment", null, "jar"); private static final String NAMESPACE = UI_JAR.getGroupId() + "." + UI_JAR.getArtifactId(); private static final String DEV_UI = "dev-ui"; @@ -54,7 +55,7 @@ public EndpointBuildItem collectEndpoints(CombinedIndexBuildItem combinedIndexBu .filter(target -> target.kind().equals(AnnotationTarget.Kind.CLASS)) .map(AnnotationTarget::asClass) .filter(c -> !SIGNALS_HANDLER.equals(c.name())) - .map(EndpointInfo::from) + .map(e -> EndpointInfo.from(e, combinedIndexBuildItem.getComputingIndex())) .toList(); return new EndpointBuildItem(endpoints); } From 82de2eede6a54e3beeaf590a8dc54c88284c7bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Sun, 12 Jan 2025 01:14:59 +0100 Subject: [PATCH 07/17] Fix formatting --- .../deployment/devui/EndpointBuildItem.java | 4 +--- .../devui/QuarkusHillaDevUIProcessor.java | 22 +++++++++++++++---- .../devui/QuarkusHillaDevUIProcessor.java | 22 +++++++++++++++---- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java index f73f2d18..32b0aceb 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/EndpointBuildItem.java @@ -32,8 +32,6 @@ public List getEndpoints() { } public int getEndpointMethodCount() { - return endpoints.stream() - .mapToInt(a -> a.children().size()) - .sum(); + return endpoints.stream().mapToInt(a -> a.children().size()).sum(); } } diff --git a/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java b/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java index eded8a03..0c79f210 100644 --- a/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java +++ b/lit/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java @@ -1,18 +1,32 @@ +/* + * Copyright 2025 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.devui; -import com.github.mcollovati.quarkus.hilla.deployment.devui.EndpointBuildItem; import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.devui.spi.page.CardPageBuildItem; import io.quarkus.devui.spi.page.Page; +import com.github.mcollovati.quarkus.hilla.deployment.devui.EndpointBuildItem; + public class QuarkusHillaDevUIProcessor { @BuildStep(onlyIf = IsDevelopment.class) - public void pages( - BuildProducer cardPageProducer, - EndpointBuildItem endpointBuildItem) { + public void pages(BuildProducer cardPageProducer, EndpointBuildItem endpointBuildItem) { CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); final var page = Page.webComponentPageBuilder() .title("Browser callables") diff --git a/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java b/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java index 0db2ae71..ccdf3bf9 100644 --- a/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java +++ b/react/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/devui/QuarkusHillaDevUIProcessor.java @@ -1,18 +1,32 @@ +/* + * Copyright 2025 Marco Collovati, Dario Götze + * + * 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 com.github.mcollovati.quarkus.hilla.devui; -import com.github.mcollovati.quarkus.hilla.deployment.devui.EndpointBuildItem; import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.devui.spi.page.CardPageBuildItem; import io.quarkus.devui.spi.page.Page; +import com.github.mcollovati.quarkus.hilla.deployment.devui.EndpointBuildItem; + public class QuarkusHillaDevUIProcessor { @BuildStep(onlyIf = IsDevelopment.class) - public void pages( - BuildProducer cardPageProducer, - EndpointBuildItem endpointBuildItem) { + public void pages(BuildProducer cardPageProducer, EndpointBuildItem endpointBuildItem) { CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); final var page = Page.webComponentPageBuilder() .title("Browser callables") From 47f631ac4767c0dba8ef4ab60b797a2ce3864129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Sun, 12 Jan 2025 01:27:42 +0100 Subject: [PATCH 08/17] Remove unusable sort column --- .../dev-ui/qwc-quarkus-hilla-browser-callables.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js b/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js index 3988c434..8a8c4eb0 100644 --- a/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js +++ b/commons/deployment/src/main/resources/dev-ui/qwc-quarkus-hilla-browser-callables.js @@ -81,13 +81,14 @@ export class QwcQuarkusHillaBrowserCallables extends LitElement { return html` - - + + auto-width> `; } } From 9b705ae824ba4cb0283516c14898537668c1b8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Sun, 12 Jan 2025 01:29:42 +0100 Subject: [PATCH 09/17] Sort endpoints by full name --- .../deployment/devui/QuarkusHillaDevUICommonsProcessor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java index 19e7f2a7..61f6a981 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/devui/QuarkusHillaDevUICommonsProcessor.java @@ -17,6 +17,7 @@ import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; @@ -32,6 +33,7 @@ import io.quarkus.vertx.http.deployment.webjar.WebJarResourcesFilter; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; public class QuarkusHillaDevUICommonsProcessor { @@ -55,6 +57,7 @@ public EndpointBuildItem collectEndpoints(CombinedIndexBuildItem combinedIndexBu .filter(target -> target.kind().equals(AnnotationTarget.Kind.CLASS)) .map(AnnotationTarget::asClass) .filter(c -> !SIGNALS_HANDLER.equals(c.name())) + .sorted(Comparator.comparing(ClassInfo::name)) .map(e -> EndpointInfo.from(e, combinedIndexBuildItem.getComputingIndex())) .toList(); return new EndpointBuildItem(endpoints); From 9c7d93529b61c03cfa321d368330c56699ec0ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Mon, 6 Jan 2025 23:36:04 +0100 Subject: [PATCH 10/17] Enable QuarkusNavigationAccessControl also for OIDC --- .../QuarkusHillaExtensionProcessor.java | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index 6ccc5602..3c379697 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -73,6 +73,7 @@ import io.quarkus.undertow.deployment.ServletBuildItem; import io.quarkus.vertx.http.deployment.BodyHandlerBuildItem; import io.quarkus.vertx.http.deployment.FilterBuildItem; +import io.quarkus.vertx.http.deployment.SecurityInformationBuildItem; import io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism; import org.atmosphere.client.TrackMessageSizeInterceptor; import org.atmosphere.cpr.ApplicationConfig; @@ -449,20 +450,16 @@ void configureNavigationControlAccessCheckers( void registerNavigationAccessControl( AuthFormBuildItem authFormBuildItem, CombinedIndexBuildItem index, + List securityInformation, BuildProducer beans, BuildProducer accessControlProducer, BuildProducer accessCheckerProducer) { - Set securityAnnotations = Set.of( - DotName.createSimple(DenyAll.class.getName()), - DotName.createSimple(AnonymousAllowed.class.getName()), - DotName.createSimple(RolesAllowed.class.getName()), - DotName.createSimple(PermitAll.class.getName())); - boolean hasSecuredRoutes = - index.getComputingIndex().getAnnotations(DotName.createSimple(Route.class.getName())).stream() - .flatMap(route -> route.target().annotations().stream().map(AnnotationInstance::name)) - .anyMatch(securityAnnotations::contains); - if (authFormBuildItem.isEnabled()) { + boolean oidcEnabled = securityInformation.stream() + .map(SecurityInformationBuildItem::getSecurityModel) + .anyMatch(model -> model == SecurityInformationBuildItem.SecurityModel.oidc); + + if (authFormBuildItem.isEnabled() || oidcEnabled) { beans.produce(AdditionalBeanBuildItem.builder() .addBeanClasses( QuarkusNavigationAccessControl.class, @@ -470,18 +467,39 @@ void registerNavigationAccessControl( DefaultAccessCheckDecisionResolver.class) .setUnremovable() .build()); - if (hasSecuredRoutes) { + + if (hasSecuredRoutes(index)) { accessCheckerProducer.produce( new NavigationAccessCheckerBuildItem(DotName.createSimple(AnnotatedViewAccessChecker.class))); } - ConfigProvider.getConfig() - .getOptionalValue("quarkus.http.auth.form.login-page", String.class) - .map(NavigationAccessControlBuildItem::new) - .ifPresent(accessControlProducer::produce); + if (authFormBuildItem.isEnabled()) { + ConfigProvider.getConfig() + .getOptionalValue("quarkus.http.auth.form.login-page", String.class) + .map(NavigationAccessControlBuildItem::new) + .ifPresent(accessControlProducer::produce); + } + + if (oidcEnabled) { + ConfigProvider.getConfig() + .getOptionalValue("vaadin.oidc.login.path", String.class) + .map(NavigationAccessControlBuildItem::new) + .ifPresent(accessControlProducer::produce); + } } } + private boolean hasSecuredRoutes(CombinedIndexBuildItem indexBuildItem) { + Set securityAnnotations = Set.of( + DotName.createSimple(DenyAll.class.getName()), + DotName.createSimple(AnonymousAllowed.class.getName()), + DotName.createSimple(RolesAllowed.class.getName()), + DotName.createSimple(PermitAll.class.getName())); + return indexBuildItem.getComputingIndex().getAnnotations(DotName.createSimple(Route.class.getName())).stream() + .flatMap(route -> route.target().annotations().stream().map(AnnotationInstance::name)) + .anyMatch(securityAnnotations::contains); + } + @BuildStep void registerServiceInitEventPropagator( QuarkusHillaEnvironmentBuildItem quarkusHillaEnv, From 1f2ef66e2dd17cc2b5c35bfc131e6e7c0e210820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Tue, 7 Jan 2025 00:54:21 +0100 Subject: [PATCH 11/17] Refactor AuthFormBuildItem to HillaSecurityBuildItem * Run build steps only for associated security policy --- ...dItem.java => HillaSecurityBuildItem.java} | 22 ++++++--- .../QuarkusHillaExtensionProcessor.java | 45 ++++++++++--------- .../quarkus/hilla/HillaSecurityRecorder.java | 1 + 3 files changed, 42 insertions(+), 26 deletions(-) rename commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/{AuthFormBuildItem.java => HillaSecurityBuildItem.java} (63%) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/AuthFormBuildItem.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java similarity index 63% rename from commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/AuthFormBuildItem.java rename to commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java index 1ed90878..b963adae 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/AuthFormBuildItem.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java @@ -17,15 +17,25 @@ import io.quarkus.builder.item.SimpleBuildItem; -public final class AuthFormBuildItem extends SimpleBuildItem { +public final class HillaSecurityBuildItem extends SimpleBuildItem { - private final boolean enabled; + private final SecurityPolicy policy; - public AuthFormBuildItem(boolean enabled) { - this.enabled = enabled; + public HillaSecurityBuildItem(SecurityPolicy policy) { + this.policy = policy; } - public boolean isEnabled() { - return enabled; + public SecurityPolicy getSecurityPolicy() { + return policy; + } + + boolean isAuthEnabled() { + return policy != SecurityPolicy.NONE; + } + + enum SecurityPolicy { + NONE, + FORM, + OIDC } } diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index 3c379697..95536743 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -249,11 +249,20 @@ void registerJaxrsApplicationToFixApplicationPath(BuildProducer securityInformation) { + final boolean authFormEnabled = ConfigProvider.getConfig() .getOptionalValue("quarkus.http.auth.form.enabled", Boolean.class) .orElse(false); - return new AuthFormBuildItem(authFormEnabled); + + if (authFormEnabled) return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityPolicy.FORM); + + final boolean oidcEnabled = securityInformation.stream() + .map(SecurityInformationBuildItem::getSecurityModel) + .anyMatch(model -> model == SecurityInformationBuildItem.SecurityModel.oidc); + + if (oidcEnabled) return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityPolicy.OIDC); + + return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityPolicy.NONE); } @BuildStep @@ -385,8 +394,9 @@ public void transform(TransformationContext ctx) { } @BuildStep - void registerHillaSecurityPolicy(AuthFormBuildItem authFormEnabled, BuildProducer beans) { - if (authFormEnabled.isEnabled()) { + void registerHillaSecurityPolicy( + HillaSecurityBuildItem hillaSecurityBuildItem, BuildProducer beans) { + if (hillaSecurityBuildItem.isAuthEnabled()) { beans.produce(AdditionalBeanBuildItem.builder() .addBeanClasses(HillaSecurityPolicy.class) .setDefaultScope(DotNames.APPLICATION_SCOPED) @@ -398,10 +408,10 @@ void registerHillaSecurityPolicy(AuthFormBuildItem authFormEnabled, BuildProduce @BuildStep @Record(ExecutionTime.RUNTIME_INIT) void registerHillaFormAuthenticationMechanism( - AuthFormBuildItem authFormBuildItem, + HillaSecurityBuildItem hillaSecurityBuildItem, HillaSecurityRecorder recorder, BuildProducer producer) { - if (authFormBuildItem.isEnabled()) { + if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.FORM) { producer.produce(SyntheticBeanBuildItem.configure(HillaFormAuthenticationMechanism.class) .types(HttpAuthenticationMechanism.class) .setRuntimeInit() @@ -417,8 +427,10 @@ void registerHillaFormAuthenticationMechanism( @Record(ExecutionTime.RUNTIME_INIT) @Consume(SyntheticBeansRuntimeInitBuildItem.class) void configureHillaSecurityComponents( - AuthFormBuildItem authFormBuildItem, HillaSecurityRecorder recorder, BeanContainerBuildItem beanContainer) { - if (authFormBuildItem.isEnabled()) { + HillaSecurityBuildItem hillaSecurityBuildItem, + HillaSecurityRecorder recorder, + BeanContainerBuildItem beanContainer) { + if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.FORM) { recorder.configureHttpSecurityPolicy(beanContainer.getValue()); } } @@ -448,18 +460,13 @@ void configureNavigationControlAccessCheckers( @BuildStep void registerNavigationAccessControl( - AuthFormBuildItem authFormBuildItem, + HillaSecurityBuildItem hillaSecurityBuildItem, CombinedIndexBuildItem index, - List securityInformation, BuildProducer beans, BuildProducer accessControlProducer, BuildProducer accessCheckerProducer) { - boolean oidcEnabled = securityInformation.stream() - .map(SecurityInformationBuildItem::getSecurityModel) - .anyMatch(model -> model == SecurityInformationBuildItem.SecurityModel.oidc); - - if (authFormBuildItem.isEnabled() || oidcEnabled) { + if (hillaSecurityBuildItem.isAuthEnabled()) { beans.produce(AdditionalBeanBuildItem.builder() .addBeanClasses( QuarkusNavigationAccessControl.class, @@ -473,14 +480,12 @@ void registerNavigationAccessControl( new NavigationAccessCheckerBuildItem(DotName.createSimple(AnnotatedViewAccessChecker.class))); } - if (authFormBuildItem.isEnabled()) { + if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.FORM) { ConfigProvider.getConfig() .getOptionalValue("quarkus.http.auth.form.login-page", String.class) .map(NavigationAccessControlBuildItem::new) .ifPresent(accessControlProducer::produce); - } - - if (oidcEnabled) { + } else if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.OIDC) { ConfigProvider.getConfig() .getOptionalValue("vaadin.oidc.login.path", String.class) .map(NavigationAccessControlBuildItem::new) diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java index 323eb1d2..7b3091e1 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java @@ -43,6 +43,7 @@ public void configureHttpSecurityPolicy(BeanContainer container) { Config config = ConfigProvider.getConfig(); HillaSecurityPolicy policy = container.beanInstance(HillaSecurityPolicy.class); policy.withFormLogin(config); + // TODO move somewhere else, so it is also called for OIDC QuarkusHillaExtension.markSecurityPolicyUsed(); } From 44bfaeaa07bde1f4e3548d976d9ee43a0c0faff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Tue, 7 Jan 2025 23:43:29 +0100 Subject: [PATCH 12/17] Refactor path matching --- .../deployment/HillaSecurityBuildItem.java | 16 ++++++++----- .../QuarkusHillaExtensionProcessor.java | 23 ++++++++----------- .../quarkus/hilla/HillaSecurityPolicy.java | 20 +++++++++------- .../hilla/QuarkusEndpointConfiguration.java | 23 ++++++++++++++++--- .../quarkus/hilla/QuarkusHandlerHelper.java | 2 +- 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java index b963adae..e028857b 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/HillaSecurityBuildItem.java @@ -19,21 +19,25 @@ public final class HillaSecurityBuildItem extends SimpleBuildItem { - private final SecurityPolicy policy; + private final SecurityModel policy; - public HillaSecurityBuildItem(SecurityPolicy policy) { - this.policy = policy; + public HillaSecurityBuildItem(SecurityModel securityModel) { + this.policy = securityModel; } - public SecurityPolicy getSecurityPolicy() { + public SecurityModel getSecurityModel() { return policy; } boolean isAuthEnabled() { - return policy != SecurityPolicy.NONE; + return policy != SecurityModel.NONE; } - enum SecurityPolicy { + boolean isFormAuthEnabled() { + return policy == SecurityModel.FORM; + } + + enum SecurityModel { NONE, FORM, OIDC diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index 95536743..718d326e 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -254,15 +254,15 @@ HillaSecurityBuildItem hillaSecurityBuildItem(List .getOptionalValue("quarkus.http.auth.form.enabled", Boolean.class) .orElse(false); - if (authFormEnabled) return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityPolicy.FORM); + if (authFormEnabled) return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityModel.FORM); final boolean oidcEnabled = securityInformation.stream() .map(SecurityInformationBuildItem::getSecurityModel) .anyMatch(model -> model == SecurityInformationBuildItem.SecurityModel.oidc); - if (oidcEnabled) return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityPolicy.OIDC); + if (oidcEnabled) return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityModel.OIDC); - return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityPolicy.NONE); + return new HillaSecurityBuildItem(HillaSecurityBuildItem.SecurityModel.NONE); } @BuildStep @@ -305,14 +305,9 @@ void registerHillaPushServlet( NativeConfig nativeConfig) { ServletBuildItem.Builder builder = ServletBuildItem.builder( QuarkusAtmosphereServlet.class.getName(), QuarkusAtmosphereServlet.class.getName()); - String prefix = endpointConfiguration.getEndpointPrefix(); - if (prefix.matches("^/?connect/?$")) { + String prefix = endpointConfiguration.GetStandardizedEndpointPrefix(); + if (prefix.equals(QuarkusEndpointConfiguration.DEFAULT_ENDPOINT_PREFIX)) { prefix = "/"; - } else if (!prefix.startsWith("/")) { - prefix = "/" + prefix; - } - if (prefix.endsWith("/")) { - prefix = prefix.substring(0, prefix.length() - 1); } String hillaPushMapping = prefix + "/HILLA/push"; @@ -411,7 +406,7 @@ void registerHillaFormAuthenticationMechanism( HillaSecurityBuildItem hillaSecurityBuildItem, HillaSecurityRecorder recorder, BuildProducer producer) { - if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.FORM) { + if (hillaSecurityBuildItem.isFormAuthEnabled()) { producer.produce(SyntheticBeanBuildItem.configure(HillaFormAuthenticationMechanism.class) .types(HttpAuthenticationMechanism.class) .setRuntimeInit() @@ -430,7 +425,7 @@ void configureHillaSecurityComponents( HillaSecurityBuildItem hillaSecurityBuildItem, HillaSecurityRecorder recorder, BeanContainerBuildItem beanContainer) { - if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.FORM) { + if (hillaSecurityBuildItem.isFormAuthEnabled()) { recorder.configureHttpSecurityPolicy(beanContainer.getValue()); } } @@ -480,12 +475,12 @@ void registerNavigationAccessControl( new NavigationAccessCheckerBuildItem(DotName.createSimple(AnnotatedViewAccessChecker.class))); } - if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.FORM) { + if (hillaSecurityBuildItem.isFormAuthEnabled()) { ConfigProvider.getConfig() .getOptionalValue("quarkus.http.auth.form.login-page", String.class) .map(NavigationAccessControlBuildItem::new) .ifPresent(accessControlProducer::produce); - } else if (hillaSecurityBuildItem.getSecurityPolicy() == HillaSecurityBuildItem.SecurityPolicy.OIDC) { + } else if (hillaSecurityBuildItem.getSecurityModel() == HillaSecurityBuildItem.SecurityModel.OIDC) { ConfigProvider.getConfig() .getOptionalValue("vaadin.oidc.login.path", String.class) .map(NavigationAccessControlBuildItem::new) diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java index 2f49fdb7..ef91c3e7 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java @@ -17,7 +17,6 @@ import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; -import java.util.Arrays; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -38,6 +37,7 @@ import com.vaadin.flow.server.auth.AccessCheckResult; import com.vaadin.flow.server.auth.NavigationAccessControl; import com.vaadin.flow.server.auth.NavigationContext; +import com.vaadin.hilla.parser.utils.Streams; import io.quarkus.runtime.Startup; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.vertx.http.runtime.security.AuthenticatedHttpSecurityPolicy; @@ -59,6 +59,9 @@ public class HillaSecurityPolicy implements HttpSecurityPolicy { @Inject NavigationAccessControl accessControl; + @Inject + QuarkusEndpointConfiguration endpointConfiguration; + VaadinService vaadinService; public HillaSecurityPolicy() { @@ -68,12 +71,14 @@ public HillaSecurityPolicy() { private void buildPathMatcher(Consumer> customizer) { ImmutablePathMatcher.ImmutablePathMatcherBuilder pathMatcherBuilder = ImmutablePathMatcher.builder(); - Arrays.stream(HandlerHelper.getPublicResourcesRequiringSecurityContext()) - .map(this::computePath) - .forEach(p -> pathMatcherBuilder.addPath(p, true)); + String connectPath = endpointConfiguration.GetStandardizedEndpointPrefix(); + pathMatcherBuilder.addPath(connectPath + "/*", true); pathMatcherBuilder.addPath("/HILLA/*", true); - pathMatcherBuilder.addPath("/connect/*", true); - Arrays.stream(HandlerHelper.getPublicResources()) + Streams.combine( + HandlerHelper.getPublicResources(), + HandlerHelper.getPublicResourcesRoot(), + // Contains /VAADIN/* + HandlerHelper.getPublicResourcesRequiringSecurityContext()) .map(this::computePath) .forEach(p -> pathMatcherBuilder.addPath(p, true)); if (customizer != null) { @@ -86,10 +91,9 @@ private void buildPathMatcher(Consumer checkPermission( RoutingContext request, Uni identity, AuthorizationRequestContext requestContext) { Boolean permittedPath = pathMatcher.match(request.request().path()).getValue(); - NavigationContext navigationContext = tryCreateNavigationContext(request); if ((permittedPath != null && permittedPath) || isFrameworkInternalRequest(request) - || isAnonymousRoute(navigationContext, request.normalizedPath())) { + || isAnonymousRoute(tryCreateNavigationContext(request), request.normalizedPath())) { return Uni.createFrom().item(CheckResult.PERMIT); } return authenticatedHttpSecurityPolicy.checkPermission(request, identity, requestContext); diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java index fe31c3e0..38059277 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java @@ -24,7 +24,7 @@ import static com.github.mcollovati.quarkus.hilla.QuarkusEndpointConfiguration.CONFIG_PREFIX; /** - * hilla conf + * The configuration for the Vaadin endpoint. */ @ConfigMapping(prefix = CONFIG_PREFIX) @ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) @@ -32,11 +32,28 @@ public interface QuarkusEndpointConfiguration { String CONFIG_PREFIX = "vaadin.endpoint"; String VAADIN_ENDPOINT_PREFIX = CONFIG_PREFIX + ".prefix"; + String DEFAULT_ENDPOINT_PREFIX = "/connect"; /** - * prefix + * The prefix for the Vaadin endpoint. + * @return the connect endpoint prefix, default is "/connect" */ @WithName("prefix") - @WithDefault("/connect") + @WithDefault(DEFAULT_ENDPOINT_PREFIX) String getEndpointPrefix(); + + /** + * It is the same as {@link #getEndpointPrefix()} but without trailing slashes. + * @return the trimmed endpoint prefix, default is "/connect" + */ + default String GetStandardizedEndpointPrefix() { + String prefix = getEndpointPrefix(); + if (!prefix.startsWith("/")) { + prefix = "/" + prefix; + } + if (prefix.endsWith("/")) { + prefix = prefix.substring(0, prefix.length() - 1); + } + return prefix; + } } diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusHandlerHelper.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusHandlerHelper.java index 8f0d8a5b..62a09b36 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusHandlerHelper.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusHandlerHelper.java @@ -64,7 +64,7 @@ private static boolean isFrameworkInternalRequest( // This is only an internal request if it is for the Vaadin servlet Optional requestedPathWithoutServletMapping = getPathIfInsideServlet(servletMappingPath, requestedPath); - if (!requestedPathWithoutServletMapping.isPresent()) { + if (requestedPathWithoutServletMapping.isEmpty()) { return false; } else if (isInternalRequestInsideServlet(requestedPathWithoutServletMapping.get(), requestTypeParameter)) { return true; From b98fa304dd0556e3efcfd4540ca9016f818cfb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Tue, 7 Jan 2025 23:56:16 +0100 Subject: [PATCH 13/17] Mark security policy used for all auth types that we support --- .../hilla/deployment/QuarkusHillaExtensionProcessor.java | 5 ++++- .../mcollovati/quarkus/hilla/HillaSecurityRecorder.java | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index 718d326e..b488c842 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -426,7 +426,10 @@ void configureHillaSecurityComponents( HillaSecurityRecorder recorder, BeanContainerBuildItem beanContainer) { if (hillaSecurityBuildItem.isFormAuthEnabled()) { - recorder.configureHttpSecurityPolicy(beanContainer.getValue()); + recorder.configureFormLoginHttpSecurityPolicy(beanContainer.getValue()); + } + if (hillaSecurityBuildItem.isAuthEnabled()) { + recorder.markSecurityPolicyUsed(); } } diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java index 7b3091e1..5b2787b4 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityRecorder.java @@ -39,11 +39,13 @@ public Supplier setupFormAuthenticationMechani }; } - public void configureHttpSecurityPolicy(BeanContainer container) { + public void configureFormLoginHttpSecurityPolicy(BeanContainer container) { Config config = ConfigProvider.getConfig(); HillaSecurityPolicy policy = container.beanInstance(HillaSecurityPolicy.class); policy.withFormLogin(config); - // TODO move somewhere else, so it is also called for OIDC + } + + public void markSecurityPolicyUsed() { QuarkusHillaExtension.markSecurityPolicyUsed(); } From aaf93282774eca2babe9fec965a43470440ba9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Wed, 8 Jan 2025 00:44:34 +0100 Subject: [PATCH 14/17] Small improvements --- .../hilla/deployment/QuarkusHillaExtensionProcessor.java | 7 +++---- .../quarkus/hilla/QuarkusEndpointConfiguration.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index b488c842..ce3aebb7 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -478,13 +478,12 @@ void registerNavigationAccessControl( new NavigationAccessCheckerBuildItem(DotName.createSimple(AnnotatedViewAccessChecker.class))); } - if (hillaSecurityBuildItem.isFormAuthEnabled()) { - ConfigProvider.getConfig() + switch (hillaSecurityBuildItem.getSecurityModel()) { + case FORM -> ConfigProvider.getConfig() .getOptionalValue("quarkus.http.auth.form.login-page", String.class) .map(NavigationAccessControlBuildItem::new) .ifPresent(accessControlProducer::produce); - } else if (hillaSecurityBuildItem.getSecurityModel() == HillaSecurityBuildItem.SecurityModel.OIDC) { - ConfigProvider.getConfig() + case OIDC -> ConfigProvider.getConfig() .getOptionalValue("vaadin.oidc.login.path", String.class) .map(NavigationAccessControlBuildItem::new) .ifPresent(accessControlProducer::produce); diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java index 38059277..3532e4ab 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java @@ -43,7 +43,7 @@ public interface QuarkusEndpointConfiguration { String getEndpointPrefix(); /** - * It is the same as {@link #getEndpointPrefix()} but without trailing slashes. + * It is the same as {@link #getEndpointPrefix()} but ensures a starting slash and removes a trailing slash. * @return the trimmed endpoint prefix, default is "/connect" */ default String GetStandardizedEndpointPrefix() { From 53a490b7d1d0438cc7540eadeaa34e8d943c6dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Sat, 11 Jan 2025 20:32:44 +0100 Subject: [PATCH 15/17] Fix HillaSecurityPolicy injection --- .../quarkus/hilla/HillaSecurityPolicy.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java index ef91c3e7..3503a6d7 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java @@ -16,7 +16,6 @@ package com.github.mcollovati.quarkus.hilla; import jakarta.enterprise.event.Observes; -import jakarta.inject.Inject; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -56,16 +55,16 @@ public class HillaSecurityPolicy implements HttpSecurityPolicy { private ImmutablePathMatcher pathMatcher; private final AuthenticatedHttpSecurityPolicy authenticatedHttpSecurityPolicy; - @Inject - NavigationAccessControl accessControl; - - @Inject - QuarkusEndpointConfiguration endpointConfiguration; + private final NavigationAccessControl accessControl; + private final QuarkusEndpointConfiguration endpointConfiguration; VaadinService vaadinService; - public HillaSecurityPolicy() { - authenticatedHttpSecurityPolicy = new AuthenticatedHttpSecurityPolicy(); + public HillaSecurityPolicy( + NavigationAccessControl accessControl, QuarkusEndpointConfiguration endpointConfiguration) { + this.authenticatedHttpSecurityPolicy = new AuthenticatedHttpSecurityPolicy(); + this.accessControl = accessControl; + this.endpointConfiguration = endpointConfiguration; buildPathMatcher(null); } From a1e35ca7a4239ad09456835c2a547c3862b17ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Go=CC=88tze?= Date: Sat, 11 Jan 2025 20:33:38 +0100 Subject: [PATCH 16/17] Add QuarkusEndpointConfiguration.isDefaultEndpointPrefix --- .../hilla/deployment/QuarkusHillaExtensionProcessor.java | 7 +++---- .../quarkus/hilla/QuarkusEndpointConfiguration.java | 8 ++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index ce3aebb7..038bd1f8 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -305,10 +305,9 @@ void registerHillaPushServlet( NativeConfig nativeConfig) { ServletBuildItem.Builder builder = ServletBuildItem.builder( QuarkusAtmosphereServlet.class.getName(), QuarkusAtmosphereServlet.class.getName()); - String prefix = endpointConfiguration.GetStandardizedEndpointPrefix(); - if (prefix.equals(QuarkusEndpointConfiguration.DEFAULT_ENDPOINT_PREFIX)) { - prefix = "/"; - } + String prefix = endpointConfiguration.isDefaultEndpointPrefix() + ? "" + : endpointConfiguration.GetStandardizedEndpointPrefix(); String hillaPushMapping = prefix + "/HILLA/push"; builder.addMapping(hillaPushMapping) diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java index 3532e4ab..16f2b277 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java @@ -56,4 +56,12 @@ default String GetStandardizedEndpointPrefix() { } return prefix; } + + /** + * Checks if the endpoint prefix is the default one. + * @return true if the endpoint prefix is the default one + */ + default boolean isDefaultEndpointPrefix() { + return DEFAULT_ENDPOINT_PREFIX.equals(GetStandardizedEndpointPrefix()); + } } From 57a5949e3a1060a44ea78d135abe1d0ce21ac90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20G=C3=B6tze?= Date: Sun, 12 Jan 2025 13:44:28 +0100 Subject: [PATCH 17/17] Apply suggestions from code review Co-authored-by: Marco Collovati --- .../hilla/deployment/QuarkusHillaExtensionProcessor.java | 2 +- .../github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java | 2 +- .../quarkus/hilla/QuarkusEndpointConfiguration.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java index 038bd1f8..b75129bb 100644 --- a/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java +++ b/commons/deployment/src/main/java/com/github/mcollovati/quarkus/hilla/deployment/QuarkusHillaExtensionProcessor.java @@ -307,7 +307,7 @@ void registerHillaPushServlet( QuarkusAtmosphereServlet.class.getName(), QuarkusAtmosphereServlet.class.getName()); String prefix = endpointConfiguration.isDefaultEndpointPrefix() ? "" - : endpointConfiguration.GetStandardizedEndpointPrefix(); + : endpointConfiguration.getStandardizedEndpointPrefix(); String hillaPushMapping = prefix + "/HILLA/push"; builder.addMapping(hillaPushMapping) diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java index 3503a6d7..6dac8def 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/HillaSecurityPolicy.java @@ -70,7 +70,7 @@ public HillaSecurityPolicy( private void buildPathMatcher(Consumer> customizer) { ImmutablePathMatcher.ImmutablePathMatcherBuilder pathMatcherBuilder = ImmutablePathMatcher.builder(); - String connectPath = endpointConfiguration.GetStandardizedEndpointPrefix(); + String connectPath = endpointConfiguration.getStandardizedEndpointPrefix(); pathMatcherBuilder.addPath(connectPath + "/*", true); pathMatcherBuilder.addPath("/HILLA/*", true); Streams.combine( diff --git a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java index 16f2b277..91292746 100644 --- a/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java +++ b/commons/runtime/src/main/java/com/github/mcollovati/quarkus/hilla/QuarkusEndpointConfiguration.java @@ -46,7 +46,7 @@ public interface QuarkusEndpointConfiguration { * It is the same as {@link #getEndpointPrefix()} but ensures a starting slash and removes a trailing slash. * @return the trimmed endpoint prefix, default is "/connect" */ - default String GetStandardizedEndpointPrefix() { + default String getStandardizedEndpointPrefix() { String prefix = getEndpointPrefix(); if (!prefix.startsWith("/")) { prefix = "/" + prefix; @@ -62,6 +62,6 @@ default String GetStandardizedEndpointPrefix() { * @return true if the endpoint prefix is the default one */ default boolean isDefaultEndpointPrefix() { - return DEFAULT_ENDPOINT_PREFIX.equals(GetStandardizedEndpointPrefix()); + return DEFAULT_ENDPOINT_PREFIX.equals(getStandardizedEndpointPrefix()); } }