├── README.md
├── feign-istio-fake
├── README.md
├── istio-fake.iml
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── istio
│ │ └── fake
│ │ ├── FakeClientsRegistrar.java
│ │ ├── FakeException.java
│ │ ├── Util
│ │ └── Util.java
│ │ ├── annotation
│ │ ├── EnableFakeClients.java
│ │ ├── FakeClient.java
│ │ ├── PathVariableParameterProcessor.java
│ │ ├── QueryMapParameterProcessor.java
│ │ ├── RequestHeaderParameterProcessor.java
│ │ └── RequestParamParameterProcessor.java
│ │ ├── base
│ │ ├── Body.java
│ │ ├── Client.java
│ │ ├── CollectionFormat.java
│ │ ├── Contract.java
│ │ ├── DefaultMethodHandler.java
│ │ ├── ExceptionPropagationPolicy.java
│ │ ├── HeaderMap.java
│ │ ├── Headers.java
│ │ ├── InvocationHandlerFactory.java
│ │ ├── MethodMetadata.java
│ │ ├── Param.java
│ │ ├── QueryMap.java
│ │ ├── QueryMapEncoder.java
│ │ ├── ReflectiveFake.java
│ │ ├── Request.java
│ │ ├── RequestInterceptor.java
│ │ ├── RequestLine.java
│ │ ├── RequestTemplate.java
│ │ ├── Response.java
│ │ ├── ResponseMapper.java
│ │ ├── SynchronousMethodHandler.java
│ │ ├── Types.java
│ │ ├── codec
│ │ │ ├── Decoder.java
│ │ │ ├── Encoder.java
│ │ │ ├── ErrorDecoder.java
│ │ │ └── StringDecoder.java
│ │ ├── log
│ │ │ ├── DefaultFakeLoggerFactory.java
│ │ │ ├── FakeLogger.java
│ │ │ ├── FakeLoggerFactory.java
│ │ │ └── Slf4JFakeLogger.java
│ │ ├── querymap
│ │ │ └── FieldQueryMapEncoder.java
│ │ └── template
│ │ │ ├── BodyTemplate.java
│ │ │ ├── Expression.java
│ │ │ ├── Expressions.java
│ │ │ ├── HeaderTemplate.java
│ │ │ ├── Literal.java
│ │ │ ├── QueryTemplate.java
│ │ │ ├── Template.java
│ │ │ ├── TemplateChunk.java
│ │ │ ├── UriTemplate.java
│ │ │ └── UriUtils.java
│ │ ├── configuration
│ │ ├── FakeAutoConfiguration.java
│ │ └── FakeClientsConfiguration.java
│ │ ├── openfake
│ │ ├── AnnotatedParameterProcessor.java
│ │ ├── DefaultTargeter.java
│ │ ├── Fake.java
│ │ ├── FakeClientFactoryBean.java
│ │ ├── FakeClientProperties.java
│ │ ├── FakeClientSpecification.java
│ │ ├── FakeContext.java
│ │ ├── FakeFormatterRegistrar.java
│ │ ├── OptionalDecoder.java
│ │ ├── SpringQueryMap.java
│ │ ├── Target.java
│ │ ├── Targeter.java
│ │ └── Types.java
│ │ └── support
│ │ ├── AbstractWriter.java
│ │ ├── ByteArrayWriter.java
│ │ ├── ContentProcessor.java
│ │ ├── ContentType.java
│ │ ├── DelegateWriter.java
│ │ ├── FakeHttpClientProperties.java
│ │ ├── FormData.java
│ │ ├── FormDataWriter.java
│ │ ├── FormEncoder.java
│ │ ├── FormProperty.java
│ │ ├── HttpRequestHeaderHolder.java
│ │ ├── HttpRequestHeaderHolderImpl.java
│ │ ├── ManyFilesWriter.java
│ │ ├── ManyParametersWriter.java
│ │ ├── MultipartFormContentProcessor.java
│ │ ├── Output.java
│ │ ├── PageJacksonModule.java
│ │ ├── PageableSpringEncoder.java
│ │ ├── PojoUtil.java
│ │ ├── PojoWriter.java
│ │ ├── ResponseEntityDecoder.java
│ │ ├── SingleFileWriter.java
│ │ ├── SingleParameterWriter.java
│ │ ├── SpringDecoder.java
│ │ ├── SpringEncoder.java
│ │ ├── SpringFormEncoder.java
│ │ ├── SpringManyMultipartFilesWriter.java
│ │ ├── SpringMvcContract.java
│ │ ├── SpringSingleMultipartFileWriter.java
│ │ ├── UrlencodedFormContentProcessor.java
│ │ └── Writer.java
│ └── test
│ └── java
│ └── cn
│ └── focusmedia
│ └── bigdata
│ └── pyramid
│ └── AppTest.java
├── k8s
├── destination-rule-all.yaml
├── micro-api-canary-istio-v1.yaml
├── micro-api-canary-istio-v2.yaml
├── micro-api-canary.yaml
├── micro-api.yaml
├── micro-gateway.yaml
├── micro-order.yaml
├── micro-pay.yaml
└── virtual-service-all.yaml
├── micro-api
├── docker
│ └── Dockerfile
├── micro-api.iml
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── wudimanong
│ │ └── micro
│ │ └── api
│ │ ├── MicroApi.java
│ │ ├── config
│ │ ├── AutoResultReturnHandler.java
│ │ └── WebMvcConfig.java
│ │ ├── controller
│ │ ├── ApiOrderController.java
│ │ └── TestController.java
│ │ └── exception
│ │ ├── GlobalCodeEnum.java
│ │ ├── GlobalExceptionHandler.java
│ │ ├── ResponseResult.java
│ │ └── ServiceException.java
│ └── resources
│ ├── application-dev.yml
│ └── application.yml
├── micro-order-client
├── micro-order-client.iml
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── wudimanong
│ └── micro
│ └── order
│ └── client
│ ├── OrderServiceClient.java
│ ├── bo
│ └── CreateOrderBO.java
│ └── dto
│ ├── CreateOrderDTO.java
│ └── result
│ ├── GlobalCodeEnum.java
│ └── ResponseResult.java
├── micro-order
├── docker
│ └── Dockerfile
├── micro-order.iml
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── wudimanong
│ │ └── micro
│ │ └── order
│ │ ├── MicroOrder.java
│ │ ├── config
│ │ ├── AutoResultReturnHandler.java
│ │ ├── GrpcClientCommandLineRunner.java
│ │ ├── GrpcClientConfiguration.java
│ │ └── WebMvcConfig.java
│ │ ├── controller
│ │ └── OrderController.java
│ │ ├── exception
│ │ ├── GlobalExceptionHandler.java
│ │ └── ServiceException.java
│ │ └── service
│ │ ├── OrderService.java
│ │ └── impl
│ │ └── OrderServiceImpl.java
│ └── resources
│ ├── application-dev.yml
│ └── application.yml
├── micro-pay-client
├── micro-pay-client.iml
├── pom.xml
└── src
│ └── main
│ └── proto
│ └── paycore.proto
├── micro-pay
├── docker
│ └── Dockerfile
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── wudimanong
│ │ └── micro
│ │ └── pay
│ │ ├── MicroPay.java
│ │ ├── config
│ │ ├── GrpcCommandLineRunner.java
│ │ └── GrpcServerConfiguration.java
│ │ └── provider
│ │ └── PayCoreProvider.java
│ └── resources
│ └── application.yml
└── pom.xml
/README.md:
--------------------------------------------------------------------------------
1 | # istio-micro-service-demo
2 | 基于Spring Boot+Istio的Service Mesh微服务架构示例代码
3 |
4 | 模拟App客户端服务调用的服务架构,其调用链路如下:
5 |
6 | micro-api(面向外部客户端的Api服务)
7 | |
8 | | http协议
9 | |
10 | micro-order(内部订单服务)
11 | |
12 | | Grpc协议
13 | |
14 | mciro-pay(内部支付服务)
15 |
16 | 如上所示链路,具体说明如下:
17 |
18 | 1)、为了完整演示在Service Mesh架构下的微服务研发过程,这里我们定义三个微服务,其中micro-api服务是面向外部客户端的接入Api服务提供Http协议访问;
19 |
20 | 2)、而micro-api与micro-order则基于微服务的注册发现机制进行内部微服务调用访问,采用Http协议;
21 |
22 | 3)、micro-order与micro-pay之间也基于微服务注册发现机制进行内部微服务调用访问,为了演示多种场景,这里两个微服务的调用采用GRpc协议;
23 |
24 |
25 | 更详细的文章说明链接:
26 | https://mp.weixin.qq.com/s/L1LoiI9NZqwZWsuCzEJN1A
27 |
28 | https://mp.weixin.qq.com/s/o2SrM7yrK9Kja2B40U63Ug
--------------------------------------------------------------------------------
/feign-istio-fake/README.md:
--------------------------------------------------------------------------------
1 | 对于传统采用Spring Cloud框架构建的微服务,服务之间一般会通过FeignClient方式进行微服务调用。但在Service Mesh微服务架构下,微服务之间的通信调用则不再需要原生OpenFeign所提供的客户端负载、熔断等功能。
2 |
3 | 但是为了快速支持或迁移Spring Cloud微服务至Service Mesh体系,需要在服务调用编程方式上尽量保持原有FeignClient的调用方式,但需要去掉其中所有熔断、负载均衡相关的服务治理代码。在Service Mesh体系中这些功能将交给Istio去完成。
4 |
5 | 本项目的编写目的就是为了适应上述要求,具体功能如下:
6 |
7 | 1、支持在istio服务网格体系下,完成服务间的快速调用(体验和原先Spring Cloud Feign类似);
8 |
9 | 2、支持多环境配置,例如本地环境微服务的调用地址可配置为本地,其他环境默认为Kubernetes集群中的服务;
10 |
11 | 3、支持链路追踪,默认透传如下Header,可以自动支持jaeger、zipkin链路追踪;
12 | `"x-request-id", "x-b3-traceid", "x-b3-spanid", "x-b3-sampled", "x-b3-flags", "x-b3-parentspanid","x-ot-span-context", "x-datadog-trace-id", "x-datadog-parent-id", "x-datadog-sampled", "end-user", "user-agent"
13 | `
14 |
--------------------------------------------------------------------------------
/feign-istio-fake/istio-fake.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/feign-istio-fake/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | istio-micro-demo
8 | com.wudimanong
9 | 1.0-SNAPSHOT
10 |
11 |
12 | istio.fake
13 | feign-istio-fake
14 | 1.0-SNAPSHOT
15 |
16 | feign-istio-fake
17 |
18 |
19 | UTF-8
20 | 1.8
21 | 1.8
22 |
23 |
24 |
25 |
26 | junit
27 | junit
28 | 4.11
29 | test
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-autoconfigure
34 | 2.1.6.RELEASE
35 |
36 |
37 | org.springframework.cloud
38 | spring-cloud-context
39 | 2.1.2.RELEASE
40 |
41 |
42 | org.slf4j
43 | slf4j-api
44 | 1.7.22
45 |
46 |
47 | org.springframework
48 | spring-web
49 | 5.1.8.RELEASE
50 |
51 |
52 | org.projectlombok
53 | lombok
54 | 1.18.8
55 |
56 |
57 | org.springframework.data
58 | spring-data-commons
59 | 2.1.9.RELEASE
60 |
61 |
62 | com.fasterxml.jackson.core
63 | jackson-databind
64 | 2.9.9
65 |
66 |
67 | javax.servlet
68 | javax.servlet-api
69 | 4.0.1
70 | provided
71 |
72 |
73 | com.alibaba
74 | fastjson
75 | 1.2.75
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-source-plugin
84 |
85 |
86 | attach-sources
87 |
88 | jar
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/annotation/EnableFakeClients.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.annotation;
18 |
19 | import java.lang.annotation.Documented;
20 | import java.lang.annotation.ElementType;
21 | import java.lang.annotation.Retention;
22 | import java.lang.annotation.RetentionPolicy;
23 | import java.lang.annotation.Target;
24 |
25 | import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
26 | import org.springframework.context.annotation.Import;
27 |
28 | import istio.fake.FakeClientsRegistrar;
29 | import istio.fake.configuration.FakeAutoConfiguration;
30 | import istio.fake.configuration.FakeClientsConfiguration;
31 |
32 | /**
33 | * Scans for interfaces that declare they are feign clients (via
34 | * {@link org.springframework.cloud.openfeign.FeignClient} @FeignClient
).
35 | * Configures component scanning directives for use with
36 | * {@link org.springframework.context.annotation.Configuration}
37 | * @Configuration
classes.
38 | *
39 | * @author Spencer Gibb
40 | * @author Dave Syer
41 | * @since 1.0
42 | */
43 | @Retention(RetentionPolicy.RUNTIME)
44 | @Target(ElementType.TYPE)
45 | @Documented
46 | @Import(FakeClientsRegistrar.class)
47 | @ImportAutoConfiguration({FakeAutoConfiguration.class, FakeClientsConfiguration.class})
48 | public @interface EnableFakeClients {
49 |
50 | /**
51 | * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
52 | * declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
53 | * {@code @ComponentScan(basePackages="org.my.pkg")}.
54 | * @return the array of 'basePackages'.
55 | */
56 | String[] value() default {};
57 |
58 | /**
59 | * Base packages to scan for annotated components.
60 | *
61 | * {@link #value()} is an alias for (and mutually exclusive with) this attribute.
62 | *
63 | * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
64 | * package names.
65 | * @return the array of 'basePackages'.
66 | */
67 | String[] basePackages() default {};
68 |
69 | /**
70 | * Type-safe alternative to {@link #basePackages()} for specifying the packages to
71 | * scan for annotated components. The package of each class specified will be scanned.
72 | *
73 | * Consider creating a special no-op marker class or interface in each package that
74 | * serves no purpose other than being referenced by this attribute.
75 | * @return the array of 'basePackageClasses'.
76 | */
77 | Class>[] basePackageClasses() default {};
78 |
79 | /**
80 | * A custom @Configuration
for all feign clients. Can contain override
81 | * @Bean
definition for the pieces that make up the client, for instance
82 | * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
83 | *
84 | * @return list of default configurations
85 | */
86 | Class>[] defaultConfiguration() default {};
87 |
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/annotation/FakeClient.java:
--------------------------------------------------------------------------------
1 | package istio.fake.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | import org.springframework.core.annotation.AliasFor;
10 |
11 | import istio.fake.configuration.FakeClientsConfiguration;
12 |
13 | /**
14 | * @author fandy
15 | */
16 | @Target(ElementType.TYPE)
17 | @Retention(RetentionPolicy.RUNTIME)
18 | @Documented
19 | public @interface FakeClient {
20 |
21 | @AliasFor("name")
22 | String value() default "";
23 |
24 | @AliasFor("value")
25 | String name() default "";
26 |
27 | /**
28 | * A custom @Configuration
for the feign client. Can contain override
29 | * @Bean
definition for the pieces that make up the client, for instance
30 | * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
31 | *
32 | * @see FakeClientsConfiguration for the defaults
33 | */
34 | Class>[] configuration() default {FakeClientsConfiguration.class};
35 |
36 | /**
37 | * @return whether to mark the feign proxy as a primary bean. Defaults to true.
38 | */
39 | boolean primary() default true;
40 |
41 | /**
42 | * @return the @Qualifier
value for the feign client.
43 | */
44 | String qualifier() default "";
45 |
46 | /**
47 | * @return whether 404s should be decoded instead of throwing FeignExceptions
48 | */
49 | boolean decode404() default false;
50 | }
51 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/annotation/PathVariableParameterProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.annotation;
18 |
19 | import java.lang.annotation.Annotation;
20 | import java.lang.reflect.Method;
21 | import java.util.Collection;
22 | import java.util.Map;
23 |
24 | import org.springframework.web.bind.annotation.PathVariable;
25 |
26 | import istio.fake.util.Util;
27 | import istio.fake.base.MethodMetadata;
28 | import istio.fake.openfake.AnnotatedParameterProcessor;
29 |
30 | /**
31 | * {@link PathVariable} parameter processor.
32 | *
33 | * @author Jakub Narloch
34 | * @author Abhijit Sarkar
35 | * @see AnnotatedParameterProcessor
36 | */
37 | public class PathVariableParameterProcessor implements AnnotatedParameterProcessor {
38 |
39 | private static final Class ANNOTATION = PathVariable.class;
40 |
41 | @Override
42 | public Class extends Annotation> getAnnotationType() {
43 | return ANNOTATION;
44 | }
45 |
46 | @Override
47 | public boolean processArgument(AnnotatedParameterContext context,
48 | Annotation annotation, Method method) {
49 | String name = ANNOTATION.cast(annotation).value();
50 | Util.checkState(Util.emptyToNull(name) != null,
51 | "PathVariable annotation was empty on param %s.",
52 | context.getParameterIndex());
53 | context.setParameterName(name);
54 |
55 | MethodMetadata data = context.getMethodMetadata();
56 | String varName = '{' + name + '}';
57 | if (!data.template().url().contains(varName)
58 | && !searchMapValues(data.template().queries(), varName)
59 | && !searchMapValues(data.template().headers(), varName)) {
60 | data.formParams().add(name);
61 | }
62 | return true;
63 | }
64 |
65 | private boolean searchMapValues(Map> map, V search) {
66 | Collection> values = map.values();
67 | if (values == null) {
68 | return false;
69 | }
70 | for (Collection entry : values) {
71 | if (entry.contains(search)) {
72 | return true;
73 | }
74 | }
75 | return false;
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/annotation/QueryMapParameterProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.annotation;
18 |
19 | import java.lang.annotation.Annotation;
20 | import java.lang.reflect.Method;
21 |
22 | import istio.fake.base.MethodMetadata;
23 | import istio.fake.openfake.AnnotatedParameterProcessor;
24 | import istio.fake.openfake.SpringQueryMap;
25 |
26 | /**
27 | * {@link SpringQueryMap} parameter processor.
28 | *
29 | * @author Aram Peres
30 | * @see AnnotatedParameterProcessor
31 | */
32 | public class QueryMapParameterProcessor implements AnnotatedParameterProcessor {
33 |
34 | private static final Class ANNOTATION = SpringQueryMap.class;
35 |
36 | @Override
37 | public Class extends Annotation> getAnnotationType() {
38 | return ANNOTATION;
39 | }
40 |
41 | @Override
42 | public boolean processArgument(AnnotatedParameterContext context,
43 | Annotation annotation, Method method) {
44 | int paramIndex = context.getParameterIndex();
45 | MethodMetadata metadata = context.getMethodMetadata();
46 | if (metadata.queryMapIndex() == null) {
47 | metadata.queryMapIndex(paramIndex);
48 | metadata.queryMapEncoded(SpringQueryMap.class.cast(annotation).encoded());
49 | }
50 | return true;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/annotation/RequestHeaderParameterProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.annotation;
18 |
19 | import static istio.fake.util.Util.checkState;
20 | import static istio.fake.util.Util.emptyToNull;
21 |
22 | import java.lang.annotation.Annotation;
23 | import java.lang.reflect.Method;
24 | import java.util.Collection;
25 | import java.util.Map;
26 |
27 | import org.springframework.web.bind.annotation.RequestHeader;
28 |
29 | import istio.fake.base.MethodMetadata;
30 | import istio.fake.openfake.AnnotatedParameterProcessor;
31 |
32 | /**
33 | * {@link RequestHeader} parameter processor.
34 | *
35 | * @author Jakub Narloch
36 | * @author Abhijit Sarkar
37 | * @see AnnotatedParameterProcessor
38 | */
39 | public class RequestHeaderParameterProcessor implements AnnotatedParameterProcessor {
40 |
41 | private static final Class ANNOTATION = RequestHeader.class;
42 |
43 | @Override
44 | public Class extends Annotation> getAnnotationType() {
45 | return ANNOTATION;
46 | }
47 |
48 | @Override
49 | public boolean processArgument(AnnotatedParameterContext context,
50 | Annotation annotation, Method method) {
51 | int parameterIndex = context.getParameterIndex();
52 | Class> parameterType = method.getParameterTypes()[parameterIndex];
53 | MethodMetadata data = context.getMethodMetadata();
54 |
55 | if (Map.class.isAssignableFrom(parameterType)) {
56 | checkState(data.headerMapIndex() == null,
57 | "Header map can only be present once.");
58 | data.headerMapIndex(parameterIndex);
59 |
60 | return true;
61 | }
62 |
63 | String name = ANNOTATION.cast(annotation).value();
64 | checkState(emptyToNull(name) != null,
65 | "RequestHeader.value() was empty on parameter %s", parameterIndex);
66 | context.setParameterName(name);
67 |
68 | Collection header = context.setTemplateParameter(name,
69 | data.template().headers().get(name));
70 | data.template().header(name, header);
71 | return true;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/annotation/RequestParamParameterProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.annotation;
18 |
19 | import java.lang.annotation.Annotation;
20 | import java.lang.reflect.Method;
21 | import java.util.Collection;
22 | import java.util.Map;
23 |
24 | import org.springframework.web.bind.annotation.RequestParam;
25 |
26 | import istio.fake.util.Util;
27 | import istio.fake.base.MethodMetadata;
28 | import istio.fake.openfake.AnnotatedParameterProcessor;
29 |
30 | /**
31 | * {@link RequestParam} parameter processor.
32 | *
33 | * @author Jakub Narloch
34 | * @author Abhijit Sarkar
35 | * @see AnnotatedParameterProcessor
36 | */
37 | public class RequestParamParameterProcessor implements AnnotatedParameterProcessor {
38 |
39 | private static final Class ANNOTATION = RequestParam.class;
40 |
41 | @Override
42 | public Class extends Annotation> getAnnotationType() {
43 | return ANNOTATION;
44 | }
45 |
46 | @Override
47 | public boolean processArgument(AnnotatedParameterContext context,
48 | Annotation annotation, Method method) {
49 | int parameterIndex = context.getParameterIndex();
50 | Class> parameterType = method.getParameterTypes()[parameterIndex];
51 | MethodMetadata data = context.getMethodMetadata();
52 |
53 | if (Map.class.isAssignableFrom(parameterType)) {
54 | Util.checkState(data.queryMapIndex() == null,
55 | "Query map can only be present once.");
56 | data.queryMapIndex(parameterIndex);
57 |
58 | return true;
59 | }
60 |
61 | RequestParam requestParam = ANNOTATION.cast(annotation);
62 | String name = requestParam.value();
63 | Util.checkState(Util.emptyToNull(name) != null,
64 | "RequestParam.value() was empty on parameter %s", parameterIndex);
65 | context.setParameterName(name);
66 |
67 | Collection query = context.setTemplateParameter(name,
68 | data.template().queries().get(name));
69 | data.template().query(name, query);
70 | return true;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/Body.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import static java.lang.annotation.ElementType.METHOD;
17 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
18 |
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.Target;
21 | import java.util.Map;
22 |
23 | /**
24 | * A possibly templated body of a PUT or POST command. variables wrapped in curly braces are
25 | * expanded before the request is submitted.
26 | * ex.
27 | *
28 | *
29 | * @Body("<v01:getResourceRecordsOfZone><zoneName>{zoneName}</zoneName><rrType>0</rrType></v01:getResourceRecordsOfZone>")
30 | * List<Record> listByZone(@Param("zoneName") String zoneName);
31 | *
32 | *
33 | *
34 | * Note that if you'd like curly braces literally in the body, urlencode them first.
35 | *
36 | * @see RequestTemplate#expand(String, Map)
37 | */
38 | @Target(METHOD)
39 | @Retention(RUNTIME)
40 | public @interface Body {
41 |
42 | String value();
43 | }
44 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/CollectionFormat.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import java.nio.charset.Charset;
17 | import java.util.Collection;
18 |
19 | import istio.fake.base.template.UriUtils;
20 |
21 | /**
22 | * Various ways to encode collections in URL parameters.
23 | *
24 | *
25 | * These specific cases are inspired by the OpenAPI
26 | * specification .
27 | *
28 | */
29 | public enum CollectionFormat {
30 | /** Comma separated values, eg foo=bar,baz */
31 | CSV(","),
32 | /** Space separated values, eg foo=bar baz */
33 | SSV(" "),
34 | /** Tab separated values, eg foo=bar[tab]baz */
35 | TSV("\t"),
36 | /** Values separated with the pipe (|) character, eg foo=bar|baz */
37 | PIPES("|"),
38 | /** Parameter name repeated for each value, eg foo=bar&foo=baz */
39 | // Using null as a special case since there is no single separator character
40 | EXPLODED(null);
41 |
42 | private final String separator;
43 |
44 | CollectionFormat(String separator) {
45 | this.separator = separator;
46 | }
47 |
48 | /**
49 | * Joins the field and possibly multiple values with the given separator.
50 | *
51 | *
52 | * Calling EXPLODED.join("foo", ["bar"]) will return "foo=bar".
53 | *
54 | *
55 | *
56 | * Calling CSV.join("foo", ["bar", "baz"]) will return "foo=bar,baz".
57 | *
58 | *
59 | *
60 | * Null values are treated somewhat specially. With EXPLODED, the field is repeated without any
61 | * "=" for backwards compatibility. With all other formats, null values are not included in the
62 | * joined value list.
63 | *
64 | *
65 | * @param field The field name corresponding to these values.
66 | * @param values A collection of value strings for the given field.
67 | * @param charset to encode the sequence
68 | * @return The formatted char sequence of the field and joined values. If the value collection is
69 | * empty, an empty char sequence will be returned.
70 | */
71 | public CharSequence join(String field, Collection values, Charset charset) {
72 | StringBuilder builder = new StringBuilder();
73 | int valueCount = 0;
74 | for (String value : values) {
75 | if (separator == null) {
76 | // exploded
77 | builder.append(valueCount++ == 0 ? "" : "&");
78 | builder.append(UriUtils.queryEncode(field, charset));
79 | if (value != null) {
80 | builder.append('=');
81 | builder.append(UriUtils.queryEncode(value, charset));
82 | }
83 | } else {
84 | // delimited with a separator character
85 | if (builder.length() == 0) {
86 | builder.append(UriUtils.queryEncode(field, charset));
87 | }
88 | if (value == null) {
89 | continue;
90 | }
91 | builder.append(valueCount++ == 0 ? "=" : separator);
92 | builder.append(UriUtils.queryEncode(value, charset));
93 | }
94 | }
95 | return builder;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/DefaultMethodHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import java.lang.invoke.MethodHandle;
17 | import java.lang.invoke.MethodHandles.Lookup;
18 | import java.lang.reflect.Field;
19 | import java.lang.reflect.Method;
20 |
21 |
22 | /**
23 | * Handles default methods by directly invoking the default method code on the interface. The bindTo
24 | * method must be called on the result before invoke is called.
25 | */
26 | final class DefaultMethodHandler implements InvocationHandlerFactory.MethodHandler {
27 | // Uses Java 7 MethodHandle based reflection. As default methods will only exist when
28 | // run on a Java 8 JVM this will not affect use on legacy JVMs.
29 | // When Feign upgrades to Java 7, remove the @IgnoreJRERequirement annotation.
30 | private final MethodHandle unboundHandle;
31 |
32 | // handle is effectively final after bindTo has been called.
33 | private MethodHandle handle;
34 |
35 | public DefaultMethodHandler(Method defaultMethod) {
36 | try {
37 | Class> declaringClass = defaultMethod.getDeclaringClass();
38 | Field field = Lookup.class.getDeclaredField("IMPL_LOOKUP");
39 | field.setAccessible(true);
40 | Lookup lookup = (Lookup) field.get(null);
41 |
42 | this.unboundHandle = lookup.unreflectSpecial(defaultMethod, declaringClass);
43 | } catch (NoSuchFieldException ex) {
44 | throw new IllegalStateException(ex);
45 | } catch (IllegalAccessException ex) {
46 | throw new IllegalStateException(ex);
47 | }
48 | }
49 |
50 | /**
51 | * Bind this handler to a proxy object. After bound, DefaultMethodHandler#invoke will act as if it
52 | * was called on the proxy object. Must be called once and only once for a given instance of
53 | * DefaultMethodHandler
54 | */
55 | public void bindTo(Object proxy) {
56 | if (handle != null) {
57 | throw new IllegalStateException(
58 | "Attempted to rebind a default method handler that was already bound");
59 | }
60 | handle = unboundHandle.bindTo(proxy);
61 | }
62 |
63 | /**
64 | * Invoke this method. DefaultMethodHandler#bindTo must be called before the first time invoke is
65 | * called.
66 | */
67 | @Override
68 | public Object invoke(Object[] argv) throws Throwable {
69 | if (handle == null) {
70 | throw new IllegalStateException(
71 | "Default method handler invoked before proxy has been bound.");
72 | }
73 | return handle.invokeWithArguments(argv);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/ExceptionPropagationPolicy.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | public enum ExceptionPropagationPolicy {
17 | NONE, UNWRAP
18 | }
19 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/HeaderMap.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import static java.lang.annotation.ElementType.PARAMETER;
17 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
18 |
19 | import java.lang.annotation.Retention;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | * A template parameter that can be applied to a Map that contains header entries, where the keys
25 | * are Strings that are the header field names and the values are the header field values. The
26 | * headers specified by the map will be applied to the request after all other processing, and will
27 | * take precedence over any previously specified header parameters.
28 | * This parameter is useful in cases where different header fields and values need to be set on an
29 | * API method on a per-request basis in a thread-safe manner and independently of Feign client
30 | * construction. A concrete example of a case like this are custom metadata header fields (e.g. as
31 | * "x-amz-meta-*" or "x-goog-meta-*") where the header field names are dynamic and the range of keys
32 | * cannot be determined a priori. The {@link Headers} annotation does not allow this because the
33 | * header fields that it defines are static (it is not possible to add or remove fields on a
34 | * per-request basis), and doing this using a custom {@link Target} or {@link RequestInterceptor}
35 | * can be cumbersome (it requires more code for per-method customization, it is difficult to
36 | * implement in a thread-safe manner and it requires customization when the Feign client for the API
37 | * is built).
38 | *
39 | *
40 | * ...
41 | * @RequestLine("GET /servers/{serverId}")
42 | * void get(@Param("serverId") String serverId, @HeaderMap Map);
43 | * ...
44 | *
45 | *
46 | * The annotated parameter must be an instance of {@link Map}, and the keys must be Strings. The
47 | * header field value of a key will be the value of its toString method, except in the following
48 | * cases:
49 | *
50 | *
51 | * if the value is null, the value will remain null (rather than converting to the String
52 | * "null")
53 | * if the value is an {@link Iterable}, it is converted to a {@link List} of String objects
54 | * where each value in the list is either null if the original value was null or the value's
55 | * toString representation otherwise.
56 | *
57 | *
58 | * Once this conversion is applied, the query keys and resulting String values follow the same
59 | * contract as if they were set using {@link RequestTemplate#header(String, String...)}.
60 | */
61 | @Retention(RUNTIME)
62 | @java.lang.annotation.Target(PARAMETER)
63 | public @interface HeaderMap {
64 | }
65 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/Headers.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import static java.lang.annotation.ElementType.METHOD;
17 | import static java.lang.annotation.ElementType.TYPE;
18 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
19 |
20 | import java.lang.annotation.Retention;
21 | import java.lang.annotation.Target;
22 |
23 | /**
24 | * Expands headers supplied in the {@code value}. Variables to the the right of the colon are
25 | * expanded.
26 | *
27 | *
28 | * @Headers("Content-Type: application/xml")
29 | * interface SoapApi {
30 | * ...
31 | * @RequestLine("GET /")
32 | * @Headers("Cache-Control: max-age=640000")
33 | * ...
34 | *
35 | * @RequestLine("POST /")
36 | * @Headers({
37 | * "X-Foo: Bar",
38 | * "X-Ping: {token}"
39 | * }) void post(@Param("token") String token);
40 | * ...
41 | *
42 | *
43 | *
44 | * Notes:
45 | *
46 | * If you'd like curly braces literally in the header, urlencode them first.
47 | * Headers do not overwrite each other. All headers with the same name will be included in the
48 | * request.
49 | *
50 | *
51 | * Relationship to JAXRS
52 | *
53 | * The following two forms are identical.
54 | *
55 | * Feign:
56 | *
57 | *
58 | * @RequestLine("POST /")
59 | * @Headers({
60 | * "X-Ping: {token}"
61 | * }) void post(@Named("token") String token);
62 | * ...
63 | *
64 | *
65 | *
66 | * JAX-RS:
67 | *
68 | *
69 | * @POST @Path("/")
70 | * void post(@HeaderParam("X-Ping") String token);
71 | * ...
72 | *
73 | */
74 | @Target({METHOD, TYPE})
75 | @Retention(RUNTIME)
76 | public @interface Headers {
77 |
78 | String[] value();
79 | }
80 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/InvocationHandlerFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import java.lang.reflect.InvocationHandler;
17 | import java.lang.reflect.Method;
18 | import java.util.Map;
19 |
20 | import istio.fake.openfake.Target;
21 |
22 | /**
23 | * Controls reflective method dispatch.
24 | */
25 | public interface InvocationHandlerFactory {
26 |
27 | InvocationHandler create(Target target, Map dispatch);
28 |
29 | /**
30 | * Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a
31 | * single method.
32 | */
33 | interface MethodHandler {
34 |
35 | Object invoke(Object[] argv) throws Throwable;
36 | }
37 |
38 | static final class Default implements InvocationHandlerFactory {
39 |
40 | @Override
41 | public InvocationHandler create(Target target, Map dispatch) {
42 | return new ReflectiveFake.FeignInvocationHandler(target, dispatch);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/Param.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import static java.lang.annotation.ElementType.PARAMETER;
17 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
18 |
19 | import java.lang.annotation.Retention;
20 |
21 | /**
22 | * A named template parameter applied to {@link Headers}, {@linkplain RequestLine} or
23 | * {@linkplain Body}
24 | */
25 | @Retention(RUNTIME)
26 | @java.lang.annotation.Target(PARAMETER)
27 | public @interface Param {
28 |
29 | /**
30 | * The name of the template parameter.
31 | */
32 | String value();
33 |
34 | /**
35 | * How to expand the value of this parameter, if {@link ToStringExpander} isn't adequate.
36 | */
37 | Class extends Expander> expander() default ToStringExpander.class;
38 |
39 | /**
40 | * Specifies whether argument is already encoded The value is ignored for headers (headers are
41 | * never encoded)
42 | *
43 | * @see QueryMap#encoded
44 | */
45 | boolean encoded() default false;
46 |
47 | interface Expander {
48 |
49 | /**
50 | * Expands the value into a string. Does not accept or return null.
51 | */
52 | String expand(Object value);
53 | }
54 |
55 | final class ToStringExpander implements Expander {
56 |
57 | @Override
58 | public String expand(Object value) {
59 | return value.toString();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/QueryMap.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import static java.lang.annotation.ElementType.PARAMETER;
17 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
18 |
19 | import java.lang.annotation.Retention;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | * A template parameter that can be applied to a Map that contains query parameters, where the keys
25 | * are Strings that are the parameter names and the values are the parameter values. The queries
26 | * specified by the map will be applied to the request after all other processing, and will take
27 | * precedence over any previously specified query parameters. It is not necessary to reference the
28 | * parameter map as a variable.
29 | *
30 | *
31 | *
32 | * ...
33 | * @RequestLine("POST /servers")
34 | * void servers(@QueryMap Map);
35 | * ...
36 | *
37 | * @RequestLine("GET /servers/{serverId}?count={count}")
38 | * void get(@Param("serverId") String serverId, @Param("count") int count, @QueryMap Map);
39 | * ...
40 | *
41 | *
42 | * The annotated parameter must be an instance of {@link Map}, and the keys must be Strings. The
43 | * query value of a key will be the value of its toString method, except in the following cases:
44 | *
45 | *
46 | *
47 | * if the value is null, the value will remain null (rather than converting to the String
48 | * "null")
49 | * if the value is an {@link Iterable}, it is converted to a {@link List} of String objects
50 | * where each value in the list is either null if the original value was null or the value's
51 | * toString representation otherwise.
52 | *
53 | *
54 | * Once this conversion is applied, the query keys and resulting String values follow the same
55 | * contract as if they were set using {@link RequestTemplate#query(String, String...)}.
56 | */
57 | @Retention(RUNTIME)
58 | @java.lang.annotation.Target(PARAMETER)
59 | public @interface QueryMap {
60 | /**
61 | * Specifies whether parameter names and values are already encoded.
62 | *
63 | * @see Param#encoded
64 | */
65 | boolean encoded() default false;
66 | }
67 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/QueryMapEncoder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import java.util.Map;
17 |
18 | import istio.fake.base.querymap.FieldQueryMapEncoder;
19 |
20 | /**
21 | * A QueryMapEncoder encodes Objects into maps of query parameter names to values.
22 | *
23 | * @see FieldQueryMapEncoder
24 | * @see BeanQueryMapEncoder
25 | *
26 | */
27 | public interface QueryMapEncoder {
28 |
29 | /**
30 | * Encodes the given object into a query map.
31 | *
32 | * @param object the object to encode
33 | * @return the map represented by the object
34 | */
35 | Map encode(Object object);
36 |
37 | /**
38 | * @deprecated use {@link BeanQueryMapEncoder} instead. default encoder uses reflection to inspect
39 | * provided objects Fields to expand the objects values into a query string. If you
40 | * prefer that the query string be built using getter and setter methods, as defined
41 | * in the Java Beans API, please use the {@link BeanQueryMapEncoder}
42 | */
43 | class Default extends FieldQueryMapEncoder {
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/RequestInterceptor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | /**
17 | * Zero or more {@code RequestInterceptors} may be configured for purposes such as adding headers to
18 | * all requests. No guarantees are give with regards to the order that interceptors are applied.
19 | * Once interceptors are applied, {@link Target#apply(RequestTemplate)} is called to create the
20 | * immutable http request sent via {@link Client#execute(Request, feign.Request.Options)}.
21 | *
22 | * For example:
23 | *
24 | *
25 | * public void apply(RequestTemplate input) {
26 | * input.header("X-Auth", currentToken);
27 | * }
28 | *
29 | *
30 | *
31 | *
32 | * Configuration
33 | *
34 | * {@code RequestInterceptors} are configured via {@link Feign.Builder#requestInterceptors}.
35 | *
36 | * Implementation notes
37 | *
38 | * Do not add parameters, such as {@code /path/{foo}/bar } in your implementation of
39 | * {@link #apply(RequestTemplate)}.
40 | * Interceptors are applied after the template's parameters are
41 | * {@link RequestTemplate#resolve(java.util.Map) resolved}. This is to ensure that you can implement
42 | * signatures are interceptors.
43 | *
44 | *
45 | * Relationship to Retrofit 1.x
46 | *
47 | * This class is similar to {@code RequestInterceptor.intercept()}, except that the implementation
48 | * can read, remove, or otherwise mutate any part of the request template.
49 | */
50 | public interface RequestInterceptor {
51 |
52 | /**
53 | * Called for every request. Add data using methods on the supplied {@link RequestTemplate}.
54 | */
55 | void apply(RequestTemplate template);
56 | }
57 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/RequestLine.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import static java.lang.annotation.ElementType.METHOD;
17 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
18 |
19 | import java.lang.annotation.Retention;
20 |
21 | /**
22 | * Expands the uri template supplied in the {@code value}, permitting path and query variables, or
23 | * just the http method. Templates should conform to
24 | * RFC 6570 . Support is limited to Simple String
25 | * expansion and Reserved Expansion (Level 1 and Level 2) expressions.
26 | */
27 | @java.lang.annotation.Target(METHOD)
28 | @Retention(RUNTIME)
29 | public @interface RequestLine {
30 |
31 | String value();
32 |
33 | boolean decodeSlash() default true;
34 |
35 | CollectionFormat collectionFormat() default CollectionFormat.EXPLODED;
36 | }
37 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/ResponseMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base;
15 |
16 | import java.lang.reflect.Type;
17 |
18 | /**
19 | * Map function to apply to the response before decoding it.
20 | *
21 | *
22 | * {@code
23 | * new ResponseMapper() {
24 | * @Override
25 | * public Response map(Response response, Type type) {
26 | * try {
27 | * return response
28 | * .toBuilder()
29 | * .body(Util.toString(response.body().asReader()).toUpperCase().getBytes())
30 | * .build();
31 | * } catch (IOException e) {
32 | * throw new RuntimeException(e);
33 | * }
34 | * }
35 | * };
36 | * }
37 | *
38 | */
39 | public interface ResponseMapper {
40 |
41 | Response map(Response response, Type type);
42 | }
43 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/codec/Decoder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.codec;
15 |
16 | import java.io.IOException;
17 | import java.lang.reflect.Type;
18 |
19 | import istio.fake.FakeException;
20 | import istio.fake.util.Util;
21 | import istio.fake.base.Response;
22 |
23 | /**
24 | * Decodes an HTTP response into a single object of the given {@code type}. Invoked when
25 | * {@link Response#status()} is in the 2xx range and the return type is neither {@code void} nor
26 | * {@code
27 | * Response}.
28 | *
29 | *
30 | * Example Implementation:
31 | *
32 | *
33 | *
34 | * public class GsonDecoder implements Decoder {
35 | * private final Gson gson = new Gson();
36 | *
37 | * @Override
38 | * public Object decode(Response response, Type type) throws IOException {
39 | * try {
40 | * return gson.fromJson(response.body().asReader(), type);
41 | * } catch (JsonIOException e) {
42 | * if (e.getCause() != null &&
43 | * e.getCause() instanceof IOException) {
44 | * throw IOException.class.cast(e.getCause());
45 | * }
46 | * throw e;
47 | * }
48 | * }
49 | * }
50 | *
51 | *
52 | *
53 | * Implementation Note The {@code type} parameter will correspond to the
54 | * {@link java.lang.reflect.Method#getGenericReturnType() generic return type} of an
55 | * {@link feign.Target#type() interface} processed by {@link feign.Feign#newInstance(feign.Target)}.
56 | * When writing your implementation of Decoder, ensure you also test parameterized types such as
57 | * {@code
58 | * List}.
59 | * Note on exception propagation Exceptions thrown by {@link Decoder}s get wrapped in a
60 | * {@link DecodeException} unless they are a subclass of {@link FeignException} already, and unless
61 | * the client was configured with {@link Feign.Builder#decode404()}.
62 | */
63 | public interface Decoder {
64 |
65 | /**
66 | * Decodes an http response into an object corresponding to its
67 | * {@link java.lang.reflect.Method#getGenericReturnType() generic return type}. If you need to
68 | * wrap exceptions, please do so via {@link DecodeException}.
69 | *
70 | * @param response the response to decode
71 | * @param type {@link java.lang.reflect.Method#getGenericReturnType() generic return type} of the
72 | * method corresponding to this {@code response}.
73 | * @return instance of {@code type}
74 | * @throws IOException will be propagated safely to the caller.
75 | * @throws DecodeException when decoding failed due to a checked exception besides IOException.
76 | * @throws FeignException when decoding succeeds, but conveys the operation failed.
77 | */
78 | Object decode(Response response, Type type) throws IOException, FakeException;
79 |
80 | /** Default implementation of {@code Decoder}. */
81 | public class Default extends StringDecoder {
82 |
83 | @Override
84 | public Object decode(Response response, Type type) throws IOException {
85 | if (response.status() == 404 || response.status() == 204){
86 | return Util.emptyValueOf(type);
87 | }
88 |
89 | if (response.body() == null){
90 | return null;
91 | }
92 |
93 | if (byte[].class.equals(type)) {
94 | return Util.toByteArray(response.body().asInputStream());
95 | }
96 | return super.decode(response, type);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/codec/Encoder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.codec;
15 |
16 | import static java.lang.String.format;
17 |
18 | import java.lang.reflect.Type;
19 |
20 | import istio.fake.FakeException;
21 | import istio.fake.util.Util;
22 | import istio.fake.base.RequestTemplate;
23 |
24 | /**
25 | * Encodes an object into an HTTP request body. Like {@code javax.websocket.Encoder}. {@code
26 | * Encoder} is used when a method parameter has no {@code @Param} annotation. For example:
27 | *
28 | *
29 | *
30 | * @POST
31 | * @Path("/")
32 | * void create(User user);
33 | *
34 | *
35 | * Example implementation:
36 | *
37 | *
38 | *
39 | * public class GsonEncoder implements Encoder {
40 | * private final Gson gson;
41 | *
42 | * public GsonEncoder(Gson gson) {
43 | * this.gson = gson;
44 | * }
45 | *
46 | * @Override
47 | * public void encode(Object object, Type bodyType, RequestTemplate template) {
48 | * template.body(gson.toJson(object, bodyType));
49 | * }
50 | * }
51 | *
52 | *
53 | *
54 | *
Form encoding
55 | *
56 | * If any parameters are found in {@link fake.MethodMetadata#formParams()}, they will be collected
57 | * and passed to the Encoder as a map.
58 | *
59 | *
60 | * Ex. The following is a form. Notice the parameters aren't consumed in the request line. A map
61 | * including "username" and "password" keys will passed to the encoder, and the body type will be
62 | * {@link #MAP_STRING_WILDCARD}.
63 | *
64 | *
65 | * @RequestLine("POST /")
66 | * Session login(@Param("username") String username, @Param("password") String password);
67 | *
68 | */
69 | public interface Encoder {
70 | /** Type literal for {@code Map}, indicating the object to encode is a form. */
71 | Type MAP_STRING_WILDCARD = Util.MAP_STRING_WILDCARD;
72 |
73 | /**
74 | * Converts objects to an appropriate representation in the template.
75 | *
76 | * @param object what to encode as the request body.
77 | * @param bodyType the type the object should be encoded as. {@link #MAP_STRING_WILDCARD}
78 | * indicates form encoding.
79 | * @param template the request template to populate.
80 | * @throws FakeException when encoding failed due to a checked exception.
81 | */
82 | void encode(Object object, Type bodyType, RequestTemplate template) throws FakeException;
83 |
84 | /**
85 | * Default implementation of {@code Encoder}.
86 | */
87 | public class Default implements Encoder {
88 |
89 | @Override
90 | public void encode(Object object, Type bodyType, RequestTemplate template) {
91 | if (bodyType == String.class) {
92 | template.body(object.toString());
93 | } else if (bodyType == byte[].class) {
94 | template.body((byte[]) object, null);
95 | } else if (object != null) {
96 | throw new FakeException(
97 | format("%s is not a type supported by this encoder.", object.getClass()));
98 | }
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/codec/StringDecoder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.codec;
15 |
16 | import static java.lang.String.format;
17 |
18 | import java.io.IOException;
19 | import java.lang.reflect.Type;
20 |
21 | import istio.fake.FakeException;
22 | import istio.fake.util.Util;
23 | import istio.fake.base.Response;
24 |
25 | public class StringDecoder implements Decoder {
26 |
27 | @Override
28 | public Object decode(Response response, Type type) throws IOException {
29 | Response.Body body = response.body();
30 | if (body == null) {
31 | return null;
32 | }
33 | if (String.class.equals(type)) {
34 | return Util.toString(body.asReader());
35 | }
36 | throw new FakeException(
37 | format("status:%d, %s is not a type supported by this decoder.", response.status(), type));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/log/DefaultFakeLoggerFactory.java:
--------------------------------------------------------------------------------
1 | package istio.fake.base.log;
2 |
3 | public class DefaultFakeLoggerFactory implements FakeLoggerFactory {
4 |
5 | private FakeLogger fakeLogger;
6 |
7 | public DefaultFakeLoggerFactory(FakeLogger fakeLogger) {
8 | this.fakeLogger = fakeLogger;
9 | }
10 |
11 | @Override
12 | public FakeLogger create(Class> type) {
13 | return this.fakeLogger != null ? this.fakeLogger : new Slf4JFakeLogger(type);
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/log/FakeLoggerFactory.java:
--------------------------------------------------------------------------------
1 | package istio.fake.base.log;
2 |
3 | public interface FakeLoggerFactory {
4 |
5 | /**
6 | * Factory method to provide a {@link FakeLogger} for a given {@link Class}.
7 | * @param type the {@link Class} for which a {@link FakeLogger} instance is to be created
8 | * @return a {@link FakeLogger} instance
9 | */
10 | FakeLogger create(Class> type);
11 |
12 | }
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/log/Slf4JFakeLogger.java:
--------------------------------------------------------------------------------
1 | package istio.fake.base.log;
2 |
3 | import java.io.IOException;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import istio.fake.base.Request;
9 | import istio.fake.base.Response;
10 |
11 | public class Slf4JFakeLogger extends FakeLogger {
12 |
13 | private final Logger logger;
14 |
15 | public Slf4JFakeLogger() {
16 | this(FakeLogger.class);
17 | }
18 |
19 | public Slf4JFakeLogger(Class> clazz) {
20 | this(LoggerFactory.getLogger(clazz));
21 | }
22 |
23 | public Slf4JFakeLogger(String name) {
24 | this(LoggerFactory.getLogger(name));
25 | }
26 |
27 | Slf4JFakeLogger(Logger logger) {
28 | this.logger = logger;
29 | }
30 |
31 | @Override
32 | public void logRequest(String configKey, Level logLevel, Request request) {
33 | if (logger.isDebugEnabled()) {
34 | super.logRequest(configKey, logLevel, request);
35 | }
36 | }
37 |
38 | @Override
39 | public Response logAndRebufferResponse(String configKey,
40 | Level logLevel,
41 | Response response,
42 | long elapsedTime)
43 | throws IOException {
44 | if (logger.isDebugEnabled()) {
45 | return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
46 | }
47 | return response;
48 | }
49 |
50 | @Override
51 | protected void log(String configKey, String format, Object... args) {
52 | // Not using SLF4J's support for parameterized messages (even though it would be more efficient)
53 | // because it would
54 | // require the incoming message formats to be SLF4J-specific.
55 | if (logger.isDebugEnabled()) {
56 | logger.debug(String.format(methodTag(configKey) + format, args));
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/querymap/FieldQueryMapEncoder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.querymap;
15 |
16 | import java.lang.reflect.Field;
17 | import java.util.Arrays;
18 | import java.util.Collections;
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 | import java.util.stream.Collectors;
23 |
24 | import istio.fake.FakeException;
25 | import istio.fake.base.QueryMapEncoder;
26 |
27 | /**
28 | * the query map will be generated using member variable names as query parameter names.
29 | *
30 | * eg: "/uri?name={name}&number={number}"
31 | *
32 | * order of included query parameters not guaranteed, and as usual, if any value is null, it will be
33 | * left out
34 | */
35 | public class FieldQueryMapEncoder implements QueryMapEncoder {
36 |
37 | private final Map, ObjectParamMetadata> classToMetadata =
38 | new HashMap, ObjectParamMetadata>();
39 |
40 | @Override
41 | public Map encode(Object object) throws FakeException {
42 | try {
43 | ObjectParamMetadata metadata = getMetadata(object.getClass());
44 | Map fieldNameToValue = new HashMap();
45 | for (Field field : metadata.objectFields) {
46 | Object value = field.get(object);
47 | if (value != null && value != object) {
48 | fieldNameToValue.put(field.getName(), value);
49 | }
50 | }
51 | return fieldNameToValue;
52 | } catch (IllegalAccessException e) {
53 | throw new FakeException("Failure encoding object into query map", e);
54 | }
55 | }
56 |
57 | private ObjectParamMetadata getMetadata(Class> objectType) {
58 | ObjectParamMetadata metadata = classToMetadata.get(objectType);
59 | if (metadata == null) {
60 | metadata = ObjectParamMetadata.parseObjectType(objectType);
61 | classToMetadata.put(objectType, metadata);
62 | }
63 | return metadata;
64 | }
65 |
66 | private static class ObjectParamMetadata {
67 |
68 | private final List objectFields;
69 |
70 | private ObjectParamMetadata(List objectFields) {
71 | this.objectFields = Collections.unmodifiableList(objectFields);
72 | }
73 |
74 | private static ObjectParamMetadata parseObjectType(Class> type) {
75 | return new ObjectParamMetadata(
76 | Arrays.stream(type.getDeclaredFields())
77 | .filter(field -> !field.isSynthetic())
78 | .peek(field -> field.setAccessible(true))
79 | .collect(Collectors.toList()));
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/template/BodyTemplate.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.template;
15 |
16 | import java.nio.charset.Charset;
17 | import java.util.Map;
18 |
19 | import istio.fake.util.Util;
20 |
21 | /**
22 | * Template for @{@link fake.Body} annotated Templates. Unresolved expressions are preserved as
23 | * literals and literals are not URI encoded.
24 | */
25 | public final class BodyTemplate extends Template {
26 |
27 | private static final String JSON_TOKEN_START = "{";
28 | private static final String JSON_TOKEN_END = "}";
29 | private static final String JSON_TOKEN_START_ENCODED = "%7B";
30 | private static final String JSON_TOKEN_END_ENCODED = "%7D";
31 | private boolean json = false;
32 |
33 | /**
34 | * Create a new Body Template.
35 | *
36 | * @param template to parse.
37 | * @return a Body Template instance.
38 | */
39 | public static BodyTemplate create(String template) {
40 | return new BodyTemplate(template, Util.UTF_8);
41 | }
42 |
43 | private BodyTemplate(String value, Charset charset) {
44 | super(value, ExpansionOptions.ALLOW_UNRESOLVED, EncodingOptions.NOT_REQUIRED, false, charset);
45 | if (value.startsWith(JSON_TOKEN_START_ENCODED) && value.endsWith(JSON_TOKEN_END_ENCODED)) {
46 | this.json = true;
47 | }
48 | }
49 |
50 | @Override
51 | public String expand(Map variables) {
52 | String expanded = super.expand(variables);
53 | if (this.json) {
54 | /* decode only the first and last character */
55 | StringBuilder sb = new StringBuilder();
56 | sb.append(JSON_TOKEN_START);
57 | sb.append(expanded,
58 | expanded.indexOf(JSON_TOKEN_START_ENCODED) + JSON_TOKEN_START_ENCODED.length(),
59 | expanded.lastIndexOf(JSON_TOKEN_END_ENCODED));
60 | sb.append(JSON_TOKEN_END);
61 | return sb.toString();
62 | }
63 | return expanded;
64 | }
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/template/Expression.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.template;
15 |
16 | import java.util.Optional;
17 | import java.util.regex.Pattern;
18 |
19 | /**
20 | * URI Template Expression.
21 | */
22 | abstract class Expression implements TemplateChunk {
23 |
24 | private String name;
25 | private Pattern pattern;
26 |
27 | /**
28 | * Create a new Expression.
29 | *
30 | * @param name of the variable
31 | * @param pattern the resolved variable must adhere to, optional.
32 | */
33 | Expression(String name, String pattern) {
34 | this.name = name;
35 | Optional.ofNullable(pattern).ifPresent(s -> this.pattern = Pattern.compile(s));
36 | }
37 |
38 | abstract String expand(Object variable, boolean encode);
39 |
40 | public String getName() {
41 | return this.name;
42 | }
43 |
44 | Pattern getPattern() {
45 | return pattern;
46 | }
47 |
48 | /**
49 | * Checks if the provided value matches the variable pattern, if one is defined. Always true if no
50 | * pattern is defined.
51 | *
52 | * @param value to check.
53 | * @return true if it matches.
54 | */
55 | boolean matches(String value) {
56 | if (pattern == null) {
57 | return true;
58 | }
59 | return pattern.matcher(value).matches();
60 | }
61 |
62 | @Override
63 | public String getValue() {
64 | if (this.pattern != null) {
65 | return "{" + this.name + ":" + this.pattern + "}";
66 | }
67 | return "{" + this.name + "}";
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return this.getValue();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/template/HeaderTemplate.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.template;
15 |
16 | import java.nio.charset.Charset;
17 | import java.util.Collection;
18 | import java.util.Collections;
19 | import java.util.Iterator;
20 | import java.util.LinkedHashSet;
21 | import java.util.Set;
22 | import java.util.stream.Collectors;
23 | import java.util.stream.StreamSupport;
24 |
25 | import istio.fake.util.Util;
26 |
27 | /**
28 | * Template for HTTP Headers. Variables that are unresolved are ignored and Literals are not
29 | * encoded.
30 | */
31 | public final class HeaderTemplate extends Template {
32 |
33 | /* cache a copy of the variables for lookup later */
34 | private Set values;
35 | private String name;
36 |
37 | public static HeaderTemplate create(String name, Iterable values) {
38 | if (name == null || name.isEmpty()) {
39 | throw new IllegalArgumentException("name is required.");
40 | }
41 |
42 | if (values == null) {
43 | throw new IllegalArgumentException("values are required");
44 | }
45 |
46 | /* construct a uri template from the name and values */
47 | StringBuilder template = new StringBuilder();
48 | template.append(name)
49 | .append(" ");
50 |
51 | /* create a comma separated template for the header values */
52 | Iterator iterator = values.iterator();
53 | while (iterator.hasNext()) {
54 | template.append(iterator.next());
55 | if (iterator.hasNext()) {
56 | template.append(", ");
57 | }
58 | }
59 | return new HeaderTemplate(template.toString(), name, values, Util.UTF_8);
60 | }
61 |
62 | /**
63 | * Append values to a Header Template.
64 | *
65 | * @param headerTemplate to append to.
66 | * @param values to append.
67 | * @return a new Header Template with the values added.
68 | */
69 | public static HeaderTemplate append(HeaderTemplate headerTemplate, Iterable values) {
70 | Set headerValues = new LinkedHashSet<>(headerTemplate.getValues());
71 | headerValues.addAll(StreamSupport.stream(values.spliterator(), false)
72 | .filter(Util::isNotBlank)
73 | .collect(Collectors.toSet()));
74 | return create(headerTemplate.getName(), headerValues);
75 | }
76 |
77 | /**
78 | * Creates a new Header Template.
79 | *
80 | * @param template to parse.
81 | */
82 | private HeaderTemplate(String template, String name, Iterable values, Charset charset) {
83 | super(template, ExpansionOptions.REQUIRED, EncodingOptions.NOT_REQUIRED, false, charset);
84 | this.values = StreamSupport.stream(values.spliterator(), false)
85 | .filter(Util::isNotBlank)
86 | .collect(Collectors.toSet());
87 | this.name = name;
88 | }
89 |
90 | public Collection getValues() {
91 | return Collections.unmodifiableCollection(values);
92 | }
93 |
94 | public String getName() {
95 | return name;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/template/Literal.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.template;
15 |
16 | /**
17 | * URI Template Literal.
18 | */
19 | class Literal implements TemplateChunk {
20 |
21 | private final String value;
22 |
23 | /**
24 | * Create a new Literal.
25 | *
26 | * @param value of the literal.
27 | * @return the new Literal.
28 | */
29 | public static Literal create(String value) {
30 | return new Literal(value);
31 | }
32 |
33 | /**
34 | * Create a new Literal.
35 | *
36 | * @param value of the literal.
37 | */
38 | Literal(String value) {
39 | if (value == null || value.isEmpty()) {
40 | throw new IllegalArgumentException("a value is required.");
41 | }
42 | this.value = value;
43 | }
44 |
45 | @Override
46 | public String getValue() {
47 | return this.value;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/template/TemplateChunk.java:
--------------------------------------------------------------------------------
1 | package istio.fake.base.template;
2 |
3 | @FunctionalInterface
4 | interface TemplateChunk {
5 |
6 | String getValue();
7 |
8 | }
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/base/template/UriTemplate.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.base.template;
15 |
16 | import java.nio.charset.Charset;
17 |
18 | /**
19 | * URI Template, as defined by RFC 6570 ,
20 | * supporting Level 1 expressions,
21 | * with the following differences:
22 | *
23 | *
24 | * unresolved variables are preserved as literals
25 | * all literals are pct-encoded
26 | *
27 | */
28 | public class UriTemplate extends Template {
29 |
30 | /**
31 | * Create a Uri Template.
32 | *
33 | * @param template representing the uri.
34 | * @param charset for encoding.
35 | * @return a new Uri Template instance.
36 | */
37 | public static UriTemplate create(String template, Charset charset) {
38 | return new UriTemplate(template, true, charset);
39 | }
40 |
41 | /**
42 | * Create a Uri Template.
43 | *
44 | * @param template representing the uri
45 | * @param encodeSlash flag if slash characters should be encoded.
46 | * @param charset for the template.
47 | * @return a new Uri Template instance.
48 | */
49 | public static UriTemplate create(String template, boolean encodeSlash, Charset charset) {
50 | return new UriTemplate(template, encodeSlash, charset);
51 | }
52 |
53 | /**
54 | * Append a uri fragment to the template.
55 | *
56 | * @param uriTemplate to append to.
57 | * @param fragment to append.
58 | * @return a new UriTemplate with the fragment appended.
59 | */
60 | public static UriTemplate append(UriTemplate uriTemplate, String fragment) {
61 | return new UriTemplate(uriTemplate.toString() + fragment, uriTemplate.encodeSlash(),
62 | uriTemplate.getCharset());
63 | }
64 |
65 | /**
66 | * Create a new Uri Template.
67 | *
68 | * @param template for the uri.
69 | * @param encodeSlash flag for encoding slash characters.
70 | * @param charset to use when encoding.
71 | */
72 | private UriTemplate(String template, boolean encodeSlash, Charset charset) {
73 | super(template, ExpansionOptions.REQUIRED, EncodingOptions.REQUIRED, encodeSlash, charset);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/AnnotatedParameterProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.openfake;
18 |
19 | import java.lang.annotation.Annotation;
20 | import java.lang.reflect.Method;
21 | import java.util.Collection;
22 |
23 | import istio.fake.base.MethodMetadata;
24 |
25 | /**
26 | * Feign contract method parameter processor.
27 | *
28 | * @author Jakub Narloch
29 | * @author Abhijit Sarkar
30 | */
31 | public interface AnnotatedParameterProcessor {
32 |
33 | /**
34 | * Retrieves the processor supported annotation type.
35 | * @return the annotation type
36 | */
37 | Class extends Annotation> getAnnotationType();
38 |
39 | /**
40 | * Process the annotated parameter.
41 | * @param context the parameter context
42 | * @param annotation the annotation instance
43 | * @param method the method that contains the annotation
44 | * @return whether the parameter is http
45 | */
46 | boolean processArgument(AnnotatedParameterContext context, Annotation annotation,
47 | Method method);
48 |
49 | /**
50 | * Specifies the parameter context.
51 | *
52 | * @author Jakub Narloch
53 | */
54 | interface AnnotatedParameterContext {
55 |
56 | /**
57 | * Retrieves the method metadata.
58 | * @return the method metadata
59 | */
60 | MethodMetadata getMethodMetadata();
61 |
62 | /**
63 | * Retrieves the index of the parameter.
64 | * @return the parameter index
65 | */
66 | int getParameterIndex();
67 |
68 | /**
69 | * Sets the parameter name.
70 | * @param name the name of the parameter
71 | */
72 | void setParameterName(String name);
73 |
74 | /**
75 | * Sets the template parameter.
76 | * @param name the template parameter
77 | * @param rest the existing parameter values
78 | * @return parameters
79 | */
80 | Collection setTemplateParameter(String name, Collection rest);
81 |
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/DefaultTargeter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.openfake;
18 |
19 | /**
20 | * @author Spencer Gibb
21 | * @author Erik Kringen
22 | */
23 | public class DefaultTargeter implements Targeter {
24 |
25 | @Override
26 | public T target(FakeClientFactoryBean factory, Fake.Builder fake,
27 | FakeContext context, Target.HardCodedTarget target) {
28 |
29 | return fake.target(target);
30 | }
31 |
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/FakeClientSpecification.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.openfake;
18 |
19 | import java.util.Arrays;
20 | import java.util.Objects;
21 |
22 | import org.springframework.cloud.context.named.NamedContextFactory;
23 |
24 | /**
25 | * @author Dave Syer
26 | * @author Gregor Zurowski
27 | */
28 | public class FakeClientSpecification implements NamedContextFactory.Specification {
29 |
30 | private String name;
31 |
32 | private Class>[] configuration;
33 |
34 | FakeClientSpecification() {
35 | }
36 |
37 | FakeClientSpecification(String name, Class>[] configuration) {
38 | this.name = name;
39 | this.configuration = configuration;
40 | }
41 |
42 | @Override
43 | public String getName() {
44 | return this.name;
45 | }
46 |
47 | public void setName(String name) {
48 | this.name = name;
49 | }
50 |
51 | @Override
52 | public Class>[] getConfiguration() {
53 | return this.configuration;
54 | }
55 |
56 | public void setConfiguration(Class>[] configuration) {
57 | this.configuration = configuration;
58 | }
59 |
60 | @Override
61 | public boolean equals(Object o) {
62 | if (this == o) {
63 | return true;
64 | }
65 | if (o == null || getClass() != o.getClass()) {
66 | return false;
67 | }
68 | FakeClientSpecification that = (FakeClientSpecification) o;
69 | return Objects.equals(this.name, that.name)
70 | && Arrays.equals(this.configuration, that.configuration);
71 | }
72 |
73 | @Override
74 | public int hashCode() {
75 | return Objects.hash(this.name, this.configuration);
76 | }
77 |
78 | @Override
79 | public String toString() {
80 | return new StringBuilder("FeignClientSpecification{").append("name='")
81 | .append(this.name).append("', ").append("configuration=")
82 | .append(Arrays.toString(this.configuration)).append("}").toString();
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/FakeContext.java:
--------------------------------------------------------------------------------
1 | package istio.fake.openfake;
2 |
3 | import org.springframework.cloud.context.named.NamedContextFactory;
4 |
5 | import istio.fake.configuration.FakeClientsConfiguration;
6 |
7 | public class FakeContext extends NamedContextFactory {
8 |
9 | public FakeContext() {
10 | super(FakeClientsConfiguration.class, "fake", "fake.client.name");
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/FakeFormatterRegistrar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.openfake;
18 |
19 | import org.springframework.format.FormatterRegistrar;
20 | import org.springframework.format.support.FormattingConversionService;
21 |
22 | /**
23 | * Allows an application to customize the Feign {@link FormattingConversionService}.
24 | *
25 | * @author Matt Benson
26 | */
27 | public interface FakeFormatterRegistrar extends FormatterRegistrar {
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/OptionalDecoder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2012-2019 The Feign Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 | package istio.fake.openfake;
15 |
16 | import java.io.IOException;
17 | import java.lang.reflect.ParameterizedType;
18 | import java.lang.reflect.Type;
19 | import java.util.Objects;
20 | import java.util.Optional;
21 |
22 | import istio.fake.util.Util;
23 | import istio.fake.base.Response;
24 | import istio.fake.base.codec.Decoder;
25 |
26 | public final class OptionalDecoder implements Decoder {
27 | final Decoder delegate;
28 |
29 | public OptionalDecoder(Decoder delegate) {
30 | Objects.requireNonNull(delegate, "Decoder must not be null. ");
31 | this.delegate = delegate;
32 | }
33 |
34 | @Override
35 | public Object decode(Response response, Type type) throws IOException {
36 | if (!isOptional(type)) {
37 | return delegate.decode(response, type);
38 | }
39 | if (response.status() == 404 || response.status() == 204) {
40 | return Optional.empty();
41 | }
42 | Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);
43 | return Optional.ofNullable(delegate.decode(response, enclosedType));
44 | }
45 |
46 | static boolean isOptional(Type type) {
47 | if (!(type instanceof ParameterizedType)) {
48 | return false;
49 | }
50 | ParameterizedType parameterizedType = (ParameterizedType) type;
51 | return parameterizedType.getRawType().equals(Optional.class);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/SpringQueryMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.openfake;
18 |
19 | import java.lang.annotation.ElementType;
20 | import java.lang.annotation.Retention;
21 | import java.lang.annotation.RetentionPolicy;
22 | import java.lang.annotation.Target;
23 |
24 | import org.springframework.core.annotation.AliasFor;
25 |
26 | /**
27 | * Spring MVC equivalent of OpenFeign's {@link feign.QueryMap} parameter annotation.
28 | *
29 | * @author Aram Peres
30 | * @see feign.QueryMap
31 | * @see org.springframework.cloud.openfeign.annotation.QueryMapParameterProcessor
32 | */
33 | @Retention(RetentionPolicy.RUNTIME)
34 | @Target({ ElementType.PARAMETER })
35 | public @interface SpringQueryMap {
36 |
37 | /**
38 | * @see QueryMap#encoded()
39 | * @return alias for {@link #encoded()}.
40 | */
41 | @AliasFor("encoded")
42 | boolean value() default false;
43 |
44 | /**
45 | * @see QueryMap#encoded()
46 | * @return Specifies whether parameter names and values are already encoded.
47 | */
48 | @AliasFor("value")
49 | boolean encoded() default false;
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/openfake/Targeter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.openfake;
18 |
19 | /**
20 | * @author Spencer Gibb
21 | */
22 | public interface Targeter {
23 |
24 | T target(FakeClientFactoryBean factory, Fake.Builder feign,
25 | FakeContext context, Target.HardCodedTarget target);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/AbstractWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 |
20 | import java.net.URLConnection;
21 |
22 | import istio.fake.FakeException;
23 | import lombok.SneakyThrows;
24 | import lombok.val;
25 |
26 | /**
27 | *
28 | * @author Artem Labazin
29 | */
30 | public abstract class AbstractWriter implements Writer {
31 |
32 | @Override
33 | public void write (Output output, String boundary, String key, Object value) throws FakeException {
34 | output.write("--").write(boundary).write(ContentProcessor.CRLF);
35 | write(output, key, value);
36 | output.write(ContentProcessor.CRLF);
37 | }
38 |
39 | /**
40 | * Writes data for it's children.
41 | *
42 | * @param output output writer.
43 | * @param key name for piece of data.
44 | * @param value piece of data.
45 | *
46 | * @throws FakeException in case of write errors
47 | */
48 | @SuppressWarnings({
49 | "PMD.UncommentedEmptyMethodBody",
50 | "PMD.EmptyMethodInAbstractClassShouldBeAbstract"
51 | })
52 | protected void write (Output output, String key, Object value) throws FakeException {
53 | }
54 |
55 | /**
56 | * Writes file's metadata.
57 | *
58 | * @param output output writer.
59 | * @param name name for piece of data.
60 | * @param fileName file name.
61 | * @param contentType type of file content. May be the {@code null}, in that case it will be determined by file name.
62 | */
63 | @SneakyThrows
64 | protected void writeFileMetadata (Output output, String name, String fileName, String contentType) {
65 | val contentDespositionBuilder = new StringBuilder()
66 | .append("Content-Disposition: form-data; name=\"").append(name).append("\"");
67 | if (fileName != null) {
68 | contentDespositionBuilder.append("; ").append("filename=\"").append(fileName).append("\"");
69 | }
70 |
71 | String fileContentType = contentType;
72 | if (fileContentType == null) {
73 | if (fileName != null) {
74 | fileContentType = URLConnection.guessContentTypeFromName(fileName);
75 | }
76 | if (fileContentType == null) {
77 | fileContentType = "application/octet-stream";
78 | }
79 | }
80 |
81 | val string = new StringBuilder()
82 | .append(contentDespositionBuilder.toString()).append(ContentProcessor.CRLF)
83 | .append("Content-Type: ").append(fileContentType).append(ContentProcessor.CRLF)
84 | .append("Content-Transfer-Encoding: binary").append(ContentProcessor.CRLF)
85 | .append(ContentProcessor.CRLF)
86 | .toString();
87 |
88 | output.write(string);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/ByteArrayWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import istio.fake.FakeException;
20 |
21 | /**
22 | *
23 | * @author Artem Labazin
24 | */
25 | public class ByteArrayWriter extends AbstractWriter {
26 |
27 | @Override
28 | public boolean isApplicable (Object value) {
29 | return value instanceof byte[];
30 | }
31 |
32 | @Override
33 | protected void write (Output output, String key, Object value) throws FakeException {
34 | writeFileMetadata(output, key, null, null);
35 |
36 | byte[] bytes = (byte[]) value;
37 | output.write(bytes);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/ContentProcessor.java:
--------------------------------------------------------------------------------
1 | //
2 | // Source code recreated from a .class file by IntelliJ IDEA
3 | // (powered by Fernflower decompiler)
4 | //
5 |
6 | package istio.fake.support;
7 |
8 | import java.nio.charset.Charset;
9 | import java.util.Map;
10 |
11 | import istio.fake.FakeException;
12 | import istio.fake.base.RequestTemplate;
13 |
14 | public interface ContentProcessor {
15 | String CONTENT_TYPE_HEADER = "Content-Type";
16 | String CRLF = "\r\n";
17 |
18 | void process(RequestTemplate var1, Charset var2, Map var3) throws FakeException;
19 |
20 | ContentType getSupportedContentType();
21 | }
22 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/ContentType.java:
--------------------------------------------------------------------------------
1 | //
2 | // Source code recreated from a .class file by IntelliJ IDEA
3 | // (powered by Fernflower decompiler)
4 | //
5 |
6 | package istio.fake.support;
7 |
8 | public enum ContentType {
9 | UNDEFINED("undefined"),
10 | URLENCODED("application/x-www-form-urlencoded"),
11 | MULTIPART("multipart/form-data");
12 |
13 | private final String header;
14 |
15 | private ContentType(String header) {
16 | this.header = header;
17 | }
18 |
19 | public static ContentType of(String str) {
20 | if (str == null) {
21 | return UNDEFINED;
22 | } else {
23 | String trimmed = str.trim();
24 | ContentType[] var2 = values();
25 | int var3 = var2.length;
26 |
27 | for(int var4 = 0; var4 < var3; ++var4) {
28 | ContentType type = var2[var4];
29 | if (trimmed.startsWith(type.getHeader())) {
30 | return type;
31 | }
32 | }
33 |
34 | return UNDEFINED;
35 | }
36 | }
37 |
38 | public String getHeader() {
39 | return this.header;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/DelegateWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static lombok.AccessLevel.PRIVATE;
20 |
21 | import istio.fake.FakeException;
22 | import istio.fake.base.RequestTemplate;
23 | import istio.fake.base.codec.Encoder;
24 | import lombok.RequiredArgsConstructor;
25 | import lombok.experimental.FieldDefaults;
26 | import lombok.val;
27 |
28 | /**
29 | *
30 | * @author Artem Labazin
31 | */
32 | @RequiredArgsConstructor
33 | @FieldDefaults(level = PRIVATE, makeFinal = true)
34 | public class DelegateWriter extends AbstractWriter {
35 |
36 | Encoder delegate;
37 |
38 | SingleParameterWriter parameterWriter = new SingleParameterWriter();
39 |
40 | @Override
41 | public boolean isApplicable (Object value) {
42 | return true;
43 | }
44 |
45 | @Override
46 | protected void write (Output output, String key, Object value) throws FakeException {
47 | val fake = new RequestTemplate();
48 | delegate.encode(value, value.getClass(), fake);
49 | val bytes = fake.requestBody().asBytes();
50 | val string = new String(bytes, output.getCharset()).replaceAll("\n", "");
51 | parameterWriter.write(output, key, string);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/FormData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static lombok.AccessLevel.PRIVATE;
20 |
21 | import lombok.AllArgsConstructor;
22 | import lombok.Builder;
23 | import lombok.Data;
24 | import lombok.NoArgsConstructor;
25 | import lombok.experimental.FieldDefaults;
26 |
27 | /**
28 | * This object encapsulates a byte array and its associated content type.
29 | * Use if if you want to specify the content type of your provided byte array.
30 | *
31 | * @author Guillaume Simard
32 | * @since 24.03.2018
33 | */
34 | @Data
35 | @Builder
36 | @NoArgsConstructor
37 | @AllArgsConstructor
38 | @FieldDefaults(level = PRIVATE)
39 | public class FormData {
40 |
41 | String contentType;
42 |
43 | String fileName;
44 |
45 | byte[] data;
46 | }
47 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/FormDataWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import istio.fake.FakeException;
20 | import lombok.val;
21 |
22 | /**
23 | *
24 | * @author Guillaume Simard
25 | * @since 24.03.2018
26 | */
27 | public class FormDataWriter extends AbstractWriter {
28 |
29 | @Override
30 | public boolean isApplicable (Object value) {
31 | return value instanceof FormData;
32 | }
33 |
34 | @Override
35 | protected void write (Output output, String key, Object value) throws FakeException {
36 | val formData = (FormData) value;
37 | writeFileMetadata(output, key, formData.getFileName(), formData.getContentType());
38 | output.write(formData.getData());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/FormProperty.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static java.lang.annotation.ElementType.FIELD;
20 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
21 |
22 | import java.lang.annotation.Documented;
23 | import java.lang.annotation.Retention;
24 | import java.lang.annotation.Target;
25 |
26 | /**
27 | *
28 | * @author marembo
29 | */
30 | @Documented
31 | @Target(FIELD)
32 | @Retention(RUNTIME)
33 | public @interface FormProperty {
34 |
35 | /**
36 | * The name of the property.
37 | */
38 | String value ();
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/HttpRequestHeaderHolder.java:
--------------------------------------------------------------------------------
1 | package istio.fake.support;
2 |
3 | import java.util.Map;
4 |
5 | import javax.servlet.ServletRequestListener;
6 |
7 | public abstract class HttpRequestHeaderHolder implements ServletRequestListener {
8 |
9 | public abstract Map getHeaderMap();
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/HttpRequestHeaderHolderImpl.java:
--------------------------------------------------------------------------------
1 | package istio.fake.support;
2 |
3 | import java.util.HashMap;
4 | import java.util.List;
5 | import java.util.Map;
6 |
7 | import javax.servlet.ServletRequestEvent;
8 | import javax.servlet.http.HttpServletRequest;
9 |
10 | import org.springframework.util.CollectionUtils;
11 |
12 | /**
13 | * @author tanghuan@focusmedia.cn
14 | * @date 2019/7/14
15 | */
16 | public class HttpRequestHeaderHolderImpl extends HttpRequestHeaderHolder {
17 |
18 | private List tracingHeaderList;
19 |
20 | public HttpRequestHeaderHolderImpl(List tracingHeaderList) {
21 | this.tracingHeaderList = tracingHeaderList;
22 | }
23 |
24 | private ThreadLocal httpServletRequestHolder =
25 | new InheritableThreadLocal<>();
26 |
27 | @Override
28 | public void requestInitialized(ServletRequestEvent requestEvent) {
29 | HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
30 | httpServletRequestHolder.set(request);
31 | }
32 |
33 | @Override
34 | public void requestDestroyed(ServletRequestEvent requestEvent) {
35 | httpServletRequestHolder.remove();
36 | }
37 |
38 | public HttpServletRequest getHttpServletRequest() {
39 | return httpServletRequestHolder.get();
40 | }
41 |
42 | @Override
43 | public Map getHeaderMap() {
44 | HttpServletRequest request = getHttpServletRequest();
45 | if (request == null) {
46 | return null;
47 | }
48 |
49 | if (CollectionUtils.isEmpty(tracingHeaderList)) {
50 | return null;
51 | }
52 |
53 | Map headerMap = new HashMap<>(16);
54 | for (String name : tracingHeaderList) {
55 | String value = request.getHeader(name);
56 | if (value != null) {
57 | headerMap.put(name, request.getHeader(name));
58 | }
59 | }
60 | return headerMap;
61 |
62 | }
63 | }
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/ManyFilesWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static lombok.AccessLevel.PRIVATE;
20 |
21 | import java.io.File;
22 |
23 | import istio.fake.FakeException;
24 | import lombok.experimental.FieldDefaults;
25 | import lombok.val;
26 |
27 | /**
28 | *
29 | * @author Artem Labazin
30 | */
31 | @FieldDefaults(level = PRIVATE, makeFinal = true)
32 | public class ManyFilesWriter extends AbstractWriter {
33 |
34 | SingleFileWriter fileWriter = new SingleFileWriter();
35 |
36 | @Override
37 | public boolean isApplicable (Object value) {
38 | if (value instanceof File[]) {
39 | return true;
40 | }
41 | if (!(value instanceof Iterable)) {
42 | return false;
43 | }
44 | val iterable = (Iterable>) value;
45 | val iterator = iterable.iterator();
46 | return iterator.hasNext() && iterator.next() instanceof File;
47 | }
48 |
49 | @Override
50 | public void write (Output output, String boundary, String key, Object value) throws FakeException {
51 | if (value instanceof File[]) {
52 | val files = (File[]) value;
53 | for (val file : files) {
54 | fileWriter.write(output, boundary, key, file);
55 | }
56 | } else if (value instanceof Iterable) {
57 | val iterable = (Iterable>) value;
58 | for (val file : iterable) {
59 | fileWriter.write(output, boundary, key, file);
60 | }
61 | } else {
62 | throw new IllegalArgumentException();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/ManyParametersWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static lombok.AccessLevel.PRIVATE;
20 |
21 | import istio.fake.FakeException;
22 | import lombok.experimental.FieldDefaults;
23 | import lombok.val;
24 |
25 | /**
26 | *
27 | * @author Artem Labazin
28 | */
29 | @FieldDefaults(level = PRIVATE, makeFinal = true)
30 | public class ManyParametersWriter extends AbstractWriter {
31 |
32 | SingleParameterWriter parameterWriter = new SingleParameterWriter();
33 |
34 | @Override
35 | public boolean isApplicable (Object value) {
36 | if (value.getClass().isArray()) {
37 | Object[] values = (Object[]) value;
38 | return values.length > 0 && parameterWriter.isApplicable(values[0]);
39 | }
40 | if (!(value instanceof Iterable)) {
41 | return false;
42 | }
43 | val iterable = (Iterable>) value;
44 | val iterator = iterable.iterator();
45 | return iterator.hasNext() && parameterWriter.isApplicable(iterator.next());
46 | }
47 |
48 | @Override
49 | public void write (Output output, String boundary, String key, Object value) throws FakeException {
50 | if (value.getClass().isArray()) {
51 | val objects = (Object[]) value;
52 | for (val object : objects) {
53 | parameterWriter.write(output, boundary, key, object);
54 | }
55 | } else if (value instanceof Iterable) {
56 | val iterable = (Iterable>) value;
57 | for (val object : iterable) {
58 | parameterWriter.write(output, boundary, key, object);
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/Output.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static lombok.AccessLevel.PRIVATE;
20 |
21 | import java.io.ByteArrayOutputStream;
22 | import java.io.Closeable;
23 | import java.io.IOException;
24 | import java.nio.charset.Charset;
25 |
26 | import lombok.Getter;
27 | import lombok.RequiredArgsConstructor;
28 | import lombok.SneakyThrows;
29 | import lombok.experimental.FieldDefaults;
30 |
31 | /**
32 | * Output representation utility class.
33 | *
34 | * @author Artem Labazin
35 | */
36 | @RequiredArgsConstructor
37 | @FieldDefaults(level = PRIVATE, makeFinal = true)
38 | public class Output implements Closeable {
39 |
40 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
41 |
42 | @Getter
43 | Charset charset;
44 |
45 | /**
46 | * Writes the string to the output.
47 | *
48 | * @param string string to write to this output
49 | *
50 | * @return this output
51 | */
52 | public Output write (String string) {
53 | return write(string.getBytes(charset));
54 | }
55 |
56 | /**
57 | * Writes the byte array to the output.
58 | *
59 | * @param bytes byte arrays to write to this output
60 | *
61 | * @return this output
62 | */
63 | @SneakyThrows
64 | public Output write (byte[] bytes) {
65 | outputStream.write(bytes);
66 | return this;
67 | }
68 |
69 | /**
70 | * Writes the byte array to the output with specified offset and fixed length.
71 | *
72 | * @param bytes byte arrays to write to this output
73 | * @param offset the offset within the array of the first byte to be read. Must be non-negative and no larger than bytes.length
74 | * @param length the number of bytes to be read from the given array
75 | *
76 | * @return this output
77 | */
78 | @SneakyThrows
79 | public Output write (byte[] bytes, int offset, int length) {
80 | outputStream.write(bytes, offset, length);
81 | return this;
82 | }
83 |
84 | /**
85 | * Returns byte array representation of this output class.
86 | *
87 | * @return byte array representation of output
88 | */
89 | public byte[] toByteArray () {
90 | return outputStream.toByteArray();
91 | }
92 |
93 | @Override
94 | public void close () throws IOException {
95 | outputStream.close();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/PageableSpringEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import java.lang.reflect.Type;
20 | import java.util.ArrayList;
21 | import java.util.Collection;
22 | import java.util.List;
23 |
24 | import org.springframework.data.domain.Pageable;
25 | import org.springframework.data.domain.Sort;
26 |
27 | import istio.fake.FakeException;
28 | import istio.fake.base.RequestTemplate;
29 | import istio.fake.base.codec.Encoder;
30 |
31 |
32 | /**
33 | * Provides support for encoding spring Pageable via composition.
34 | *
35 | * @author Pascal Büttiker
36 | */
37 | public class PageableSpringEncoder implements Encoder {
38 |
39 | private final Encoder delegate;
40 |
41 | /**
42 | * Creates a new PageableSpringEncoder with the given delegate for fallback. If no
43 | * delegate is provided and this encoder cant handle the request, an EncodeException
44 | * is thrown.
45 | * @param delegate The optional delegate.
46 | */
47 | public PageableSpringEncoder(Encoder delegate) {
48 | this.delegate = delegate;
49 | }
50 |
51 | @Override
52 | public void encode(Object object, Type bodyType, RequestTemplate template)
53 | throws FakeException {
54 |
55 | if (supports(object)) {
56 | if (object instanceof Pageable) {
57 | Pageable pageable = (Pageable) object;
58 | template.query("page", pageable.getPageNumber() + "");
59 | template.query("size", pageable.getPageSize() + "");
60 | if (pageable.getSort() != null) {
61 | applySort(template, pageable.getSort());
62 | }
63 | }
64 | else if (object instanceof Sort) {
65 | Sort sort = (Sort) object;
66 | applySort(template, sort);
67 | }
68 | }
69 | else {
70 | if (delegate != null) {
71 | delegate.encode(object, bodyType, template);
72 | }
73 | else {
74 | throw new FakeException(
75 | "PageableSpringEncoder does not support the given object "
76 | + object.getClass()
77 | + " and no delegate was provided for fallback!");
78 | }
79 | }
80 | }
81 |
82 | private void applySort(RequestTemplate template, Sort sort) {
83 | Collection existingSorts = template.queries().get("sort");
84 | List sortQueries = existingSorts != null ? new ArrayList<>(existingSorts)
85 | : new ArrayList<>();
86 | for (Sort.Order order : sort) {
87 | sortQueries.add(order.getProperty() + "," + order.getDirection());
88 | }
89 | if (!sortQueries.isEmpty()) {
90 | template.query("sort", sortQueries);
91 | }
92 | }
93 |
94 | protected boolean supports(Object object) {
95 | return object instanceof Pageable || object instanceof Sort;
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/PojoUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static java.lang.reflect.Modifier.isFinal;
20 | import static java.lang.reflect.Modifier.isStatic;
21 | import static lombok.AccessLevel.PRIVATE;
22 |
23 | import java.lang.reflect.Field;
24 | import java.lang.reflect.Type;
25 | import java.rmi.UnexpectedException;
26 | import java.security.AccessController;
27 | import java.security.PrivilegedAction;
28 | import java.util.HashMap;
29 | import java.util.Map;
30 |
31 | import org.springframework.lang.Nullable;
32 |
33 | import lombok.NoArgsConstructor;
34 | import lombok.NonNull;
35 | import lombok.Setter;
36 | import lombok.SneakyThrows;
37 | import lombok.experimental.FieldDefaults;
38 | import lombok.val;
39 |
40 | /**
41 | *
42 | * @author Artem Labazin
43 | */
44 | public final class PojoUtil {
45 |
46 | public static boolean isUserPojo (@NonNull Object object) {
47 | val type = object.getClass();
48 | val packageName = type.getPackage().getName();
49 | return !packageName.startsWith("java.");
50 | }
51 |
52 | public static boolean isUserPojo (@NonNull Type type) {
53 | val typeName = type.toString();
54 | return !typeName.startsWith("class java.");
55 | }
56 |
57 | @SneakyThrows
58 | public static Map toMap (@NonNull Object object) {
59 | val result = new HashMap();
60 | val type = object.getClass();
61 | val setAccessibleAction = new SetAccessibleAction();
62 | for (val field : type.getDeclaredFields()) {
63 | val modifiers = field.getModifiers();
64 | if (isFinal(modifiers) || isStatic(modifiers)) {
65 | continue;
66 | }
67 | setAccessibleAction.setField(field);
68 | AccessController.doPrivileged(setAccessibleAction);
69 |
70 | val fieldValue = field.get(object);
71 | if (fieldValue == null) {
72 | continue;
73 | }
74 |
75 | val propertyKey = field.isAnnotationPresent(FormProperty.class)
76 | ? field.getAnnotation(FormProperty.class).value()
77 | : field.getName();
78 |
79 | result.put(propertyKey, fieldValue);
80 | }
81 | return result;
82 | }
83 |
84 | private PojoUtil () throws UnexpectedException {
85 | throw new UnexpectedException("It is not allowed to instantiate this class");
86 | }
87 |
88 | @Setter
89 | @NoArgsConstructor
90 | @FieldDefaults(level = PRIVATE)
91 | private static class SetAccessibleAction implements PrivilegedAction {
92 |
93 | @Nullable
94 | Field field;
95 |
96 | @Override
97 | public Object run () {
98 | field.setAccessible(true);
99 | return null;
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/PojoWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static istio.fake.support.PojoUtil.isUserPojo;
20 | import static istio.fake.support.PojoUtil.toMap;
21 | import static lombok.AccessLevel.PRIVATE;
22 |
23 | import istio.fake.FakeException;
24 | import lombok.RequiredArgsConstructor;
25 | import lombok.experimental.FieldDefaults;
26 | import lombok.val;
27 |
28 | /**
29 | *
30 | * @author Artem Labazin
31 | */
32 | @RequiredArgsConstructor
33 | @FieldDefaults(level = PRIVATE, makeFinal = true)
34 | public class PojoWriter extends AbstractWriter {
35 |
36 | Iterable writers;
37 |
38 | @Override
39 | public boolean isApplicable (Object object) {
40 | return isUserPojo(object);
41 | }
42 |
43 | @Override
44 | public void write (Output output, String boundary, String key, Object object) throws FakeException {
45 | val map = toMap(object);
46 | for (val entry : map.entrySet()) {
47 | val writer = findApplicableWriter(entry.getValue());
48 | if (writer == null) {
49 | continue;
50 | }
51 |
52 | writer.write(output, boundary, entry.getKey(), entry.getValue());
53 | }
54 | }
55 |
56 | private Writer findApplicableWriter (Object value) {
57 | for (val writer : writers) {
58 | if (writer.isApplicable(value)) {
59 | return writer;
60 | }
61 | }
62 | return null;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/ResponseEntityDecoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import java.io.IOException;
20 | import java.lang.reflect.ParameterizedType;
21 | import java.lang.reflect.Type;
22 | import java.util.LinkedList;
23 |
24 | import org.springframework.http.HttpEntity;
25 | import org.springframework.http.HttpStatus;
26 | import org.springframework.http.ResponseEntity;
27 | import org.springframework.util.LinkedMultiValueMap;
28 | import org.springframework.util.MultiValueMap;
29 |
30 | import istio.fake.FakeException;
31 | import istio.fake.base.Response;
32 | import istio.fake.base.codec.Decoder;
33 |
34 | /**
35 | * Decoder adds compatibility for Spring MVC's ResponseEntity to any other decoder via
36 | * composition.
37 | *
38 | * @author chad jaros
39 | */
40 | public class ResponseEntityDecoder implements Decoder {
41 |
42 | private Decoder decoder;
43 |
44 | public ResponseEntityDecoder(Decoder decoder) {
45 | this.decoder = decoder;
46 | }
47 |
48 | @Override
49 | public Object decode(final Response response, Type type)
50 | throws IOException, FakeException {
51 |
52 | if (isParameterizeHttpEntity(type)) {
53 | type = ((ParameterizedType) type).getActualTypeArguments()[0];
54 | Object decodedObject = this.decoder.decode(response, type);
55 |
56 | return createResponse(decodedObject, response);
57 | }
58 | else if (isHttpEntity(type)) {
59 | return createResponse(null, response);
60 | }
61 | else {
62 | return this.decoder.decode(response, type);
63 | }
64 | }
65 |
66 | private boolean isParameterizeHttpEntity(Type type) {
67 | if (type instanceof ParameterizedType) {
68 | return isHttpEntity(((ParameterizedType) type).getRawType());
69 | }
70 | return false;
71 | }
72 |
73 | private boolean isHttpEntity(Type type) {
74 | if (type instanceof Class) {
75 | Class c = (Class) type;
76 | return HttpEntity.class.isAssignableFrom(c);
77 | }
78 | return false;
79 | }
80 |
81 | @SuppressWarnings("unchecked")
82 | private ResponseEntity createResponse(Object instance, Response response) {
83 |
84 | MultiValueMap headers = new LinkedMultiValueMap<>();
85 | for (String key : response.headers().keySet()) {
86 | headers.put(key, new LinkedList<>(response.headers().get(key)));
87 | }
88 |
89 | return new ResponseEntity<>((T) instance, headers,
90 | HttpStatus.valueOf(response.status()));
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/SingleFileWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import java.io.File;
20 | import java.io.FileInputStream;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 |
24 | import istio.fake.FakeException;
25 | import lombok.extern.slf4j.Slf4j;
26 | import lombok.val;
27 |
28 | /**
29 | *
30 | * @author Artem Labazin
31 | */
32 | @Slf4j
33 | public class SingleFileWriter extends AbstractWriter {
34 |
35 | @Override
36 | public boolean isApplicable (Object value) {
37 | return value instanceof File;
38 | }
39 |
40 | @Override
41 | protected void write (Output output, String key, Object value) throws FakeException {
42 | val file = (File) value;
43 | writeFileMetadata(output, key, file.getName(), null);
44 |
45 | InputStream input = null;
46 | try {
47 | input = new FileInputStream(file);
48 | val buf = new byte[4096];
49 | int length = input.read(buf);
50 | while (length > 0) {
51 | output.write(buf, 0, length);
52 | length = input.read(buf);
53 | }
54 | } catch (IOException ex) {
55 | val message = String.format("Writing file's '%s' content error", file.getName());
56 | throw new FakeException(message, ex);
57 | } finally {
58 | if (input != null) {
59 | try {
60 | input.close();
61 | } catch (IOException ex) {
62 | log.error("Closing file '{}' error", file.getName(), ex);
63 | }
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/SingleParameterWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import istio.fake.FakeException;
20 | import lombok.val;
21 |
22 | /**
23 | *
24 | * @author Artem Labazin
25 | */
26 | public class SingleParameterWriter extends AbstractWriter {
27 |
28 | @Override
29 | public boolean isApplicable (Object value) {
30 | return value instanceof Number ||
31 | value instanceof CharSequence ||
32 | value instanceof Boolean;
33 | }
34 |
35 | @Override
36 | protected void write (Output output, String key, Object value) throws FakeException {
37 | val string = new StringBuilder()
38 | .append("Content-Disposition: form-data; name=\"").append(key).append('"').append(ContentProcessor.CRLF)
39 | .append("Content-Type: text/plain; charset=").append(output.getCharset().name()).append(ContentProcessor.CRLF)
40 | .append(ContentProcessor.CRLF)
41 | .append(value.toString())
42 | .toString();
43 |
44 | output.write(string);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/SpringDecoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013-2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.lang.reflect.ParameterizedType;
22 | import java.lang.reflect.Type;
23 | import java.lang.reflect.WildcardType;
24 |
25 | import org.springframework.beans.factory.ObjectFactory;
26 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
27 | import org.springframework.http.HttpHeaders;
28 | import org.springframework.http.HttpStatus;
29 | import org.springframework.http.client.ClientHttpResponse;
30 | import org.springframework.web.client.HttpMessageConverterExtractor;
31 |
32 | import istio.fake.FakeException;
33 | import istio.fake.util.Util;
34 | import istio.fake.base.Response;
35 | import istio.fake.base.codec.Decoder;
36 |
37 | /**
38 | * @author Spencer Gibb
39 | */
40 | public class SpringDecoder implements Decoder {
41 |
42 | private ObjectFactory messageConverters;
43 |
44 | public SpringDecoder(ObjectFactory messageConverters) {
45 | this.messageConverters = messageConverters;
46 | }
47 |
48 | @Override
49 | public Object decode(final Response response, Type type)
50 | throws IOException, FakeException {
51 | if (type instanceof Class || type instanceof ParameterizedType
52 | || type instanceof WildcardType) {
53 | @SuppressWarnings({ "unchecked", "rawtypes" })
54 | HttpMessageConverterExtractor> extractor = new HttpMessageConverterExtractor(
55 | type, this.messageConverters.getObject().getConverters());
56 |
57 | return extractor.extractData(new FeignResponseAdapter(response));
58 | }
59 | throw new FakeException(response.status(),
60 | "type is not an instance of Class or ParameterizedType: " + type);
61 | }
62 |
63 | private final class FeignResponseAdapter implements ClientHttpResponse {
64 |
65 | private final Response response;
66 |
67 | private FeignResponseAdapter(Response response) {
68 | this.response = response;
69 | }
70 |
71 | @Override
72 | public HttpStatus getStatusCode() throws IOException {
73 | return HttpStatus.valueOf(this.response.status());
74 | }
75 |
76 | @Override
77 | public int getRawStatusCode() throws IOException {
78 | return this.response.status();
79 | }
80 |
81 | @Override
82 | public String getStatusText() throws IOException {
83 | return this.response.reason();
84 | }
85 |
86 | @Override
87 | public void close() {
88 | try {
89 | this.response.body().close();
90 | }
91 | catch (IOException ex) {
92 | // Ignore exception on close...
93 | }
94 | }
95 |
96 | @Override
97 | public InputStream getBody() throws IOException {
98 | return this.response.body().asInputStream();
99 | }
100 |
101 | @Override
102 | public HttpHeaders getHeaders() {
103 | return Util.getHttpHeaders(this.response.headers());
104 | }
105 |
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/SpringFormEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static java.util.Collections.singletonMap;
20 |
21 | import java.lang.reflect.Type;
22 | import java.util.HashMap;
23 |
24 | import org.springframework.web.multipart.MultipartFile;
25 |
26 | import istio.fake.FakeException;
27 | import istio.fake.base.RequestTemplate;
28 | import istio.fake.base.codec.Encoder;
29 | import lombok.val;
30 |
31 | /**
32 | * Adds support for {@link MultipartFile} type to {@link FormEncoder}.
33 | *
34 | * @author Tomasz Juchniewicz <tjuchniewicz@gmail.com>
35 | * @since 14.09.2016
36 | */
37 | public class SpringFormEncoder extends FormEncoder {
38 |
39 | /**
40 | * Constructor with the default Feign's encoder as a delegate.
41 | */
42 | public SpringFormEncoder () {
43 | this(new Encoder.Default());
44 | }
45 |
46 | /**
47 | * Constructor with specified delegate encoder.
48 | *
49 | * @param delegate delegate encoder, if this encoder couldn't encode object.
50 | */
51 | public SpringFormEncoder (Encoder delegate) {
52 | super(delegate);
53 |
54 | val processor = (MultipartFormContentProcessor) getContentProcessor(ContentType.MULTIPART);
55 | processor.addFirstWriter(new SpringSingleMultipartFileWriter());
56 | processor.addFirstWriter(new SpringManyMultipartFilesWriter());
57 | }
58 |
59 | @Override
60 | public void encode (Object object, Type bodyType, RequestTemplate template) throws FakeException {
61 | if (bodyType.equals(MultipartFile[].class)) {
62 | val files = (MultipartFile[]) object;
63 | val data = new HashMap(files.length, 1.F);
64 | for (val file : files) {
65 | data.put(file.getName(), file);
66 | }
67 | super.encode(data, MAP_STRING_WILDCARD, template);
68 | } else if (bodyType.equals(MultipartFile.class)) {
69 | val file = (MultipartFile) object;
70 | val data = singletonMap(file.getName(), object);
71 | super.encode(data, MAP_STRING_WILDCARD, template);
72 | } else if (isMultipartFileCollection(object)) {
73 | val iterable = (Iterable>) object;
74 | val data = new HashMap();
75 | for (val item : iterable) {
76 | val file = (MultipartFile) item;
77 | data.put(file.getName(), file);
78 | }
79 | super.encode(data, MAP_STRING_WILDCARD, template);
80 | } else {
81 | super.encode(object, bodyType, template);
82 | }
83 | }
84 |
85 | private boolean isMultipartFileCollection (Object object) {
86 | if (!(object instanceof Iterable)) {
87 | return false;
88 | }
89 | val iterable = (Iterable>) object;
90 | val iterator = iterable.iterator();
91 | return iterator.hasNext() && iterator.next() instanceof MultipartFile;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/SpringManyMultipartFilesWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import static lombok.AccessLevel.PRIVATE;
20 |
21 | import org.springframework.web.multipart.MultipartFile;
22 |
23 | import istio.fake.FakeException;
24 | import lombok.experimental.FieldDefaults;
25 | import lombok.val;
26 |
27 | /**
28 | *
29 | * @author Artem Labazin
30 | */
31 | @FieldDefaults(level = PRIVATE, makeFinal = true)
32 | public class SpringManyMultipartFilesWriter extends AbstractWriter {
33 |
34 | SpringSingleMultipartFileWriter fileWriter = new SpringSingleMultipartFileWriter();
35 |
36 | @Override
37 | public boolean isApplicable (Object value) {
38 | if (value instanceof MultipartFile[]) {
39 | return true;
40 | }
41 | if (!(value instanceof Iterable)) {
42 | return false;
43 | }
44 | val iterable = (Iterable>) value;
45 | val iterator = iterable.iterator();
46 | return iterator.hasNext() && iterator.next() instanceof MultipartFile;
47 | }
48 |
49 | @Override
50 | public void write (Output output, String boundary, String key, Object value) throws FakeException {
51 | if (value instanceof MultipartFile[]) {
52 | val files = (MultipartFile[]) value;
53 | for (val file : files) {
54 | fileWriter.write(output, boundary, key, file);
55 | }
56 | } else if (value instanceof Iterable) {
57 | val iterable = (Iterable>) value;
58 | for (val file : iterable) {
59 | fileWriter.write(output, boundary, key, file);
60 | }
61 | } else {
62 | throw new IllegalArgumentException();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/SpringSingleMultipartFileWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 | import java.io.IOException;
20 |
21 | import org.springframework.web.multipart.MultipartFile;
22 |
23 | import istio.fake.FakeException;
24 | import lombok.val;
25 |
26 | /**
27 | *
28 | * @author Artem Labazin
29 | */
30 | public class SpringSingleMultipartFileWriter extends AbstractWriter {
31 |
32 | @Override
33 | public boolean isApplicable (Object value) {
34 | return value instanceof MultipartFile;
35 | }
36 |
37 | @Override
38 | protected void write (Output output, String key, Object value) throws FakeException {
39 | val file = (MultipartFile) value;
40 | writeFileMetadata(output, key, file.getOriginalFilename(), file.getContentType());
41 |
42 | byte[] bytes;
43 | try {
44 | bytes = file.getBytes();
45 | } catch (IOException ex) {
46 | throw new FakeException("Getting multipart file's content bytes error", ex);
47 | }
48 | output.write(bytes);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/UrlencodedFormContentProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 |
20 | import static istio.fake.support.ContentType.URLENCODED;
21 |
22 | import java.net.URLEncoder;
23 | import java.nio.charset.Charset;
24 | import java.util.Collection;
25 | import java.util.Collections;
26 | import java.util.Map;
27 | import java.util.Map.Entry;
28 |
29 | import istio.fake.FakeException;
30 | import istio.fake.base.Request;
31 | import istio.fake.base.RequestTemplate;
32 | import lombok.SneakyThrows;
33 | import lombok.val;
34 |
35 | /**
36 | *
37 | * @author Artem Labazin
38 | */
39 | public class UrlencodedFormContentProcessor implements ContentProcessor {
40 |
41 | private static final char QUERY_DELIMITER = '&';
42 |
43 | private static final char EQUAL_SIGN = '=';
44 |
45 | @SneakyThrows
46 | private static String encode (Object string, Charset charset) {
47 | return URLEncoder.encode(string.toString(), charset.name());
48 | }
49 |
50 | @Override
51 | public void process (RequestTemplate template, Charset charset, Map data) throws FakeException {
52 | val bodyData = new StringBuilder();
53 | for (Entry entry : data.entrySet()) {
54 | if (entry == null || entry.getKey() == null) {
55 | continue;
56 | }
57 | if (bodyData.length() > 0) {
58 | bodyData.append(QUERY_DELIMITER);
59 | }
60 | bodyData.append(createKeyValuePair(entry, charset));
61 | }
62 |
63 | val contentTypeValue = new StringBuilder()
64 | .append(getSupportedContentType().getHeader())
65 | .append("; charset=").append(charset.name())
66 | .toString();
67 |
68 | val bytes = bodyData.toString().getBytes(charset);
69 | val body = Request.Body.encoded(bytes, charset);
70 |
71 | template.header(CONTENT_TYPE_HEADER, Collections.emptyList()); // reset header
72 | template.header(CONTENT_TYPE_HEADER, contentTypeValue);
73 | template.body(body);
74 | }
75 |
76 | @Override
77 | public ContentType getSupportedContentType () {
78 | return URLENCODED;
79 | }
80 |
81 | private String createKeyValuePair (Entry entry, Charset charset) {
82 | String encodedKey = encode(entry.getKey(), charset);
83 | Object value = entry.getValue();
84 |
85 | if (value == null) {
86 | return encodedKey;
87 | } else if (value.getClass().isArray()) {
88 | return createKeyValuePairFromArray(encodedKey, value, charset);
89 | } else if (value instanceof Collection) {
90 | return createKeyValuePairFromCollection(encodedKey, value, charset);
91 | }
92 | return new StringBuilder()
93 | .append(encodedKey)
94 | .append(EQUAL_SIGN)
95 | .append(encode(value, charset))
96 | .toString();
97 | }
98 |
99 | @SuppressWarnings("unchecked")
100 | private String createKeyValuePairFromCollection (String key, Object values, Charset charset) {
101 | val collection = (Collection) values;
102 | val array = collection.toArray(new Object[0]);
103 | return createKeyValuePairFromArray(key, array, charset);
104 | }
105 |
106 | private String createKeyValuePairFromArray (String key, Object values, Charset charset) {
107 | val result = new StringBuilder();
108 | val array = (Object[]) values;
109 |
110 | for (int index = 0; index < array.length; index++) {
111 | val value = array[index];
112 | if (value == null) {
113 | continue;
114 | }
115 |
116 | if (index > 0) {
117 | result.append(QUERY_DELIMITER);
118 | }
119 |
120 | result
121 | .append(key)
122 | .append(EQUAL_SIGN)
123 | .append(encode(value, charset));
124 | }
125 | return result.toString();
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/main/java/istio/fake/support/Writer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package istio.fake.support;
18 |
19 |
20 | import istio.fake.FakeException;
21 |
22 | /**
23 | *
24 | * @author Artem Labazin
25 | */
26 | public interface Writer {
27 |
28 | /**
29 | * Processing form data to request body.
30 | *
31 | * @param output output writer.
32 | * @param boundary data boundary.
33 | * @param key name for piece of data.
34 | * @param value piece of data.
35 | *
36 | * @throws FakeException in case of any encode exception
37 | */
38 | void write (Output output, String boundary, String key, Object value) throws FakeException;
39 |
40 | /**
41 | * Answers on question - "could this writer properly write the value".
42 | *
43 | * @param value object to write.
44 | *
45 | * @return {@code true} - if could write this object, otherwise {@code true}
46 | */
47 | boolean isApplicable (Object value);
48 | }
49 |
--------------------------------------------------------------------------------
/feign-istio-fake/src/test/java/cn/focusmedia/bigdata/pyramid/AppTest.java:
--------------------------------------------------------------------------------
1 | package cn.focusmedia.bigdata.pyramid;
2 |
3 | import static org.junit.Assert.assertTrue;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | {
12 | /**
13 | * Rigorous Test :-)
14 | */
15 | @Test
16 | public void shouldAnswerWithTrue()
17 | {
18 | assertTrue( true );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/k8s/destination-rule-all.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: networking.istio.io/v1alpha3
3 | kind: DestinationRule
4 | metadata:
5 | name: micro-api-destination
6 | spec:
7 | host: micro-api
8 | #流量策略设置:负载均衡策略、连接池大小、局部异常检测等,在路由发生后作用于流量
9 | trafficPolicy:
10 | #限流策略
11 | connectionPool:
12 | tcp:
13 | maxConnections: 10
14 | http:
15 | http1MaxPendingRequests: 1
16 | maxRequestsPerConnection: 1
17 | #设置目的地的负债均衡算法
18 | loadBalancer:
19 | simple: ROUND_ROBIN
20 | #目的地指的是不同的子集(subset)或服务版本。通子集(subset),可以识别应用程序的不同版本,以实现流量在不同服务版本之间的切换
21 | subsets:
22 | - name: v1
23 | labels:
24 | version: v1
25 | - name: v2
26 | labels:
27 | version: v2
28 |
29 | ---
30 |
31 | apiVersion: networking.istio.io/v1alpha3
32 | kind: DestinationRule
33 | metadata:
34 | name: micro-pay
35 | spec:
36 | host: micro-pay
37 | trafficPolicy:
38 | #限流策略
39 | connectionPool:
40 | tcp:
41 | maxConnections: 1
42 | http:
43 | #http2MaxRequests: 1
44 | http1MaxPendingRequests: 1
45 | maxRequestsPerConnection: 1
46 | #熔断策略
47 | outlierDetection:
48 | consecutive5xxErrors: 1
49 | interval: 30s
50 | baseEjectionTime: 3m
51 | maxEjectionPercent: 100
52 | ---
--------------------------------------------------------------------------------
/k8s/micro-api-canary-istio-v1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: micro-api
5 | spec:
6 | type: ClusterIP
7 | ports:
8 | - name: http
9 | port: 19090
10 | targetPort: 9090
11 | selector:
12 | app: micro-api
13 |
14 | ---
15 |
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: micro-api-v1
20 | spec:
21 | selector:
22 | matchLabels:
23 | app: micro-api
24 | #这里是关键,需要设置版本标签,以便实现灰度发布
25 | version: v1
26 | replicas: 3
27 | #设置滚动升级策略
28 | #Kubernetes在等待设置的时间后才开始进行升级,例如5秒
29 | minReadySeconds: 5
30 | strategy:
31 | type: RollingUpdate
32 | rollingUpdate:
33 | #升级过程中最多可以比原先设置多出的Pod数量
34 | maxSurge: 1
35 | #升级过程中Deployment控制器最多可以删除多少个旧Pod,主要用于提供缓冲时间
36 | maxUnavailable: 1
37 | template:
38 | metadata:
39 | labels:
40 | app: micro-api
41 | #设置版本标签,便于灰度发布
42 | version: v1
43 | spec:
44 | #设置的阿里云私有镜像仓库登陆信息的secret
45 | imagePullSecrets:
46 | - name: regcred
47 | containers:
48 | - name: micro-api
49 | image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.1-SNAPSHOT
50 | imagePullPolicy: Always
51 | tty: true
52 | ports:
53 | - name: http
54 | protocol: TCP
55 | containerPort: 19090
56 |
--------------------------------------------------------------------------------
/k8s/micro-api-canary-istio-v2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: micro-api-v2
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: micro-api
9 | #设置好版本标签,便于灰度发布
10 | version: v2
11 | replicas: 3
12 | #设置滚动升级策略
13 | #Kubernetes在等待设置的时间后才开始进行升级,例如5秒
14 | minReadySeconds: 5
15 | strategy:
16 | type: RollingUpdate
17 | rollingUpdate:
18 | #升级过程中最多可以比原先设置多出的Pod数量
19 | maxSurge: 1
20 | #升级过程中Deployment控制器最多可以删除多少个旧Pod,主要用于提供缓冲时间
21 | maxUnavailable: 1
22 | template:
23 | metadata:
24 | labels:
25 | app: micro-api
26 | #设置好版本标签,便于灰度发布
27 | version: v2
28 | spec:
29 | #设置的阿里云私有镜像仓库登陆信息的secret
30 | imagePullSecrets:
31 | - name: regcred
32 | containers:
33 | - name: micro-api
34 | image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.3-SNAPSHOT
35 | imagePullPolicy: Always
36 | tty: true
37 | ports:
38 | - name: http
39 | protocol: TCP
40 | containerPort: 19090
41 |
--------------------------------------------------------------------------------
/k8s/micro-api-canary.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: micro-api
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: micro-api
9 | replicas: 3
10 | #设置滚动升级策略
11 | #Kubernetes在等待设置的时间后才开始进行升级,例如5秒
12 | minReadySeconds: 5
13 | strategy:
14 | type: RollingUpdate
15 | rollingUpdate:
16 | #升级过程中最多可以比原先设置多出的Pod数量
17 | maxSurge: 1
18 | #升级过程中Deployment控制器最多可以删除多少个旧Pod,主要用于提供缓冲时间
19 | maxUnavailable: 1
20 | template:
21 | metadata:
22 | labels:
23 | app: micro-api
24 | #增加新的标签(演示k8s的灰度发布)
25 | track: canary
26 | spec:
27 | #设置的阿里云私有镜像仓库登陆信息的secret(对应2.1.2的设置)
28 | imagePullSecrets:
29 | - name: regcred
30 | containers:
31 | - name: micro-api
32 | image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.3-SNAPSHOT
33 | imagePullPolicy: Always
34 | tty: true
35 | ports:
36 | - name: http
37 | protocol: TCP
38 | containerPort: 19090
39 |
--------------------------------------------------------------------------------
/k8s/micro-api.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: micro-api
5 | spec:
6 | type: ClusterIP
7 | ports:
8 | - name: http
9 | port: 19090
10 | targetPort: 9090
11 | selector:
12 | app: micro-api
13 |
14 | ---
15 | apiVersion: apps/v1
16 | kind: Deployment
17 | metadata:
18 | name: micro-api
19 | spec:
20 | selector:
21 | matchLabels:
22 | app: micro-api
23 | replicas: 3
24 | #设置滚动升级策略
25 | #Kubernetes在等待设置的时间后才开始进行升级,例如5秒
26 | minReadySeconds: 5
27 | strategy:
28 | type: RollingUpdate
29 | rollingUpdate:
30 | #升级过程中最多可以比原先设置多出的Pod数量
31 | maxSurge: 1
32 | #升级过程中Deployment控制器最多可以删除多少个旧Pod,主要用于提供缓冲时间
33 | maxUnavailable: 1
34 | template:
35 | metadata:
36 | labels:
37 | app: micro-api
38 | spec:
39 | #设置的阿里云私有镜像仓库登陆信息的secret(对应2.1.2的设置)
40 | imagePullSecrets:
41 | - name: regcred
42 | containers:
43 | - name: micro-api
44 | image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.0-SNAPSHOT
45 | imagePullPolicy: Always
46 | tty: true
47 | ports:
48 | - name: http
49 | protocol: TCP
50 | containerPort: 19090
51 |
--------------------------------------------------------------------------------
/k8s/micro-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: Gateway
3 | metadata:
4 | name: micro-gateway
5 | spec:
6 | selector:
7 | istio: ingressgateway
8 | servers:
9 | - port:
10 | number: 80
11 | name: http
12 | protocol: HTTP
13 | hosts:
14 | - "*"
--------------------------------------------------------------------------------
/k8s/micro-order.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: micro-order
5 | labels:
6 | app: micro-order
7 | service: micro-order
8 | spec:
9 | type: ClusterIP
10 | ports:
11 | - name: http
12 | #此处设置80端口的原因在于改造的Mock FeignClient代码默认是基于80端口进行服务调用
13 | port: 80
14 | targetPort: 9091
15 | selector:
16 | app: micro-order
17 |
18 | ---
19 | apiVersion: apps/v1
20 | kind: Deployment
21 | metadata:
22 | name: micro-order-v1
23 | labels:
24 | app: micro-order
25 | version: v1
26 | spec:
27 | replicas: 1
28 | selector:
29 | matchLabels:
30 | app: micro-order
31 | version: v1
32 | template:
33 | metadata:
34 | labels:
35 | app: micro-order
36 | version: v1
37 | spec:
38 | #设置的阿里云私有镜像仓库登陆信息的secret(对应2.1.2的设置)
39 | imagePullSecrets:
40 | - name: regcred
41 | containers:
42 | - name: micro-order
43 | image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-order:1.0-SNAPSHOT
44 | imagePullPolicy: Always
45 | tty: true
46 | ports:
47 | - name: http
48 | protocol: TCP
49 | containerPort: 19091
50 | #环境参数设置(设置微服务返回gRPC服务端的地址+端口)
51 | env:
52 | - name: GRPC_SERVER_HOST
53 | value: micro-pay
54 | - name: GRPC_SERVER_PORT
55 | value: "18888"
56 |
57 |
58 |
--------------------------------------------------------------------------------
/k8s/micro-pay.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: micro-pay
5 | labels:
6 | app: micro-pay
7 | service: micro-pay
8 | spec:
9 | type: ClusterIP
10 | ports:
11 | - name: http
12 | #容器暴露端口
13 | port: 19092
14 | #目标应用端口
15 | targetPort: 9092
16 | #设置gRPC端口
17 | - name: grpc
18 | port: 18888
19 | targetPort: 18888
20 | selector:
21 | app: micro-pay
22 |
23 | ---
24 | apiVersion: apps/v1
25 | kind: Deployment
26 | metadata:
27 | name: micro-pay-v1
28 | labels:
29 | app: micro-pay
30 | version: v1
31 | spec:
32 | replicas: 1
33 | selector:
34 | matchLabels:
35 | app: micro-pay
36 | version: v1
37 | template:
38 | metadata:
39 | labels:
40 | app: micro-pay
41 | version: v1
42 | spec:
43 | #设置的阿里云私有镜像仓库登陆信息的secret(对应2.1.2的设置)
44 | imagePullSecrets:
45 | - name: regcred
46 | containers:
47 | - name: micro-pay
48 | image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-pay:1.0-SNAPSHOT
49 | imagePullPolicy: Always
50 | tty: true
51 | ports:
52 | - name: http
53 | protocol: TCP
54 | containerPort: 19092
55 | #指定服务gRPC端口
56 | - name: grpc
57 | protocol: TCP
58 | containerPort: 18888
--------------------------------------------------------------------------------
/k8s/virtual-service-all.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: VirtualService
3 | metadata:
4 | name: micro-api-route
5 | spec:
6 | #用于定义流量被发送到的目标主机(这里为部署在k8s中的micro-api服务)
7 | hosts:
8 | - micro-api.default.svc.cluster.local
9 | #将VirtualService绑定到Istio网关,通过网关来暴露路由目标
10 | gateways:
11 | - micro-gateway
12 | http:
13 | - route:
14 | #设置旧版本(V1)版本的流量占比为70%
15 | - destination:
16 | host: micro-api.default.svc.cluster.local
17 | subset: v1
18 | #通过权重值来设置流量占比
19 | weight: 0
20 | #设置新版本(V2)版本的流量占比为30%
21 | - destination:
22 | host: micro-api.default.svc.cluster.local
23 | subset: v2
24 | weight: 100
--------------------------------------------------------------------------------
/micro-api/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8u191-jre-alpine3.9
2 | ENTRYPOINT ["/usr/bin/java", "-jar", "/app.jar"]
3 | ARG JAR_FILE
4 | ADD ${JAR_FILE} /app.jar
5 | EXPOSE 9090
--------------------------------------------------------------------------------
/micro-api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.wudimanong
8 | micro-api
9 | 1.3-SNAPSHOT
10 |
11 |
12 | com.wudimanong
13 | istio-micro-demo
14 | 1.0-SNAPSHOT
15 |
16 |
17 |
18 |
19 |
20 | org.springframework.boot
21 | spring-boot-starter
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-web
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-test
31 | test
32 |
33 |
34 |
35 |
36 | org.projectlombok
37 | lombok
38 |
39 |
40 |
41 | com.alibaba
42 | fastjson
43 |
44 |
45 |
46 | com.wudimanong
47 | micro-order-client
48 | 1.0-SNAPSHOT
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-maven-plugin
58 |
59 |
60 |
61 |
62 | com.spotify
63 | dockerfile-maven-plugin
64 | 1.4.13
65 |
66 |
67 | javax.activation
68 | activation
69 | 1.1
70 |
71 |
72 |
73 |
74 | build-image
75 | package
76 |
77 | build
78 | push
79 |
80 |
81 |
82 |
83 |
84 | docker/Dockerfile
85 | ${docker.repository}/wudimanong/${project.artifactId}
86 | ${project.version}
87 |
88 |
89 | target/${project.build.finalName}.jar
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/MicroApi.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api;
2 |
3 | import istio.fake.annotation.EnableFakeClients;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | /**
8 | * @author jiangqiao
9 | */
10 | @SpringBootApplication
11 | @EnableFakeClients(basePackages = "com.wudimanong.micro.order.client")
12 | public class MicroApi {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(MicroApi.class, args);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/config/AutoResultReturnHandler.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.config;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.wudimanong.micro.api.exception.ResponseResult;
5 | import java.io.IOException;
6 | import java.io.PrintWriter;
7 | import javax.servlet.http.HttpServletResponse;
8 | import org.springframework.core.MethodParameter;
9 | import org.springframework.core.annotation.AnnotatedElementUtils;
10 | import org.springframework.web.bind.annotation.ResponseBody;
11 | import org.springframework.web.context.request.NativeWebRequest;
12 | import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
13 | import org.springframework.web.method.support.ModelAndViewContainer;
14 |
15 | /**
16 | * @author jiangqiao
17 | */
18 | public class AutoResultReturnHandler implements HandlerMethodReturnValueHandler {
19 |
20 | @Override
21 | public boolean supportsReturnType(MethodParameter returnType) {
22 | return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
23 | returnType.hasMethodAnnotation(ResponseBody.class));
24 | }
25 |
26 | /**
27 | * Controller层接口返回值统一封装方法
28 | *
29 | * @param returnValue
30 | * @param returnType
31 | * @param mavContainer
32 | * @param webRequest
33 | */
34 | @Override
35 | public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
36 | NativeWebRequest webRequest) {
37 | mavContainer.setRequestHandled(true);
38 | HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
39 | response.setContentType("application/json;charset=UTF-8");
40 | PrintWriter writer = null;
41 | try {
42 | writer = response.getWriter();
43 | writer.print(JSON.toJSONString(ResponseResult.OK(returnValue)));
44 | writer.flush();
45 | } catch (IOException e) {
46 | e.printStackTrace();
47 | } finally {
48 | if (writer != null) {
49 | writer.close();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/config/WebMvcConfig.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.config;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import org.springframework.beans.factory.InitializingBean;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
9 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
10 |
11 | /**
12 | * @author jiangqiao
13 | */
14 | @Configuration
15 | public class WebMvcConfig implements InitializingBean {
16 |
17 | @Autowired
18 | RequestMappingHandlerAdapter requestMappingHandlerAdapter;
19 |
20 | @Override
21 | public void afterPropertiesSet() {
22 | List returnValueHandlers = requestMappingHandlerAdapter
23 | .getReturnValueHandlers();
24 | List list = new ArrayList<>();
25 | //自定义returnHandler
26 | list.add(new AutoResultReturnHandler());
27 | list.addAll(returnValueHandlers);
28 | requestMappingHandlerAdapter.setReturnValueHandlers(list);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/controller/ApiOrderController.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.controller;
2 |
3 | import com.wudimanong.micro.api.exception.ServiceException;
4 | import com.wudimanong.micro.order.client.OrderServiceClient;
5 | import com.wudimanong.micro.order.client.bo.CreateOrderBO;
6 | import com.wudimanong.micro.order.client.dto.CreateOrderDTO;
7 | import com.wudimanong.micro.order.client.dto.result.GlobalCodeEnum;
8 | import com.wudimanong.micro.order.client.dto.result.ResponseResult;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.web.bind.annotation.PostMapping;
11 | import org.springframework.web.bind.annotation.RequestBody;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | /**
16 | * @author jiangqiao
17 | */
18 | @RestController
19 | @RequestMapping("/api/order")
20 | public class ApiOrderController {
21 |
22 | /**
23 | * 订单微服务api接口依赖
24 | */
25 | @Autowired
26 | OrderServiceClient orderServiceClient;
27 |
28 | /**
29 | * 下单接口
30 | *
31 | * @param createOrderDTO
32 | * @return
33 | */
34 | @PostMapping("/create")
35 | public CreateOrderBO create(@RequestBody CreateOrderDTO createOrderDTO) {
36 | ResponseResult result = orderServiceClient.create(createOrderDTO);
37 | if (result.getCode().equals(GlobalCodeEnum.GL_SUCC_0.getCode())) {
38 | return result.getData();
39 | } else {
40 | throw new ServiceException(result.getCode(), result.getMessage());
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/controller/TestController.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.controller;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | /**
9 | * @author jiangqiao
10 | */
11 | @Slf4j
12 | @RestController
13 | @RequestMapping("/test")
14 | public class TestController {
15 |
16 | @GetMapping("/test")
17 | public String test() {
18 | log.info("测试接口被调用!");
19 | return "V3|无依赖测试接口返回->OK!";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/exception/GlobalCodeEnum.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.exception;
2 |
3 | /**
4 | * @author qiaojiang
5 | */
6 | public enum GlobalCodeEnum {
7 |
8 | /**
9 | * 全局返回码定义 - 0000开头
10 | */
11 | GL_SUCC_0(0, "成功"),
12 | GL_FAIL_9995(9995, "依赖服务异常"),
13 | GL_FAIL_9996(9996, "不支持的HttpMethod"),
14 | GL_FAIL_9997(9997, "HTTP错误"),
15 | GL_FAIL_9998(9998, "参数错误"),
16 | GL_FAIL_9999(9999, "系统异常");
17 | /**
18 | * 编码
19 | */
20 | private Integer code;
21 |
22 | /**
23 | * 描述
24 | */
25 | private String desc;
26 |
27 |
28 | GlobalCodeEnum(Integer code, String desc) {
29 | this.code = code;
30 | this.desc = desc;
31 | }
32 |
33 | /**
34 | * 根据编码获取枚举类型
35 | *
36 | * @param code 编码
37 | * @return
38 | */
39 | public static GlobalCodeEnum getByCode(String code) {
40 | //判空
41 | if (code == null) {
42 | return null;
43 | }
44 | //循环处理
45 | GlobalCodeEnum[] values = GlobalCodeEnum.values();
46 | for (GlobalCodeEnum value : values) {
47 | if (value.getCode().equals(code)) {
48 | return value;
49 | }
50 | }
51 | return null;
52 | }
53 |
54 | public Integer getCode() {
55 | return code;
56 | }
57 |
58 | public String getDesc() {
59 | return desc;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/exception/ResponseResult.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.exception;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.annotation.JsonPropertyOrder;
5 | import java.io.Serializable;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Builder;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 |
11 | /**
12 | * @author qiaojiang
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | @JsonPropertyOrder({"code", "message", "data"})
19 | public class ResponseResult implements Serializable {
20 |
21 | private static final long serialVersionUID = 1L;
22 |
23 | /**
24 | * 返回的对象
25 | */
26 | @JsonInclude(JsonInclude.Include.NON_NULL)
27 | private T data;
28 | /**
29 | * 返回的编码
30 | */
31 | private Integer code;
32 | /**
33 | * 返回的信息
34 | */
35 | private String message;
36 |
37 | /**
38 | * @return 响应结果
39 | */
40 | public static ResponseResult OK() {
41 | return packageObject("", GlobalCodeEnum.GL_SUCC_0);
42 | }
43 |
44 | /**
45 | * @param data 返回的数据
46 | * @param 返回的数据类型
47 | * @return 响应结果
48 | */
49 | public static ResponseResult OK(T data) {
50 | return packageObject(data, GlobalCodeEnum.GL_SUCC_0);
51 | }
52 |
53 | /**
54 | * 对返回的消息进行打包
55 | *
56 | * @param data 返回的数据
57 | * @param globalCodeEnum 自定义的返回码枚举类型
58 | * @param 返回的数据类型
59 | * @return 响应结果
60 | */
61 | public static ResponseResult packageObject(T data, GlobalCodeEnum globalCodeEnum) {
62 | ResponseResult responseResult = new ResponseResult<>();
63 | responseResult.setCode(globalCodeEnum.getCode());
64 | responseResult.setMessage(globalCodeEnum.getDesc());
65 | responseResult.setData(data);
66 | return responseResult;
67 | }
68 |
69 | /**
70 | * 对返回的消息进行打包
71 | *
72 | * @param data 返回的数据
73 | * @param code 返回的状态码
74 | * @param message 返回的消息
75 | * @param 返回的数据类型
76 | * @return 响应结果
77 | */
78 | public static ResponseResult packageObject(T data, Integer code, String message) {
79 | ResponseResult responseResult = new ResponseResult<>();
80 | responseResult.setCode(code);
81 | responseResult.setMessage(message);
82 | responseResult.setData(data);
83 | return responseResult;
84 | }
85 |
86 | /**
87 | * 系统服务不可用
88 | *
89 | * @param globalCodeEnum Feign依赖服务不可用的返回码枚举类型
90 | * @param 返回的数据类型
91 | * @return 响应结果
92 | */
93 | public static ResponseResult systemError(GlobalCodeEnum globalCodeEnum) {
94 | return packageObject(null, globalCodeEnum);
95 | }
96 |
97 | /**
98 | * 未查询到相关的数据
99 | *
100 | * @param globalCodeEnum 未查询到相关信息的返回码枚举类型
101 | * @param 返回的数据类型
102 | * @return 响应结果
103 | */
104 | public static ResponseResult noData(GlobalCodeEnum globalCodeEnum) {
105 | return packageObject(null, globalCodeEnum);
106 | }
107 |
108 | /**
109 | * 系统异常(使用默认的异常返回码)
110 | *
111 | * @param 返回的数据类型
112 | * @return 响应结果
113 | */
114 | public static ResponseResult systemException() {
115 | return packageObject(null, GlobalCodeEnum.GL_FAIL_9999);
116 | }
117 |
118 | /**
119 | * 系统异常
120 | *
121 | * @param globalCodeEnum 异常返回码枚举类型
122 | * @param 返回的数据类型
123 | * @return 响应结果
124 | */
125 | public static ResponseResult systemException(GlobalCodeEnum globalCodeEnum) {
126 | return packageObject(null, globalCodeEnum);
127 | }
128 |
129 | /**
130 | * 自定义系统异常信息
131 | *
132 | * @param code
133 | * @param message 自定义消息
134 | * @param
135 | * @return
136 | */
137 | public static ResponseResult systemException(Integer code, String message) {
138 | return packageObject(null, code, message);
139 | }
140 | }
--------------------------------------------------------------------------------
/micro-api/src/main/java/com/wudimanong/micro/api/exception/ServiceException.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.api.exception;
2 |
3 | /**
4 | * @author jiangqiao
5 | */
6 | public class ServiceException extends RuntimeException {
7 |
8 | private final Integer code;
9 |
10 | public ServiceException(Integer code, String message) {
11 | super(message);
12 | this.code = code;
13 | }
14 |
15 | public ServiceException(Integer code, String message, Throwable e) {
16 | super(message, e);
17 | this.code = code;
18 | }
19 |
20 | public Integer getCode() {
21 | return code;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/micro-api/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | fake:
2 | micro-order: 127.0.0.1:9091
3 |
--------------------------------------------------------------------------------
/micro-api/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: micro-api
4 | server:
5 | port: 9090
6 |
--------------------------------------------------------------------------------
/micro-order-client/micro-order-client.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/micro-order-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | istio-micro-demo
7 | com.wudimanong
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | com.wudimanong
13 | micro-order-client
14 | 1.0-SNAPSHOT
15 |
16 |
17 |
18 |
19 | org.projectlombok
20 | lombok
21 |
22 |
23 |
24 | com.alibaba
25 | fastjson
26 |
27 |
28 |
29 | istio.fake
30 | istio-fake
31 | 1.0-SNAPSHOT
32 |
33 |
34 |
--------------------------------------------------------------------------------
/micro-order-client/src/main/java/com/wudimanong/micro/order/client/OrderServiceClient.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.client;
2 |
3 | import com.wudimanong.micro.order.client.bo.CreateOrderBO;
4 | import com.wudimanong.micro.order.client.dto.CreateOrderDTO;
5 | import com.wudimanong.micro.order.client.dto.result.ResponseResult;
6 | import istio.fake.annotation.FakeClient;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 |
11 | /**
12 | * @author jiangqiao
13 | */
14 | @FakeClient(name = "micro-order")
15 | @RequestMapping("/order")
16 | public interface OrderServiceClient {
17 |
18 | /**
19 | * 订单创建
20 | *
21 | * @param createOrderDTO
22 | * @return
23 | */
24 | @PostMapping("/create")
25 | ResponseResult create(@RequestBody CreateOrderDTO createOrderDTO);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/micro-order-client/src/main/java/com/wudimanong/micro/order/client/bo/CreateOrderBO.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.client.bo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author jiangqiao
10 | */
11 | @Data
12 | @Builder
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class CreateOrderBO {
16 |
17 | /**
18 | * 订单号
19 | */
20 | private String orderId;
21 | /**
22 | * 订单ID
23 | */
24 | private Integer status;
25 | }
26 |
--------------------------------------------------------------------------------
/micro-order-client/src/main/java/com/wudimanong/micro/order/client/dto/CreateOrderDTO.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.client.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author jiangqiao
7 | */
8 | @Data
9 | public class CreateOrderDTO {
10 |
11 | /**
12 | * 业务订单号
13 | */
14 | private String businessId;
15 |
16 | /**
17 | * 下单金额
18 | */
19 | private Integer amount;
20 |
21 | /**
22 | * 下单渠道
23 | */
24 | private Integer channel;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/micro-order-client/src/main/java/com/wudimanong/micro/order/client/dto/result/GlobalCodeEnum.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.client.dto.result;
2 |
3 | /**
4 | * @author qiaojiang
5 | */
6 | public enum GlobalCodeEnum {
7 |
8 | /**
9 | * 全局返回码定义 - 0000开头
10 | */
11 | GL_SUCC_0(0, "成功"),
12 | GL_FAIL_9995(9995, "依赖服务异常"),
13 | GL_FAIL_9996(9996, "不支持的HttpMethod"),
14 | GL_FAIL_9997(9997, "HTTP错误"),
15 | GL_FAIL_9998(9998, "参数错误"),
16 | GL_FAIL_9999(9999, "系统异常");
17 | /**
18 | * 编码
19 | */
20 | private Integer code;
21 |
22 | /**
23 | * 描述
24 | */
25 | private String desc;
26 |
27 |
28 | GlobalCodeEnum(Integer code, String desc) {
29 | this.code = code;
30 | this.desc = desc;
31 | }
32 |
33 | /**
34 | * 根据编码获取枚举类型
35 | *
36 | * @param code 编码
37 | * @return
38 | */
39 | public static GlobalCodeEnum getByCode(String code) {
40 | //判空
41 | if (code == null) {
42 | return null;
43 | }
44 | //循环处理
45 | GlobalCodeEnum[] values = GlobalCodeEnum.values();
46 | for (GlobalCodeEnum value : values) {
47 | if (value.getCode().equals(code)) {
48 | return value;
49 | }
50 | }
51 | return null;
52 | }
53 |
54 | public Integer getCode() {
55 | return code;
56 | }
57 |
58 | public String getDesc() {
59 | return desc;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/micro-order-client/src/main/java/com/wudimanong/micro/order/client/dto/result/ResponseResult.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.client.dto.result;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.annotation.JsonPropertyOrder;
5 | import java.io.Serializable;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Builder;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 |
11 | /**
12 | * @author qiaojiang
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | @JsonPropertyOrder({"code", "message", "data"})
19 | public class ResponseResult implements Serializable {
20 |
21 | private static final long serialVersionUID = 1L;
22 |
23 | /**
24 | * 返回的对象
25 | */
26 | @JsonInclude(JsonInclude.Include.NON_NULL)
27 | private T data;
28 | /**
29 | * 返回的编码
30 | */
31 | private Integer code;
32 | /**
33 | * 返回的信息
34 | */
35 | private String message;
36 |
37 | /**
38 | * @return 响应结果
39 | */
40 | public static ResponseResult OK() {
41 | return packageObject("", GlobalCodeEnum.GL_SUCC_0);
42 | }
43 |
44 | /**
45 | * @param data 返回的数据
46 | * @param 返回的数据类型
47 | * @return 响应结果
48 | */
49 | public static ResponseResult OK(T data) {
50 | return packageObject(data, GlobalCodeEnum.GL_SUCC_0);
51 | }
52 |
53 | /**
54 | * 对返回的消息进行打包
55 | *
56 | * @param data 返回的数据
57 | * @param globalCodeEnum 自定义的返回码枚举类型
58 | * @param 返回的数据类型
59 | * @return 响应结果
60 | */
61 | public static ResponseResult packageObject(T data, GlobalCodeEnum globalCodeEnum) {
62 | ResponseResult responseResult = new ResponseResult<>();
63 | responseResult.setCode(globalCodeEnum.getCode());
64 | responseResult.setMessage(globalCodeEnum.getDesc());
65 | responseResult.setData(data);
66 | return responseResult;
67 | }
68 |
69 | /**
70 | * 对返回的消息进行打包
71 | *
72 | * @param data 返回的数据
73 | * @param code 返回的状态码
74 | * @param message 返回的消息
75 | * @param 返回的数据类型
76 | * @return 响应结果
77 | */
78 | public static ResponseResult packageObject(T data, Integer code, String message) {
79 | ResponseResult responseResult = new ResponseResult<>();
80 | responseResult.setCode(code);
81 | responseResult.setMessage(message);
82 | responseResult.setData(data);
83 | return responseResult;
84 | }
85 |
86 | /**
87 | * 系统服务不可用
88 | *
89 | * @param globalCodeEnum Feign依赖服务不可用的返回码枚举类型
90 | * @param 返回的数据类型
91 | * @return 响应结果
92 | */
93 | public static ResponseResult systemError(GlobalCodeEnum globalCodeEnum) {
94 | return packageObject(null, globalCodeEnum);
95 | }
96 |
97 | /**
98 | * 未查询到相关的数据
99 | *
100 | * @param globalCodeEnum 未查询到相关信息的返回码枚举类型
101 | * @param 返回的数据类型
102 | * @return 响应结果
103 | */
104 | public static ResponseResult noData(GlobalCodeEnum globalCodeEnum) {
105 | return packageObject(null, globalCodeEnum);
106 | }
107 |
108 | /**
109 | * 系统异常(使用默认的异常返回码)
110 | *
111 | * @param 返回的数据类型
112 | * @return 响应结果
113 | */
114 | public static ResponseResult systemException() {
115 | return packageObject(null, GlobalCodeEnum.GL_FAIL_9999);
116 | }
117 |
118 | /**
119 | * 系统异常
120 | *
121 | * @param globalCodeEnum 异常返回码枚举类型
122 | * @param 返回的数据类型
123 | * @return 响应结果
124 | */
125 | public static ResponseResult systemException(GlobalCodeEnum globalCodeEnum) {
126 | return packageObject(null, globalCodeEnum);
127 | }
128 |
129 | /**
130 | * 自定义系统异常信息
131 | *
132 | * @param code
133 | * @param message 自定义消息
134 | * @param
135 | * @return
136 | */
137 | public static ResponseResult systemException(Integer code, String message) {
138 | return packageObject(null, code, message);
139 | }
140 | }
--------------------------------------------------------------------------------
/micro-order/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8u191-jre-alpine3.9
2 | ENTRYPOINT ["/usr/bin/java", "-jar", "/app.jar"]
3 | ARG JAR_FILE
4 | ADD ${JAR_FILE} /app.jar
5 | EXPOSE 9091
--------------------------------------------------------------------------------
/micro-order/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.wudimanong
8 | micro-order
9 | 1.0-SNAPSHOT
10 |
11 |
12 | com.wudimanong
13 | istio-micro-demo
14 | 1.0-SNAPSHOT
15 |
16 |
17 |
18 |
19 |
20 | org.springframework.boot
21 | spring-boot-starter
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-web
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-test
31 | test
32 |
33 |
34 |
35 | com.wudimanong
36 | micro-order-client
37 | 1.0-SNAPSHOT
38 |
39 |
40 |
41 |
42 | com.wudimanong
43 | micro-pay-client
44 | 1.0-SNAPSHOT
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-maven-plugin
54 |
55 |
56 |
57 | com.spotify
58 | dockerfile-maven-plugin
59 | 1.4.13
60 |
61 |
62 | javax.activation
63 | activation
64 | 1.1
65 |
66 |
67 |
68 |
69 | build-image
70 | package
71 |
72 | build
73 | push
74 |
75 |
76 |
77 |
78 |
79 | docker/Dockerfile
80 | ${docker.repository}/wudimanong/${project.artifactId}
81 | ${project.version}
82 |
83 |
84 | target/${project.build.finalName}.jar
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/MicroOrder.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * @author jiangqiao
8 | */
9 | @SpringBootApplication
10 | public class MicroOrder {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(MicroOrder.class, args);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/config/AutoResultReturnHandler.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.config;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.wudimanong.micro.order.client.dto.result.ResponseResult;
5 | import java.io.IOException;
6 | import java.io.PrintWriter;
7 | import javax.servlet.http.HttpServletResponse;
8 | import org.springframework.core.MethodParameter;
9 | import org.springframework.core.annotation.AnnotatedElementUtils;
10 | import org.springframework.web.bind.annotation.ResponseBody;
11 | import org.springframework.web.context.request.NativeWebRequest;
12 | import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
13 | import org.springframework.web.method.support.ModelAndViewContainer;
14 |
15 | /**
16 | * @author jiangqiao
17 | */
18 | public class AutoResultReturnHandler implements HandlerMethodReturnValueHandler {
19 |
20 | @Override
21 | public boolean supportsReturnType(MethodParameter returnType) {
22 | return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
23 | returnType.hasMethodAnnotation(ResponseBody.class));
24 | }
25 |
26 | /**
27 | * Controller层接口返回值统一封装方法
28 | *
29 | * @param returnValue
30 | * @param returnType
31 | * @param mavContainer
32 | * @param webRequest
33 | */
34 | @Override
35 | public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
36 | NativeWebRequest webRequest) {
37 | mavContainer.setRequestHandled(true);
38 | HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
39 | response.setContentType("application/json;charset=UTF-8");
40 | PrintWriter writer = null;
41 | try {
42 | writer = response.getWriter();
43 | writer.print(JSON.toJSONString(ResponseResult.OK(returnValue)));
44 | writer.flush();
45 | } catch (IOException e) {
46 | e.printStackTrace();
47 | } finally {
48 | if (writer != null) {
49 | writer.close();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/config/GrpcClientCommandLineRunner.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.config;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.CommandLineRunner;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * @author jiangqiao
10 | */
11 | @Component
12 | @Slf4j
13 | public class GrpcClientCommandLineRunner implements CommandLineRunner {
14 |
15 | @Autowired
16 | GrpcClientConfiguration configuration;
17 |
18 | @Override
19 | public void run(String... args) throws Exception {
20 | //开启gRPC客户端
21 | configuration.start();
22 |
23 | //添加客户端关闭的逻辑
24 | Runtime.getRuntime().addShutdownHook(new Thread(() -> {
25 | try {
26 | configuration.shutdown();
27 | } catch (InterruptedException e) {
28 | e.printStackTrace();
29 | }
30 | }));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/config/GrpcClientConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.config;
2 |
3 | import com.wudimanong.micro.pay.proto.PayServiceGrpc;
4 | import io.grpc.ManagedChannel;
5 | import io.grpc.ManagedChannelBuilder;
6 | import java.util.concurrent.TimeUnit;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.stereotype.Component;
10 |
11 | /**
12 | * @author jiangqiao
13 | */
14 | @Slf4j
15 | @Component
16 | public class GrpcClientConfiguration {
17 |
18 | /**
19 | * 支付gRPC Server的地址
20 | */
21 | @Value("${server-host}")
22 | private String host;
23 |
24 | /**
25 | * 支付gRPC Server的端口
26 | */
27 | @Value("${server-port}")
28 | private int port;
29 |
30 | private ManagedChannel channel;
31 |
32 | /**
33 | * 支付服务stub对象
34 | */
35 | private PayServiceGrpc.PayServiceBlockingStub stub;
36 |
37 | public void start() {
38 | //开启channel
39 | channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
40 |
41 | //通过channel获取到服务端的stub
42 | stub = PayServiceGrpc.newBlockingStub(channel);
43 | log.info("gRPC client started, server address: {}:{}", host, port);
44 | }
45 |
46 | public void shutdown() throws InterruptedException {
47 | //调用shutdown方法后等待1秒关闭channel
48 | channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
49 | log.info("gRPC client shut down successfully.");
50 | }
51 |
52 | public PayServiceGrpc.PayServiceBlockingStub getStub() {
53 | return this.stub;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/config/WebMvcConfig.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.config;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import org.springframework.beans.factory.InitializingBean;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
9 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
10 |
11 | /**
12 | * @author jiangqiao
13 | */
14 | @Configuration
15 | public class WebMvcConfig implements InitializingBean {
16 |
17 | @Autowired
18 | RequestMappingHandlerAdapter requestMappingHandlerAdapter;
19 |
20 | @Override
21 | public void afterPropertiesSet() {
22 | List returnValueHandlers = requestMappingHandlerAdapter
23 | .getReturnValueHandlers();
24 | List list = new ArrayList<>();
25 | //自定义returnHandler
26 | list.add(new AutoResultReturnHandler());
27 | list.addAll(returnValueHandlers);
28 | requestMappingHandlerAdapter.setReturnValueHandlers(list);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/controller/OrderController.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.controller;
2 |
3 | import com.wudimanong.micro.order.client.bo.CreateOrderBO;
4 | import com.wudimanong.micro.order.client.dto.CreateOrderDTO;
5 | import com.wudimanong.micro.order.service.OrderService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | /**
13 | * @author jiangqiao
14 | */
15 | @RestController
16 | @RequestMapping("/order")
17 | public class OrderController {
18 |
19 | @Autowired
20 | OrderService orderServiceImpl;
21 |
22 | /**
23 | * 下单接口
24 | *
25 | * @param createOrderDTO
26 | * @return
27 | */
28 | @PostMapping("/create")
29 | public CreateOrderBO create(@RequestBody CreateOrderDTO createOrderDTO) {
30 | return orderServiceImpl.create(createOrderDTO);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/exception/ServiceException.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.exception;
2 |
3 | /**
4 | * @author jiangqiao
5 | */
6 | public class ServiceException extends RuntimeException {
7 |
8 | private final Integer code;
9 |
10 | public ServiceException(Integer code, String message) {
11 | super(message);
12 | this.code = code;
13 | }
14 |
15 | public ServiceException(Integer code, String message, Throwable e) {
16 | super(message, e);
17 | this.code = code;
18 | }
19 |
20 | public Integer getCode() {
21 | return code;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/service/OrderService.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.service;
2 |
3 |
4 | import com.wudimanong.micro.order.client.bo.CreateOrderBO;
5 | import com.wudimanong.micro.order.client.dto.CreateOrderDTO;
6 |
7 | /**
8 | * @author jiangqiao
9 | */
10 | public interface OrderService {
11 |
12 | /**
13 | * 下单接口
14 | *
15 | * @param createOrderDTO
16 | * @return
17 | */
18 | CreateOrderBO create(CreateOrderDTO createOrderDTO);
19 | }
20 |
--------------------------------------------------------------------------------
/micro-order/src/main/java/com/wudimanong/micro/order/service/impl/OrderServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.order.service.impl;
2 |
3 | import com.wudimanong.micro.order.client.bo.CreateOrderBO;
4 | import com.wudimanong.micro.order.client.dto.CreateOrderDTO;
5 | import com.wudimanong.micro.order.config.GrpcClientConfiguration;
6 | import com.wudimanong.micro.order.service.OrderService;
7 | import com.wudimanong.micro.pay.proto.PayRequest;
8 | import com.wudimanong.micro.pay.proto.PayResponse;
9 | import java.util.Random;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.stereotype.Service;
13 |
14 | /**
15 | * @author jiangqiao
16 | */
17 | @Slf4j
18 | @Service
19 | public class OrderServiceImpl implements OrderService {
20 |
21 | /**
22 | * 引入gRPC客户端配置依赖
23 | */
24 | @Autowired
25 | GrpcClientConfiguration gRpcClent;
26 |
27 | @Override
28 | public CreateOrderBO create(CreateOrderDTO createOrderDTO) {
29 | log.info("现在开始处理下单请求.....");
30 | //生成订单号
31 | String orderId = String.valueOf(new Random(100).nextInt(100000) + System.currentTimeMillis());
32 | //构建支付请求(gRPC调用)
33 | PayRequest payRequest = PayRequest.newBuilder().setOrderId(orderId).setAmount(createOrderDTO.getAmount())
34 | .build();
35 | //使用stub发送请求到服务端
36 | PayResponse payResponse = gRpcClent.getStub().doPay(payRequest);
37 | log.info("pay gRpc response->" + payResponse.toString());
38 | return CreateOrderBO.builder().orderId(orderId).status(payResponse.getStatus()).build();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/micro-order/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | #支付微服务Grpc服务地址、端口配置
2 | server-host: 127.0.0.1
3 | server-port: 18888
4 |
--------------------------------------------------------------------------------
/micro-order/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: micro-order
4 | server:
5 | port: 9091
6 |
7 | #支付微服务Grpc服务地址、端口配置
8 | server-host: ${grpc_server_host}
9 | server-port: ${grpc_server_port}
10 |
--------------------------------------------------------------------------------
/micro-pay-client/micro-pay-client.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/micro-pay-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | istio-micro-demo
7 | com.wudimanong
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | com.wudimanong
13 | micro-pay-client
14 | 1.0-SNAPSHOT
15 |
16 |
17 |
18 |
19 | org.projectlombok
20 | lombok
21 |
22 |
23 |
24 | com.alibaba
25 | fastjson
26 |
27 |
28 |
29 | io.grpc
30 | grpc-all
31 | 1.36.1
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | kr.motd.maven
40 | os-maven-plugin
41 | 1.6.2
42 |
43 |
44 |
45 |
46 | org.xolstice.maven.plugins
47 | protobuf-maven-plugin
48 | 0.6.1
49 |
50 | com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}
51 | grpc-java
52 | io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}
53 |
54 |
55 |
56 |
57 | compile
58 | compile-custom
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/micro-pay-client/src/main/proto/paycore.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.wudimanong.pay.client;
4 |
5 | option java_multiple_files = true;
6 | option java_package = "com.wudimanong.micro.pay.proto";
7 |
8 | service PayService {
9 | //定义支付rpc方法
10 | rpc doPay (PayRequest) returns (PayResponse);
11 | }
12 |
13 | message PayRequest {
14 | string orderId = 1;
15 | int32 amount=2;
16 | }
17 |
18 | message PayResponse {
19 | int32 status = 1;
20 | }
--------------------------------------------------------------------------------
/micro-pay/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8u191-jre-alpine3.9
2 | ENTRYPOINT ["/usr/bin/java", "-jar", "/app.jar"]
3 | ARG JAR_FILE
4 | ADD ${JAR_FILE} /app.jar
5 | EXPOSE 9092
--------------------------------------------------------------------------------
/micro-pay/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.wudimanong
8 | micro-pay
9 | 1.0-SNAPSHOT
10 |
11 |
12 | com.wudimanong
13 | istio-micro-demo
14 | 1.0-SNAPSHOT
15 |
16 |
17 |
18 |
19 |
20 | org.springframework.boot
21 | spring-boot-starter
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-web
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-test
31 | test
32 |
33 |
34 |
35 | org.projectlombok
36 | lombok
37 |
38 |
39 |
40 |
41 | com.wudimanong
42 | micro-pay-client
43 | 1.0-SNAPSHOT
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-maven-plugin
53 |
54 |
55 |
56 | com.spotify
57 | dockerfile-maven-plugin
58 | 1.4.13
59 |
60 |
61 | javax.activation
62 | activation
63 | 1.1
64 |
65 |
66 |
67 |
68 | build-image
69 | package
70 |
71 | build
72 | push
73 |
74 |
75 |
76 |
77 |
78 | docker/Dockerfile
79 | ${docker.repository}/wudimanong/${project.artifactId}
80 | ${project.version}
81 |
82 |
83 | target/${project.build.finalName}.jar
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/micro-pay/src/main/java/com/wudimanong/micro/pay/MicroPay.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.pay;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * @author jiangqiao
8 | */
9 | @SpringBootApplication
10 | public class MicroPay {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(MicroPay.class, args);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/micro-pay/src/main/java/com/wudimanong/micro/pay/config/GrpcCommandLineRunner.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.pay.config;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.CommandLineRunner;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * @author jiangqiao
9 | */
10 | @Component
11 | public class GrpcCommandLineRunner implements CommandLineRunner {
12 |
13 | @Autowired
14 | GrpcServerConfiguration configuration;
15 |
16 | @Override
17 | public void run(String... args) throws Exception {
18 | configuration.start();
19 | configuration.block();
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/micro-pay/src/main/java/com/wudimanong/micro/pay/config/GrpcServerConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.pay.config;
2 |
3 | import com.wudimanong.micro.pay.provider.PayCoreProvider;
4 | import io.grpc.Server;
5 | import io.grpc.ServerBuilder;
6 | import java.io.IOException;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.beans.factory.annotation.Value;
10 | import org.springframework.stereotype.Component;
11 |
12 | /**
13 | * @author jiangqiao
14 | */
15 | @Slf4j
16 | @Component
17 | public class GrpcServerConfiguration {
18 |
19 | @Autowired
20 | PayCoreProvider service;
21 |
22 | /**
23 | * 注入配置文件中的端口信息
24 | */
25 | @Value("${grpc.server-port}")
26 | private int port;
27 | private Server server;
28 |
29 | public void start() throws IOException {
30 | // 构建服务端
31 | log.info("Starting gRPC on port {}.", port);
32 | server = ServerBuilder.forPort(port).addService(service).build().start();
33 | log.info("gRPC server started, listening on {}.", port);
34 |
35 | // 添加服务端关闭的逻辑
36 | Runtime.getRuntime().addShutdownHook(new Thread(() -> {
37 | log.info("Shutting down gRPC server.");
38 | GrpcServerConfiguration.this.stop();
39 | log.info("gRPC server shut down successfully.");
40 | }));
41 | }
42 |
43 | private void stop() {
44 | if (server != null) {
45 | // 关闭服务端
46 | server.shutdown();
47 | }
48 | }
49 |
50 | public void block() throws InterruptedException {
51 | if (server != null) {
52 | // 服务端启动后直到应用关闭都处于阻塞状态,方便接收请求
53 | server.awaitTermination();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/micro-pay/src/main/java/com/wudimanong/micro/pay/provider/PayCoreProvider.java:
--------------------------------------------------------------------------------
1 | package com.wudimanong.micro.pay.provider;
2 |
3 | import com.wudimanong.micro.pay.proto.PayRequest;
4 | import com.wudimanong.micro.pay.proto.PayResponse;
5 | import com.wudimanong.micro.pay.proto.PayServiceGrpc;
6 | import io.grpc.stub.StreamObserver;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.stereotype.Component;
9 |
10 | /**
11 | * @author jiangqiao
12 | */
13 | @Slf4j
14 | @Component
15 | public class PayCoreProvider extends PayServiceGrpc.PayServiceImplBase {
16 |
17 | /**
18 | * 实现ProtoBuf中定义的服务方法
19 | *
20 | * @param request
21 | * @param responseStreamObserver
22 | */
23 | @Override
24 | public void doPay(PayRequest request, StreamObserver responseStreamObserver) {
25 | //逻辑处理(简单模拟打印日志)
26 | log.info("处理gRPC支付处理请求,orderId->{};payAmount{}", request.getOrderId(), request.getAmount());
27 | //构建返回对象(构建处理状态)
28 | PayResponse response = PayResponse.newBuilder().setStatus(2).build();
29 | //设置数据响应
30 | responseStreamObserver.onNext(response);
31 | responseStreamObserver.onCompleted();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/micro-pay/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: micro-pay
4 | server:
5 | port: 9092
6 |
7 | #定义gRPC服务开放的端口
8 | grpc:
9 | server-port: 18888
10 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | com.wudimanong
7 | istio-micro-demo
8 | pom
9 | 1.0-SNAPSHOT
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 2.1.5.RELEASE
15 |
16 |
17 |
18 | micro-api
19 | micro-order
20 | micro-pay
21 | micro-order-client
22 | micro-pay-client
23 | feign-istio-fake
24 |
25 |
26 |
27 |
28 | registry.cn-hangzhou.aliyuncs.com
29 |
30 |
31 |
32 |
33 |
34 |
35 | com.alibaba
36 | fastjson
37 | 1.2.70
38 | compile
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------