From 1ae51eb30c91a688698f35fa156b8364b1183a66 Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Fri, 3 Feb 2023 13:33:07 +0100 Subject: [PATCH] Implement the cache card for the new dev ui --- extensions/cache/deployment/pom.xml | 9 ++ .../CacheDevUiConsoleProcessor.java | 28 +++++ .../dev-ui/cache/qwc-cache-caches.js | 119 ++++++++++++++++++ .../devconsole/CacheJsonRPCService.java | 72 +++++++++++ 4 files changed, 228 insertions(+) create mode 100644 extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevUiConsoleProcessor.java create mode 100644 extensions/cache/deployment/src/main/resources/dev-ui/cache/qwc-cache-caches.js create mode 100644 extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/devconsole/CacheJsonRPCService.java diff --git a/extensions/cache/deployment/pom.xml b/extensions/cache/deployment/pom.xml index 98136ccb95c4b..fa851fa0289a9 100644 --- a/extensions/cache/deployment/pom.xml +++ b/extensions/cache/deployment/pom.xml @@ -34,6 +34,15 @@ io.quarkus quarkus-mutiny-deployment + + io.quarkus + quarkus-vertx-http-dev-ui-spi + + + io.quarkus + quarkus-vertx-http-deployment + true + diff --git a/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevUiConsoleProcessor.java b/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevUiConsoleProcessor.java new file mode 100644 index 0000000000000..b35eb2f58b73f --- /dev/null +++ b/extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/devconsole/CacheDevUiConsoleProcessor.java @@ -0,0 +1,28 @@ +package io.quarkus.cache.deployment.devconsole; + +import io.quarkus.cache.runtime.devconsole.CacheJsonRPCService; +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; +import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; + +public class CacheDevUiConsoleProcessor { + + @BuildStep(onlyIf = IsDevelopment.class) + CardPageBuildItem create(CurateOutcomeBuildItem bi) { + CardPageBuildItem pageBuildItem = new CardPageBuildItem("Cache"); + pageBuildItem.addPage(Page.webComponentPageBuilder() + .title("Caches") + .componentLink("qwc-cache-caches.js") + .icon("font-awesome-solid:database")); + + return pageBuildItem; + } + + @BuildStep(onlyIf = IsDevelopment.class) + JsonRPCProvidersBuildItem createJsonRPCServiceForCache() { + return new JsonRPCProvidersBuildItem("Cache", CacheJsonRPCService.class); + } +} diff --git a/extensions/cache/deployment/src/main/resources/dev-ui/cache/qwc-cache-caches.js b/extensions/cache/deployment/src/main/resources/dev-ui/cache/qwc-cache-caches.js new file mode 100644 index 0000000000000..3218fa3775036 --- /dev/null +++ b/extensions/cache/deployment/src/main/resources/dev-ui/cache/qwc-cache-caches.js @@ -0,0 +1,119 @@ +import { LitElement, html, css} from 'lit'; +import { JsonRpc } from 'jsonrpc'; +import '@vaadin/icon'; +import '@vaadin/button'; +import '@vaadin/text-field'; +import '@vaadin/text-area'; +import '@vaadin/form-layout'; +import '@vaadin/progress-bar'; +import '@vaadin/checkbox'; +import { until } from 'lit/directives/until.js'; +import '@vaadin/grid'; +import { columnBodyRenderer } from '@vaadin/grid/lit.js'; +import '@vaadin/grid/vaadin-grid-sort-column.js'; + +export class QwcCacheCaches extends LitElement { + + jsonRpc = new JsonRpc("Cache"); + + // Component style + static styles = css` + .button { + background-color: transparent; + cursor: pointer; + } + .clearIcon { + color: orange; + } + `; + + // Component properties + static properties = { + "_caches": {state: true} + } + + // Components callbacks + + /** + * Called when displayed + */ + connectedCallback() { + super.connectedCallback(); + this.jsonRpc.getAll().then(jsonRpcResponse => { + this._caches = new Map(); + jsonRpcResponse.result.forEach(c => { + this._caches.set(c.name, c); + }); + }); + } + + /** + * Called when it needs to render the components + * @returns {*} + */ + render() { + return html`${until(this._renderCacheTable(), html`Loading caches...`)}`; + } + + // View / Templates + + _renderCacheTable() { + if (this._caches) { + let caches = [...this._caches.values()]; + return html` + + + + + + + + + + `; + } + } + + _actionRenderer(cache) { + return html` + this._clear(cache.name)} class="button"> + Clear + `; + } + + _nameRenderer(cache) { + return html` + this._refresh(cache.name)} class="button"> + + + ${cache.name}`; + } + + _clear(name) { + this.jsonRpc.clear({name: name}).then(jsonRpcResponse => { + this._updateCache(jsonRpcResponse.result) + }); + } + + _refresh(name) { + this.jsonRpc.refresh({name: name}).then(jsonRpcResponse => { + this._updateCache(jsonRpcResponse.result) + }); + } + + _updateCache(cache){ + if (this._caches.has(cache.name) && cache.size !== -1) { + this._caches.set(cache.name, cache); + this.requestUpdate(); + } + } + +} +customElements.define('qwc-cache-caches', QwcCacheCaches); diff --git a/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/devconsole/CacheJsonRPCService.java b/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/devconsole/CacheJsonRPCService.java new file mode 100644 index 0000000000000..3bf4cfcc74384 --- /dev/null +++ b/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/devconsole/CacheJsonRPCService.java @@ -0,0 +1,72 @@ +package io.quarkus.cache.runtime.devconsole; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.jboss.logging.Logger; + +import io.quarkus.cache.Cache; +import io.quarkus.cache.CacheManager; +import io.quarkus.cache.CaffeineCache; +import io.quarkus.cache.runtime.caffeine.CaffeineCacheImpl; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; + +@ApplicationScoped +public class CacheJsonRPCService { + + @Inject + CacheManager manager; + + @Inject + Logger logger; + + public JsonArray getAll() { + Collection names = manager.getCacheNames(); + List allCaches = new ArrayList<>(names.size()); + for (String name : names) { + Optional cache = manager.getCache(name); + if (cache.isPresent() && cache.get() instanceof CaffeineCache) { + allCaches.add((CaffeineCache) cache.get()); + } + } + allCaches.sort(Comparator.comparing(CaffeineCache::getName)); + + var array = new JsonArray(); + for (CaffeineCache cc : allCaches) { + array.add(getJsonRepresentationForCache(cc)); + } + return array; + } + + private JsonObject getJsonRepresentationForCache(Cache cc) { + return new JsonObject().put("name", cc.getName()).put("size", ((CaffeineCacheImpl) cc).getSize()); + } + + public JsonObject clear(String name) { + Optional cache = manager.getCache(name); + if (cache.isPresent()) { + cache.get().invalidateAll().subscribe().asCompletionStage() + .thenAccept(x -> logger.infof("Cache %s cleared", name)); + return getJsonRepresentationForCache(cache.get()); + } else { + return new JsonObject().put("name", name).put("size", -1); + } + } + + public JsonObject refresh(String name) { + Optional cache = manager.getCache(name); + if (cache.isPresent()) { + return getJsonRepresentationForCache(cache.get()); + } else { + return new JsonObject().put("name", name).put("size", -1); + } + } + +}