You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ma...@apache.org on 2019/08/07 10:41:54 UTC
[servicecomb-samples] 13/37: 增加分布式运维的例子
This is an automated email from the ASF dual-hosted git repository.
mabin pushed a commit to branch houserush-sample
in repository https://gitbox.apache.org/repos/asf/servicecomb-samples.git
commit e51b877c927d39f421ea3a215625b78012ee340b
Author: liubao <ba...@huawei.com>
AuthorDate: Fri Apr 26 17:56:08 2019 +0800
增加分布式运维的例子
---
.../api/{ => common/endpoint}/pom.xml | 20 +-
.../samples/porter/file/api/InspectorEndpoint.java | 206 +++++++++++++++++++++
.../samples/porter/file/api/LogEndpoint.java | 72 +++++++
porter_lightweight/api/{ => common}/pom.xml | 8 +-
.../api/{ => common/service}/pom.xml | 13 +-
.../samples/porter/common/api/LogService.java | 26 +++
porter_lightweight/api/pom.xml | 1 +
porter_lightweight/file-service/pom.xml | 9 +
.../main/resources/META-INF/spring/file.bean.xml | 3 +-
.../src/main/resources/microservice.yaml | 13 +-
porter_lightweight/gateway-service/pom.xml | 9 +
.../porter/gateway/CustomVertxRestDispatcher.java | 196 ++++++++++++++++++++
...cecomb.transport.rest.vertx.VertxHttpDispatcher | 3 +-
.../main/resources/META-INF/spring/cse.bean.xml} | 16 +-
.../src/main/resources/microservice.yaml | 13 ++
porter_lightweight/user-service/pom.xml | 9 +
.../main/resources/META-INF/spring/user.bean.xml | 4 +-
.../src/main/resources/microservice.yaml | 13 +-
18 files changed, 599 insertions(+), 35 deletions(-)
diff --git a/porter_lightweight/api/pom.xml b/porter_lightweight/api/common/endpoint/pom.xml
similarity index 77%
copy from porter_lightweight/api/pom.xml
copy to porter_lightweight/api/common/endpoint/pom.xml
index 018a879..df1628b 100644
--- a/porter_lightweight/api/pom.xml
+++ b/porter_lightweight/api/common/endpoint/pom.xml
@@ -15,22 +15,24 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.servicecomb.samples.porter</groupId>
- <artifactId>porter-application</artifactId>
+ <artifactId>common-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
- <artifactId>porter-api</artifactId>
- <packaging>pom</packaging>
+ <artifactId>common-api-endpoint</artifactId>
+ <packaging>jar</packaging>
- <modules>
- <module>file-service</module>
- <module>user-service</module>
- </modules>
-</project>
\ No newline at end of file
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.servicecomb.samples.porter</groupId>
+ <artifactId>common-api-service</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/porter_lightweight/api/common/endpoint/src/main/java/org/apache/servicecomb/samples/porter/file/api/InspectorEndpoint.java b/porter_lightweight/api/common/endpoint/src/main/java/org/apache/servicecomb/samples/porter/file/api/InspectorEndpoint.java
new file mode 100644
index 0000000..731f6ac
--- /dev/null
+++ b/porter_lightweight/api/common/endpoint/src/main/java/org/apache/servicecomb/samples/porter/file/api/InspectorEndpoint.java
@@ -0,0 +1,206 @@
+/*
+ * 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.servicecomb.samples.porter.file.api;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.servlet.http.Part;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.servicecomb.common.rest.resource.ClassPathStaticResourceHandler;
+import org.apache.servicecomb.common.rest.resource.StaticResourceHandler;
+import org.apache.servicecomb.config.inject.ConfigObjectFactory;
+import org.apache.servicecomb.foundation.common.part.InputStreamPart;
+import org.apache.servicecomb.inspector.internal.InspectorConfig;
+import org.apache.servicecomb.inspector.internal.swagger.AppendStyleProcessor;
+import org.apache.servicecomb.inspector.internal.swagger.SchemaFormat;
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.swagger.SwaggerUtils;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.asciidoctor.Asciidoctor;
+import org.asciidoctor.Asciidoctor.Factory;
+import org.asciidoctor.Attributes;
+import org.asciidoctor.AttributesBuilder;
+import org.asciidoctor.OptionsBuilder;
+import org.asciidoctor.SafeMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Ordering;
+
+import io.github.swagger2markup.Swagger2MarkupConfig;
+import io.github.swagger2markup.Swagger2MarkupConverter;
+import io.github.swagger2markup.Swagger2MarkupConverter.Builder;
+import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.models.parameters.Parameter;
+
+// copied from org.apache.servicecomb.inspector.internal.InspectorImpl;
+@RestSchema(schemaId = "inspector")
+@Path("/inspector")
+public class InspectorEndpoint {
+ private static final Logger LOGGER = LoggerFactory.getLogger(InspectorEndpoint.class);
+
+ private InspectorConfig inspectorConfig;
+
+ private volatile Asciidoctor asciidoctor;
+
+ private StaticResourceHandler resourceHandler = new ClassPathStaticResourceHandler();
+
+ public InspectorEndpoint() {
+ this.inspectorConfig = new ConfigObjectFactory().create(InspectorConfig.class);
+ }
+
+ @Path("/schemas")
+ @GET
+ public Collection<String> getSchemaIds() {
+ return RegistryUtils.getServiceRegistry().getMicroservice().getSchemaMap().keySet();
+ }
+
+ @Path("/download/schemas")
+ @GET
+ @ApiResponse(code = 200, message = "", response = File.class)
+ public Response downloadSchemas(@QueryParam("format") SchemaFormat format) {
+ if (format == null) {
+ format = SchemaFormat.SWAGGER;
+ }
+
+ // normally, schema will not be too big, just save them in memory temporarily
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ try (ZipOutputStream zos = new ZipOutputStream(os)) {
+ for (Entry<String, String> entry : RegistryUtils.getServiceRegistry().getMicroservice().getSchemaMap().entrySet()) {
+ // begin writing a new ZIP entry, positions the stream to the start of the entry data
+ zos.putNextEntry(new ZipEntry(entry.getKey() + format.getSuffix()));
+
+ String content = entry.getValue();
+ if (SchemaFormat.HTML.equals(format)) {
+ content = swaggerToHtml(content);
+ }
+ zos.write(content.getBytes(StandardCharsets.UTF_8));
+ zos.closeEntry();
+ }
+ } catch (Throwable e) {
+ String msg = "failed to create schemas zip file, format=" + format + ".";
+ LOGGER.error(msg, e);
+ return Response.failResp(new InvocationException(Status.INTERNAL_SERVER_ERROR, msg));
+ }
+
+ Part part = new InputStreamPart(null, new ByteArrayInputStream(os.toByteArray()))
+ .setSubmittedFileName(RegistryUtils.getMicroservice().getServiceName() + format.getSuffix() + ".zip");
+ return Response.ok(part);
+ }
+
+ @Path("/schemas/{schemaId}")
+ @GET
+ @ApiResponse(code = 200, message = "", response = File.class)
+ public Response getSchemaContentById(@PathParam("schemaId") String schemaId,
+ @QueryParam("format") SchemaFormat format, @QueryParam("download") boolean download) {
+ String swaggerContent = RegistryUtils.getServiceRegistry().getMicroservice().getSchemaMap().get(schemaId);
+ if (swaggerContent == null) {
+ return Response.failResp(new InvocationException(Status.NOT_FOUND, Status.NOT_FOUND.getReasonPhrase()));
+ }
+
+ if (format == null) {
+ format = SchemaFormat.SWAGGER;
+ }
+
+ byte[] bytes;
+ if (SchemaFormat.HTML.equals(format)) {
+ String html = swaggerToHtml(swaggerContent);
+ bytes = html.getBytes(StandardCharsets.UTF_8);
+ } else {
+ bytes = swaggerContent.getBytes(StandardCharsets.UTF_8);
+ }
+
+ Part part = new InputStreamPart(null, new ByteArrayInputStream(bytes))
+ .setSubmittedFileName(schemaId + format.getSuffix());
+
+ Response response = Response.ok(part);
+ if (!download) {
+ response.getHeaders().addHeader(HttpHeaders.CONTENT_DISPOSITION, "inline");
+ }
+ response.getHeaders().addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML);
+ return response;
+ }
+
+ // swagger not support cookie parameter
+ // so if swaggerContent contains cookie parameter, will cause problem.
+ private String swaggerToHtml(String swaggerContent) {
+ if (asciidoctor == null) {
+ synchronized (this) {
+ if (asciidoctor == null) {
+ // very slow, need a few seconds
+ LOGGER.info("create AsciiDoctor start.");
+ asciidoctor = Factory.create();
+ asciidoctor.javaExtensionRegistry().docinfoProcessor(AppendStyleProcessor.class);
+ LOGGER.info("create AsciiDoctor end.");
+ }
+ }
+ }
+
+ // swagger to markup
+ Builder markupBuilder = Swagger2MarkupConverter.from(SwaggerUtils.parseSwagger(swaggerContent));
+ // default not support cookie parameter
+ // so must customize config
+ Swagger2MarkupConfig markupConfig = new Swagger2MarkupConfigBuilder()
+ .withParameterOrdering(Ordering
+ .explicit("path", "query", "header", "cookie", "formData", "body")
+ .onResultOf(Parameter::getIn))
+ .build();
+ String markup = markupBuilder.withConfig(markupConfig).build().toString();
+
+ // markup to html
+ OptionsBuilder builder = OptionsBuilder.options();
+ builder.docType("book")
+ .backend("html5")
+ .headerFooter(true)
+ .safe(SafeMode.UNSAFE)
+ .attributes(AttributesBuilder.attributes()
+ .attribute("toclevels", 3)
+ .attribute(Attributes.TOC_2, true)
+ .attribute(Attributes.TOC_POSITION, "left")
+ .attribute(Attributes.LINK_CSS, true)
+ .attribute(Attributes.STYLESHEET_NAME, inspectorConfig.getAsciidoctorCss())
+ .attribute(Attributes.SECTION_NUMBERS, true)
+ .attribute(Attributes.SECT_NUM_LEVELS, 4));
+ return asciidoctor.convert(markup, builder.asMap());
+ }
+
+ @Path("/{path : .+}")
+ @GET
+ @ApiResponse(code = 200, message = "", response = File.class)
+ public Response getStaticResource(@PathParam("path") String path) {
+ return resourceHandler.handle(path);
+ }
+}
+
diff --git a/porter_lightweight/api/common/endpoint/src/main/java/org/apache/servicecomb/samples/porter/file/api/LogEndpoint.java b/porter_lightweight/api/common/endpoint/src/main/java/org/apache/servicecomb/samples/porter/file/api/LogEndpoint.java
new file mode 100644
index 0000000..8e49a6e
--- /dev/null
+++ b/porter_lightweight/api/common/endpoint/src/main/java/org/apache/servicecomb/samples/porter/file/api/LogEndpoint.java
@@ -0,0 +1,72 @@
+/*
+ * 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.servicecomb.samples.porter.file.api;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.apache.servicecomb.samples.porter.common.api.LogService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+@RestSchema(schemaId = "log")
+@RequestMapping(path = "/v1/log")
+public class LogEndpoint implements LogService {
+ // protect your file in real applications
+ private static final File LOG_DIR =
+ new File(DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.samples.logdir", ".").get());
+
+ private static final String FILE_POST_FIX = ".log";
+
+ @Override
+ @GetMapping(path = "/getLogFileList")
+ public List<String> getLogFileList() {
+ File[] files = LOG_DIR.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ return isLogFile(file);
+ }
+ });
+
+ List<String> result = new ArrayList<>(files.length);
+ for (int i = 0; i < files.length; i++) {
+ result.add(files[i].getName());
+ }
+ return result;
+ }
+
+ @Override
+ @GetMapping(path = "/getLogFileContent")
+ public File getLogFileContent(@RequestParam(name = "fileName") String fileName) {
+ File file = new File(LOG_DIR, fileName);
+ if (isLogFile(file)) {
+ return file;
+ }
+ return null;
+ }
+
+ private boolean isLogFile(File file) {
+ return file.isFile() && file.canRead() && file.getName().endsWith(FILE_POST_FIX);
+ }
+}
diff --git a/porter_lightweight/api/pom.xml b/porter_lightweight/api/common/pom.xml
similarity index 88%
copy from porter_lightweight/api/pom.xml
copy to porter_lightweight/api/common/pom.xml
index 018a879..5c28887 100644
--- a/porter_lightweight/api/pom.xml
+++ b/porter_lightweight/api/common/pom.xml
@@ -22,15 +22,15 @@
<parent>
<groupId>org.apache.servicecomb.samples.porter</groupId>
- <artifactId>porter-application</artifactId>
+ <artifactId>porter-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
- <artifactId>porter-api</artifactId>
+ <artifactId>common-api</artifactId>
<packaging>pom</packaging>
<modules>
- <module>file-service</module>
- <module>user-service</module>
+ <module>service</module>
+ <module>endpoint</module>
</modules>
</project>
\ No newline at end of file
diff --git a/porter_lightweight/api/pom.xml b/porter_lightweight/api/common/service/pom.xml
similarity index 84%
copy from porter_lightweight/api/pom.xml
copy to porter_lightweight/api/common/service/pom.xml
index 018a879..41a7d85 100644
--- a/porter_lightweight/api/pom.xml
+++ b/porter_lightweight/api/common/service/pom.xml
@@ -15,22 +15,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.servicecomb.samples.porter</groupId>
- <artifactId>porter-application</artifactId>
+ <artifactId>common-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
- <artifactId>porter-api</artifactId>
- <packaging>pom</packaging>
+ <artifactId>common-api-service</artifactId>
+ <packaging>jar</packaging>
- <modules>
- <module>file-service</module>
- <module>user-service</module>
- </modules>
-</project>
\ No newline at end of file
+</project>
diff --git a/porter_lightweight/api/common/service/src/main/java/org/apache/servicecomb/samples/porter/common/api/LogService.java b/porter_lightweight/api/common/service/src/main/java/org/apache/servicecomb/samples/porter/common/api/LogService.java
new file mode 100644
index 0000000..9991543
--- /dev/null
+++ b/porter_lightweight/api/common/service/src/main/java/org/apache/servicecomb/samples/porter/common/api/LogService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.servicecomb.samples.porter.common.api;
+
+import java.io.File;
+import java.util.List;
+
+public interface LogService {
+ List<String> getLogFileList();
+ File getLogFileContent(String fileName);
+}
diff --git a/porter_lightweight/api/pom.xml b/porter_lightweight/api/pom.xml
index 018a879..faa2d56 100644
--- a/porter_lightweight/api/pom.xml
+++ b/porter_lightweight/api/pom.xml
@@ -30,6 +30,7 @@
<packaging>pom</packaging>
<modules>
+ <module>common</module>
<module>file-service</module>
<module>user-service</module>
</modules>
diff --git a/porter_lightweight/file-service/pom.xml b/porter_lightweight/file-service/pom.xml
index 6ae53d6..02eea87 100644
--- a/porter_lightweight/file-service/pom.xml
+++ b/porter_lightweight/file-service/pom.xml
@@ -30,10 +30,19 @@
<dependencies>
<dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>inspector</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.servicecomb.samples.porter</groupId>
<artifactId>file-service-api-endpoint</artifactId>
<version>${project.parent.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb.samples.porter</groupId>
+ <artifactId>common-api-endpoint</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
</dependencies>
<properties>
<main.class>org.apache.servicecomb.samples.porter.file.FileMain</main.class>
diff --git a/porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml b/porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml
index c679960..692102e 100644
--- a/porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml
+++ b/porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml
@@ -23,5 +23,6 @@
xsi:schemaLocation="
http://www.springframework.org/schema/beans classpath:org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
+ <bean id="servicecomb.samples.executor.groupThreadPool" class="org.apache.servicecomb.core.executor.GroupExecutor"
+ init-method="init"/>
</beans>
\ No newline at end of file
diff --git a/porter_lightweight/file-service/src/main/resources/microservice.yaml b/porter_lightweight/file-service/src/main/resources/microservice.yaml
index dc4a845..f473dbe 100644
--- a/porter_lightweight/file-service/src/main/resources/microservice.yaml
+++ b/porter_lightweight/file-service/src/main/resources/microservice.yaml
@@ -36,4 +36,15 @@ servicecomb:
address: 0.0.0.0:9091
uploads:
- directory: tmp_for_upload_file
\ No newline at end of file
+ directory: tmp_for_upload_file
+
+ samples:
+ logdir: D:\code\servicecomb-samples\porter_lightweight\file-service
+
+ inspector:
+ enabled: false
+
+ executors:
+ Provider:
+ log: servicecomb.samples.executor.groupThreadPool
+ inspector: servicecomb.samples.executor.groupThreadPool
\ No newline at end of file
diff --git a/porter_lightweight/gateway-service/pom.xml b/porter_lightweight/gateway-service/pom.xml
index 252935e..343beb3 100644
--- a/porter_lightweight/gateway-service/pom.xml
+++ b/porter_lightweight/gateway-service/pom.xml
@@ -34,11 +34,20 @@
<dependencies>
<dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>inspector</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.servicecomb.samples.porter</groupId>
<artifactId>user-service-api-service</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.servicecomb.samples.porter</groupId>
+ <artifactId>common-api-endpoint</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>edge-core</artifactId>
</dependency>
diff --git a/porter_lightweight/gateway-service/src/main/java/org/apache/servicecomb/samples/porter/gateway/CustomVertxRestDispatcher.java b/porter_lightweight/gateway-service/src/main/java/org/apache/servicecomb/samples/porter/gateway/CustomVertxRestDispatcher.java
new file mode 100644
index 0000000..245e0af
--- /dev/null
+++ b/porter_lightweight/gateway-service/src/main/java/org/apache/servicecomb/samples/porter/gateway/CustomVertxRestDispatcher.java
@@ -0,0 +1,196 @@
+/*
+ * 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.servicecomb.samples.porter.gateway;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.Response.Status.Family;
+
+import org.apache.servicecomb.common.rest.AbstractRestInvocation;
+import org.apache.servicecomb.common.rest.RestConst;
+import org.apache.servicecomb.common.rest.VertxRestInvocation;
+import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.core.CseContext;
+import org.apache.servicecomb.core.Transport;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
+import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest;
+import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.apache.servicecomb.transport.rest.vertx.AbstractVertxHttpDispatcher;
+import org.apache.servicecomb.transport.rest.vertx.VertxRestDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.handler.CookieHandler;
+
+// copied from org.apache.servicecomb.transport.rest.vertx.VertxRestDispatcher
+public class CustomVertxRestDispatcher extends AbstractVertxHttpDispatcher {
+ private static final Logger LOGGER = LoggerFactory.getLogger(VertxRestDispatcher.class);
+
+ private Transport transport;
+
+ @Override
+ public int getOrder() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public boolean enabled() {
+ return true;
+ }
+
+ @Override
+ public void init(Router router) {
+ String regex = "[/v1/log/|/inspector](.*)";
+ router.routeWithRegex(regex).handler(CookieHandler.create());
+ router.routeWithRegex(regex).handler(createBodyHandler());
+ router.routeWithRegex(regex).failureHandler(this::failureHandler).handler(this::onRequest);
+ }
+
+ private void failureHandler(RoutingContext context) {
+ LOGGER.error("http server failed.", context.failure());
+
+ AbstractRestInvocation restProducerInvocation = context.get(RestConst.REST_PRODUCER_INVOCATION);
+ Throwable e = context.failure();
+ if (ErrorDataDecoderException.class.isInstance(e)) {
+ Throwable cause = e.getCause();
+ if (InvocationException.class.isInstance(cause)) {
+ e = cause;
+ }
+ }
+
+ // only when unexpected exception happens, it will run into here.
+ // the connection should be closed.
+ handleFailureAndClose(context, restProducerInvocation, e);
+ }
+
+ /**
+ * Try to find out the failure information and send it in response.
+ */
+ private void handleFailureAndClose(RoutingContext context, AbstractRestInvocation restProducerInvocation,
+ Throwable e) {
+ if (null != restProducerInvocation) {
+ // if there is restProducerInvocation, let it send exception in response. The exception is allowed to be null.
+ sendFailResponseByInvocation(context, restProducerInvocation, e);
+ return;
+ }
+
+ if (null != e) {
+ // if there exists exception, try to send this exception by RoutingContext
+ sendExceptionByRoutingContext(context, e);
+ return;
+ }
+
+ // if there is no exception, the response is determined by status code.
+ sendFailureRespDeterminedByStatus(context);
+ }
+
+ /**
+ * Try to determine response by status code, and send response.
+ */
+ private void sendFailureRespDeterminedByStatus(RoutingContext context) {
+ Family statusFamily = Family.familyOf(context.statusCode());
+ if (Family.CLIENT_ERROR.equals(statusFamily) || Family.SERVER_ERROR.equals(statusFamily) || Family.OTHER
+ .equals(statusFamily)) {
+ context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+ .setStatusCode(context.statusCode()).end();
+ } else {
+ // it seems the status code is not set properly
+ context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+ .setStatusCode(Status.INTERNAL_SERVER_ERROR.getStatusCode())
+ .setStatusMessage(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())
+ .end(wrapResponseBody(Status.INTERNAL_SERVER_ERROR.getReasonPhrase()));
+ }
+ context.response().close();
+ }
+
+ /**
+ * Use routingContext to send failure information in throwable.
+ */
+ private void sendExceptionByRoutingContext(RoutingContext context, Throwable e) {
+ if (InvocationException.class.isInstance(e)) {
+ InvocationException invocationException = (InvocationException) e;
+ context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+ .setStatusCode(invocationException.getStatusCode()).setStatusMessage(invocationException.getReasonPhrase())
+ .end(wrapResponseBody(invocationException.getReasonPhrase()));
+ } else {
+ context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)
+ .setStatusCode(Status.INTERNAL_SERVER_ERROR.getStatusCode()).end(wrapResponseBody(e.getMessage()));
+ }
+ context.response().close();
+ }
+
+ /**
+ * Consumer will treat the response body as json by default, so it's necessary to wrap response body as Json string
+ * to avoid deserialization error.
+ *
+ * @param message response body
+ * @return response body wrapped as Json string
+ */
+ String wrapResponseBody(String message) {
+ if (isValidJson(message)) {
+ return message;
+ }
+
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.put("message", message);
+
+ return jsonObject.toString();
+ }
+
+ /**
+ * Check if the message is a valid Json string.
+ * @param message the message to be checked.
+ * @return true if message is a valid Json string, otherwise false.
+ */
+ private boolean isValidJson(String message) {
+ try {
+ new JsonObject(message);
+ } catch (Exception ignored) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Use restProducerInvocation to send failure message. The throwable is allowed to be null.
+ */
+ private void sendFailResponseByInvocation(RoutingContext context, AbstractRestInvocation restProducerInvocation,
+ Throwable e) {
+ restProducerInvocation.sendFailResponse(e);
+ context.response().close();
+ }
+
+ private void onRequest(RoutingContext context) {
+ if (transport == null) {
+ transport = CseContext.getInstance().getTransportManager().findTransport(Const.RESTFUL);
+ }
+ HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context);
+ HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response());
+
+ VertxRestInvocation vertxRestInvocation = new VertxRestInvocation();
+ context.put(RestConst.REST_PRODUCER_INVOCATION, vertxRestInvocation);
+ vertxRestInvocation.invoke(transport, requestEx, responseEx, httpServerFilters);
+ }
+}
diff --git a/porter_lightweight/gateway-service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/porter_lightweight/gateway-service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
index 71009db..bada1de 100644
--- a/porter_lightweight/gateway-service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
+++ b/porter_lightweight/gateway-service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher
@@ -16,4 +16,5 @@
#
org.apache.servicecomb.samples.porter.gateway.ApiDispatcher
-org.apache.servicecomb.samples.porter.gateway.StaticWebpageDispatcher
\ No newline at end of file
+org.apache.servicecomb.samples.porter.gateway.StaticWebpageDispatcher
+org.apache.servicecomb.samples.porter.gateway.CustomVertxRestDispatcher
\ No newline at end of file
diff --git a/porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml b/porter_lightweight/gateway-service/src/main/resources/META-INF/spring/cse.bean.xml
similarity index 60%
copy from porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml
copy to porter_lightweight/gateway-service/src/main/resources/META-INF/spring/cse.bean.xml
index c679960..b5816c3 100644
--- a/porter_lightweight/file-service/src/main/resources/META-INF/spring/file.bean.xml
+++ b/porter_lightweight/gateway-service/src/main/resources/META-INF/spring/cse.bean.xml
@@ -16,12 +16,12 @@
~ limitations under the License.
-->
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
- xmlns:util="http://www.springframework.org/schema/util"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans classpath:org/springframework/beans/factory/xml/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-</beans>
\ No newline at end of file
+ <bean id="servicecomb.samples.executor.groupThreadPool" class="org.apache.servicecomb.core.executor.GroupExecutor"
+ init-method="init"/>
+</beans>
diff --git a/porter_lightweight/gateway-service/src/main/resources/microservice.yaml b/porter_lightweight/gateway-service/src/main/resources/microservice.yaml
index 2462c7f..c05dc5a 100644
--- a/porter_lightweight/gateway-service/src/main/resources/microservice.yaml
+++ b/porter_lightweight/gateway-service/src/main/resources/microservice.yaml
@@ -42,6 +42,19 @@ servicecomb:
uploads:
directory: tmp_for_upload_gateway
+ samples:
+ logdir: D:\code\servicecomb-samples\porter_lightweight\gateway-service
+
+ inspector:
+ enabled: false
+
+ executors:
+ Provider:
+ log: servicecomb.samples.executor.groupThreadPool
+ inspector: servicecomb.samples.executor.groupThreadPool
+
servicecomb.http.dispatcher.edge.default.enabled: false
+# StaticWebpageDispatcher checking file exists is async, and will mark request status to ended, and VertxRestDispatcher read
+# body will print exception.
servicecomb.http.dispatcher.rest.enabled: false
gateway.webroot: /code/servicecomb-samples/porter_lightweight/gateway-service/src/main/resources
diff --git a/porter_lightweight/user-service/pom.xml b/porter_lightweight/user-service/pom.xml
index 7e8c20f..100bdcf 100644
--- a/porter_lightweight/user-service/pom.xml
+++ b/porter_lightweight/user-service/pom.xml
@@ -35,11 +35,20 @@
<dependencies>
<dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>inspector</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.servicecomb.samples.porter</groupId>
<artifactId>user-service-api-endpoint</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.servicecomb.samples.porter</groupId>
+ <artifactId>common-api-endpoint</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
diff --git a/porter_lightweight/user-service/src/main/resources/META-INF/spring/user.bean.xml b/porter_lightweight/user-service/src/main/resources/META-INF/spring/user.bean.xml
index 3cc2dd2..661608f 100644
--- a/porter_lightweight/user-service/src/main/resources/META-INF/spring/user.bean.xml
+++ b/porter_lightweight/user-service/src/main/resources/META-INF/spring/user.bean.xml
@@ -25,7 +25,9 @@
http://www.springframework.org/schema/beans classpath:org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
+ <bean id="servicecomb.samples.executor.groupThreadPool" class="org.apache.servicecomb.core.executor.GroupExecutor"
+ init-method="init"/>
+
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
diff --git a/porter_lightweight/user-service/src/main/resources/microservice.yaml b/porter_lightweight/user-service/src/main/resources/microservice.yaml
index 5daaea5..af37379 100644
--- a/porter_lightweight/user-service/src/main/resources/microservice.yaml
+++ b/porter_lightweight/user-service/src/main/resources/microservice.yaml
@@ -32,4 +32,15 @@ servicecomb:
watch: false
rest:
- address: 0.0.0.0:9093
\ No newline at end of file
+ address: 0.0.0.0:9093
+
+ samples:
+ logdir: D:\code\servicecomb-samples\porter_lightweight\user-service
+
+ inspector:
+ enabled: false
+
+ executors:
+ Provider:
+ log: servicecomb.samples.executor.groupThreadPool
+ inspector: servicecomb.samples.executor.groupThreadPool
\ No newline at end of file