You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2019/07/08 06:56:27 UTC
[servicecomb-java-chassis] 01/02: [SCB-1348[WIP][WEAK] change
SchemaLoader to SwaggerLoader
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch weak-contract-type
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
commit 54af14c81cd849027ab8d715aac2c5f7f46da330
Author: wujimin <wu...@huawei.com>
AuthorDate: Sat Jul 6 22:12:29 2019 +0800
[SCB-1348[WIP][WEAK] change SchemaLoader to SwaggerLoader
---
.../servicecomb/serviceregistry/RegistryUtils.java | 4 +
.../consumer/StaticMicroserviceVersions.java | 7 +-
.../registry/ServiceRegistryFactory.java | 3 +-
.../serviceregistry/swagger/SwaggerLoader.java | 90 ++++++++++++++++++----
.../serviceregistry/swagger/TestSwaggerLoader.java | 84 +++++++++++++++++++-
5 files changed, 166 insertions(+), 22 deletions(-)
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index e75eeec..cdfad6b 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -58,6 +58,10 @@ public final class RegistryUtils {
}
public static void init() {
+ if (serviceRegistry != null) {
+ return;
+ }
+
MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader();
MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels());
serviceRegistry =
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java
index 99b144a..1df2a23 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java
@@ -25,6 +25,9 @@ import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse;
import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
import org.apache.servicecomb.serviceregistry.version.Version;
+import org.apache.servicecomb.swagger.SwaggerUtils;
+
+import io.swagger.models.Swagger;
public class StaticMicroserviceVersions extends MicroserviceVersions {
private Class<?> schemaIntfCls;
@@ -40,7 +43,9 @@ public class StaticMicroserviceVersions extends MicroserviceVersions {
public StaticMicroserviceVersions init(Class<?> schemaIntfCls, String version,
List<MicroserviceInstance> addedInstances) {
this.schemaIntfCls = schemaIntfCls;
- this.appManager.getServiceRegistry().getSwaggerLoader().registerSwagger(appId, shortName, shortName, schemaIntfCls);
+ Swagger swagger = this.appManager.getServiceRegistry().getSwaggerLoader()
+ .registerSwagger(appId, shortName, shortName, schemaIntfCls);
+ microservice.addSchema(shortName, SwaggerUtils.swaggerToString(swagger));
createMicroservice(version);
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
index 1acccad..ce44b79 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
@@ -18,6 +18,7 @@
package org.apache.servicecomb.serviceregistry.registry;
import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader;
+import org.apache.servicecomb.foundation.common.event.SimpleEventBus;
import org.apache.servicecomb.serviceregistry.ServiceRegistry;
import org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl;
import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
@@ -62,7 +63,7 @@ public final class ServiceRegistryFactory {
}
public static ServiceRegistry createLocal(String localFile) {
- EventBus eventBus = new EventBus();
+ EventBus eventBus = new SimpleEventBus();
ServiceRegistryConfig serviceRegistryConfig = ServiceRegistryConfig.INSTANCE;
MicroserviceConfigLoader loader = new MicroserviceConfigLoader();
loader.loadAndSort();
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java
index 6a3339e..9740399 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java
@@ -16,11 +16,16 @@
*/
package org.apache.servicecomb.serviceregistry.swagger;
+import java.io.InputStream;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
import org.apache.servicecomb.foundation.common.utils.JvmUtils;
import org.apache.servicecomb.serviceregistry.ServiceRegistry;
@@ -47,20 +52,83 @@ public class SwaggerLoader {
this.serviceRegistry = serviceRegistry;
}
+ /**
+ * <pre>
+ * register swaggers in the location to current microservice
+ * Scenes for contract first mode:
+ * 1.consumer
+ * manager manage some product, can only know product microservice names after deploy
+ * and can only register swagger after product registered
+ * in fact, consumers can load swagger from ServiceCenter
+ * so for consumer, this logic is not necessary, just keep it for compatible
+ * 2.producer
+ * deploy to different microservice name in different product
+ * can register swaggers in BootListener.onBeforeProducerProvider
+ * </pre>
+ * @param swaggersLocation eg. "test/schemas", will load all test/schemas/*.yaml
+ */
+ public void registerSwaggersInLocation(String swaggersLocation) {
+ String microserviceName = serviceRegistry.getMicroservice().getServiceName();
+ registerSwaggersInLocation(microserviceName, swaggersLocation);
+ }
+
+ public void registerSwaggersInLocation(String microserviceName, String swaggersLocation) {
+ try (InputStream inputStream = JvmUtils.findClassLoader().getResourceAsStream(swaggersLocation)) {
+ if (inputStream == null) {
+ LOGGER.error("register swagger in not exist location: \"{}\".", swaggersLocation);
+ return;
+ }
+
+ List<String> files = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
+
+ for (String file : files) {
+ if (!file.endsWith(".yaml")) {
+ continue;
+ }
+
+ URL url = JvmUtils.findClassLoader().getResource(swaggersLocation + "/" + file);
+ String schemaId = FilenameUtils.getBaseName(url.getPath());
+ Swagger swagger = SwaggerUtils.parseAndValidateSwagger(url);
+ registerSwagger(microserviceName, schemaId, swagger);
+ }
+ } catch (Throwable e) {
+ throw new IllegalStateException(String.format(
+ "failed to register swaggers, microserviceName=%s, location=%s.", microserviceName, swaggersLocation),
+ e);
+ }
+ }
+
+ public void registerSwagger(String schemaId, Swagger swagger) {
+ registerSwagger(serviceRegistry.getMicroservice().getServiceName(), schemaId, swagger);
+ }
+
+ public void registerSwagger(String microserviceName, String schemaId, String swaggerContent) {
+ try {
+ Swagger swagger = SwaggerUtils.parseAndValidateSwagger(swaggerContent);
+ registerSwagger(microserviceName, schemaId, swagger);
+ } catch (Throwable e) {
+ throw new IllegalStateException(
+ String.format("Parse the swagger for %s:%s failed", microserviceName, schemaId),
+ e);
+ }
+ }
+
public void registerSwagger(String microserviceName, String schemaId, Swagger swagger) {
MicroserviceNameParser parser = new MicroserviceNameParser(serviceRegistry.getAppId(), microserviceName);
registerSwagger(parser.getAppId(), parser.getShortName(), schemaId, swagger);
}
- public void registerSwagger(String appId, String shortName, String schemaId, Class<?> cls) {
+ public Swagger registerSwagger(String appId, String shortName, String schemaId, Class<?> cls) {
Swagger swagger = SwaggerGenerator.generate(cls);
registerSwagger(appId, shortName, schemaId, swagger);
+ return swagger;
}
public void registerSwagger(String appId, String shortName, String schemaId, Swagger swagger) {
apps.computeIfAbsent(appId, k -> new ConcurrentHashMapEx<>())
.computeIfAbsent(shortName, k -> new ConcurrentHashMapEx<>())
.put(schemaId, swagger);
+ LOGGER.info("register swagger appId={}, name={}, schemaId={}.", appId, shortName, schemaId);
}
public void unregisterSwagger(String appId, String shortName, String schemaId) {
@@ -78,7 +146,7 @@ public class SwaggerLoader {
return loadFromRemote(microservice, schemaId);
}
- private Swagger loadLocalSwagger(String appId, String shortName, String schemaId) {
+ public Swagger loadLocalSwagger(String appId, String shortName, String schemaId) {
Swagger swagger = loadFromMemory(appId, shortName, schemaId);
if (swagger != null) {
return swagger;
@@ -87,7 +155,7 @@ public class SwaggerLoader {
return loadFromResource(appId, shortName, schemaId);
}
- private Swagger loadFromMemory(String appId, String shortName, String schemaId) {
+ Swagger loadFromMemory(String appId, String shortName, String schemaId) {
return Optional.ofNullable(apps.get(appId))
.map(microservices -> microservices.get(shortName))
.map(schemas -> schemas.get(schemaId))
@@ -111,19 +179,7 @@ public class SwaggerLoader {
return null;
}
- return parseAndValidateSwagger(url);
- }
-
- private Swagger parseAndValidateSwagger(URL url) {
- Swagger swagger = SwaggerUtils.parseSwagger(url);
- SwaggerUtils.validateSwagger(swagger);
- return swagger;
- }
-
- private Swagger parseAndValidateSwagger(String swaggerContent) {
- Swagger swagger = SwaggerUtils.parseSwagger(swaggerContent);
- SwaggerUtils.validateSwagger(swagger);
- return swagger;
+ return SwaggerUtils.parseAndValidateSwagger(url);
}
private Swagger loadFromRemote(Microservice microservice, String schemaId) {
@@ -138,7 +194,7 @@ public class SwaggerLoader {
microservice.getServiceId(),
schemaId);
LOGGER.debug(schemaContent);
- return parseAndValidateSwagger(schemaContent);
+ return SwaggerUtils.parseAndValidateSwagger(schemaContent);
}
throw new IllegalStateException(
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java
index ae4372c..68261e7 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java
@@ -16,11 +16,25 @@
*/
package org.apache.servicecomb.serviceregistry.swagger;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.hasProperty;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.core.Is.is;
+
+import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.ws.Holder;
import org.apache.commons.io.IOUtils;
+import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
import org.apache.servicecomb.foundation.common.utils.JvmUtils;
import org.apache.servicecomb.serviceregistry.TestRegistryBase;
import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
@@ -32,6 +46,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import io.swagger.models.Swagger;
+import mockit.Deencapsulation;
import mockit.Expectations;
import mockit.Mock;
import mockit.MockUp;
@@ -123,14 +138,41 @@ public class TestSwaggerLoader extends TestRegistryBase {
Assert.assertEquals(swagger, loadedSwagger);
}
- private void mockLocalResource(Swagger swagger, String path) throws IOException {
+ private void mockLocalResource(Swagger swagger, String path) {
+ mockLocalResource(SwaggerUtils.swaggerToString(swagger), path);
+ }
+
+ private void mockLocalResource(String content, String path) {
+ Map<String, String> resourceMap = new HashMap<>();
+ resourceMap.put(path, content);
+
+ mockLocalResource(resourceMap);
+ }
+
+ private void mockLocalResource(Map<String, String> resourceMap) {
+ Holder<String> pathHolder = new Holder<>();
URL url = new MockUp<URL>() {
+ @Mock
+ String getPath() {
+ return pathHolder.value;
+ }
+ @Mock
+ String toExternalForm() {
+ return pathHolder.value;
+ }
}.getMockInstance();
ClassLoader classLoader = new MockUp<ClassLoader>() {
@Mock
URL getResource(String name) {
- return path.equals(name) ? url : null;
+ pathHolder.value = name;
+ return resourceMap.containsKey(name) ? url : null;
+ }
+
+ @Mock
+ InputStream getResourceAsStream(String name) {
+ String content = resourceMap.get(name);
+ return content == null ? null : new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
}
}.getMockInstance();
new Expectations(JvmUtils.class) {
@@ -142,8 +184,44 @@ public class TestSwaggerLoader extends TestRegistryBase {
new MockUp<IOUtils>() {
@Mock
String toString(URL url, Charset encoding) {
- return SwaggerUtils.swaggerToString(swagger);
+ return resourceMap.get(url.getPath());
}
};
}
+
+ @Test
+ public void should_ignore_not_exist_location_when_register_swagger_in_location() {
+ Map<String, Object> apps = Deencapsulation.getField(serviceRegistry.getSwaggerLoader(), "apps");
+ apps.clear();
+ serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("notExistPath");
+ assertThat(apps).isEmpty();
+ }
+
+ @Test
+ public void should_ignore_non_yaml_file_when_register_swagger_in_location() {
+ serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("swagger-del");
+ assertThat(serviceRegistry.getSwaggerLoader().loadFromMemory(appId, serviceName, "other")).isNull();
+ }
+
+ @Test
+ public void should_throw_exception_when_register_invalid_swagger_in_location() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("failed to register swaggers, microserviceName=default, location=location.");
+ expectedException.expectCause(instanceOf(ServiceCombException.class));
+ expectedException.expectCause(allOf(instanceOf(ServiceCombException.class),
+ hasProperty("message", is("Parse swagger from url failed, url=location/invalid.yaml"))));
+
+ Map<String, String> resourceMap = new HashMap<>();
+ resourceMap.put("location", "invalid.yaml");
+ resourceMap.put("location/invalid.yaml", "invalid yaml content");
+ mockLocalResource(resourceMap);
+
+ serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("location");
+ }
+
+ @Test
+ public void should_correct_register_swagger_in_location() {
+ serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("swagger-del");
+ assertThat(serviceRegistry.getSwaggerLoader().loadFromMemory(appId, serviceName, "hello")).isNotNull();
+ }
}