From 6d9202bcd6b00f109946cb1a7ef71fffab0c8d16 Mon Sep 17 00:00:00 2001 From: Peter Palaga Date: Wed, 3 Jan 2024 00:56:46 +0100 Subject: [PATCH] DevUI: Split the client and service lists into separate cards, add links to their WSDLs #1015 --- .../cxf/deployment/CxfClientProcessor.java | 72 +++++--- .../cxf/deployment/devui/DevUIProcessor.java | 34 +++- .../main/resources/dev-ui/qwc-cxf-clients.js | 114 ++++++++++++ .../main/resources/dev-ui/qwc-cxf-services.js | 167 +++++++----------- .../java/io/quarkiverse/cxf/CXFRecorder.java | 1 + .../quarkiverse/cxf/ClientInjectionPoint.java | 39 ++++ .../io/quarkiverse/cxf/CxfClientProducer.java | 12 +- .../cxf/devui/CxfJsonRPCService.java | 75 ++++++-- .../cxf/devui/DevUiClientInfo.java | 39 ++++ .../quarkiverse/cxf/devui/DevUiRecorder.java | 13 ++ 10 files changed, 407 insertions(+), 159 deletions(-) create mode 100644 extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-clients.js create mode 100644 extensions/core/runtime/src/main/java/io/quarkiverse/cxf/ClientInjectionPoint.java create mode 100644 extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiClientInfo.java create mode 100644 extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiRecorder.java diff --git a/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/CxfClientProcessor.java b/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/CxfClientProcessor.java index 0b09d00b2..9e34d9f63 100644 --- a/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/CxfClientProcessor.java +++ b/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/CxfClientProcessor.java @@ -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; @@ -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; @@ -178,34 +180,52 @@ private static AnnotationInstance findWebServiceClientAnnotation(IndexView index return null; } + public static Stream 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); + return new ClientInjectionPoint(annotationInstance.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 findClientSEIsInUse(IndexView index, CxfFixedConfig config) { final Map 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; } diff --git a/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/devui/DevUIProcessor.java b/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/devui/DevUIProcessor.java index 94f9e85f4..451942286 100644 --- a/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/devui/DevUIProcessor.java +++ b/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/devui/DevUIProcessor.java @@ -1,12 +1,17 @@ package io.quarkiverse.cxf.deployment.devui; import java.util.List; +import java.util.stream.Collectors; -import io.quarkiverse.cxf.deployment.CxfClientBuildItem; -import io.quarkiverse.cxf.deployment.CxfEndpointImplementationBuildItem; +import io.quarkiverse.cxf.ClientInjectionPoint; +import io.quarkiverse.cxf.deployment.CxfClientProcessor; import io.quarkiverse.cxf.devui.CxfJsonRPCService; +import io.quarkiverse.cxf.devui.DevUiRecorder; import io.quarkus.deployment.IsDevelopment; 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.devui.spi.JsonRPCProvidersBuildItem; import io.quarkus.devui.spi.page.CardPageBuildItem; import io.quarkus.devui.spi.page.Page; @@ -14,18 +19,21 @@ public class DevUIProcessor { @BuildStep(onlyIf = IsDevelopment.class) - public CardPageBuildItem pages(List services, - List 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; } @@ -34,4 +42,14 @@ public CardPageBuildItem pages(List services JsonRPCProvidersBuildItem createJsonRPCServiceForCache() { return new JsonRPCProvidersBuildItem(CxfJsonRPCService.class); } + + @BuildStep(onlyIf = IsDevelopment.class) + @Record(ExecutionTime.RUNTIME_INIT) + void collectClients(CombinedIndexBuildItem combinedIndexBuildItem, DevUiRecorder devuiRecorder) { + final List injectionPoints = CxfClientProcessor.findClientInjectionPoints( + combinedIndexBuildItem.getIndex()) + .collect(Collectors.toList()); + devuiRecorder.addClientInjectionPoints(injectionPoints); + } + } diff --git a/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-clients.js b/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-clients.js new file mode 100644 index 000000000..3c3958366 --- /dev/null +++ b/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-clients.js @@ -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`
No clients found
`; + } + } else { + return html``; + } + } + + _renderClientList(){ + return html` + + + + + + + + + `; + } + + _classNameRenderer(client){ + return html` + @CXFClient("${client.configKey}") + ${client.sei} + `; + } + + _addressRenderer(client) { + return html` +   + ${client.address} + `; + } + + _wsdlRenderer(client) { + return html` +   + ${client.wsdl} + `; + } + +} +customElements.define('qwc-cxf-clients', QwcCxfClients); \ No newline at end of file diff --git a/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-services.js b/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-services.js index 5bd586877..c5a0e3565 100644 --- a/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-services.js +++ b/extensions/core/deployment/src/main/resources/dev-ui/qwc-cxf-services.js @@ -1,18 +1,31 @@ -import { LitElement, html, css} from 'lit'; +import { LitElement, html, css} from 'lit'; import 'qui-card'; import '@vaadin/progress-bar'; -import '@vaadin/grid'; +import '@vaadin/grid'; import { columnBodyRenderer } from '@vaadin/grid/lit.js'; import { JsonRpc } from 'jsonrpc'; import 'qui-ide-link'; /** - * This component shows the List SOAP Web Services and clients + * This component shows the list of Service endpoints */ -export class QwcCxfServices extends LitElement { +export class QwcCxfServices extends LitElement { jsonRpc = new JsonRpc(this); - - static styles = css` + + static styles = css` + .cxf-table { + height: 100%; + padding-bottom: 10px; + } + + code { + font-size: 85%; + } + + .service-sei { + color: var(--lumo-contrast-50pct); + } + :host { display: flex; flex-direction:column; @@ -23,125 +36,67 @@ export class QwcCxfServices extends LitElement { .nothing-found { padding: 5px; }`; - + static properties = { - _services: {state: true}, - _clients: {state: true} + _services: {state: true} }; - - constructor() { + + constructor() { super(); this._services = null; - this._clients = null; } connectedCallback() { super.connectedCallback(); - this.jsonRpc.getServices().then(jsonRpcResponse => { + this.jsonRpc.getServices().then(jsonRpcResponse => { this._services = jsonRpcResponse.result; }); - this.jsonRpc.getClients().then(jsonRpcResponse => { - this._clients = jsonRpcResponse.result; - }); } - render() { - return html`${this._renderSoapServiceCard()} - ${this._renderSoapClientsCard()}`; - } - - _renderSoapServiceCard(){ - return html` -
- ${this._renderSoapServices()} -
-
`; - } - - _renderSoapServices(){ - if(this._services){ - if(this._services.length>0) { - return html` - - - - - - `; + render() { + if (this._services) { + if (this._services.length > 0) { + return this._renderServiceList(); }else { - return html`
No SOAP Services found
`; + return html`
No service endpoints found
`; } - }else{ + } else { return html``; } } - - _classNameRenderer(service){ - return html`${service.className}`; - } - - _pathRenderer(service) { - return html`${service.path}${service.relativePath}`; - } - - _renderSoapClientsCard(){ - return html` -
- ${this._renderSoapClients()} -
-
`; - } - - _renderSoapClients(){ - if(this._clients){ - if(this._clients.length>0) { - - return html` - - - - - `; - }else { - return html`
No SOAP Clients found
`; - } - }else{ - return html``; - } + _renderServiceList(){ + return html` + + + + + + `; } - - _seiRenderer(client){ - return html`${client.sei}`; + + _classNameRenderer(service){ + /* service.sei always the same as service.className + ${service.sei} + */ + return html` + ${service.className} + `; } - - _endpointAddressRenderer(client){ - if(client.wsdlUrl){ - return html`${client.wsdlUrl}`; - }else if(client.endpointAddress){ - return html`${client.endpointAddress}`; - }else { - return html`N/A`; - } + + _wsdlRenderer(service) { + return html`${service.path}${service.relativePath}?wsdl`; } - + } -customElements.define('qwc-cxf-services', QwcCxfServices); \ No newline at end of file +customElements.define('qwc-cxf-services', QwcCxfServices); diff --git a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CXFRecorder.java b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CXFRecorder.java index 2aa4ef59f..ef9ecdc75 100644 --- a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CXFRecorder.java +++ b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CXFRecorder.java @@ -142,6 +142,7 @@ public Handler initServer( public void resetDestinationRegistry(ShutdownContext context) { context.addShutdownTask(VertxDestinationFactory::resetRegistry); + context.addShutdownTask(CxfJsonRPCService::shutdown); } public void addRuntimeBusCustomizer(RuntimeValue> customizer) { diff --git a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/ClientInjectionPoint.java b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/ClientInjectionPoint.java new file mode 100644 index 000000000..79f60833b --- /dev/null +++ b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/ClientInjectionPoint.java @@ -0,0 +1,39 @@ +package io.quarkiverse.cxf; + +import java.util.Objects; + +public class ClientInjectionPoint { + private final String configKey; + private final Class sei; + + public ClientInjectionPoint(String configKey, Class sei) { + super(); + this.configKey = configKey; + this.sei = sei; + } + + public String getConfigKey() { + return configKey; + } + + public Class getSei() { + return sei; + } + + @Override + public int hashCode() { + return Objects.hash(configKey, sei); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ClientInjectionPoint other = (ClientInjectionPoint) obj; + return Objects.equals(configKey, other.configKey) && Objects.equals(sei, other.sei); + } +} \ No newline at end of file diff --git a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CxfClientProducer.java b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CxfClientProducer.java index c323b0ebc..3a701cab4 100644 --- a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CxfClientProducer.java +++ b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/CxfClientProducer.java @@ -5,6 +5,7 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Annotation; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -146,6 +147,7 @@ private Object produceCxfClient(CXFClientInfo cxfClientInfo) { QuarkusJaxWsProxyFactoryBean factory = new QuarkusJaxWsProxyFactoryBean(quarkusClientFactoryBean, interfaces); final Map props = new LinkedHashMap<>(); factory.setProperties(props); + props.put(CXFClientInfo.class.getName(), cxfClientInfo); factory.setServiceClass(seiClass); LOGGER.debugf("using servicename {%s}%s", cxfClientInfo.getWsNamespace(), cxfClientInfo.getWsName()); factory.setServiceName(new QName(cxfClientInfo.getWsNamespace(), cxfClientInfo.getWsName())); @@ -376,9 +378,11 @@ protected static CXFClientInfo selectorCXFClientInfo( // If injection point is annotated with @CXFClient then determine a // configuration by looking up annotated config value: - if (ip.getAnnotated().isAnnotationPresent(CXFClient.class)) { - CXFClient anno = ip.getAnnotated().getAnnotation(CXFClient.class); - String configKey = anno.value(); + Optional cxfClientAnnot = ip.getQualifiers().stream() + .filter(an -> an.annotationType().equals(CXFClient.class)).findFirst(); + if (cxfClientAnnot.isPresent()) { + CXFClient annot = (CXFClient) cxfClientAnnot.get(); + String configKey = annot.value(); if (config.isClientPresent(configKey)) { return new CXFClientInfo(meta, config.getClient(configKey), configKey); @@ -387,7 +391,7 @@ protected static CXFClientInfo selectorCXFClientInfo( // If config-key is present and not default: This is an error: if (configKey != null && !configKey.isEmpty()) { throw new IllegalStateException( - "quarkus.cxf.\"" + configKey + "\" is referenced in " + ip.getMember() + "quarkus.cxf.client.\"" + configKey + "\" is referenced in " + ip.getMember() + " but no such build time configuration entry exists"); } } diff --git a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/CxfJsonRPCService.java b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/CxfJsonRPCService.java index 9d5c23b06..93a05b5c4 100644 --- a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/CxfJsonRPCService.java +++ b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/CxfJsonRPCService.java @@ -1,41 +1,86 @@ package io.quarkiverse.cxf.devui; import java.util.ArrayList; -import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; -import jakarta.enterprise.inject.spi.CDI; +import jakarta.enterprise.util.AnnotationLiteral; +import jakarta.xml.ws.BindingProvider; import io.quarkiverse.cxf.CXFClientInfo; import io.quarkiverse.cxf.CXFServletInfo; import io.quarkiverse.cxf.CXFServletInfos; +import io.quarkiverse.cxf.ClientInjectionPoint; +import io.quarkiverse.cxf.annotation.CXFClient; +import io.quarkus.arc.Arc; public class CxfJsonRPCService { - private static CXFServletInfos cxfServletInfos; + private static List servletInfos = Collections.emptyList(); + private static List clientInjectionPoints = Collections.emptyList(); public List getServices() { - List servletInfos = cxfServletInfos != null ? new ArrayList<>(cxfServletInfos.getInfos()) - : new ArrayList<>(); - servletInfos.sort(Comparator.comparing(CXFServletInfo::getSei)); return servletInfos; } - public List getClients() { - List clientInfos = new ArrayList<>(allClientInfos()); - clientInfos.sort(Comparator.comparing(CXFClientInfo::getSei)); - return clientInfos; + public int getServiceCount() { + return servletInfos.size(); + } + + public int getClientCount() { + return clientInjectionPoints.size(); } - private static Collection allClientInfos() { - return CDI.current().select(CXFClientInfo.class).stream().collect(Collectors.toCollection(ArrayList::new)); + public List getClients() { + List result = new ArrayList<>(clientInjectionPoints.size()); + for (ClientInjectionPoint ip : clientInjectionPoints) { + + final Object rawClient = Arc.container().instance(ip.getSei(), new CxfClientAnnotationLiteral(ip.getConfigKey())) + .get(); + if (rawClient instanceof BindingProvider) { + final CXFClientInfo clientInfo = (CXFClientInfo) ((BindingProvider) rawClient).getRequestContext() + .get(CXFClientInfo.class.getName()); + final DevUiClientInfo devUiIInfo = new DevUiClientInfo(ip.getConfigKey(), ip.getSei().getName(), + clientInfo.getEndpointAddress(), clientInfo.getWsdlUrl()); + result.add(devUiIInfo); + } + } + result.sort(Comparator.comparing(DevUiClientInfo::getSei)); + return result; + } + + public static void setClientInjectionPoints(List injectionPoints) { + clientInjectionPoints = Collections.unmodifiableList(new ArrayList<>(injectionPoints)); } public static void setServletInfos(CXFServletInfos infos) { - if (cxfServletInfos == null) { - cxfServletInfos = infos; + List tmp = infos != null ? new ArrayList<>(infos.getInfos()) + : new ArrayList<>(); + tmp.sort(Comparator.comparing(CXFServletInfo::getSei)); + servletInfos = Collections.unmodifiableList(tmp); + } + + public static void shutdown() { + servletInfos = Collections.emptyList(); + clientInjectionPoints = Collections.emptyList(); + } + + public static final class CxfClientAnnotationLiteral extends AnnotationLiteral implements CXFClient { + private static final long serialVersionUID = 1L; + + private final String value; + + public CxfClientAnnotationLiteral(String value) { + super(); + this.value = value; } + + @Override + public String value() { + return value; + } + } + } diff --git a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiClientInfo.java b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiClientInfo.java new file mode 100644 index 000000000..fcaaaa698 --- /dev/null +++ b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiClientInfo.java @@ -0,0 +1,39 @@ +package io.quarkiverse.cxf.devui; + +public class DevUiClientInfo { + + private final String configKey; + private final String sei; + private final String address; + private final String wsdl; + + public DevUiClientInfo(String configKey, String sei, String address, String wsdl) { + super(); + this.configKey = configKey; + this.sei = sei; + this.address = address; + this.wsdl = wsdl; + } + + public String getConfigKey() { + return configKey; + } + + public String getSei() { + return sei; + } + + public String getAddress() { + return address; + } + + public String getWsdl() { + return wsdl; + } + + @Override + public String toString() { + return "DevUiClientInfo [configKey=" + configKey + ", sei=" + sei + ", address=" + address + ", wsdl=" + wsdl + "]"; + } + +} \ No newline at end of file diff --git a/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiRecorder.java b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiRecorder.java new file mode 100644 index 000000000..9117e5cdf --- /dev/null +++ b/extensions/core/runtime/src/main/java/io/quarkiverse/cxf/devui/DevUiRecorder.java @@ -0,0 +1,13 @@ +package io.quarkiverse.cxf.devui; + +import java.util.List; + +import io.quarkiverse.cxf.ClientInjectionPoint; +import io.quarkus.runtime.annotations.Recorder; + +@Recorder +public class DevUiRecorder { + public void addClientInjectionPoints(List injectionPoints) { + CxfJsonRPCService.setClientInjectionPoints(injectionPoints); + } +}