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 <[email protected]> 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
