Skip to content

Commit

Permalink
DevUI: Split the client and service lists into separate cards, add li…
Browse files Browse the repository at this point in the history
…nks to their WSDLs quarkiverse#1015
  • Loading branch information
ppalaga committed Jan 4, 2024
1 parent 38c053f commit 1432afa
Show file tree
Hide file tree
Showing 19 changed files with 1,205 additions and 169 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkiverse.cxf.deployment;

import io.quarkiverse.cxf.CXFServletInfos;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.runtime.RuntimeValue;

/**
* Holds the runtime {@link CXFServletInfos} reference.
*/
public final class CXFServletInfosBuildItem extends SimpleBuildItem {
private final RuntimeValue<CXFServletInfos> cxfServletInfos;

public CXFServletInfosBuildItem(RuntimeValue<CXFServletInfos> cxfServletInfos) {
super();
this.cxfServletInfos = cxfServletInfos;
}

public RuntimeValue<CXFServletInfos> getCxfServletInfos() {
return cxfServletInfos;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Disposes;
Expand All @@ -35,6 +36,7 @@
import io.quarkiverse.cxf.CXFClientData;
import io.quarkiverse.cxf.CXFClientInfo;
import io.quarkiverse.cxf.CXFRecorder;
import io.quarkiverse.cxf.ClientInjectionPoint;
import io.quarkiverse.cxf.CxfClientConfig.HTTPConduitImpl;
import io.quarkiverse.cxf.CxfClientProducer;
import io.quarkiverse.cxf.CxfFixedConfig;
Expand Down Expand Up @@ -178,34 +180,53 @@ private static AnnotationInstance findWebServiceClientAnnotation(IndexView index
return null;
}

public static Stream<ClientInjectionPoint> findClientInjectionPoints(IndexView index) {
return index.getAnnotations(CxfDotNames.CXFCLIENT_ANNOTATION).stream()
.map(annotationInstance -> {
final AnnotationTarget target = annotationInstance.target();
Type type;
switch (target.kind()) {
case FIELD:
type = target.asField().type();
break;
case METHOD_PARAMETER:
MethodParameterInfo paramInfo = target.asMethodParameter();
MethodInfo method = paramInfo.method();
type = method.parameterTypes().get(paramInfo.position());
break;
default:
type = null;
break;
}
if (type != null) {
type = type.name().equals(CxfDotNames.INJECT_INSTANCE) ? type.asParameterizedType().arguments().get(0)
: type;
final String typeName = type.name().toString();
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
final Class<?> sei = Class.forName(typeName, true, cl);
final AnnotationValue value = annotationInstance.value();
return new ClientInjectionPoint(value != null ? value.asString() : "", sei);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Could not load Service Endpoint Interface " + typeName);
}
} else {
return null;
}
})
.filter(ip -> ip != null)
.distinct();
}

private static Map<String, ClientFixedConfig> findClientSEIsInUse(IndexView index, CxfFixedConfig config) {
final Map<String, ClientFixedConfig> seiToClientConfig = new TreeMap<>();
index.getAnnotations(CxfDotNames.CXFCLIENT_ANNOTATION).forEach(annotationInstance -> {
final AnnotationTarget target = annotationInstance.target();
Type type;
switch (target.kind()) {
case FIELD:
type = target.asField().type();
break;
case METHOD_PARAMETER:
MethodParameterInfo paramInfo = target.asMethodParameter();
MethodInfo method = paramInfo.method();
type = method.parameterTypes().get(paramInfo.position());
break;
default:
type = null;
break;
}
if (type != null) {
type = type.name().equals(CxfDotNames.INJECT_INSTANCE) ? type.asParameterizedType().arguments().get(0)
: type;
final String typeName = type.name().toString();
final ClientFixedConfig clientConfig = findClientConfig(
config,
Optional.ofNullable(annotationInstance.value()).map(AnnotationValue::asString).orElse(null),
typeName);
seiToClientConfig.put(typeName, clientConfig);
}
findClientInjectionPoints(index).forEach(clientInjectionPoint -> {
String sei = clientInjectionPoint.getSei().getName();
final ClientFixedConfig clientConfig = findClientConfig(
config,
clientInjectionPoint.getConfigKey(),
sei);
seiToClientConfig.put(sei, clientConfig);
});
return seiToClientConfig;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ void collectEndpoints(

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void startRoute(CXFRecorder recorder,
CXFServletInfosBuildItem startRoute(CXFRecorder recorder,
BuildProducer<RouteBuildItem> routes,
BeanContainerBuildItem beanContainer,
List<CxfEndpointImplementationBuildItem> cxfEndpoints,
Expand Down Expand Up @@ -154,6 +154,8 @@ void startRoute(CXFRecorder recorder,
LOGGER.debug(
"Not registering a Vert.x handler for CXF as no WS endpoints were found at build time and no other extension requested it");
}

return new CXFServletInfosBuildItem(infos);
}

private static String getMappingPath(String path) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
package io.quarkiverse.cxf.deployment.devui;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import io.quarkiverse.cxf.deployment.CxfClientBuildItem;
import io.quarkiverse.cxf.deployment.CxfEndpointImplementationBuildItem;
import org.jboss.jandex.DotName;
import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
import org.jboss.jandex.Type.Kind;

import io.quarkiverse.cxf.ClientInjectionPoint;
import io.quarkiverse.cxf.deployment.CXFServletInfosBuildItem;
import io.quarkiverse.cxf.deployment.CxfClientProcessor;
import io.quarkiverse.cxf.devui.CxfJsonRPCService;
import io.quarkiverse.cxf.devui.DevUiRecorder;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.devui.spi.JsonRPCProvidersBuildItem;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;

public class DevUIProcessor {

@BuildStep(onlyIf = IsDevelopment.class)
public CardPageBuildItem pages(List<CxfEndpointImplementationBuildItem> services,
List<CxfClientBuildItem> clients) {
public CardPageBuildItem pages() {

CardPageBuildItem cardPageBuildItem = new CardPageBuildItem();

int total = services.size() + clients.size();
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Clients")
.icon("font-awesome-solid:message")
.componentLink("qwc-cxf-clients.js")
.dynamicLabelJsonRPCMethodName("getClientCount"));

cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("List of SOAP WS")
.icon("font-awesome-solid:cubes")
.title("Service Endpoints")
.icon("font-awesome-solid:gears")
.componentLink("qwc-cxf-services.js")
.staticLabel(String.valueOf(total)));
.dynamicLabelJsonRPCMethodName("getServiceCount"));

return cardPageBuildItem;
}
Expand All @@ -34,4 +52,42 @@ public CardPageBuildItem pages(List<CxfEndpointImplementationBuildItem> services
JsonRPCProvidersBuildItem createJsonRPCServiceForCache() {
return new JsonRPCProvidersBuildItem(CxfJsonRPCService.class);
}

@BuildStep(onlyIf = IsDevelopment.class)
@Record(ExecutionTime.STATIC_INIT)
void collectClients(
CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<SyntheticBeanBuildItem> synthetics,
DevUiRecorder recorder) {
final List<ClientInjectionPoint> injectionPoints = CxfClientProcessor.findClientInjectionPoints(
combinedIndexBuildItem.getIndex())
.sorted(Comparator.comparing(ClientInjectionPoint::getConfigKey).thenComparing(cip -> cip.getSei().getName()))
.collect(Collectors.toList());
synthetics.produce(SyntheticBeanBuildItem
.configure(List.class)
.types(
ParameterizedType.create(
DotName.createSimple(List.class.getName()),
Type.create(DotName.createSimple(ClientInjectionPoint.class.getName()), Kind.CLASS)))
.named("clientInjectionPoints")
.runtimeValue(recorder.clientInjectionPoints(injectionPoints))
.done());
}

@BuildStep(onlyIf = IsDevelopment.class)
@Record(ExecutionTime.RUNTIME_INIT)
void collectServices(
CXFServletInfosBuildItem infos,
DevUiRecorder recorder) {
recorder.servletInfos(infos.getCxfServletInfos());
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void shutDown(
DevUiRecorder recorder,
ShutdownContextBuildItem shutdownContext) {
recorder.shutdown(shutdownContext);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { LitElement, html, css} from 'lit';
import 'qui-card';
import '@vaadin/progress-bar';
import '@vaadin/grid';
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
import { JsonRpc } from 'jsonrpc';
import 'qui-ide-link';

/**
* This component shows the list of clients
*/
export class QwcCxfClients extends LitElement {
jsonRpc = new JsonRpc(this);

static styles = css`
.cxf-table {
height: 100%;
padding-bottom: 10px;
}
code {
font-size: 85%;
}
.annotation {
color: var(--lumo-contrast-50pct);
}
:host {
display: flex;
flex-direction:column;
gap: 20px;
padding-left: 10px;
padding-right: 10px;
}
.nothing-found {
padding: 5px;
}`;

static properties = {
_clients: {state: true}
};

constructor() {
super();
this._clients = null;
}

connectedCallback() {
super.connectedCallback();
this.jsonRpc.getClients().then(jsonRpcResponse => {
this._clients = jsonRpcResponse.result;
});
}

render() {
if (this._clients) {
if (this._clients.length > 0) {
return this._renderClientList();
} else {
return html`<div class="nothing-found">No clients found</div>`;
}
} else {
return html`<vaadin-progress-bar class="progress" indeterminate></vaadin-progress-bar>`;
}
}

_renderClientList(){
return html`<vaadin-grid .items="${this._clients}" class="cxf-table" theme="no-border" all-rows-visible>
<vaadin-grid-column auto-width
header="Service Endpoint Interface (SEI)"
${columnBodyRenderer(this._classNameRenderer, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Address"
${columnBodyRenderer(this._addressRenderer, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="WSDL"
${columnBodyRenderer(this._wsdlRenderer, [])}
resizable>
</vaadin-grid-column>
</vaadin-grid>`;
}

_classNameRenderer(client){
return html`<vaadin-vertical-layout>
<code class="annotation">@CXFClient("${client.configKey}")</code>
<qui-ide-link title='Service Endpoint Interface (SEI)'
fileName='${client.sei}'
lineNumber=0><code>${client.sei}</code></qui-ide-link>
</vaadin-vertical-layout>`;
}

_addressRenderer(client) {
return html`<vaadin-vertical-layout>
<code class="annotation">&nbsp;</code>
<code><a href="${client.address}" target="_blank">${client.address}</a></code>
</vaadin-vertical-layout>`;
}

_wsdlRenderer(client) {
return html`<vaadin-vertical-layout>
<code class="annotation">&nbsp;</code>
<code><a href="${client.wsdl}" target="_blank">${client.wsdl}</a></code>
</vaadin-vertical-layout>`;
}

}
customElements.define('qwc-cxf-clients', QwcCxfClients);
Loading

0 comments on commit 1432afa

Please sign in to comment.