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();
+  }
 }