Merge branch 'develop' into service-test
diff --git a/dubbo-admin-backend/pom.xml b/dubbo-admin-backend/pom.xml
index 0e29b39..8d04e90 100644
--- a/dubbo-admin-backend/pom.xml
+++ b/dubbo-admin-backend/pom.xml
@@ -87,6 +87,10 @@
</exclusions>
</dependency>
<dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-recipes</artifactId>
+ </dependency>
+ <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
new file mode 100644
index 0000000..ad84fd0
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.admin.common.util;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.admin.model.domain.MethodMetadata;
+import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
+import org.apache.dubbo.metadata.definition.model.MethodDefinition;
+import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
+import org.apache.dubbo.metadata.definition.model.TypeDefinition;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class ServiceTestUtil {
+ private static Pattern COLLECTION_PATTERN = Pattern.compile("^java\\.util\\..*(Set|List|Queue|Collection|Deque)(<.*>)*$");
+ private static Pattern MAP_PATTERN = Pattern.compile("^java\\.util\\..*Map.*(<.*>)*$");
+
+ public static boolean sameMethod(MethodDefinition m, String methodSig) {
+ String name = m.getName();
+ String[] parameters = m.getParameterTypes();
+ StringBuilder sb = new StringBuilder();
+ sb.append(name).append("~");
+ for (String parameter : parameters) {
+ sb.append(parameter).append(";");
+ }
+ String sig = StringUtils.removeEnd(sb.toString(), ";");
+ return sig.equals(methodSig);
+ }
+
+ public static MethodMetadata generateMethodMeta(FullServiceDefinition serviceDefinition, MethodDefinition methodDefinition) {
+ MethodMetadata methodMetadata = new MethodMetadata();
+ String[] parameterTypes = methodDefinition.getParameterTypes();
+ String returnType = methodDefinition.getReturnType();
+ String signature = methodDefinition.getName() + "~" + Arrays.stream(parameterTypes).collect(Collectors.joining(";"));
+ methodMetadata.setSignature(signature);
+ methodMetadata.setReturnType(returnType);
+ List parameters = generateParameterTypes(parameterTypes, serviceDefinition);
+ methodMetadata.setParameterTypes(parameters);
+ return methodMetadata;
+ }
+
+ private static boolean isPrimitiveType(TypeDefinition td) {
+ String type = td.getType();
+ return type.equals("byte") || type.equals("java.lang.Byte") ||
+ type.equals("short") || type.equals("java.lang.Short") ||
+ type.equals("int") || type.equals("java.lang.Integer") ||
+ type.equals("long") || type.equals("java.lang.Long") ||
+ type.equals("float") || type.equals("java.lang.Float") ||
+ type.equals("double") || type.equals("java.lang.Double") ||
+ type.equals("boolean") || type.equals("java.lang.Boolean") ||
+ type.equals("void") || type.equals("java.lang.Void") ||
+ type.equals("java.lang.String") ||
+ type.equals("java.util.Date") ||
+ type.equals("java.lang.Object");
+ }
+
+ private static List generateParameterTypes(String[] parameterTypes, ServiceDefinition serviceDefinition) {
+ List parameters = new ArrayList();
+ for (String type : parameterTypes) {
+ Object result = generateType(serviceDefinition, type);
+ parameters.add(result);
+ }
+ return parameters;
+ }
+
+ private static TypeDefinition findTypeDefinition(ServiceDefinition serviceDefinition, String type) {
+ return serviceDefinition.getTypes().stream()
+ .filter(t -> t.getType().equals(type))
+ .findFirst().orElse(new TypeDefinition(type));
+ }
+
+ private static void generateComplexType(ServiceDefinition sd, TypeDefinition td, Map holder) {
+ for (Map.Entry<String, TypeDefinition> entry : td.getProperties().entrySet()) {
+ if (isPrimitiveType(td)) {
+ holder.put(entry.getKey(), generatePrimitiveType(td));
+ } else {
+ generateEnclosedType(holder, entry.getKey(), sd, entry.getValue());
+ }
+ }
+ }
+ private static Object generateComplexType(ServiceDefinition sd, TypeDefinition td) {
+ Map<String, Object> holder = new HashMap<>();
+ generateComplexType(sd, td, holder);
+ return holder;
+ }
+
+ private static boolean isMap(TypeDefinition td) {
+ String type = StringUtils.substringBefore(td.getType(), "<");
+ Matcher matcher = MAP_PATTERN.matcher(type);
+ return matcher.matches();
+ }
+
+ private static boolean isCollection(TypeDefinition td) {
+ String type = StringUtils.substringBefore(td.getType(), "<");
+ Matcher matcher = COLLECTION_PATTERN.matcher(type);
+ return matcher.matches();
+ }
+
+ private static boolean isArray(TypeDefinition td) {
+ return StringUtils.endsWith(td.getType(), "[]");
+ }
+
+ private static Object generatePrimitiveType(TypeDefinition td) {
+ String type = td.getType();
+ switch (type) {
+ case "byte":
+ case "java.lang.Byte":
+ case "short":
+ case "java.lang.Short":
+ case "int":
+ case "java.lang.Integer":
+ case "long":
+ case "java.lang.Long":
+ return 0;
+ case "float":
+ case "java.lang.Float":
+ case "double":
+ case "java.lang.Double":
+ return 0.0;
+ case "boolean":
+ case "java.lang.Boolean":
+ return true;
+ case "void":
+ case "java.lang.Void":
+ return null;
+ case "java.lang.String":
+ return "";
+ case "java.lang.Object":
+ return Collections.emptyMap();
+ case "java.util.Date":
+ return System.currentTimeMillis();
+ default:
+ return Collections.emptyMap();
+ }
+ }
+
+ private static Object generateType(ServiceDefinition sd, String type) {
+ TypeDefinition td = findTypeDefinition(sd, type);
+ return generateType(sd, td);
+ }
+
+ private static Object generateType(ServiceDefinition sd, TypeDefinition td) {
+ if (isPrimitiveType(td)) {
+ return generatePrimitiveType(td);
+ } else if (isMap(td)) {
+ return generateMapType(sd, td);
+ } else if (isArray(td)) {
+ return generateArrayType(sd, td);
+ } else if (isCollection(td)) {
+ return generateCollectionType(sd, td);
+ } else {
+ return generateComplexType(sd, td);
+ }
+ }
+
+ private static Object generateMapType(ServiceDefinition sd, TypeDefinition td) {
+ String keyType = StringUtils.substringAfter(td.getType(), "<");
+ keyType = StringUtils.substringBefore(keyType, ",");
+ keyType = StringUtils.strip(keyType);
+
+ Map<Object, Object> map = new HashMap<>();
+ // 生成 key 默认值
+ Object key = generateType(sd, keyType);
+
+ // 生成 value 默认值
+ String valueType = StringUtils.substringAfter(td.getType(), ",");
+ valueType = StringUtils.substringBefore(valueType, ">");
+ valueType = StringUtils.strip(valueType);
+ valueType = StringUtils.isNotEmpty(valueType) ? valueType : "java.lang.Object";
+ Object value = generateType(sd, valueType);
+ map.put(key, value);
+ return map;
+ }
+
+ private static Object generateCollectionType(ServiceDefinition sd, TypeDefinition td) {
+ String type = StringUtils.substringAfter(td.getType(), "<");
+ type = StringUtils.substringBefore(type, ">");
+ if (StringUtils.isEmpty(type)) {
+ // 如果 collection 类型未声明,则生成空 collection
+ return new Object[] {};
+ }
+ return new Object[]{generateType(sd, type)};
+
+ }
+ private static Object generateArrayType(ServiceDefinition sd, TypeDefinition td) {
+ String type = StringUtils.substringBeforeLast(td.getType(), "[]");
+ return new Object[]{generateType(sd, type)};
+ }
+
+ private static void generateEnclosedType(Map<String, Object> holder, String key, ServiceDefinition sd, TypeDefinition td) {
+ if (td.getProperties() == null || td.getProperties().size() == 0 || isPrimitiveType(td)) {
+ holder.put(key, generateType(sd, td));
+ } else {
+ Map<String, Object> enclosedMap = new HashMap<>();
+ holder.put(key, enclosedMap);
+ generateComplexType(sd, td, enclosedMap);
+ }
+ }
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
index 0b48ec0..dfbc607 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
@@ -82,6 +82,10 @@
FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
serviceDetailDTO.setMetadata(serviceDefinition);
}
+ serviceDetailDTO.setConsumers(consumers);
+ serviceDetailDTO.setProviders(providers);
+ serviceDetailDTO.setService(service);
+ serviceDetailDTO.setApplication(application);
return serviceDetailDTO;
}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
new file mode 100644
index 0000000..bf0497b
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
@@ -0,0 +1,60 @@
+package org.apache.dubbo.admin.controller;
+
+import com.google.gson.Gson;
+import org.apache.dubbo.admin.common.util.ConvertUtil;
+import org.apache.dubbo.admin.common.util.ServiceTestUtil;
+import org.apache.dubbo.admin.model.domain.MethodMetadata;
+import org.apache.dubbo.admin.model.dto.ServiceTestDTO;
+import org.apache.dubbo.admin.service.ProviderService;
+import org.apache.dubbo.admin.service.impl.GenericServiceImpl;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
+import org.apache.dubbo.metadata.definition.model.MethodDefinition;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/{env}/test")
+public class ServiceTestController {
+
+ @Autowired
+ private GenericServiceImpl genericService;
+
+ @Autowired
+ private ProviderService providerService;
+
+ @RequestMapping(method = RequestMethod.POST)
+ public Object test(@PathVariable String env, @RequestBody ServiceTestDTO serviceTestDTO) {
+ return genericService.invoke(serviceTestDTO.getService(), serviceTestDTO.getMethod(), serviceTestDTO.getParamaterTypes(), serviceTestDTO.getParams());
+// return null;
+ }
+
+ @RequestMapping(value = "/method", method = RequestMethod.GET)
+ public MethodMetadata methodDetail(@PathVariable String env, @RequestParam String application, @RequestParam String service,
+ @RequestParam String method) {
+ Map<String, String> info = ConvertUtil.serviceName2Map(service);
+ MetadataIdentifier identifier = new MetadataIdentifier(info.get(Constants.INTERFACE_KEY),
+ info.get(Constants.VERSION_KEY),
+ info.get(Constants.GROUP_KEY), Constants.PROVIDER_SIDE, application);
+ String metadata = providerService.getProviderMetaData(identifier);
+ MethodMetadata methodMetadata = null;
+ if (metadata != null) {
+ Gson gson = new Gson();
+ FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
+ List<MethodDefinition> methods = serviceDefinition.getMethods();
+ if (methods != null) {
+ for (MethodDefinition m : methods) {
+ if (ServiceTestUtil.sameMethod(m, method)) {
+ methodMetadata = ServiceTestUtil.generateMethodMeta(serviceDefinition, m);
+ break;
+ }
+ }
+ }
+ }
+ return methodMetadata;
+ }
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/domain/MethodMetadata.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/domain/MethodMetadata.java
new file mode 100644
index 0000000..25a98c9
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/domain/MethodMetadata.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.admin.model.domain;
+
+import java.util.List;
+import java.util.Map;
+
+public class MethodMetadata {
+ private String signature;
+ private List parameterTypes;
+ private String returnType;
+
+ public String getSignature() {
+ return signature;
+ }
+
+ public void setSignature(String signature) {
+ this.signature = signature;
+ }
+
+ public List getParameterTypes() {
+ return parameterTypes;
+ }
+
+ public void setParameterTypes(List parameterTypes) {
+ this.parameterTypes = parameterTypes;
+ }
+
+ public String getReturnType() {
+ return returnType;
+ }
+
+ public void setReturnType(String returnType) {
+ this.returnType = returnType;
+ }
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/MethodDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/MethodDTO.java
new file mode 100644
index 0000000..fdd6ffb
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/MethodDTO.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.admin.model.dto;
+
+
+
+import java.util.List;
+
+public class MethodDTO {
+ private String application;
+ private String service;
+ private String name;
+ private List<String> parameterTypes;
+ private String returnType;
+
+ public String getApplication() {
+ return application;
+ }
+
+ public void setApplication(String application) {
+ this.application = application;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+ public void setService(String service) {
+ this.service = service;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<String> getParameterTypes() {
+ return parameterTypes;
+ }
+
+ public void setParameterTypes(List<String> parameterTypes) {
+ this.parameterTypes = parameterTypes;
+ }
+
+ public String getReturnType() {
+ return returnType;
+ }
+
+ public void setReturnType(String returnType) {
+ this.returnType = returnType;
+ }
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
index 2a738f5..1ef4beb 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
@@ -27,9 +27,26 @@
List<Provider> providers;
List<Consumer> consumers;
+ private String service;
+ private String application;
FullServiceDefinition metadata;
+ public String getService() {
+ return service;
+ }
+
+ public void setService(String service) {
+ this.service = service;
+ }
+
+ public String getApplication() {
+ return application;
+ }
+
+ public void setApplication(String application) {
+ this.application = application;
+ }
public List<Provider> getProviders() {
return providers;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java
new file mode 100644
index 0000000..7a398f7
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java
@@ -0,0 +1,40 @@
+package org.apache.dubbo.admin.model.dto;
+
+public class ServiceTestDTO {
+ private String service;
+ private String method;
+ private String[] paramaterTypes;
+ private Object[] params;
+
+ public String getService() {
+ return service;
+ }
+
+ public void setService(String service) {
+ this.service = service;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String[] getParamaterTypes() {
+ return paramaterTypes;
+ }
+
+ public void setParamaterTypes(String[] paramaterTypes) {
+ this.paramaterTypes = paramaterTypes;
+ }
+
+ public Object[] getParams() {
+ return params;
+ }
+
+ public void setParams(Object[] params) {
+ this.params = params;
+ }
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/GenericServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/GenericServiceImpl.java
new file mode 100644
index 0000000..469ec9e
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/GenericServiceImpl.java
@@ -0,0 +1,50 @@
+package org.apache.dubbo.admin.service.impl;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.rpc.service.GenericService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@Component
+public class GenericServiceImpl {
+
+ private ReferenceConfig<GenericService> reference;
+
+ @Autowired
+ private Registry registry;
+
+ @PostConstruct
+ public void init() {
+ reference = new ReferenceConfig<>();
+ reference.setGeneric(true);
+
+ RegistryConfig registryConfig = new RegistryConfig();
+ registryConfig.setAddress(registry.getUrl().getProtocol() + "://" + registry.getUrl().getAddress());
+
+ ApplicationConfig applicationConfig = new ApplicationConfig();
+ applicationConfig.setName("dubbo-admin");
+ applicationConfig.setRegistry(registryConfig);
+
+ reference.setApplication(applicationConfig);
+ }
+
+ public Object invoke(String service, String method, String[] parameterTypes, Object[] params) {
+
+ reference.setInterface(service);
+ GenericService genericService = reference.get();
+ Object result = genericService.$invoke(method, parameterTypes, params);
+ System.out.println(result);
+ return result;
+ }
+
+ public static void main(String[] args) {
+ GenericServiceImpl genericService = new GenericServiceImpl();
+ genericService.init();
+ genericService.invoke("org.apache.dubbo.demo.api.DemoService", "sayHello", new String[]{"java.lang.String"}, new Object[]{"hello"});
+ }
+}
diff --git a/dubbo-admin-frontend/package.json b/dubbo-admin-frontend/package.json
index 3625632..6a0a9ce 100644
--- a/dubbo-admin-frontend/package.json
+++ b/dubbo-admin-frontend/package.json
@@ -15,6 +15,7 @@
"brace": "^0.11.1",
"http-status": "^1.2.0",
"js-yaml": "^3.12.0",
+ "jsoneditor": "^5.26.2",
"vue": "^2.5.2",
"vue-i18n": "^8.6.0",
"vue-router": "^3.0.1",
diff --git a/dubbo-admin-frontend/src/components/public/Footers.vue b/dubbo-admin-frontend/src/components/public/Footers.vue
index a5bbab6..331bea7 100644
--- a/dubbo-admin-frontend/src/components/public/Footers.vue
+++ b/dubbo-admin-frontend/src/components/public/Footers.vue
@@ -16,7 +16,7 @@
-->
<template>
- <v-footer inset height="auto" class="pa-3 footer-border-top" app>
+ <v-footer inset height="auto" class="pa-3 footer-border-top">
<v-spacer></v-spacer>
<span class="caption mr-1"><strong>Copyright</strong> ©{{ new Date().getFullYear() }} <strong>The Apache Software Foundation.</strong></span>
</v-footer>
diff --git a/dubbo-admin-frontend/src/components/public/JsonEditor.vue b/dubbo-admin-frontend/src/components/public/JsonEditor.vue
new file mode 100644
index 0000000..327e5ff
--- /dev/null
+++ b/dubbo-admin-frontend/src/components/public/JsonEditor.vue
@@ -0,0 +1,84 @@
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements. See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+<template>
+ <div class="jsoneditor-vue-container"></div>
+</template>
+
+<script>
+ import JSONEditor from 'jsoneditor'
+ import 'jsoneditor/dist/jsoneditor.css'
+
+ export default {
+ name: 'json-editor',
+ props: {
+ value: null,
+ mode: {
+ type: String,
+ default: 'tree'
+ },
+ modes: {
+ type: Array,
+ default: () => ['tree', 'code']
+ },
+ templates: Array
+ },
+ data () {
+ return {
+ $jsoneditor: null
+ }
+ },
+ watch: {
+ value (newVal, oldVal) {
+ if (newVal !== oldVal && this.$jsoneditor) {
+ this.$jsoneditor.update(newVal)
+ }
+ }
+ },
+ mounted () {
+ const options = {
+ name: 'Parameters',
+ navigationBar: false,
+ search: false,
+ mode: this.mode,
+ modes: this.modes,
+ onChange: () => {
+ if (this.$jsoneditor) {
+ var json = this.$jsoneditor.get()
+ this.$emit('input', json)
+ }
+ },
+ templates: this.templates
+ }
+ this.$jsoneditor = new JSONEditor(this.$el, options)
+ this.$jsoneditor.set(this.value)
+ this.$jsoneditor.expandAll()
+ },
+ beforeDestroy () {
+ if (this.$jsoneditor) {
+ this.$jsoneditor.destroy()
+ this.$jsoneditor = null
+ }
+ }
+ }
+</script>
+
+<style scoped>
+ .jsoneditor-vue-container {
+ width: 100%;
+ height: 100%;
+ }
+</style>
diff --git a/dubbo-admin-frontend/src/components/test/ServiceTest.vue b/dubbo-admin-frontend/src/components/test/ServiceTest.vue
index 971e2f4..a9568ad 100644
--- a/dubbo-admin-frontend/src/components/test/ServiceTest.vue
+++ b/dubbo-admin-frontend/src/components/test/ServiceTest.vue
@@ -14,32 +14,199 @@
- See the License for the specific language governing permissions and
- limitations under the License.
-->
-
<template>
- <v-container
- fill-height
- >
- <v-layout align-center>
- <v-flex text-xs-center>
- <h1 class="display-2 primary--text">{{$t('later.serviceTest')}}</h1>
- <v-btn
- href="#/service"
- color="primary"
- outline
- >
- {{$t('goIndex')}}
- </v-btn>
+ <v-container grid-list-xl fluid>
+ <v-layout row wrap>
+ <v-flex xs12>
+ <search id="serviceSearch" v-model="filter" label="Search by service name" :submit="search"></search>
+ </v-flex>
+ <v-flex xs12>
+ <h3>Methods</h3>
+ </v-flex>
+ <v-flex xs12>
+ <v-data-table :headers="headers" :items="methods" hide-actions class="elevation-1">
+ <template slot="items" slot-scope="props">
+ <td>{{ props.item.name }}</td>
+ <td><v-chip xs v-for="(type, index) in props.item.parameterTypes" :key="index" label>{{ type }}</v-chip></td>
+ <td><v-chip label>{{ props.item.returnType }}</v-chip></td>
+ <td class="text-xs-right">
+ <v-tooltip bottom>
+ <v-btn
+ fab dark small color="blue" slot="activator"
+ :href="getHref(props.item.application, props.item.service, props.item.signature)"
+ >
+ <v-icon>edit</v-icon>
+ </v-btn>
+ <span>Try it</span>
+ </v-tooltip>
+ </td>
+ </template>
+ </v-data-table>
</v-flex>
</v-layout>
+
+ <v-dialog v-model="modal.enable" width="1000px" persistent>
+ <v-card>
+ <v-card-title>
+ <span class="headline">Test {{ modal.method }}</span>
+ </v-card-title>
+ <v-container grid-list-xl fluid>
+ <v-layout row>
+ <v-flex lg6>
+ <json-editor v-model="modal.json" />
+ </v-flex>
+ <v-flex lg6>
+ <json-editor v-model="modal.json" />
+ </v-flex>
+ </v-layout>
+ </v-container>
+ <v-card-actions>
+ <v-spacer></v-spacer>
+ <v-btn color="darken-1"
+ flat
+ @click="modal.enable = false">Close</v-btn>
+ <v-btn color="primary"
+ depressed
+ @click="test">Execute</v-btn>
+ </v-card-actions>
+ </v-card>
+ </v-dialog>
</v-container>
</template>
<script>
+ import JsonEditor from '@/components/public/JsonEditor'
+ import Search from '@/components/public/Search'
+
export default {
- name: 'ServiceTest'
+ name: 'ServiceTest',
+ data () {
+ return {
+ filter: '',
+ headers: [
+ {
+ text: 'Method Name',
+ value: 'method',
+ sortable: false
+ },
+ {
+ text: 'Parameter List',
+ value: 'parameter',
+ sortable: false
+ },
+ {
+ text: 'Return Type',
+ value: 'returnType',
+ sortable: false
+ },
+ {
+ text: '',
+ value: 'operation',
+ sortable: false
+ }
+ ],
+ service: null,
+ methods: [],
+ modal: {
+ method: null,
+ enable: false,
+ paramaterTypes: null,
+ json: []
+ }
+ }
+ },
+ methods: {
+ search () {
+ if (!this.filter) {
+ this.filter = document.querySelector('#serviceSearch').value.trim()
+ if (!this.filter) {
+ return
+ }
+ }
+ this.$router.push({
+ path: 'test',
+ query: { service: this.filter }
+ })
+ this.$axios.get('/service/' + this.filter).then(response => {
+ this.service = response.data
+ if (this.service.hasOwnProperty('metadata')) {
+ let data = this.service.metadata.methods
+ for (let i = 0; i < data.length; i++) {
+ let method = {}
+ let sig = data[i].name + '~'
+ let parameters = data[i].parameterTypes
+ let length = parameters.length
+ for (let j = 0; j < length; j++) {
+ sig = sig + parameters[j]
+ if (j !== length - 1) {
+ sig = sig + ';'
+ }
+ }
+ method.signature = sig
+ method.name = data[i].name
+ method.parameterTypes = data[i].parameterTypes
+ method.returnType = data[i].returnType
+ method.service = response.data.service
+ method.application = response.data.application
+ this.methods.push(method)
+ }
+ }
+ }).catch(error => {
+ this.showSnackbar('error', error.response.data.message)
+ })
+ },
+ toTest (item) {
+ Object.assign(this.modal, {
+ enable: true,
+ method: item.name
+ })
+ this.modal.json = []
+ this.modal.paramaterTypes = item.parameterTypes
+ item.parameterTypes.forEach((i, index) => {
+ this.modal.json.push(this.getType(i))
+ })
+ },
+ getHref (application, service, method) {
+ let base = '/#/testMethod?'
+ let query = 'application=' + application + '&service=' + service + '&method=' + method
+ return base + query
+ },
+ test () {
+ this.$axios.post('/test', {
+ service: this.service.metadata.canonicalName,
+ method: this.modal.method,
+ paramaterTypes: this.modal.paramaterTypes,
+ params: this.modal.json
+ }).then(response => {
+ console.log(response)
+ })
+ },
+ getType (type) {
+ if (type.indexOf('java.util.List') === 0) {
+ return []
+ } else if (type.indexOf('java.util.Map') === 0) {
+ return []
+ } else {
+ return ''
+ }
+ }
+ },
+ mounted: function () {
+ let query = this.$route.query
+ let filter = null
+ Object.keys(query).forEach(function (key) {
+ if (key === 'service') {
+ filter = query[key]
+ }
+ })
+ if (filter !== null) {
+ this.filter = filter
+ this.search()
+ }
+ },
+ components: {
+ JsonEditor,
+ Search
+ }
}
</script>
-
-<style scoped>
-
-</style>
diff --git a/dubbo-admin-frontend/src/components/test/TestMethod.vue b/dubbo-admin-frontend/src/components/test/TestMethod.vue
new file mode 100644
index 0000000..9657f92
--- /dev/null
+++ b/dubbo-admin-frontend/src/components/test/TestMethod.vue
@@ -0,0 +1,129 @@
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements. See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+<template>
+ <v-container grid-list-xl fluid>
+ <v-layout row wrap>
+ <v-flex lg12>
+ </v-flex>
+ <v-flex lg12>
+ <v-card>
+ <v-flex lg8>
+ <v-card-title>
+ <span>Service: {{service}}<br> Method: {{method.name}}</span>
+ </v-card-title>
+ <v-card-text>
+ <json-editor id="test" v-model="method.json"/>
+ </v-card-text>
+ <v-card-actions>
+ <v-spacer></v-spacer>
+ <v-btn id="execute" mt-0 color="primary" @click="executeMethod()">EXECUTE</v-btn>
+ </v-card-actions>
+ </v-flex>
+ <v-flex lg8>
+ <v-card-text>
+ <h2>Test Result</h2>
+ <json-editor id="result" v-model="result" v-if="showResult"></json-editor>
+ </v-card-text>
+ </v-flex>
+ </v-card>
+ </v-flex>
+
+ </v-layout>
+
+ </v-container>
+</template>
+
+<script>
+ import JsonEditor from '@/components/public/JsonEditor'
+ export default {
+ name: 'TestMethod',
+ data () {
+ return {
+ basic: [],
+ service: null,
+ application: null,
+ method: {
+ name: null,
+ parameterTypes: [],
+ json: []
+ },
+ showResult: false,
+ result: {}
+ }
+ },
+
+ methods: {
+ executeMethod: function () {
+ let serviceTestDTO = {}
+ serviceTestDTO.service = this.service
+ serviceTestDTO.method = this.method.name
+ serviceTestDTO.parameterType = this.method.parameterTypes
+ serviceTestDTO.params = this.method.json
+ this.$axios.post('/test', serviceTestDTO)
+ .then(response => {
+ if (response.status === 200) {
+ this.result = response.data
+ this.showResult = true
+ }
+ })
+ }
+ },
+
+ mounted: function () {
+ let query = this.$route.query
+ let vm = this
+ let method = null
+ Object.keys(query).forEach(function (key) {
+ if (key === 'service') {
+ let item = {}
+ item.name = 'service'
+ item.value = query[key]
+ vm.basic.push(item)
+ vm.service = query[key]
+ }
+ if (key === 'method') {
+ let item = {}
+ item.name = 'method'
+ item.value = query[key]
+ vm.method.name = query[key].split('~')[0]
+ method = query[key]
+ vm.basic.push(item)
+ }
+ if (key === 'application') {
+ vm.application = query[key]
+ }
+ })
+ this.$axios.get('/test/method', {
+ params: {
+ application: vm.application,
+ service: vm.service,
+ method: method
+ }
+ }).then(response => {
+ this.method.json = response.data.parameterTypes
+ })
+ },
+ components: {
+ JsonEditor
+ }
+
+ }
+</script>
+
+<style scoped>
+</style>
diff --git a/dubbo-admin-frontend/src/router/index.js b/dubbo-admin-frontend/src/router/index.js
index 2ef4da4..35f8a90 100644
--- a/dubbo-admin-frontend/src/router/index.js
+++ b/dubbo-admin-frontend/src/router/index.js
@@ -19,6 +19,7 @@
import Router from 'vue-router'
import ServiceSearch from '@/components/ServiceSearch'
import ServiceDetail from '@/components/ServiceDetail'
+import TestMethod from '@/components/test/TestMethod'
import RoutingRule from '@/components/governance/RoutingRule'
import TagRule from '@/components/governance/TagRule'
import AccessControl from '@/components/governance/AccessControl'
@@ -45,6 +46,11 @@
component: ServiceDetail
},
{
+ path: '/testMethod',
+ name: 'TestMethod',
+ component: TestMethod
+ },
+ {
path: '/governance/routingRule',
name: 'RoutingRule',
component: RoutingRule
diff --git a/pom.xml b/pom.xml
index ad77093..c858050 100644
--- a/pom.xml
+++ b/pom.xml
@@ -111,6 +111,17 @@
</dependency>
<dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-recipes</artifactId>
+ <version>${curator-version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson-version}</version>