├── .gitignore ├── README.adoc ├── Setup.graffle ├── applications ├── boot1-load-sample │ ├── .gitignore │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── sample │ │ │ │ └── load │ │ │ │ ├── Boot1Application.java │ │ │ │ ├── Message.java │ │ │ │ ├── MessageAck.java │ │ │ │ ├── PassthroughController.java │ │ │ │ └── PassthroughHandler.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── sample │ │ └── load │ │ └── PassThroughMessagesTest.java ├── boot2-load-sample │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── sample │ │ │ │ └── load │ │ │ │ ├── Application.kt │ │ │ │ ├── Message.kt │ │ │ │ ├── MessageAck.kt │ │ │ │ ├── PassThroughHandler.kt │ │ │ │ └── config │ │ │ │ └── RoutesConfig.kt │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── kotlin │ │ └── sample │ │ └── load │ │ └── PassThroughMessageHandlerTest.kt ├── load-scripts │ ├── build.gradle │ └── src │ │ └── test │ │ ├── resources │ │ ├── gatling.conf │ │ ├── logback.xml │ │ └── recorder.conf │ │ └── scala │ │ └── simulations │ │ └── BootLoadSimulation.scala ├── sample-load-target │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── sample │ │ │ │ └── load │ │ │ │ ├── LoadTargetApplication.kt │ │ │ │ ├── Message.kt │ │ │ │ ├── MessageAck.kt │ │ │ │ ├── MessageHandler.kt │ │ │ │ └── config │ │ │ │ └── RoutesConfig.kt │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── kotlin │ │ └── sample │ │ └── load │ │ └── web │ │ └── MessageHandlerControllerTest.kt ├── spring-cloud-gateway-sample │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── sample │ │ │ │ └── load │ │ │ │ ├── Application.kt │ │ │ │ └── GatewayConfiguration.kt │ │ └── resources │ │ │ ├── application.yml │ │ │ └── logback.xml │ │ └── test │ │ └── kotlin │ │ └── sample │ │ └── load │ │ └── PassThroughMessageHandlerTest.kt ├── zuul-sample │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── src │ │ ├── main │ │ ├── java │ │ │ └── sample │ │ │ │ └── zuul │ │ │ │ └── ZuulSampleApplication.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── sample │ │ └── zuul │ │ └── PassThroughMessagesTest.java └── zuul2-sample │ ├── build.gradle │ ├── dependencies.lock │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── netflix │ │ │ └── zuul │ │ │ └── sample │ │ │ ├── Bootstrap.java │ │ │ ├── FiltersRegisteringService.java │ │ │ ├── SampleServerStartup.java │ │ │ ├── ZuulClasspathFiltersModule.java │ │ │ ├── ZuulSampleModule.java │ │ │ └── filters │ │ │ └── inbound │ │ │ ├── Routes.java │ │ │ └── StripPrefixFilter.java │ └── resources │ │ ├── application.properties │ │ └── log4j.properties │ └── test │ └── java │ └── com │ └── netflix │ └── zuul │ └── sample │ └── filters │ ├── FiltersRegisteringServiceTest.java │ └── inbound │ └── StripPrefixFilterTest.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images └── Setup.png ├── monitor ├── docker-compose.yml ├── grafana-dashboard.yml ├── grafana-datasource.yml └── prometheus.yml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | nbproject/private/ 21 | build/ 22 | nbbuild/ 23 | dist/ 24 | nbdist/ 25 | .nb-gradle/ 26 | out/ 27 | .DS_Store -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | # Spring Boot2 Performance Harness 2 | 3 | This is a sample Spring Boot 2 app to demonstrate the raw performance difference between a Spring Boot 2 app vs a Spring Boot 1 app. 4 | 5 | 6 | = Backing Service 7 | 8 | [source, bash] 9 | ---- 10 | ./gradlew -p applications/sample-load-target clean bootRun 11 | ---- 12 | 13 | = Spring Boot 2 based app: 14 | 15 | == Run the Spring Boot 2 based app: 16 | [source, bash] 17 | ---- 18 | ./gradlew -p applications/boot2-load-sample clean bootRun 19 | ---- 20 | 21 | == Call target endpoint 22 | 23 | Assuming that https://httpie.org/[httpie] is installed 24 | 25 | [source, bash] 26 | ---- 27 | http POST 'http://localhost:8082/passthrough/messages' id="1" payload="one" delay="1000" 28 | ---- 29 | 30 | OR with CURL 31 | 32 | [source, bash] 33 | ---- 34 | curl -X "POST" "http://localhost:8082/passthrough/messages" \ 35 | -H "Accept: application/json" \ 36 | -H "Content-Type: application/json" \ 37 | -d $'{ 38 | "id": "1", 39 | "payload": "one", 40 | "delay": "1000" 41 | }' 42 | ---- 43 | 44 | 45 | = Spring Boot 1 based app: 46 | 47 | == Run the Spring Boot 1 based app: 48 | [source, bash] 49 | ---- 50 | ./gradlew -p applications/boot1-load-sample clean bootRun 51 | ---- 52 | 53 | == Call target endpoint 54 | 55 | Assuming that https://httpie.org/[httpie] is installed 56 | 57 | [source, bash] 58 | ---- 59 | http POST 'http://localhost:8081/passthrough/messages' id="1" payload="one" delay="1000" 60 | ---- 61 | 62 | OR with CURL 63 | 64 | [source, bash] 65 | ---- 66 | curl -X "POST" "http://localhost:8081/passthrough/messages" \ 67 | -H "Accept: application/json" \ 68 | -H "Content-Type: application/json" \ 69 | -d $'{ 70 | "id": "1", 71 | "payload": "one", 72 | "delay": "1000" 73 | }' 74 | ---- 75 | 76 | = Spring Cloud Gateway based app: 77 | 78 | == Run the app: 79 | [source, bash] 80 | ---- 81 | ./gradlew -p applications/spring-cloud-gateway-sample clean bootRun 82 | ---- 83 | 84 | == Call target endpoint 85 | 86 | Assuming that https://httpie.org/[httpie] is installed 87 | 88 | [source, bash] 89 | ---- 90 | http POST 'http://localhost:8083/passthrough/messages' id="1" payload="one" delay="1000" 91 | ---- 92 | 93 | OR with CURL 94 | 95 | [source, bash] 96 | ---- 97 | curl -X "POST" "http://localhost:8083/passthrough/messages" \ 98 | -H "Accept: application/json" \ 99 | -H "Content-Type: application/json" \ 100 | -d $'{ 101 | "id": "1", 102 | "payload": "one", 103 | "delay": "1000" 104 | }' 105 | ---- 106 | 107 | 108 | = Spring Cloud Zuul based app: 109 | 110 | == Run the app: 111 | [source, bash] 112 | ---- 113 | ./gradlew -p applications/zuul-sample clean bootRun 114 | ---- 115 | 116 | == Call target endpoint 117 | 118 | Assuming that https://httpie.org/[httpie] is installed 119 | 120 | [source, bash] 121 | ---- 122 | http POST 'http://localhost:8084/passthrough/messages' id="1" payload="one" delay="1000" 123 | ---- 124 | 125 | OR with CURL 126 | 127 | [source, bash] 128 | ---- 129 | curl -X "POST" "http://localhost:8084/passthrough/messages" \ 130 | -H "Accept: application/json" \ 131 | -H "Content-Type: application/json" \ 132 | -d $'{ 133 | "id": "1", 134 | "payload": "one", 135 | "delay": "1000" 136 | }' 137 | ---- 138 | 139 | 140 | = Zuul2 based app: 141 | 142 | == Run the app: 143 | [source, bash] 144 | ---- 145 | ./gradlew -p applications/zuul2-sample clean run 146 | ---- 147 | 148 | == Call target endpoint 149 | 150 | Assuming that https://httpie.org/[httpie] is installed 151 | 152 | [source, bash] 153 | ---- 154 | http POST 'http://localhost:8085/passthrough/messages' id="1" payload="one" delay="1000" 155 | ---- 156 | 157 | OR with CURL 158 | 159 | [source, bash] 160 | ---- 161 | curl -X "POST" "http://localhost:8085/passthrough/messages" \ 162 | -H "Accept: application/json" \ 163 | -H "Content-Type: application/json" \ 164 | -d $'{ 165 | "id": "1", 166 | "payload": "one", 167 | "delay": "1000" 168 | }' 169 | ---- 170 | 171 | = Run Load tests 172 | 173 | == Against Boot 2 version of the app 174 | [source, bash] 175 | ---- 176 | ./gradlew -p applications/load-scripts -DTARGET_URL=http://localhost:8082 -DSIM_USERS=300 gatlingRun 177 | ---- 178 | 179 | == Against Boot 1 version of the app 180 | [source, bash] 181 | ---- 182 | ./gradlew -p applications/load-scripts -DTARGET_URL=http://localhost:8081 -DSIM_USERS=300 gatlingRun 183 | ---- 184 | 185 | == Against Spring Cloud Gateway version of the app 186 | [source, bash] 187 | ---- 188 | ./gradlew -p applications/load-scripts -DTARGET_URL=http://localhost:8083 -DSIM_USERS=300 gatlingRun 189 | ---- 190 | 191 | == Against Spring Cloud Zuul version of the app 192 | [source, bash] 193 | ---- 194 | ./gradlew -p applications/load-scripts -DTARGET_URL=http://localhost:8084 -DSIM_USERS=300 gatlingRun 195 | ---- 196 | 197 | == Against Zuul2 version of the app 198 | [source, bash] 199 | ---- 200 | ./gradlew -p applications/load-scripts -DTARGET_URL=http://localhost:8085 -DSIM_USERS=300 gatlingRun 201 | ---- -------------------------------------------------------------------------------- /Setup.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/boot2-load-demo/d998ee0725253c224131fd0eaf1843efacb7ac8b/Setup.graffle -------------------------------------------------------------------------------- /applications/boot1-load-sample/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | nbproject/private/ 21 | build/ 22 | nbbuild/ 23 | dist/ 24 | nbdist/ 25 | .nb-gradle/ -------------------------------------------------------------------------------- /applications/boot1-load-sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.5.13.RELEASE' 4 | wireMockVersion = "2.8.0" 5 | } 6 | repositories { 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 11 | } 12 | } 13 | 14 | apply plugin: 'java' 15 | apply plugin: 'org.springframework.boot' 16 | 17 | group = 'org.bk.samples' 18 | version = '0.0.1-SNAPSHOT' 19 | sourceCompatibility = 1.8 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | dependencies { 26 | compile('org.springframework.boot:spring-boot-starter-actuator') 27 | compile('org.springframework.boot:spring-boot-starter-web') 28 | compile('io.micrometer:micrometer-spring-legacy:1.0.2') 29 | compile('io.micrometer:micrometer-registry-prometheus:1.0.2') 30 | testCompile('org.springframework.boot:spring-boot-starter-test') 31 | testCompile("com.github.tomakehurst:wiremock:${wireMockVersion}") 32 | } 33 | -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/main/java/sample/load/Boot1Application.java: -------------------------------------------------------------------------------- 1 | package sample.load; 2 | 3 | import io.micrometer.core.instrument.MeterRegistry; 4 | import io.micrometer.spring.autoconfigure.MeterRegistryCustomizer; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | @SpringBootApplication 10 | public class Boot1Application { 11 | 12 | @Bean 13 | public MeterRegistryCustomizer commonTags() { 14 | return (registry) -> registry.config() 15 | .commonTags("application", "boot1-load-sample"); 16 | } 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(Boot1Application.class, args); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/main/java/sample/load/Message.java: -------------------------------------------------------------------------------- 1 | package sample.load; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import java.util.Objects; 7 | 8 | public class Message { 9 | 10 | private final String id; 11 | private final String payload; 12 | private final Long delay; 13 | 14 | @JsonCreator 15 | public Message( 16 | @JsonProperty("id") String id, 17 | @JsonProperty("payload") String payload, 18 | @JsonProperty("delay") Long delay 19 | ) { 20 | this.id = id; 21 | this.payload = payload; 22 | this.delay = delay; 23 | } 24 | 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public String getPayload() { 31 | return payload; 32 | } 33 | 34 | public Long getDelay() { 35 | return delay; 36 | } 37 | 38 | @Override 39 | public boolean equals(Object o) { 40 | if (this == o) return true; 41 | if (o == null || getClass() != o.getClass()) return false; 42 | Message message = (Message) o; 43 | return Objects.equals(id, message.id) && 44 | Objects.equals(payload, message.payload) && 45 | Objects.equals(delay, message.delay); 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Objects.hash(id, payload, delay); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | final StringBuffer sb = new StringBuffer("Message{"); 56 | sb.append("id='").append(id).append('\''); 57 | sb.append(", payload='").append(payload).append('\''); 58 | sb.append(", delay=").append(delay); 59 | sb.append('}'); 60 | return sb.toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/main/java/sample/load/MessageAck.java: -------------------------------------------------------------------------------- 1 | package sample.load; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import java.util.Objects; 7 | 8 | public class MessageAck { 9 | 10 | private final String id; 11 | private final String received; 12 | private final String ack; 13 | 14 | @JsonCreator 15 | public MessageAck( 16 | @JsonProperty("id") String id, 17 | @JsonProperty("received") String received, 18 | @JsonProperty("ack") String ack 19 | ) { 20 | this.id = id; 21 | this.received = received; 22 | this.ack = ack; 23 | } 24 | 25 | public String getId() { 26 | return id; 27 | } 28 | 29 | public String getReceived() { 30 | return received; 31 | } 32 | 33 | public String getAck() { 34 | return ack; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) return true; 40 | if (o == null || getClass() != o.getClass()) return false; 41 | MessageAck that = (MessageAck) o; 42 | return Objects.equals(id, that.id) && 43 | Objects.equals(received, that.received) && 44 | Objects.equals(ack, that.ack); 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return Objects.hash(id, received, ack); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | final StringBuffer sb = new StringBuffer("MessageAck{"); 55 | sb.append("id='").append(id).append('\''); 56 | sb.append(", received='").append(received).append('\''); 57 | sb.append(", ack='").append(ack).append('\''); 58 | sb.append('}'); 59 | return sb.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/main/java/sample/load/PassthroughController.java: -------------------------------------------------------------------------------- 1 | package sample.load; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | import org.springframework.web.bind.annotation.RequestBody; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class PassthroughController { 10 | 11 | private final PassthroughHandler passthroughHandler; 12 | 13 | public PassthroughController(PassthroughHandler passthroughHandler) { 14 | this.passthroughHandler = passthroughHandler; 15 | } 16 | 17 | @RequestMapping("/passthrough/messages") 18 | public ResponseEntity handlePassthrough(@RequestBody Message message) { 19 | return ResponseEntity.ok( 20 | passthroughHandler.handlePassthrough(message) 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/main/java/sample/load/PassthroughHandler.java: -------------------------------------------------------------------------------- 1 | package sample.load; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.boot.web.client.RestTemplateBuilder; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Component 10 | public class PassthroughHandler { 11 | 12 | private final RestTemplate restTemplate; 13 | 14 | private final String targetHost; 15 | 16 | public PassthroughHandler( 17 | RestTemplateBuilder restTemplateBuilder, 18 | @Value("${loadtarget.host}") String targetHost 19 | ) { 20 | this.restTemplate = restTemplateBuilder.build(); 21 | this.targetHost = targetHost; 22 | } 23 | 24 | 25 | public MessageAck handlePassthrough(Message message) { 26 | ResponseEntity responseEntity = this.restTemplate.postForEntity(targetHost + "/messages", message, MessageAck.class); 27 | return responseEntity.getBody(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | loadtarget: 4 | host: http://localhost:8080 5 | 6 | server: 7 | port: 8081 8 | 9 | management: 10 | security: 11 | enabled: false 12 | metrics: 13 | distribution: 14 | percentiles-histogram[http.server.requests]: true 15 | sla: 16 | http: 17 | server: 18 | requests: 1ms, 5ms -------------------------------------------------------------------------------- /applications/boot1-load-sample/src/test/java/sample/load/PassThroughMessagesTest.java: -------------------------------------------------------------------------------- 1 | package sample.load; 2 | 3 | 4 | import com.github.tomakehurst.wiremock.client.WireMock; 5 | import com.github.tomakehurst.wiremock.junit.WireMockRule; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | import org.springframework.test.web.servlet.MockMvc; 15 | 16 | import static com.github.tomakehurst.wiremock.client.WireMock.*; 17 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 18 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 20 | 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(properties = "loadtarget.host=http://localhost:8989") 23 | @AutoConfigureMockMvc 24 | public class PassThroughMessagesTest { 25 | 26 | @Autowired 27 | private MockMvc mockMvc; 28 | 29 | @Rule 30 | public WireMockRule wireMockRule = new WireMockRule(8989); 31 | 32 | @Test 33 | public void testPassthroughCall() throws Exception { 34 | 35 | stubFor(WireMock.post(urlEqualTo("/messages")) 36 | .willReturn(aResponse() 37 | .withStatus(200) 38 | .withHeader("Content-Type", "application/json") 39 | .withBody("{\n" + 40 | " \"id\": \"1\",\n" + 41 | " \"received\": \"sample payload\",\n" + 42 | " \"ack\": \"ack\"\n" + 43 | "}\n"))); 44 | 45 | mockMvc.perform( 46 | post("/passthrough/messages") 47 | .contentType(MediaType.APPLICATION_JSON) 48 | .content("{\n" + 49 | " \"id\": \"1\",\n" + 50 | " \"payload\": \"sample payload\",\n" + 51 | " \"delay\": 0\n" + 52 | "}\n")) 53 | .andExpect(status().is2xxSuccessful()) 54 | .andExpect(content().json("{\n" + 55 | " \"id\": \"1\",\n" + 56 | " \"received\": \"sample payload\",\n" + 57 | " \"ack\": \"ack\"\n" + 58 | "}")); 59 | 60 | verify( 61 | postRequestedFor(urlMatching("/messages")) 62 | .withRequestBody(matching(".*sample.*")) 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /applications/boot2-load-sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | kotlinVersion = '1.2.41' 4 | springBootVersion = '2.0.2.RELEASE' 5 | wireMockVersion = "2.8.0" 6 | } 7 | repositories { 8 | mavenCentral() 9 | maven { url "https://repo.spring.io/snapshot" } 10 | maven { url "https://repo.spring.io/milestone" } 11 | } 12 | dependencies { 13 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 14 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") 15 | classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") 16 | classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.2' 17 | } 18 | } 19 | 20 | apply plugin: 'kotlin' 21 | apply plugin: 'kotlin-spring' 22 | apply plugin: 'java' 23 | apply plugin: 'org.springframework.boot' 24 | apply plugin: 'io.spring.dependency-management' 25 | apply plugin: 'org.junit.platform.gradle.plugin' 26 | 27 | group = 'org.bk.samples' 28 | version = '0.0.1-SNAPSHOT' 29 | sourceCompatibility = 1.8 30 | 31 | repositories { 32 | mavenCentral() 33 | maven { url "https://repo.spring.io/snapshot" } 34 | maven { url "https://repo.spring.io/milestone" } 35 | } 36 | 37 | compileKotlin { 38 | kotlinOptions { 39 | freeCompilerArgs = ["-Xjsr305=strict"] 40 | jvmTarget = "1.8" 41 | } 42 | } 43 | compileTestKotlin { 44 | kotlinOptions { 45 | freeCompilerArgs = ["-Xjsr305=strict"] 46 | jvmTarget = "1.8" 47 | } 48 | } 49 | 50 | dependencies { 51 | compile('org.springframework.boot:spring-boot-starter-actuator') 52 | compile('org.springframework.boot:spring-boot-starter-webflux') 53 | compile("com.fasterxml.jackson.module:jackson-module-kotlin") 54 | compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}") 55 | compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") 56 | runtime("io.micrometer:micrometer-registry-prometheus") 57 | testCompile('org.springframework.boot:spring-boot-starter-test') { 58 | exclude group: "junit", module: "junit" 59 | } 60 | testCompile('io.projectreactor:reactor-test') 61 | testCompile("com.github.tomakehurst:wiremock:${wireMockVersion}") 62 | testCompile("org.junit.jupiter:junit-jupiter-api") 63 | testRuntime("org.junit.jupiter:junit-jupiter-engine") 64 | } 65 | -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/main/kotlin/sample/load/Application.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import io.micrometer.core.instrument.MeterRegistry 4 | import org.springframework.beans.factory.annotation.Value 5 | import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer 6 | import org.springframework.boot.autoconfigure.SpringBootApplication 7 | import org.springframework.boot.runApplication 8 | import org.springframework.context.annotation.Bean 9 | import org.springframework.web.reactive.function.client.WebClient 10 | 11 | @SpringBootApplication 12 | class Application { 13 | 14 | @Value("\${loadtarget.host}") 15 | lateinit var targetHost: String; 16 | 17 | @Bean 18 | fun webClient() : WebClient { 19 | return WebClient.builder() 20 | .baseUrl(targetHost) 21 | .build() 22 | } 23 | 24 | @Bean 25 | fun passThroughHandler(): PassThroughHandler { 26 | return PassThroughHandler(webClient()) 27 | } 28 | 29 | @Bean 30 | fun commonTags(): MeterRegistryCustomizer { 31 | return MeterRegistryCustomizer { registry -> 32 | registry.config() 33 | .commonTags("application", "boot2-load-sample") 34 | } 35 | } 36 | } 37 | 38 | fun main(args: Array) { 39 | runApplication(*args) 40 | } -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/main/kotlin/sample/load/Message.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | data class Message(val id: String, val payload: String, val delay: Long) -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/main/kotlin/sample/load/MessageAck.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | data class MessageAck(val id: String, val received: String, val ack: String) -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/main/kotlin/sample/load/PassThroughHandler.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import org.springframework.http.HttpHeaders 4 | import org.springframework.http.MediaType 5 | import org.springframework.web.reactive.function.BodyInserters.fromObject 6 | import org.springframework.web.reactive.function.client.ClientResponse 7 | import org.springframework.web.reactive.function.client.WebClient 8 | import org.springframework.web.reactive.function.client.bodyToMono 9 | import org.springframework.web.reactive.function.server.ServerRequest 10 | import org.springframework.web.reactive.function.server.ServerResponse 11 | import org.springframework.web.reactive.function.server.bodyToMono 12 | import reactor.core.publisher.Mono 13 | 14 | class PassThroughHandler(private val webClient: WebClient) { 15 | 16 | fun handle(serverRequest: ServerRequest): Mono { 17 | val messageMono = serverRequest.bodyToMono() 18 | 19 | return messageMono.flatMap { message -> 20 | passThrough(message) 21 | .flatMap { messageAck -> 22 | ServerResponse.ok().body(fromObject(messageAck)) 23 | } 24 | } 25 | } 26 | 27 | fun passThrough(message: Message): Mono { 28 | return webClient.post() 29 | .uri("/messages") 30 | .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 31 | .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) 32 | .body(fromObject(message)) 33 | .exchange() 34 | .flatMap { response: ClientResponse -> 35 | response.bodyToMono() 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/main/kotlin/sample/load/config/RoutesConfig.kt: -------------------------------------------------------------------------------- 1 | package sample.load.config 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import org.springframework.web.reactive.function.server.router 6 | import sample.load.PassThroughHandler 7 | 8 | @Configuration 9 | class RoutesConfig { 10 | 11 | @Bean 12 | fun apis(passThroughHandler: PassThroughHandler) = router { 13 | POST("/passthrough/messages", passThroughHandler::handle) 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | root: info 4 | 5 | 6 | loadtarget: 7 | host: http://localhost:8080 8 | 9 | server: 10 | port: 8082 11 | 12 | management: 13 | endpoints: 14 | web: 15 | exposure: 16 | include: "*" 17 | metrics: 18 | distribution: 19 | percentiles-histogram[http.server.requests]: true 20 | sla: 21 | http: 22 | server: 23 | requests: 1ms, 5ms -------------------------------------------------------------------------------- /applications/boot2-load-sample/src/test/kotlin/sample/load/PassThroughMessageHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import com.github.tomakehurst.wiremock.WireMockServer 4 | import com.github.tomakehurst.wiremock.client.WireMock.* 5 | import com.github.tomakehurst.wiremock.core.WireMockConfiguration 6 | import org.junit.jupiter.api.AfterEach 7 | import org.junit.jupiter.api.BeforeEach 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Test 10 | import org.junit.jupiter.api.extension.ExtendWith 11 | import org.springframework.beans.factory.annotation.Autowired 12 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient 13 | import org.springframework.boot.test.context.SpringBootTest 14 | import org.springframework.test.context.junit.jupiter.SpringExtension 15 | import org.springframework.test.web.reactive.server.WebTestClient 16 | import org.springframework.web.reactive.function.BodyInserters.fromObject 17 | 18 | @ExtendWith(SpringExtension::class) 19 | @SpringBootTest(properties = arrayOf("loadtarget.host=http://localhost:7684")) 20 | @AutoConfigureWebTestClient 21 | class PassThroughMessageHandlerTest { 22 | 23 | @Autowired 24 | private lateinit var webTestClient: WebTestClient 25 | 26 | private var wiremockServer = WireMockServer(WireMockConfiguration.wireMockConfig().port(7684)); 27 | 28 | @BeforeEach 29 | fun before() { 30 | wiremockServer.start() 31 | } 32 | 33 | @AfterEach 34 | fun after() { 35 | wiremockServer.stop() 36 | } 37 | 38 | @Test 39 | @DisplayName("test a passthrough call") 40 | fun testPassThroughCall() { 41 | 42 | wiremockServer.stubFor(post(urlEqualTo("/messages")) 43 | .withHeader("Accept", equalTo("application/json")) 44 | .willReturn(aResponse() 45 | .withStatus(200) 46 | .withHeader("Content-Type", "application/json") 47 | .withBody(""" 48 | | { 49 | | "id": "1", 50 | | "received": "one", 51 | | "ack": "ack" 52 | | } 53 | """.trimMargin()))) 54 | 55 | webTestClient.post() 56 | .uri("/passthrough/messages") 57 | .body(fromObject(Message("1", "one", 0))) 58 | .exchange() 59 | .expectStatus().isOk 60 | .expectBody() 61 | .json(""" 62 | | { 63 | | "id": "1", 64 | | "received": "one", 65 | | "ack": "ack" 66 | | } 67 | """.trimMargin()) 68 | 69 | wiremockServer.verify(postRequestedFor(urlMatching("/messages")) 70 | .withRequestBody(matching(".*one.*")) 71 | .withHeader("Content-Type", matching("application/json"))) 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /applications/load-scripts/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'scala' 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | testCompile 'org.scala-lang:scala-library:2.12.4' 9 | testCompile 'io.gatling:gatling-app:2.3.0' 10 | testCompile 'io.gatling.highcharts:gatling-charts-highcharts:2.3.0' 11 | } 12 | 13 | task gatlingRun(type: JavaExec) { 14 | description = 'Run gatling tests' 15 | new File("${buildDir}/reports/gatling").mkdirs() 16 | 17 | systemProperties System.getProperties() 18 | 19 | classpath = sourceSets.test.runtimeClasspath + configurations.testCompile + configurations.compile 20 | 21 | main = "io.gatling.app.Gatling" 22 | args = ['-s', 'simulations.BootLoadSimulation', 23 | '-sf', 'test/resources', 24 | '-df', 'test/resources', 25 | '-rf', "${buildDir}/reports/gatling" 26 | ] 27 | } -------------------------------------------------------------------------------- /applications/load-scripts/src/test/resources/gatling.conf: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Gatling Configuration # 3 | ######################### 4 | 5 | # This file contains all the settings configurable for Gatling with their default values 6 | 7 | gatling { 8 | core { 9 | #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp) 10 | #runDescription = "" # The description for this simulation run, displayed in each report 11 | #encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation 12 | #simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated) 13 | #mute = false # When set to true, don't ask for simulation name nor run description (currently only used by Gatling SBT plugin) 14 | 15 | extract { 16 | regex { 17 | #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching 18 | } 19 | xpath { 20 | #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching 21 | } 22 | jsonPath { 23 | #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching 24 | #preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations 25 | jackson { 26 | #allowComments = false # Allow comments in JSON files 27 | #allowUnquotedFieldNames = false # Allow unquoted JSON fields names 28 | #allowSingleQuotes = false # Allow single quoted JSON field names 29 | } 30 | 31 | } 32 | css { 33 | #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching 34 | } 35 | } 36 | 37 | timeOut { 38 | #simulation = 8640000 # Absolute timeout, in seconds, of a simulation 39 | } 40 | directory { 41 | #data = user-files/data # Folder where user's data (e.g. files used by Feeders) is located 42 | #bodies = user-files/bodies # Folder where bodies are located 43 | #simulations = user-files/simulations # Folder where the bundle's simulations are located 44 | #reportsOnly = "" # If set, name of report folder to look for in order to generate its report 45 | #binaries = "" # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target. 46 | #results = results # Name of the folder where all reports folder are located 47 | } 48 | } 49 | charting { 50 | #noReports = false # When set to true, don't generate HTML reports 51 | #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports 52 | #accuracy = 10 # Accuracy, in milliseconds, of the report's stats 53 | indicators { 54 | #lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary 55 | #higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary 56 | #percentile1 = 50 # Value for the 1st percentile to track in the reports, the console summary and GraphiteDataWriter 57 | #percentile2 = 75 # Value for the 2nd percentile to track in the reports, the console summary and GraphiteDataWriter 58 | #percentile3 = 95 # Value for the 3rd percentile to track in the reports, the console summary and GraphiteDataWriter 59 | #percentile4 = 99 # Value for the 4th percentile to track in the reports, the console summary and GraphiteDataWriter 60 | } 61 | } 62 | http { 63 | #elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable 64 | #rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable 65 | #fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable 66 | #fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable 67 | #redirectPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent redirects, set to 0 to disable 68 | #expirePerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Expire' headers, set to 0 to disable 69 | #lastModifiedPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Last-Modified' headers, set to 0 to disable 70 | #etagPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent ETag headers, set to 0 to disable 71 | #warmUpUrl = "http://gatling.io" # The URL to use to warm-up the HTTP stack (blank means disabled) 72 | #enableGA = true # Very light Google Analytics, please support 73 | ssl { 74 | trustStore { 75 | #type = "" # Type of SSLContext's TrustManagers store 76 | #file = "" # Location of SSLContext's TrustManagers store 77 | #password = "" # Password for SSLContext's TrustManagers store 78 | #algorithm = "" # Algorithm used by SSLContext's TrustManagers store 79 | } 80 | keyStore { 81 | #type = "" # Type of SSLContext's KeyManagers store 82 | #file = "" # Location of SSLContext's KeyManagers store 83 | #password = "" # Password for SSLContext's KeyManagers store 84 | #algorithm = "" # Algorithm used SSLContext's KeyManagers store 85 | } 86 | } 87 | ahc { 88 | #allowPoolingConnections = true # Allow pooling HTTP connections (keep-alive header automatically added) 89 | #allowPoolingSslConnections = true # Allow pooling HTTPS connections (keep-alive header automatically added) 90 | #compressionEnforced = false # Enforce gzip/deflate when Accept-Encoding header is not defined 91 | #connectTimeout = 60000 # Timeout when establishing a connection 92 | #pooledConnectionIdleTimeout = 60000 # Timeout when a connection stays unused in the pool 93 | #readTimeout = 60000 # Timeout when a used connection stays idle 94 | #connectionTTL = -1 # Max duration a connection can stay open (-1 means no limit) 95 | #ioThreadMultiplier = 2 # Number of Netty worker threads per core 96 | #maxConnectionsPerHost = -1 # Max number of connections per host (-1 means no limit) 97 | #maxConnections = -1 # Max number of connections (-1 means no limit) 98 | #maxRetry = 0 # Number of times that a request should be tried again 99 | #requestTimeout = 60000 # Timeout of the requests 100 | #useProxyProperties = false # When set to true, supports standard Proxy System properties 101 | #webSocketTimeout = 60000 # Timeout when a used websocket connection stays idle 102 | #useRelativeURIsWithConnectProxies = true # When set to true, use relative URIs when talking with an SSL proxy or a WebSocket proxy 103 | #acceptAnyCertificate = true # When set to true, doesn't validate SSL certificates 104 | #httpClientCodecMaxInitialLineLength = 4096 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") 105 | #httpClientCodecMaxHeaderSize = 8192 # Maximum size, in bytes, of each request's headers 106 | #httpClientCodecMaxChunkSize = 8192 # Maximum length of the content or each chunk 107 | #keepEncodingHeader = true # Don't drop Encoding response header after decoding 108 | #webSocketMaxFrameSize = 10240 # Maximum frame payload size 109 | #httpsEnabledProtocols = "" # Comma separated enabled protocols for HTTPS, if empty use the JDK defaults 110 | #httpsEnabledCipherSuites = "" # Comma separated enabled cipher suites for HTTPS, if empty use the JDK defaults 111 | #sslSessionCacheSize = 20000 # SSLSession cache size (set to 0 to disable) 112 | #sslSessionTimeout = 86400 # SSLSession timeout (default is 24, like Hotspot) 113 | } 114 | } 115 | data { 116 | #writers = "console, file" # The lists of DataWriters to which Gatling write simulation data (currently supported : "console", "file", "graphite", "jdbc") 117 | #reader = file # The DataReader used by the charting engine for reading simulation results 118 | console { 119 | #light = false # When set to true, displays a light version without detailed request stats 120 | } 121 | file { 122 | #bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes 123 | } 124 | leak { 125 | #noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening 126 | } 127 | jdbc { 128 | db { 129 | #url = "jdbc:mysql://localhost:3306/temp" # The JDBC URL used by the JDBC DataWriter 130 | #username = "root" # The database user used by the JDBC DataWriter 131 | #password = "123123q" # The password for the specified user 132 | } 133 | #bufferSize = 20 # The size for each batch of SQL inserts to send to the database 134 | create { 135 | #createRunRecordTable = "CREATE TABLE IF NOT EXISTS `RunRecords` ( `id` INT NOT NULL AUTO_INCREMENT , `runDate` DATETIME NULL , `simulationId` VARCHAR(45) NULL , `runDescription` VARCHAR(45) NULL , PRIMARY KEY (`id`) )" 136 | #createRequestRecordTable = "CREATE TABLE IF NOT EXISTS `RequestRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenario` varchar(45) DEFAULT NULL, `userId` VARCHAR(30) NULL, `name` varchar(50) DEFAULT NULL, `requestStartDate` bigint DEFAULT NULL, `requestEndDate` bigint DEFAULT NULL, `responseStartDate` bigint DEFAULT NULL, `responseEndDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, `message` varchar(4500) DEFAULT NULL, `responseTime` bigint DEFAULT NULL, PRIMARY KEY (`id`) )" 137 | #createScenarioRecordTable = "CREATE TABLE IF NOT EXISTS `ScenarioRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(30) NULL, `event` varchar(50) DEFAULT NULL, `startDate` bigint DEFAULT NULL, `endDate` bigint DEFAULT NULL, PRIMARY KEY (`id`) )" 138 | #createGroupRecordTable = "CREATE TABLE IF NOT EXISTS `GroupRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(30) NULL, `entryDate` bigint DEFAULT NULL, `exitDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, PRIMARY KEY (`id`) )" 139 | } 140 | insert { 141 | #insertRunRecord = "INSERT INTO RunRecords (runDate, simulationId, runDescription) VALUES (?,?,?)" 142 | #insertRequestRecord = "INSERT INTO RequestRecords (runId, scenario, userId, name, requestStartDate, requestEndDate, responseStartDate, responseEndDate, status, message, responseTime) VALUES (?,?,?,?,?,?,?,?,?,?,?)" 143 | #insertScenarioRecord = "INSERT INTO ScenarioRecords (runId, scenarioName, userId, event, startDate, endDate) VALUES (?,?,?,?,?,?)" 144 | #insertGroupRecord = "INSERT INTO GroupRecords (runId, scenarioName, userId, entryDate, exitDate, status) VALUES (?,?,?,?,?,?)" 145 | } 146 | } 147 | graphite { 148 | #light = false # only send the all* stats 149 | #host = "localhost" # The host where the Carbon server is located 150 | #port = 2003 # The port to which the Carbon server listens to 151 | #protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp") 152 | #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite 153 | #bufferSize = 8192 # GraphiteDataWriter's internal data buffer size, in bytes 154 | #writeInterval = 1 # GraphiteDataWriter's write interval, in seconds 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /applications/load-scripts/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /applications/load-scripts/src/test/resources/recorder.conf: -------------------------------------------------------------------------------- 1 | recorder { 2 | core { 3 | #encoding = "utf-8" # The encoding used for reading/writing request bodies and the generated simulation 4 | #outputFolder = "" # The folder where generated simulation will we written 5 | #package = "" # The package's name of the generated simulation 6 | #className = "RecordedSimulation" # The name of the generated Simulation class 7 | #thresholdForPauseCreation = 100 # The minimum time, in milliseconds, that must pass between requests to trigger a pause creation 8 | #saveConfig = false # When set to true, the configuration from the Recorder GUI overwrites this configuration 9 | } 10 | filters { 11 | #filterStrategy = "Disabled" # The selected filter resources filter strategy (currently supported : "Disabled", "BlackList", "WhiteList") 12 | #whitelist = [] # The list of ressources patterns that are part of the Recorder's whitelist 13 | #blacklist = [] # The list of ressources patterns that are part of the Recorder's blacklist 14 | } 15 | http { 16 | #automaticReferer = true # When set to false, write the referer + enable 'disableAutoReferer' in the generated simulation 17 | #followRedirect = true # When set to false, write redirect requests + enable 'disableFollowRedirect' in the generated simulation 18 | #removeConditionalCache = true # When set to true, removes from the generated requests headers leading to request caching 19 | #inferHtmlResources = true # When set to true, add inferred resources + set 'inferHtmlResources' with the configured blacklist/whitelist in the generated simulation 20 | } 21 | proxy { 22 | #port = 8000 # Local port used by Gatling's Proxy for HTTP/HTTPS 23 | outgoing { 24 | #host = "" # The outgoing proxy's hostname 25 | #username = "" # The username to use to connect to the outgoing proxy 26 | #password = "" # The password corresponding to the user to use to connect to the outgoing proxy 27 | #port = 0 # The HTTP port to use to connect to the outgoing proxy 28 | #sslPort = 0 # If set, The HTTPS port to use to connect to the outgoing proxy 29 | } 30 | } 31 | netty { 32 | #maxInitialLineLength = 10000 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") 33 | #maxHeaderSize = 20000 # Maximum size, in bytes, of each request's headers 34 | #maxChunkSize = 8192 # Maximum length of the content or each chunk 35 | #maxContentLength = 100000000 # Maximum length of the aggregated content of each response 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /applications/load-scripts/src/test/scala/simulations/BootLoadSimulation.scala: -------------------------------------------------------------------------------- 1 | package simulations 2 | 3 | import java.util.UUID 4 | 5 | import io.gatling.core.Predef._ 6 | import io.gatling.http.Predef._ 7 | 8 | import scala.concurrent.duration._ 9 | 10 | class BootLoadSimulation extends Simulation { 11 | 12 | val baseUrl = System.getProperty("TARGET_URL") 13 | val sim_users = System.getProperty("SIM_USERS").toInt 14 | 15 | val httpConf = http.baseURL(baseUrl) 16 | 17 | val headers = Map("Accept" -> """application/json""") 18 | 19 | val passThroughPage = repeat(30) { 20 | exec(http("passthrough-messages") 21 | .post("/passthrough/messages") 22 | .header("Content-Type", "application/json" ) 23 | .body(StringBody( 24 | s""" 25 | | { 26 | | "id": "${UUID.randomUUID().toString}", 27 | | "payload": "test payload", 28 | | "delay": 300 29 | | } 30 | """.stripMargin))) 31 | .pause(1 second, 2 seconds) 32 | } 33 | 34 | val scn = scenario("Passthrough Page") 35 | .exec(passThroughPage) 36 | 37 | setUp(scn.inject(rampUsers(sim_users).over(30 seconds)).protocols(httpConf)) 38 | } 39 | -------------------------------------------------------------------------------- /applications/sample-load-target/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | kotlinVersion = '1.2.41' 4 | springBootVersion = '2.0.2.RELEASE' 5 | } 6 | repositories { 7 | mavenCentral() 8 | maven { url "https://repo.spring.io/snapshot" } 9 | maven { url "https://repo.spring.io/milestone" } 10 | } 11 | dependencies { 12 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 13 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") 14 | classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") 15 | } 16 | } 17 | 18 | apply plugin: 'kotlin' 19 | apply plugin: 'kotlin-spring' 20 | apply plugin: 'java' 21 | apply plugin: 'org.springframework.boot' 22 | apply plugin: 'io.spring.dependency-management' 23 | 24 | group = 'org.bk.samples' 25 | version = '0.0.1-SNAPSHOT' 26 | sourceCompatibility = 1.8 27 | 28 | repositories { 29 | mavenCentral() 30 | maven { url "https://repo.spring.io/snapshot" } 31 | maven { url "https://repo.spring.io/milestone" } 32 | } 33 | 34 | compileKotlin { 35 | kotlinOptions { 36 | freeCompilerArgs = ["-Xjsr305=strict"] 37 | jvmTarget = "1.8" 38 | } 39 | } 40 | compileTestKotlin { 41 | kotlinOptions { 42 | freeCompilerArgs = ["-Xjsr305=strict"] 43 | jvmTarget = "1.8" 44 | } 45 | } 46 | 47 | dependencies { 48 | compile('org.springframework.boot:spring-boot-starter-actuator') 49 | compile('org.springframework.boot:spring-boot-starter-webflux') 50 | compile("com.fasterxml.jackson.module:jackson-module-kotlin") 51 | compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}") 52 | compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") 53 | runtime("io.micrometer:micrometer-registry-prometheus") 54 | testCompile('org.springframework.boot:spring-boot-starter-test') 55 | testCompile('io.projectreactor:reactor-test') 56 | } 57 | -------------------------------------------------------------------------------- /applications/sample-load-target/src/main/kotlin/sample/load/LoadTargetApplication.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import io.micrometer.core.instrument.MeterRegistry 4 | import org.springframework.boot.SpringApplication 5 | import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer 6 | import org.springframework.boot.autoconfigure.SpringBootApplication 7 | import org.springframework.context.annotation.Bean 8 | 9 | @SpringBootApplication 10 | class SampleLoadApplication { 11 | 12 | @Bean 13 | fun commonTags(): MeterRegistryCustomizer { 14 | return MeterRegistryCustomizer { registry -> 15 | registry.config() 16 | .commonTags("application", "sample-load-target") 17 | } 18 | } 19 | 20 | } 21 | 22 | fun main(args: Array) { 23 | SpringApplication.run(SampleLoadApplication::class.java, *args) 24 | } -------------------------------------------------------------------------------- /applications/sample-load-target/src/main/kotlin/sample/load/Message.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | data class Message(val id: String, val payload: String, val delay: Long) -------------------------------------------------------------------------------- /applications/sample-load-target/src/main/kotlin/sample/load/MessageAck.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | data class MessageAck(val id: String, val received: String, val ack: String) -------------------------------------------------------------------------------- /applications/sample-load-target/src/main/kotlin/sample/load/MessageHandler.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import io.micrometer.core.instrument.Metrics 4 | import org.springframework.http.HttpStatus 5 | import org.springframework.stereotype.Service 6 | import org.springframework.web.reactive.function.BodyInserters.fromObject 7 | import org.springframework.web.reactive.function.server.ServerRequest 8 | import org.springframework.web.reactive.function.server.ServerResponse 9 | import org.springframework.web.reactive.function.server.bodyToMono 10 | import reactor.core.publisher.Mono 11 | import java.time.Duration 12 | 13 | @Service 14 | class MessageHandler { 15 | 16 | private val counter = Metrics.counter("handler.calls", "uri", "/messages") 17 | 18 | fun handleMessage(req: ServerRequest): Mono { 19 | return req.bodyToMono().flatMap { m -> 20 | counter.increment() 21 | Mono 22 | .fromCallable({ MessageAck(id = m.id, received = m.payload, ack = "ack") }) 23 | .delayElement(Duration.ofMillis(m.delay)) 24 | .flatMap { messageAck -> 25 | ServerResponse 26 | .status(HttpStatus.OK) 27 | .body(fromObject(messageAck)) 28 | } 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /applications/sample-load-target/src/main/kotlin/sample/load/config/RoutesConfig.kt: -------------------------------------------------------------------------------- 1 | package sample.load.config 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import org.springframework.http.MediaType 6 | import org.springframework.web.reactive.function.server.router 7 | import sample.load.MessageHandler 8 | 9 | 10 | @Configuration 11 | class RoutesConfig { 12 | 13 | @Bean 14 | fun apis(messageHandler: MessageHandler) = router { 15 | (accept(MediaType.APPLICATION_JSON) and "/messages").nest { 16 | POST("/", messageHandler::handleMessage) 17 | } 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /applications/sample-load-target/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | --- 2 | server: 3 | port: 8080 4 | 5 | logging: 6 | level: 7 | root: info 8 | 9 | management: 10 | endpoints: 11 | web: 12 | exposure: 13 | include: "*" 14 | metrics: 15 | distribution: 16 | percentiles-histogram[http.server.requests]: true 17 | sla: 18 | http: 19 | server: 20 | requests: 1ms, 5ms -------------------------------------------------------------------------------- /applications/sample-load-target/src/test/kotlin/sample/load/web/MessageHandlerControllerTest.kt: -------------------------------------------------------------------------------- 1 | package sample.load.web 2 | 3 | import org.junit.Test 4 | import org.junit.runner.RunWith 5 | import org.springframework.beans.factory.annotation.Autowired 6 | import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest 7 | import org.springframework.test.context.junit4.SpringRunner 8 | import org.springframework.test.web.reactive.server.WebTestClient 9 | import org.springframework.web.reactive.function.BodyInserters.fromObject 10 | import sample.load.Message 11 | import sample.load.MessageHandler 12 | import sample.load.config.RoutesConfig 13 | 14 | @RunWith(SpringRunner::class) 15 | @WebFluxTest(controllers = arrayOf(RoutesConfig::class, MessageHandler::class)) 16 | class MessageHandlerControllerTest { 17 | 18 | @Autowired 19 | private lateinit var webTestClient: WebTestClient 20 | 21 | @Test 22 | fun testCallToMessageEndpoint() { 23 | webTestClient.post().uri("/messages") 24 | .body(fromObject(Message("1", "one", 0))) 25 | .exchange() 26 | .expectStatus().isOk 27 | .expectBody() 28 | .json(""" 29 | | { 30 | | "id": "1", 31 | | "received": "one", 32 | | "ack": "ack" 33 | | } 34 | """.trimMargin()) 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /applications/spring-cloud-gateway-sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | kotlinVersion = '1.2.41' 4 | springBootVersion = '2.0.2.RELEASE' 5 | springCloudVersion = 'Finchley.BUILD-SNAPSHOT' 6 | wireMockVersion = "2.8.0" 7 | } 8 | repositories { 9 | mavenCentral() 10 | maven { url "https://repo.spring.io/snapshot" } 11 | maven { url "https://repo.spring.io/milestone" } 12 | } 13 | dependencies { 14 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 15 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") 16 | classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") 17 | } 18 | } 19 | 20 | apply plugin: 'kotlin' 21 | apply plugin: 'kotlin-spring' 22 | apply plugin: 'java' 23 | apply plugin: 'org.springframework.boot' 24 | apply plugin: 'io.spring.dependency-management' 25 | 26 | group = 'org.bk.samples' 27 | version = '0.0.1-SNAPSHOT' 28 | sourceCompatibility = 1.8 29 | 30 | dependencyManagement { 31 | imports { 32 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion" 33 | } 34 | } 35 | 36 | repositories { 37 | jcenter() 38 | mavenCentral() 39 | maven { url "https://repo.spring.io/snapshot" } 40 | maven { url "https://repo.spring.io/milestone" } 41 | } 42 | 43 | compileKotlin { 44 | kotlinOptions { 45 | freeCompilerArgs = ["-Xjsr305=strict"] 46 | jvmTarget = "1.8" 47 | } 48 | } 49 | compileTestKotlin { 50 | kotlinOptions { 51 | freeCompilerArgs = ["-Xjsr305=strict"] 52 | jvmTarget = "1.8" 53 | } 54 | } 55 | 56 | dependencies { 57 | compile("org.springframework.cloud:spring-cloud-starter-gateway") 58 | compile('org.springframework.boot:spring-boot-starter-actuator') 59 | compile('org.springframework.boot:spring-boot-starter-webflux') 60 | compile("com.fasterxml.jackson.module:jackson-module-kotlin") 61 | compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}") 62 | compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") 63 | compile("io.micrometer:micrometer-registry-prometheus") 64 | testCompile('org.springframework.boot:spring-boot-starter-test') 65 | testCompile('io.projectreactor:reactor-test') 66 | testCompile("com.github.tomakehurst:wiremock-standalone:${wireMockVersion}") 67 | } 68 | -------------------------------------------------------------------------------- /applications/spring-cloud-gateway-sample/src/main/kotlin/sample/load/Application.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import io.micrometer.core.instrument.MeterRegistry 4 | import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer 5 | import org.springframework.boot.autoconfigure.SpringBootApplication 6 | import org.springframework.boot.runApplication 7 | import org.springframework.context.annotation.Bean 8 | 9 | 10 | @SpringBootApplication 11 | class Application { 12 | @Bean 13 | fun commonTags(): MeterRegistryCustomizer { 14 | return MeterRegistryCustomizer { registry -> 15 | registry.config() 16 | .commonTags("application", "spring-cloud-gateway-sample") 17 | } 18 | } 19 | } 20 | 21 | fun main(args: Array) { 22 | runApplication(*args) 23 | } -------------------------------------------------------------------------------- /applications/spring-cloud-gateway-sample/src/main/kotlin/sample/load/GatewayConfiguration.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import org.springframework.beans.factory.annotation.Value 4 | import org.springframework.cloud.gateway.route.RouteLocator 5 | import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder 6 | import org.springframework.cloud.gateway.route.builder.filters 7 | import org.springframework.cloud.gateway.route.builder.routes 8 | import org.springframework.context.annotation.Bean 9 | import org.springframework.context.annotation.Configuration 10 | 11 | @Configuration 12 | class GatewayConfiguration { 13 | @Value("\${loadtarget.host}") 14 | lateinit var targetHost: String 15 | 16 | @Bean 17 | fun routes(routeLocatorBuilder: RouteLocatorBuilder): RouteLocator = 18 | routeLocatorBuilder.routes() { 19 | route(id = "passthrough", uri = targetHost) { 20 | path("/passthrough/{segment}") 21 | 22 | filters { 23 | setPath("/{segment}") 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /applications/spring-cloud-gateway-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | loadtarget: 2 | host: http://localhost:8080 3 | 4 | server: 5 | port: 8083 6 | 7 | 8 | management: 9 | endpoints: 10 | web: 11 | exposure: 12 | include: "*" 13 | metrics: 14 | distribution: 15 | percentiles-histogram[http.server.requests]: true 16 | sla: 17 | http: 18 | server: 19 | requests: 1ms, 5ms 20 | 21 | logging: 22 | level: 23 | org.springframework.cloud.gateway: error 24 | org.springframework.http.server.reactive: error 25 | org.springframework.web.reactive: error 26 | reactor.ipc.netty: error 27 | 28 | 29 | -------------------------------------------------------------------------------- /applications/spring-cloud-gateway-sample/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /applications/spring-cloud-gateway-sample/src/test/kotlin/sample/load/PassThroughMessageHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package sample.load 2 | 3 | import com.github.tomakehurst.wiremock.client.WireMock.* 4 | import com.github.tomakehurst.wiremock.junit.WireMockRule 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.junit.Rule 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | import org.springframework.boot.test.context.SpringBootTest 10 | import org.springframework.boot.web.server.LocalServerPort 11 | import org.springframework.http.HttpStatus 12 | import org.springframework.test.context.junit4.SpringRunner 13 | import org.springframework.web.reactive.function.BodyInserters 14 | import org.springframework.web.reactive.function.client.ClientResponse 15 | import org.springframework.web.reactive.function.client.WebClient 16 | import reactor.test.StepVerifier 17 | import java.time.Duration 18 | 19 | @RunWith(SpringRunner::class) 20 | @SpringBootTest(properties = arrayOf("loadtarget.host=http://localhost:7684"), 21 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 22 | class PassThroughMessageHandlerTest { 23 | 24 | 25 | @Rule 26 | @JvmField 27 | final val wireMockRule = WireMockRule(7684) 28 | 29 | 30 | @LocalServerPort 31 | private var port: Int = 0 32 | 33 | @Test 34 | fun testPassThroughCall() { 35 | stubFor(post(urlEqualTo("/messages")) 36 | .withHeader("Accept", equalTo("application/json")) 37 | .willReturn(aResponse() 38 | .withStatus(200) 39 | .withHeader("Content-Type", "application/json") 40 | .withBody(""" 41 | | { 42 | | "id": "1", 43 | | "received": "one", 44 | | "ack": "ack" 45 | | } 46 | """.trimMargin()))) 47 | 48 | val webClient = WebClient.create("http://localhost:${port}") 49 | 50 | val clientResponse = webClient.post() 51 | .uri("/passthrough/messages") 52 | .header("Content-Type", "application/json") 53 | .header("Accept", "application/json") 54 | .body(BodyInserters.fromObject(""" 55 | | { 56 | | "id": "1", 57 | | "payload": "one", 58 | | "delay": 100 59 | | } 60 | """.trimMargin())) 61 | .exchange() 62 | 63 | StepVerifier.create(clientResponse) 64 | .consumeNextWith { response -> assertThat(response.statusCode()).isEqualTo(HttpStatus.OK) } 65 | .expectComplete() 66 | .verify(Duration.ofSeconds(3)) 67 | 68 | verify(postRequestedFor(urlMatching("/messages")) 69 | .withRequestBody(matching(".*one.*")) 70 | .withHeader("Content-Type", matching("application/json"))) 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /applications/zuul-sample/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | nbproject/private/ 22 | build/ 23 | nbbuild/ 24 | dist/ 25 | nbdist/ 26 | .nb-gradle/ -------------------------------------------------------------------------------- /applications/zuul-sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.0.RELEASE' 4 | wireMockVersion = "2.8.0" 5 | } 6 | repositories { 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 11 | } 12 | } 13 | 14 | apply plugin: 'java' 15 | apply plugin: 'eclipse' 16 | apply plugin: 'org.springframework.boot' 17 | apply plugin: 'io.spring.dependency-management' 18 | 19 | group = 'org.bk.samples' 20 | version = '0.0.1-SNAPSHOT' 21 | sourceCompatibility = 1.8 22 | 23 | repositories { 24 | mavenCentral() 25 | maven { url "https://repo.spring.io/milestone" } 26 | } 27 | 28 | 29 | ext { 30 | springCloudVersion = 'Finchley.M9' 31 | } 32 | 33 | dependencies { 34 | compile('org.springframework.cloud:spring-cloud-starter-netflix-zuul') 35 | testCompile('org.springframework.boot:spring-boot-starter-test') 36 | testCompile("com.github.tomakehurst:wiremock-standalone:${wireMockVersion}") 37 | 38 | compile('org.springframework.boot:spring-boot-starter-actuator') 39 | runtime('io.micrometer:micrometer-registry-prometheus') 40 | } 41 | 42 | dependencyManagement { 43 | imports { 44 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /applications/zuul-sample/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/boot2-load-demo/d998ee0725253c224131fd0eaf1843efacb7ac8b/applications/zuul-sample/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /applications/zuul-sample/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Feb 06 12:27:20 CET 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip 7 | -------------------------------------------------------------------------------- /applications/zuul-sample/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /applications/zuul-sample/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /applications/zuul-sample/src/main/java/sample/zuul/ZuulSampleApplication.java: -------------------------------------------------------------------------------- 1 | package sample.zuul; 2 | 3 | import io.micrometer.core.instrument.MeterRegistry; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | @EnableZuulProxy 12 | public class ZuulSampleApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ZuulSampleApplication.class, args); 16 | } 17 | 18 | @Bean 19 | public MeterRegistryCustomizer commonTags() { 20 | return registry -> 21 | registry.config() 22 | .commonTags("application", "zuul-sample"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /applications/zuul-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | zuul: 2 | routes: 3 | first: 4 | path: /passthrough/** 5 | url: http://localhost:8080 6 | strip-prefix: true 7 | 8 | 9 | server: 10 | port: 8084 11 | 12 | 13 | management: 14 | endpoints: 15 | web: 16 | exposure: 17 | include: "*" 18 | metrics: 19 | distribution: 20 | percentiles-histogram[http.server.requests]: true 21 | sla: 22 | http: 23 | server: 24 | requests: 1ms, 5ms -------------------------------------------------------------------------------- /applications/zuul-sample/src/test/java/sample/zuul/PassThroughMessagesTest.java: -------------------------------------------------------------------------------- 1 | package sample.zuul; 2 | 3 | 4 | import com.github.tomakehurst.wiremock.client.WireMock; 5 | import com.github.tomakehurst.wiremock.junit.WireMockRule; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | import org.springframework.test.web.servlet.MockMvc; 15 | 16 | import static com.github.tomakehurst.wiremock.client.WireMock.*; 17 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 18 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 20 | 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(properties = "zuul.routes.first.url=http://localhost:8989") 23 | @AutoConfigureMockMvc 24 | public class PassThroughMessagesTest { 25 | 26 | @Autowired 27 | private MockMvc mockMvc; 28 | 29 | @Rule 30 | public WireMockRule wireMockRule = new WireMockRule(8989); 31 | 32 | @Test 33 | public void testPassthroughCall() throws Exception { 34 | 35 | stubFor(WireMock.post(urlEqualTo("/messages")) 36 | .willReturn(aResponse() 37 | .withStatus(200) 38 | .withHeader("Content-Type", "application/json") 39 | .withBody("{\n" + 40 | " \"id\": \"1\",\n" + 41 | " \"received\": \"sample payload\",\n" + 42 | " \"ack\": \"ack\"\n" + 43 | "}\n"))); 44 | 45 | mockMvc.perform( 46 | post("/passthrough/messages") 47 | .contentType(MediaType.APPLICATION_JSON) 48 | .content("{\n" + 49 | " \"id\": \"1\",\n" + 50 | " \"payload\": \"sample payload\",\n" + 51 | " \"delay\": 0\n" + 52 | "}\n")) 53 | .andExpect(status().is2xxSuccessful()) 54 | .andExpect(content().json("{\n" + 55 | " \"id\": \"1\",\n" + 56 | " \"received\": \"sample payload\",\n" + 57 | " \"ack\": \"ack\"\n" + 58 | "}")); 59 | 60 | verify( 61 | postRequestedFor(urlMatching("/messages")) 62 | .withRequestBody(matching(".*sample.*")) 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /applications/zuul2-sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | zuulVersion = "2.1.2" 4 | } 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' 10 | } 11 | } 12 | 13 | apply plugin: "java" 14 | apply plugin: 'application' 15 | apply plugin: 'com.github.johnrengelman.shadow' 16 | 17 | dependencies { 18 | compile("com.netflix.zuul:zuul-core:$zuulVersion") 19 | testCompile("junit:junit:4.12") 20 | testCompile("org.assertj:assertj-core:3.9.1") 21 | compile 'com.netflix.blitz4j:blitz4j:1.37.2' 22 | } 23 | 24 | mainClassName = "com.netflix.zuul.sample.Bootstrap" 25 | 26 | applicationDefaultJvmArgs = ["-DTZ=GMT", 27 | "-Dcom.sun.management.jmxremote", 28 | "-Dcom.sun.management.jmxremote.local.only=false", 29 | "-Deureka.validateInstanceId=false", 30 | "-Deureka.mt.num_retries=1"] 31 | 32 | 33 | repositories { 34 | jcenter() 35 | mavenCentral() 36 | } -------------------------------------------------------------------------------- /applications/zuul2-sample/dependencies.lock: -------------------------------------------------------------------------------- 1 | { 2 | "compile": { 3 | "com.google.inject.extensions:guice-assistedinject": { 4 | "firstLevelTransitive": [ 5 | "com.netflix.zuul:zuul-core" 6 | ], 7 | "locked": "4.1.0", 8 | "requested": "4.0" 9 | }, 10 | "com.google.inject.extensions:guice-grapher": { 11 | "firstLevelTransitive": [ 12 | "com.netflix.zuul:zuul-core" 13 | ], 14 | "locked": "4.1.0", 15 | "requested": "4.0" 16 | }, 17 | "com.google.inject.extensions:guice-multibindings": { 18 | "firstLevelTransitive": [ 19 | "com.netflix.zuul:zuul-core" 20 | ], 21 | "locked": "4.1.0", 22 | "requested": "4.0" 23 | }, 24 | "com.google.inject.extensions:guice-servlet": { 25 | "firstLevelTransitive": [ 26 | "com.netflix.zuul:zuul-core" 27 | ], 28 | "locked": "4.0", 29 | "requested": "4.0" 30 | }, 31 | "com.google.inject.extensions:guice-throwingproviders": { 32 | "firstLevelTransitive": [ 33 | "com.netflix.zuul:zuul-core" 34 | ], 35 | "locked": "4.0", 36 | "requested": "4.0" 37 | }, 38 | "com.google.inject:guice": { 39 | "firstLevelTransitive": [ 40 | "com.netflix.zuul:zuul-core" 41 | ], 42 | "locked": "4.1.0", 43 | "requested": "4.0" 44 | }, 45 | "com.netflix.archaius:archaius-core": { 46 | "firstLevelTransitive": [ 47 | "com.netflix.zuul:zuul-core" 48 | ], 49 | "locked": "0.7.5" 50 | }, 51 | "com.netflix.astyanax:astyanax-cassandra": { 52 | "firstLevelTransitive": [ 53 | "com.netflix.zuul:zuul-core" 54 | ], 55 | "locked": "1.56.48" 56 | }, 57 | "com.netflix.astyanax:astyanax-thrift": { 58 | "firstLevelTransitive": [ 59 | "com.netflix.zuul:zuul-core" 60 | ], 61 | "locked": "1.56.48" 62 | }, 63 | "com.netflix.blitz4j:blitz4j": { 64 | "locked": "1.37.2", 65 | "requested": "1.37.2" 66 | }, 67 | "com.netflix.eureka:eureka-client": { 68 | "firstLevelTransitive": [ 69 | "com.netflix.zuul:zuul-core" 70 | ], 71 | "locked": "1.8.6" 72 | }, 73 | "com.netflix.governator:governator": { 74 | "firstLevelTransitive": [ 75 | "com.netflix.zuul:zuul-core" 76 | ], 77 | "locked": "1.17.4" 78 | }, 79 | "com.netflix.governator:governator-archaius": { 80 | "firstLevelTransitive": [ 81 | "com.netflix.zuul:zuul-core" 82 | ], 83 | "locked": "1.17.4" 84 | }, 85 | "com.netflix.hystrix:hystrix-core": { 86 | "firstLevelTransitive": [ 87 | "com.netflix.zuul:zuul-core" 88 | ], 89 | "locked": "1.4.26" 90 | }, 91 | "com.netflix.netflix-commons:netflix-commons-util": { 92 | "firstLevelTransitive": [ 93 | "com.netflix.zuul:zuul-core" 94 | ], 95 | "locked": "0.3.0" 96 | }, 97 | "com.netflix.ribbon:ribbon-core": { 98 | "firstLevelTransitive": [ 99 | "com.netflix.zuul:zuul-core" 100 | ], 101 | "locked": "2.2.4" 102 | }, 103 | "com.netflix.ribbon:ribbon-eureka": { 104 | "firstLevelTransitive": [ 105 | "com.netflix.zuul:zuul-core" 106 | ], 107 | "locked": "2.2.4" 108 | }, 109 | "com.netflix.ribbon:ribbon-httpclient": { 110 | "firstLevelTransitive": [ 111 | "com.netflix.zuul:zuul-core" 112 | ], 113 | "locked": "2.2.4" 114 | }, 115 | "com.netflix.ribbon:ribbon-loadbalancer": { 116 | "firstLevelTransitive": [ 117 | "com.netflix.zuul:zuul-core" 118 | ], 119 | "locked": "2.2.4" 120 | }, 121 | "com.netflix.servo:servo-core": { 122 | "firstLevelTransitive": [ 123 | "com.netflix.zuul:zuul-core" 124 | ], 125 | "locked": "0.10.1" 126 | }, 127 | "com.netflix.spectator:spectator-api": { 128 | "firstLevelTransitive": [ 129 | "com.netflix.zuul:zuul-core" 130 | ], 131 | "locked": "0.59.0" 132 | }, 133 | "com.netflix.zuul:zuul-core": { 134 | "project": true 135 | }, 136 | "commons-fileupload:commons-fileupload": { 137 | "firstLevelTransitive": [ 138 | "com.netflix.zuul:zuul-core" 139 | ], 140 | "locked": "1.3" 141 | }, 142 | "commons-io:commons-io": { 143 | "firstLevelTransitive": [ 144 | "com.netflix.zuul:zuul-core" 145 | ], 146 | "locked": "2.4" 147 | }, 148 | "io.netty:netty-buffer": { 149 | "firstLevelTransitive": [ 150 | "com.netflix.zuul:zuul-core" 151 | ], 152 | "locked": "4.1.21.Final" 153 | }, 154 | "io.netty:netty-codec-haproxy": { 155 | "firstLevelTransitive": [ 156 | "com.netflix.zuul:zuul-core" 157 | ], 158 | "locked": "4.1.21.Final" 159 | }, 160 | "io.netty:netty-codec-http": { 161 | "firstLevelTransitive": [ 162 | "com.netflix.zuul:zuul-core" 163 | ], 164 | "locked": "4.1.21.Final" 165 | }, 166 | "io.netty:netty-codec-http2": { 167 | "firstLevelTransitive": [ 168 | "com.netflix.zuul:zuul-core" 169 | ], 170 | "locked": "4.1.21.Final" 171 | }, 172 | "io.netty:netty-common": { 173 | "firstLevelTransitive": [ 174 | "com.netflix.zuul:zuul-core" 175 | ], 176 | "locked": "4.1.21.Final" 177 | }, 178 | "io.netty:netty-handler": { 179 | "firstLevelTransitive": [ 180 | "com.netflix.zuul:zuul-core" 181 | ], 182 | "locked": "4.1.21.Final" 183 | }, 184 | "io.netty:netty-resolver": { 185 | "firstLevelTransitive": [ 186 | "com.netflix.zuul:zuul-core" 187 | ], 188 | "locked": "4.1.21.Final" 189 | }, 190 | "io.netty:netty-tcnative-boringssl-static": { 191 | "firstLevelTransitive": [ 192 | "com.netflix.zuul:zuul-core" 193 | ], 194 | "locked": "2.0.7.Final" 195 | }, 196 | "io.netty:netty-transport": { 197 | "firstLevelTransitive": [ 198 | "com.netflix.zuul:zuul-core" 199 | ], 200 | "locked": "4.1.21.Final" 201 | }, 202 | "io.netty:netty-transport-native-epoll": { 203 | "firstLevelTransitive": [ 204 | "com.netflix.zuul:zuul-core" 205 | ], 206 | "locked": "4.1.21.Final" 207 | }, 208 | "io.reactivex:rxjava": { 209 | "firstLevelTransitive": [ 210 | "com.netflix.zuul:zuul-core" 211 | ], 212 | "locked": "1.2.1" 213 | }, 214 | "junit:junit": { 215 | "firstLevelTransitive": [ 216 | "com.netflix.zuul:zuul-core" 217 | ], 218 | "locked": "4.12" 219 | }, 220 | "org.apache.commons:commons-lang3": { 221 | "firstLevelTransitive": [ 222 | "com.netflix.zuul:zuul-core" 223 | ], 224 | "locked": "3.4" 225 | }, 226 | "org.bouncycastle:bcpg-jdk15on": { 227 | "firstLevelTransitive": [ 228 | "com.netflix.zuul:zuul-core" 229 | ], 230 | "locked": "1.59" 231 | }, 232 | "org.bouncycastle:bcprov-jdk15on": { 233 | "firstLevelTransitive": [ 234 | "com.netflix.zuul:zuul-core" 235 | ], 236 | "locked": "1.59" 237 | }, 238 | "org.codehaus.groovy:groovy-all": { 239 | "firstLevelTransitive": [ 240 | "com.netflix.zuul:zuul-core" 241 | ], 242 | "locked": "2.4.4" 243 | }, 244 | "org.json:json": { 245 | "firstLevelTransitive": [ 246 | "com.netflix.zuul:zuul-core" 247 | ], 248 | "locked": "20090211" 249 | }, 250 | "org.mockito:mockito-core": { 251 | "firstLevelTransitive": [ 252 | "com.netflix.zuul:zuul-core" 253 | ], 254 | "locked": "1.9.5" 255 | }, 256 | "org.slf4j:slf4j-api": { 257 | "firstLevelTransitive": [ 258 | "com.netflix.zuul:zuul-core" 259 | ], 260 | "locked": "1.7.25" 261 | } 262 | }, 263 | "compileClasspath": { 264 | "com.google.inject.extensions:guice-assistedinject": { 265 | "firstLevelTransitive": [ 266 | "com.netflix.zuul:zuul-core" 267 | ], 268 | "locked": "4.1.0", 269 | "requested": "4.0" 270 | }, 271 | "com.google.inject.extensions:guice-grapher": { 272 | "firstLevelTransitive": [ 273 | "com.netflix.zuul:zuul-core" 274 | ], 275 | "locked": "4.1.0", 276 | "requested": "4.0" 277 | }, 278 | "com.google.inject.extensions:guice-multibindings": { 279 | "firstLevelTransitive": [ 280 | "com.netflix.zuul:zuul-core" 281 | ], 282 | "locked": "4.1.0", 283 | "requested": "4.0" 284 | }, 285 | "com.google.inject.extensions:guice-servlet": { 286 | "firstLevelTransitive": [ 287 | "com.netflix.zuul:zuul-core" 288 | ], 289 | "locked": "4.0", 290 | "requested": "4.0" 291 | }, 292 | "com.google.inject.extensions:guice-throwingproviders": { 293 | "firstLevelTransitive": [ 294 | "com.netflix.zuul:zuul-core" 295 | ], 296 | "locked": "4.0", 297 | "requested": "4.0" 298 | }, 299 | "com.google.inject:guice": { 300 | "firstLevelTransitive": [ 301 | "com.netflix.zuul:zuul-core" 302 | ], 303 | "locked": "4.1.0", 304 | "requested": "4.0" 305 | }, 306 | "com.netflix.archaius:archaius-core": { 307 | "firstLevelTransitive": [ 308 | "com.netflix.zuul:zuul-core" 309 | ], 310 | "locked": "0.7.5" 311 | }, 312 | "com.netflix.astyanax:astyanax-cassandra": { 313 | "firstLevelTransitive": [ 314 | "com.netflix.zuul:zuul-core" 315 | ], 316 | "locked": "1.56.48" 317 | }, 318 | "com.netflix.astyanax:astyanax-thrift": { 319 | "firstLevelTransitive": [ 320 | "com.netflix.zuul:zuul-core" 321 | ], 322 | "locked": "1.56.48" 323 | }, 324 | "com.netflix.blitz4j:blitz4j": { 325 | "locked": "1.37.2", 326 | "requested": "1.37.2" 327 | }, 328 | "com.netflix.eureka:eureka-client": { 329 | "firstLevelTransitive": [ 330 | "com.netflix.zuul:zuul-core" 331 | ], 332 | "locked": "1.8.6" 333 | }, 334 | "com.netflix.governator:governator": { 335 | "firstLevelTransitive": [ 336 | "com.netflix.zuul:zuul-core" 337 | ], 338 | "locked": "1.17.4" 339 | }, 340 | "com.netflix.governator:governator-archaius": { 341 | "firstLevelTransitive": [ 342 | "com.netflix.zuul:zuul-core" 343 | ], 344 | "locked": "1.17.4" 345 | }, 346 | "com.netflix.hystrix:hystrix-core": { 347 | "firstLevelTransitive": [ 348 | "com.netflix.zuul:zuul-core" 349 | ], 350 | "locked": "1.4.26" 351 | }, 352 | "com.netflix.netflix-commons:netflix-commons-util": { 353 | "firstLevelTransitive": [ 354 | "com.netflix.zuul:zuul-core" 355 | ], 356 | "locked": "0.3.0" 357 | }, 358 | "com.netflix.ribbon:ribbon-core": { 359 | "firstLevelTransitive": [ 360 | "com.netflix.zuul:zuul-core" 361 | ], 362 | "locked": "2.2.4" 363 | }, 364 | "com.netflix.ribbon:ribbon-eureka": { 365 | "firstLevelTransitive": [ 366 | "com.netflix.zuul:zuul-core" 367 | ], 368 | "locked": "2.2.4" 369 | }, 370 | "com.netflix.ribbon:ribbon-httpclient": { 371 | "firstLevelTransitive": [ 372 | "com.netflix.zuul:zuul-core" 373 | ], 374 | "locked": "2.2.4" 375 | }, 376 | "com.netflix.ribbon:ribbon-loadbalancer": { 377 | "firstLevelTransitive": [ 378 | "com.netflix.zuul:zuul-core" 379 | ], 380 | "locked": "2.2.4" 381 | }, 382 | "com.netflix.servo:servo-core": { 383 | "firstLevelTransitive": [ 384 | "com.netflix.zuul:zuul-core" 385 | ], 386 | "locked": "0.10.1" 387 | }, 388 | "com.netflix.spectator:spectator-api": { 389 | "firstLevelTransitive": [ 390 | "com.netflix.zuul:zuul-core" 391 | ], 392 | "locked": "0.59.0" 393 | }, 394 | "com.netflix.zuul:zuul-core": { 395 | "project": true 396 | }, 397 | "commons-fileupload:commons-fileupload": { 398 | "firstLevelTransitive": [ 399 | "com.netflix.zuul:zuul-core" 400 | ], 401 | "locked": "1.3" 402 | }, 403 | "commons-io:commons-io": { 404 | "firstLevelTransitive": [ 405 | "com.netflix.zuul:zuul-core" 406 | ], 407 | "locked": "2.4" 408 | }, 409 | "io.netty:netty-buffer": { 410 | "firstLevelTransitive": [ 411 | "com.netflix.zuul:zuul-core" 412 | ], 413 | "locked": "4.1.21.Final" 414 | }, 415 | "io.netty:netty-codec-haproxy": { 416 | "firstLevelTransitive": [ 417 | "com.netflix.zuul:zuul-core" 418 | ], 419 | "locked": "4.1.21.Final" 420 | }, 421 | "io.netty:netty-codec-http": { 422 | "firstLevelTransitive": [ 423 | "com.netflix.zuul:zuul-core" 424 | ], 425 | "locked": "4.1.21.Final" 426 | }, 427 | "io.netty:netty-codec-http2": { 428 | "firstLevelTransitive": [ 429 | "com.netflix.zuul:zuul-core" 430 | ], 431 | "locked": "4.1.21.Final" 432 | }, 433 | "io.netty:netty-common": { 434 | "firstLevelTransitive": [ 435 | "com.netflix.zuul:zuul-core" 436 | ], 437 | "locked": "4.1.21.Final" 438 | }, 439 | "io.netty:netty-handler": { 440 | "firstLevelTransitive": [ 441 | "com.netflix.zuul:zuul-core" 442 | ], 443 | "locked": "4.1.21.Final" 444 | }, 445 | "io.netty:netty-resolver": { 446 | "firstLevelTransitive": [ 447 | "com.netflix.zuul:zuul-core" 448 | ], 449 | "locked": "4.1.21.Final" 450 | }, 451 | "io.netty:netty-tcnative-boringssl-static": { 452 | "firstLevelTransitive": [ 453 | "com.netflix.zuul:zuul-core" 454 | ], 455 | "locked": "2.0.7.Final" 456 | }, 457 | "io.netty:netty-transport": { 458 | "firstLevelTransitive": [ 459 | "com.netflix.zuul:zuul-core" 460 | ], 461 | "locked": "4.1.21.Final" 462 | }, 463 | "io.netty:netty-transport-native-epoll": { 464 | "firstLevelTransitive": [ 465 | "com.netflix.zuul:zuul-core" 466 | ], 467 | "locked": "4.1.21.Final" 468 | }, 469 | "io.reactivex:rxjava": { 470 | "firstLevelTransitive": [ 471 | "com.netflix.zuul:zuul-core" 472 | ], 473 | "locked": "1.2.1" 474 | }, 475 | "junit:junit": { 476 | "firstLevelTransitive": [ 477 | "com.netflix.zuul:zuul-core" 478 | ], 479 | "locked": "4.12" 480 | }, 481 | "org.apache.commons:commons-lang3": { 482 | "firstLevelTransitive": [ 483 | "com.netflix.zuul:zuul-core" 484 | ], 485 | "locked": "3.4" 486 | }, 487 | "org.bouncycastle:bcpg-jdk15on": { 488 | "firstLevelTransitive": [ 489 | "com.netflix.zuul:zuul-core" 490 | ], 491 | "locked": "1.59" 492 | }, 493 | "org.bouncycastle:bcprov-jdk15on": { 494 | "firstLevelTransitive": [ 495 | "com.netflix.zuul:zuul-core" 496 | ], 497 | "locked": "1.59" 498 | }, 499 | "org.codehaus.groovy:groovy-all": { 500 | "firstLevelTransitive": [ 501 | "com.netflix.zuul:zuul-core" 502 | ], 503 | "locked": "2.4.4" 504 | }, 505 | "org.json:json": { 506 | "firstLevelTransitive": [ 507 | "com.netflix.zuul:zuul-core" 508 | ], 509 | "locked": "20090211" 510 | }, 511 | "org.mockito:mockito-core": { 512 | "firstLevelTransitive": [ 513 | "com.netflix.zuul:zuul-core" 514 | ], 515 | "locked": "1.9.5" 516 | }, 517 | "org.slf4j:slf4j-api": { 518 | "firstLevelTransitive": [ 519 | "com.netflix.zuul:zuul-core" 520 | ], 521 | "locked": "1.7.25" 522 | } 523 | }, 524 | "default": { 525 | "com.google.inject.extensions:guice-assistedinject": { 526 | "firstLevelTransitive": [ 527 | "com.netflix.zuul:zuul-core" 528 | ], 529 | "locked": "4.1.0", 530 | "requested": "4.0" 531 | }, 532 | "com.google.inject.extensions:guice-grapher": { 533 | "firstLevelTransitive": [ 534 | "com.netflix.zuul:zuul-core" 535 | ], 536 | "locked": "4.1.0", 537 | "requested": "4.0" 538 | }, 539 | "com.google.inject.extensions:guice-multibindings": { 540 | "firstLevelTransitive": [ 541 | "com.netflix.zuul:zuul-core" 542 | ], 543 | "locked": "4.1.0", 544 | "requested": "4.0" 545 | }, 546 | "com.google.inject.extensions:guice-servlet": { 547 | "firstLevelTransitive": [ 548 | "com.netflix.zuul:zuul-core" 549 | ], 550 | "locked": "4.0", 551 | "requested": "4.0" 552 | }, 553 | "com.google.inject.extensions:guice-throwingproviders": { 554 | "firstLevelTransitive": [ 555 | "com.netflix.zuul:zuul-core" 556 | ], 557 | "locked": "4.0", 558 | "requested": "4.0" 559 | }, 560 | "com.google.inject:guice": { 561 | "firstLevelTransitive": [ 562 | "com.netflix.zuul:zuul-core" 563 | ], 564 | "locked": "4.1.0", 565 | "requested": "4.0" 566 | }, 567 | "com.netflix.archaius:archaius-core": { 568 | "firstLevelTransitive": [ 569 | "com.netflix.zuul:zuul-core" 570 | ], 571 | "locked": "0.7.5" 572 | }, 573 | "com.netflix.astyanax:astyanax-cassandra": { 574 | "firstLevelTransitive": [ 575 | "com.netflix.zuul:zuul-core" 576 | ], 577 | "locked": "1.56.48" 578 | }, 579 | "com.netflix.astyanax:astyanax-thrift": { 580 | "firstLevelTransitive": [ 581 | "com.netflix.zuul:zuul-core" 582 | ], 583 | "locked": "1.56.48" 584 | }, 585 | "com.netflix.blitz4j:blitz4j": { 586 | "locked": "1.37.2", 587 | "requested": "1.37.2" 588 | }, 589 | "com.netflix.eureka:eureka-client": { 590 | "firstLevelTransitive": [ 591 | "com.netflix.zuul:zuul-core" 592 | ], 593 | "locked": "1.8.6" 594 | }, 595 | "com.netflix.governator:governator": { 596 | "firstLevelTransitive": [ 597 | "com.netflix.zuul:zuul-core" 598 | ], 599 | "locked": "1.17.4" 600 | }, 601 | "com.netflix.governator:governator-archaius": { 602 | "firstLevelTransitive": [ 603 | "com.netflix.zuul:zuul-core" 604 | ], 605 | "locked": "1.17.4" 606 | }, 607 | "com.netflix.hystrix:hystrix-core": { 608 | "firstLevelTransitive": [ 609 | "com.netflix.zuul:zuul-core" 610 | ], 611 | "locked": "1.4.26" 612 | }, 613 | "com.netflix.netflix-commons:netflix-commons-util": { 614 | "firstLevelTransitive": [ 615 | "com.netflix.zuul:zuul-core" 616 | ], 617 | "locked": "0.3.0" 618 | }, 619 | "com.netflix.ribbon:ribbon-core": { 620 | "firstLevelTransitive": [ 621 | "com.netflix.zuul:zuul-core" 622 | ], 623 | "locked": "2.2.4" 624 | }, 625 | "com.netflix.ribbon:ribbon-eureka": { 626 | "firstLevelTransitive": [ 627 | "com.netflix.zuul:zuul-core" 628 | ], 629 | "locked": "2.2.4" 630 | }, 631 | "com.netflix.ribbon:ribbon-httpclient": { 632 | "firstLevelTransitive": [ 633 | "com.netflix.zuul:zuul-core" 634 | ], 635 | "locked": "2.2.4" 636 | }, 637 | "com.netflix.ribbon:ribbon-loadbalancer": { 638 | "firstLevelTransitive": [ 639 | "com.netflix.zuul:zuul-core" 640 | ], 641 | "locked": "2.2.4" 642 | }, 643 | "com.netflix.servo:servo-core": { 644 | "firstLevelTransitive": [ 645 | "com.netflix.zuul:zuul-core" 646 | ], 647 | "locked": "0.10.1" 648 | }, 649 | "com.netflix.spectator:spectator-api": { 650 | "firstLevelTransitive": [ 651 | "com.netflix.zuul:zuul-core" 652 | ], 653 | "locked": "0.59.0" 654 | }, 655 | "com.netflix.zuul:zuul-core": { 656 | "project": true 657 | }, 658 | "commons-fileupload:commons-fileupload": { 659 | "firstLevelTransitive": [ 660 | "com.netflix.zuul:zuul-core" 661 | ], 662 | "locked": "1.3" 663 | }, 664 | "commons-io:commons-io": { 665 | "firstLevelTransitive": [ 666 | "com.netflix.zuul:zuul-core" 667 | ], 668 | "locked": "2.4" 669 | }, 670 | "io.netty:netty-buffer": { 671 | "firstLevelTransitive": [ 672 | "com.netflix.zuul:zuul-core" 673 | ], 674 | "locked": "4.1.21.Final" 675 | }, 676 | "io.netty:netty-codec-haproxy": { 677 | "firstLevelTransitive": [ 678 | "com.netflix.zuul:zuul-core" 679 | ], 680 | "locked": "4.1.21.Final" 681 | }, 682 | "io.netty:netty-codec-http": { 683 | "firstLevelTransitive": [ 684 | "com.netflix.zuul:zuul-core" 685 | ], 686 | "locked": "4.1.21.Final" 687 | }, 688 | "io.netty:netty-codec-http2": { 689 | "firstLevelTransitive": [ 690 | "com.netflix.zuul:zuul-core" 691 | ], 692 | "locked": "4.1.21.Final" 693 | }, 694 | "io.netty:netty-common": { 695 | "firstLevelTransitive": [ 696 | "com.netflix.zuul:zuul-core" 697 | ], 698 | "locked": "4.1.21.Final" 699 | }, 700 | "io.netty:netty-handler": { 701 | "firstLevelTransitive": [ 702 | "com.netflix.zuul:zuul-core" 703 | ], 704 | "locked": "4.1.21.Final" 705 | }, 706 | "io.netty:netty-resolver": { 707 | "firstLevelTransitive": [ 708 | "com.netflix.zuul:zuul-core" 709 | ], 710 | "locked": "4.1.21.Final" 711 | }, 712 | "io.netty:netty-tcnative-boringssl-static": { 713 | "firstLevelTransitive": [ 714 | "com.netflix.zuul:zuul-core" 715 | ], 716 | "locked": "2.0.7.Final" 717 | }, 718 | "io.netty:netty-transport": { 719 | "firstLevelTransitive": [ 720 | "com.netflix.zuul:zuul-core" 721 | ], 722 | "locked": "4.1.21.Final" 723 | }, 724 | "io.netty:netty-transport-native-epoll": { 725 | "firstLevelTransitive": [ 726 | "com.netflix.zuul:zuul-core" 727 | ], 728 | "locked": "4.1.21.Final" 729 | }, 730 | "io.reactivex:rxjava": { 731 | "firstLevelTransitive": [ 732 | "com.netflix.zuul:zuul-core" 733 | ], 734 | "locked": "1.2.1" 735 | }, 736 | "junit:junit": { 737 | "firstLevelTransitive": [ 738 | "com.netflix.zuul:zuul-core" 739 | ], 740 | "locked": "4.12" 741 | }, 742 | "org.apache.commons:commons-lang3": { 743 | "firstLevelTransitive": [ 744 | "com.netflix.zuul:zuul-core" 745 | ], 746 | "locked": "3.4" 747 | }, 748 | "org.bouncycastle:bcpg-jdk15on": { 749 | "firstLevelTransitive": [ 750 | "com.netflix.zuul:zuul-core" 751 | ], 752 | "locked": "1.59" 753 | }, 754 | "org.bouncycastle:bcprov-jdk15on": { 755 | "firstLevelTransitive": [ 756 | "com.netflix.zuul:zuul-core" 757 | ], 758 | "locked": "1.59" 759 | }, 760 | "org.codehaus.groovy:groovy-all": { 761 | "firstLevelTransitive": [ 762 | "com.netflix.zuul:zuul-core" 763 | ], 764 | "locked": "2.4.4" 765 | }, 766 | "org.json:json": { 767 | "firstLevelTransitive": [ 768 | "com.netflix.zuul:zuul-core" 769 | ], 770 | "locked": "20090211" 771 | }, 772 | "org.mockito:mockito-core": { 773 | "firstLevelTransitive": [ 774 | "com.netflix.zuul:zuul-core" 775 | ], 776 | "locked": "1.9.5" 777 | }, 778 | "org.slf4j:slf4j-api": { 779 | "firstLevelTransitive": [ 780 | "com.netflix.zuul:zuul-core" 781 | ], 782 | "locked": "1.7.25" 783 | } 784 | }, 785 | "runtime": { 786 | "com.google.inject.extensions:guice-assistedinject": { 787 | "firstLevelTransitive": [ 788 | "com.netflix.zuul:zuul-core" 789 | ], 790 | "locked": "4.1.0", 791 | "requested": "4.0" 792 | }, 793 | "com.google.inject.extensions:guice-grapher": { 794 | "firstLevelTransitive": [ 795 | "com.netflix.zuul:zuul-core" 796 | ], 797 | "locked": "4.1.0", 798 | "requested": "4.0" 799 | }, 800 | "com.google.inject.extensions:guice-multibindings": { 801 | "firstLevelTransitive": [ 802 | "com.netflix.zuul:zuul-core" 803 | ], 804 | "locked": "4.1.0", 805 | "requested": "4.0" 806 | }, 807 | "com.google.inject.extensions:guice-servlet": { 808 | "firstLevelTransitive": [ 809 | "com.netflix.zuul:zuul-core" 810 | ], 811 | "locked": "4.0", 812 | "requested": "4.0" 813 | }, 814 | "com.google.inject.extensions:guice-throwingproviders": { 815 | "firstLevelTransitive": [ 816 | "com.netflix.zuul:zuul-core" 817 | ], 818 | "locked": "4.0", 819 | "requested": "4.0" 820 | }, 821 | "com.google.inject:guice": { 822 | "firstLevelTransitive": [ 823 | "com.netflix.zuul:zuul-core" 824 | ], 825 | "locked": "4.1.0", 826 | "requested": "4.0" 827 | }, 828 | "com.netflix.archaius:archaius-core": { 829 | "firstLevelTransitive": [ 830 | "com.netflix.zuul:zuul-core" 831 | ], 832 | "locked": "0.7.5" 833 | }, 834 | "com.netflix.astyanax:astyanax-cassandra": { 835 | "firstLevelTransitive": [ 836 | "com.netflix.zuul:zuul-core" 837 | ], 838 | "locked": "1.56.48" 839 | }, 840 | "com.netflix.astyanax:astyanax-thrift": { 841 | "firstLevelTransitive": [ 842 | "com.netflix.zuul:zuul-core" 843 | ], 844 | "locked": "1.56.48" 845 | }, 846 | "com.netflix.blitz4j:blitz4j": { 847 | "locked": "1.37.2", 848 | "requested": "1.37.2" 849 | }, 850 | "com.netflix.eureka:eureka-client": { 851 | "firstLevelTransitive": [ 852 | "com.netflix.zuul:zuul-core" 853 | ], 854 | "locked": "1.8.6" 855 | }, 856 | "com.netflix.governator:governator": { 857 | "firstLevelTransitive": [ 858 | "com.netflix.zuul:zuul-core" 859 | ], 860 | "locked": "1.17.4" 861 | }, 862 | "com.netflix.governator:governator-archaius": { 863 | "firstLevelTransitive": [ 864 | "com.netflix.zuul:zuul-core" 865 | ], 866 | "locked": "1.17.4" 867 | }, 868 | "com.netflix.hystrix:hystrix-core": { 869 | "firstLevelTransitive": [ 870 | "com.netflix.zuul:zuul-core" 871 | ], 872 | "locked": "1.4.26" 873 | }, 874 | "com.netflix.netflix-commons:netflix-commons-util": { 875 | "firstLevelTransitive": [ 876 | "com.netflix.zuul:zuul-core" 877 | ], 878 | "locked": "0.3.0" 879 | }, 880 | "com.netflix.ribbon:ribbon-core": { 881 | "firstLevelTransitive": [ 882 | "com.netflix.zuul:zuul-core" 883 | ], 884 | "locked": "2.2.4" 885 | }, 886 | "com.netflix.ribbon:ribbon-eureka": { 887 | "firstLevelTransitive": [ 888 | "com.netflix.zuul:zuul-core" 889 | ], 890 | "locked": "2.2.4" 891 | }, 892 | "com.netflix.ribbon:ribbon-httpclient": { 893 | "firstLevelTransitive": [ 894 | "com.netflix.zuul:zuul-core" 895 | ], 896 | "locked": "2.2.4" 897 | }, 898 | "com.netflix.ribbon:ribbon-loadbalancer": { 899 | "firstLevelTransitive": [ 900 | "com.netflix.zuul:zuul-core" 901 | ], 902 | "locked": "2.2.4" 903 | }, 904 | "com.netflix.servo:servo-core": { 905 | "firstLevelTransitive": [ 906 | "com.netflix.zuul:zuul-core" 907 | ], 908 | "locked": "0.10.1" 909 | }, 910 | "com.netflix.spectator:spectator-api": { 911 | "firstLevelTransitive": [ 912 | "com.netflix.zuul:zuul-core" 913 | ], 914 | "locked": "0.59.0" 915 | }, 916 | "com.netflix.zuul:zuul-core": { 917 | "project": true 918 | }, 919 | "commons-fileupload:commons-fileupload": { 920 | "firstLevelTransitive": [ 921 | "com.netflix.zuul:zuul-core" 922 | ], 923 | "locked": "1.3" 924 | }, 925 | "commons-io:commons-io": { 926 | "firstLevelTransitive": [ 927 | "com.netflix.zuul:zuul-core" 928 | ], 929 | "locked": "2.4" 930 | }, 931 | "io.netty:netty-buffer": { 932 | "firstLevelTransitive": [ 933 | "com.netflix.zuul:zuul-core" 934 | ], 935 | "locked": "4.1.21.Final" 936 | }, 937 | "io.netty:netty-codec-haproxy": { 938 | "firstLevelTransitive": [ 939 | "com.netflix.zuul:zuul-core" 940 | ], 941 | "locked": "4.1.21.Final" 942 | }, 943 | "io.netty:netty-codec-http": { 944 | "firstLevelTransitive": [ 945 | "com.netflix.zuul:zuul-core" 946 | ], 947 | "locked": "4.1.21.Final" 948 | }, 949 | "io.netty:netty-codec-http2": { 950 | "firstLevelTransitive": [ 951 | "com.netflix.zuul:zuul-core" 952 | ], 953 | "locked": "4.1.21.Final" 954 | }, 955 | "io.netty:netty-common": { 956 | "firstLevelTransitive": [ 957 | "com.netflix.zuul:zuul-core" 958 | ], 959 | "locked": "4.1.21.Final" 960 | }, 961 | "io.netty:netty-handler": { 962 | "firstLevelTransitive": [ 963 | "com.netflix.zuul:zuul-core" 964 | ], 965 | "locked": "4.1.21.Final" 966 | }, 967 | "io.netty:netty-resolver": { 968 | "firstLevelTransitive": [ 969 | "com.netflix.zuul:zuul-core" 970 | ], 971 | "locked": "4.1.21.Final" 972 | }, 973 | "io.netty:netty-tcnative-boringssl-static": { 974 | "firstLevelTransitive": [ 975 | "com.netflix.zuul:zuul-core" 976 | ], 977 | "locked": "2.0.7.Final" 978 | }, 979 | "io.netty:netty-transport": { 980 | "firstLevelTransitive": [ 981 | "com.netflix.zuul:zuul-core" 982 | ], 983 | "locked": "4.1.21.Final" 984 | }, 985 | "io.netty:netty-transport-native-epoll": { 986 | "firstLevelTransitive": [ 987 | "com.netflix.zuul:zuul-core" 988 | ], 989 | "locked": "4.1.21.Final" 990 | }, 991 | "io.reactivex:rxjava": { 992 | "firstLevelTransitive": [ 993 | "com.netflix.zuul:zuul-core" 994 | ], 995 | "locked": "1.2.1" 996 | }, 997 | "junit:junit": { 998 | "firstLevelTransitive": [ 999 | "com.netflix.zuul:zuul-core" 1000 | ], 1001 | "locked": "4.12" 1002 | }, 1003 | "org.apache.commons:commons-lang3": { 1004 | "firstLevelTransitive": [ 1005 | "com.netflix.zuul:zuul-core" 1006 | ], 1007 | "locked": "3.4" 1008 | }, 1009 | "org.bouncycastle:bcpg-jdk15on": { 1010 | "firstLevelTransitive": [ 1011 | "com.netflix.zuul:zuul-core" 1012 | ], 1013 | "locked": "1.59" 1014 | }, 1015 | "org.bouncycastle:bcprov-jdk15on": { 1016 | "firstLevelTransitive": [ 1017 | "com.netflix.zuul:zuul-core" 1018 | ], 1019 | "locked": "1.59" 1020 | }, 1021 | "org.codehaus.groovy:groovy-all": { 1022 | "firstLevelTransitive": [ 1023 | "com.netflix.zuul:zuul-core" 1024 | ], 1025 | "locked": "2.4.4" 1026 | }, 1027 | "org.json:json": { 1028 | "firstLevelTransitive": [ 1029 | "com.netflix.zuul:zuul-core" 1030 | ], 1031 | "locked": "20090211" 1032 | }, 1033 | "org.mockito:mockito-core": { 1034 | "firstLevelTransitive": [ 1035 | "com.netflix.zuul:zuul-core" 1036 | ], 1037 | "locked": "1.9.5" 1038 | }, 1039 | "org.slf4j:slf4j-api": { 1040 | "firstLevelTransitive": [ 1041 | "com.netflix.zuul:zuul-core" 1042 | ], 1043 | "locked": "1.7.25" 1044 | } 1045 | }, 1046 | "runtimeClasspath": { 1047 | "com.google.inject.extensions:guice-assistedinject": { 1048 | "firstLevelTransitive": [ 1049 | "com.netflix.zuul:zuul-core" 1050 | ], 1051 | "locked": "4.1.0", 1052 | "requested": "4.0" 1053 | }, 1054 | "com.google.inject.extensions:guice-grapher": { 1055 | "firstLevelTransitive": [ 1056 | "com.netflix.zuul:zuul-core" 1057 | ], 1058 | "locked": "4.1.0", 1059 | "requested": "4.0" 1060 | }, 1061 | "com.google.inject.extensions:guice-multibindings": { 1062 | "firstLevelTransitive": [ 1063 | "com.netflix.zuul:zuul-core" 1064 | ], 1065 | "locked": "4.1.0", 1066 | "requested": "4.0" 1067 | }, 1068 | "com.google.inject.extensions:guice-servlet": { 1069 | "firstLevelTransitive": [ 1070 | "com.netflix.zuul:zuul-core" 1071 | ], 1072 | "locked": "4.0", 1073 | "requested": "4.0" 1074 | }, 1075 | "com.google.inject.extensions:guice-throwingproviders": { 1076 | "firstLevelTransitive": [ 1077 | "com.netflix.zuul:zuul-core" 1078 | ], 1079 | "locked": "4.0", 1080 | "requested": "4.0" 1081 | }, 1082 | "com.google.inject:guice": { 1083 | "firstLevelTransitive": [ 1084 | "com.netflix.zuul:zuul-core" 1085 | ], 1086 | "locked": "4.1.0", 1087 | "requested": "4.0" 1088 | }, 1089 | "com.netflix.archaius:archaius-core": { 1090 | "firstLevelTransitive": [ 1091 | "com.netflix.zuul:zuul-core" 1092 | ], 1093 | "locked": "0.7.5" 1094 | }, 1095 | "com.netflix.astyanax:astyanax-cassandra": { 1096 | "firstLevelTransitive": [ 1097 | "com.netflix.zuul:zuul-core" 1098 | ], 1099 | "locked": "1.56.48" 1100 | }, 1101 | "com.netflix.astyanax:astyanax-thrift": { 1102 | "firstLevelTransitive": [ 1103 | "com.netflix.zuul:zuul-core" 1104 | ], 1105 | "locked": "1.56.48" 1106 | }, 1107 | "com.netflix.blitz4j:blitz4j": { 1108 | "locked": "1.37.2", 1109 | "requested": "1.37.2" 1110 | }, 1111 | "com.netflix.eureka:eureka-client": { 1112 | "firstLevelTransitive": [ 1113 | "com.netflix.zuul:zuul-core" 1114 | ], 1115 | "locked": "1.8.6" 1116 | }, 1117 | "com.netflix.governator:governator": { 1118 | "firstLevelTransitive": [ 1119 | "com.netflix.zuul:zuul-core" 1120 | ], 1121 | "locked": "1.17.4" 1122 | }, 1123 | "com.netflix.governator:governator-archaius": { 1124 | "firstLevelTransitive": [ 1125 | "com.netflix.zuul:zuul-core" 1126 | ], 1127 | "locked": "1.17.4" 1128 | }, 1129 | "com.netflix.hystrix:hystrix-core": { 1130 | "firstLevelTransitive": [ 1131 | "com.netflix.zuul:zuul-core" 1132 | ], 1133 | "locked": "1.4.26" 1134 | }, 1135 | "com.netflix.netflix-commons:netflix-commons-util": { 1136 | "firstLevelTransitive": [ 1137 | "com.netflix.zuul:zuul-core" 1138 | ], 1139 | "locked": "0.3.0" 1140 | }, 1141 | "com.netflix.ribbon:ribbon-core": { 1142 | "firstLevelTransitive": [ 1143 | "com.netflix.zuul:zuul-core" 1144 | ], 1145 | "locked": "2.2.4" 1146 | }, 1147 | "com.netflix.ribbon:ribbon-eureka": { 1148 | "firstLevelTransitive": [ 1149 | "com.netflix.zuul:zuul-core" 1150 | ], 1151 | "locked": "2.2.4" 1152 | }, 1153 | "com.netflix.ribbon:ribbon-httpclient": { 1154 | "firstLevelTransitive": [ 1155 | "com.netflix.zuul:zuul-core" 1156 | ], 1157 | "locked": "2.2.4" 1158 | }, 1159 | "com.netflix.ribbon:ribbon-loadbalancer": { 1160 | "firstLevelTransitive": [ 1161 | "com.netflix.zuul:zuul-core" 1162 | ], 1163 | "locked": "2.2.4" 1164 | }, 1165 | "com.netflix.servo:servo-core": { 1166 | "firstLevelTransitive": [ 1167 | "com.netflix.zuul:zuul-core" 1168 | ], 1169 | "locked": "0.10.1" 1170 | }, 1171 | "com.netflix.spectator:spectator-api": { 1172 | "firstLevelTransitive": [ 1173 | "com.netflix.zuul:zuul-core" 1174 | ], 1175 | "locked": "0.59.0" 1176 | }, 1177 | "com.netflix.zuul:zuul-core": { 1178 | "project": true 1179 | }, 1180 | "commons-fileupload:commons-fileupload": { 1181 | "firstLevelTransitive": [ 1182 | "com.netflix.zuul:zuul-core" 1183 | ], 1184 | "locked": "1.3" 1185 | }, 1186 | "commons-io:commons-io": { 1187 | "firstLevelTransitive": [ 1188 | "com.netflix.zuul:zuul-core" 1189 | ], 1190 | "locked": "2.4" 1191 | }, 1192 | "io.netty:netty-buffer": { 1193 | "firstLevelTransitive": [ 1194 | "com.netflix.zuul:zuul-core" 1195 | ], 1196 | "locked": "4.1.21.Final" 1197 | }, 1198 | "io.netty:netty-codec-haproxy": { 1199 | "firstLevelTransitive": [ 1200 | "com.netflix.zuul:zuul-core" 1201 | ], 1202 | "locked": "4.1.21.Final" 1203 | }, 1204 | "io.netty:netty-codec-http": { 1205 | "firstLevelTransitive": [ 1206 | "com.netflix.zuul:zuul-core" 1207 | ], 1208 | "locked": "4.1.21.Final" 1209 | }, 1210 | "io.netty:netty-codec-http2": { 1211 | "firstLevelTransitive": [ 1212 | "com.netflix.zuul:zuul-core" 1213 | ], 1214 | "locked": "4.1.21.Final" 1215 | }, 1216 | "io.netty:netty-common": { 1217 | "firstLevelTransitive": [ 1218 | "com.netflix.zuul:zuul-core" 1219 | ], 1220 | "locked": "4.1.21.Final" 1221 | }, 1222 | "io.netty:netty-handler": { 1223 | "firstLevelTransitive": [ 1224 | "com.netflix.zuul:zuul-core" 1225 | ], 1226 | "locked": "4.1.21.Final" 1227 | }, 1228 | "io.netty:netty-resolver": { 1229 | "firstLevelTransitive": [ 1230 | "com.netflix.zuul:zuul-core" 1231 | ], 1232 | "locked": "4.1.21.Final" 1233 | }, 1234 | "io.netty:netty-tcnative-boringssl-static": { 1235 | "firstLevelTransitive": [ 1236 | "com.netflix.zuul:zuul-core" 1237 | ], 1238 | "locked": "2.0.7.Final" 1239 | }, 1240 | "io.netty:netty-transport": { 1241 | "firstLevelTransitive": [ 1242 | "com.netflix.zuul:zuul-core" 1243 | ], 1244 | "locked": "4.1.21.Final" 1245 | }, 1246 | "io.netty:netty-transport-native-epoll": { 1247 | "firstLevelTransitive": [ 1248 | "com.netflix.zuul:zuul-core" 1249 | ], 1250 | "locked": "4.1.21.Final" 1251 | }, 1252 | "io.reactivex:rxjava": { 1253 | "firstLevelTransitive": [ 1254 | "com.netflix.zuul:zuul-core" 1255 | ], 1256 | "locked": "1.2.1" 1257 | }, 1258 | "junit:junit": { 1259 | "firstLevelTransitive": [ 1260 | "com.netflix.zuul:zuul-core" 1261 | ], 1262 | "locked": "4.12" 1263 | }, 1264 | "org.apache.commons:commons-lang3": { 1265 | "firstLevelTransitive": [ 1266 | "com.netflix.zuul:zuul-core" 1267 | ], 1268 | "locked": "3.4" 1269 | }, 1270 | "org.bouncycastle:bcpg-jdk15on": { 1271 | "firstLevelTransitive": [ 1272 | "com.netflix.zuul:zuul-core" 1273 | ], 1274 | "locked": "1.59" 1275 | }, 1276 | "org.bouncycastle:bcprov-jdk15on": { 1277 | "firstLevelTransitive": [ 1278 | "com.netflix.zuul:zuul-core" 1279 | ], 1280 | "locked": "1.59" 1281 | }, 1282 | "org.codehaus.groovy:groovy-all": { 1283 | "firstLevelTransitive": [ 1284 | "com.netflix.zuul:zuul-core" 1285 | ], 1286 | "locked": "2.4.4" 1287 | }, 1288 | "org.json:json": { 1289 | "firstLevelTransitive": [ 1290 | "com.netflix.zuul:zuul-core" 1291 | ], 1292 | "locked": "20090211" 1293 | }, 1294 | "org.mockito:mockito-core": { 1295 | "firstLevelTransitive": [ 1296 | "com.netflix.zuul:zuul-core" 1297 | ], 1298 | "locked": "1.9.5" 1299 | }, 1300 | "org.slf4j:slf4j-api": { 1301 | "firstLevelTransitive": [ 1302 | "com.netflix.zuul:zuul-core" 1303 | ], 1304 | "locked": "1.7.25" 1305 | } 1306 | }, 1307 | "testCompile": { 1308 | "com.google.inject.extensions:guice-assistedinject": { 1309 | "firstLevelTransitive": [ 1310 | "com.netflix.zuul:zuul-core" 1311 | ], 1312 | "locked": "4.1.0", 1313 | "requested": "4.0" 1314 | }, 1315 | "com.google.inject.extensions:guice-grapher": { 1316 | "firstLevelTransitive": [ 1317 | "com.netflix.zuul:zuul-core" 1318 | ], 1319 | "locked": "4.1.0", 1320 | "requested": "4.0" 1321 | }, 1322 | "com.google.inject.extensions:guice-multibindings": { 1323 | "firstLevelTransitive": [ 1324 | "com.netflix.zuul:zuul-core" 1325 | ], 1326 | "locked": "4.1.0", 1327 | "requested": "4.0" 1328 | }, 1329 | "com.google.inject.extensions:guice-servlet": { 1330 | "firstLevelTransitive": [ 1331 | "com.netflix.zuul:zuul-core" 1332 | ], 1333 | "locked": "4.0", 1334 | "requested": "4.0" 1335 | }, 1336 | "com.google.inject.extensions:guice-throwingproviders": { 1337 | "firstLevelTransitive": [ 1338 | "com.netflix.zuul:zuul-core" 1339 | ], 1340 | "locked": "4.0", 1341 | "requested": "4.0" 1342 | }, 1343 | "com.google.inject:guice": { 1344 | "firstLevelTransitive": [ 1345 | "com.netflix.zuul:zuul-core" 1346 | ], 1347 | "locked": "4.1.0", 1348 | "requested": "4.0" 1349 | }, 1350 | "com.netflix.archaius:archaius-core": { 1351 | "firstLevelTransitive": [ 1352 | "com.netflix.zuul:zuul-core" 1353 | ], 1354 | "locked": "0.7.5" 1355 | }, 1356 | "com.netflix.astyanax:astyanax-cassandra": { 1357 | "firstLevelTransitive": [ 1358 | "com.netflix.zuul:zuul-core" 1359 | ], 1360 | "locked": "1.56.48" 1361 | }, 1362 | "com.netflix.astyanax:astyanax-thrift": { 1363 | "firstLevelTransitive": [ 1364 | "com.netflix.zuul:zuul-core" 1365 | ], 1366 | "locked": "1.56.48" 1367 | }, 1368 | "com.netflix.blitz4j:blitz4j": { 1369 | "locked": "1.37.2", 1370 | "requested": "1.37.2" 1371 | }, 1372 | "com.netflix.eureka:eureka-client": { 1373 | "firstLevelTransitive": [ 1374 | "com.netflix.zuul:zuul-core" 1375 | ], 1376 | "locked": "1.8.6" 1377 | }, 1378 | "com.netflix.governator:governator": { 1379 | "firstLevelTransitive": [ 1380 | "com.netflix.zuul:zuul-core" 1381 | ], 1382 | "locked": "1.17.4" 1383 | }, 1384 | "com.netflix.governator:governator-archaius": { 1385 | "firstLevelTransitive": [ 1386 | "com.netflix.zuul:zuul-core" 1387 | ], 1388 | "locked": "1.17.4" 1389 | }, 1390 | "com.netflix.hystrix:hystrix-core": { 1391 | "firstLevelTransitive": [ 1392 | "com.netflix.zuul:zuul-core" 1393 | ], 1394 | "locked": "1.4.26" 1395 | }, 1396 | "com.netflix.netflix-commons:netflix-commons-util": { 1397 | "firstLevelTransitive": [ 1398 | "com.netflix.zuul:zuul-core" 1399 | ], 1400 | "locked": "0.3.0" 1401 | }, 1402 | "com.netflix.ribbon:ribbon-core": { 1403 | "firstLevelTransitive": [ 1404 | "com.netflix.zuul:zuul-core" 1405 | ], 1406 | "locked": "2.2.4" 1407 | }, 1408 | "com.netflix.ribbon:ribbon-eureka": { 1409 | "firstLevelTransitive": [ 1410 | "com.netflix.zuul:zuul-core" 1411 | ], 1412 | "locked": "2.2.4" 1413 | }, 1414 | "com.netflix.ribbon:ribbon-httpclient": { 1415 | "firstLevelTransitive": [ 1416 | "com.netflix.zuul:zuul-core" 1417 | ], 1418 | "locked": "2.2.4" 1419 | }, 1420 | "com.netflix.ribbon:ribbon-loadbalancer": { 1421 | "firstLevelTransitive": [ 1422 | "com.netflix.zuul:zuul-core" 1423 | ], 1424 | "locked": "2.2.4" 1425 | }, 1426 | "com.netflix.servo:servo-core": { 1427 | "firstLevelTransitive": [ 1428 | "com.netflix.zuul:zuul-core" 1429 | ], 1430 | "locked": "0.10.1" 1431 | }, 1432 | "com.netflix.spectator:spectator-api": { 1433 | "firstLevelTransitive": [ 1434 | "com.netflix.zuul:zuul-core" 1435 | ], 1436 | "locked": "0.59.0" 1437 | }, 1438 | "com.netflix.zuul:zuul-core": { 1439 | "project": true 1440 | }, 1441 | "commons-fileupload:commons-fileupload": { 1442 | "firstLevelTransitive": [ 1443 | "com.netflix.zuul:zuul-core" 1444 | ], 1445 | "locked": "1.3" 1446 | }, 1447 | "commons-io:commons-io": { 1448 | "firstLevelTransitive": [ 1449 | "com.netflix.zuul:zuul-core" 1450 | ], 1451 | "locked": "2.4" 1452 | }, 1453 | "io.netty:netty-buffer": { 1454 | "firstLevelTransitive": [ 1455 | "com.netflix.zuul:zuul-core" 1456 | ], 1457 | "locked": "4.1.21.Final" 1458 | }, 1459 | "io.netty:netty-codec-haproxy": { 1460 | "firstLevelTransitive": [ 1461 | "com.netflix.zuul:zuul-core" 1462 | ], 1463 | "locked": "4.1.21.Final" 1464 | }, 1465 | "io.netty:netty-codec-http": { 1466 | "firstLevelTransitive": [ 1467 | "com.netflix.zuul:zuul-core" 1468 | ], 1469 | "locked": "4.1.21.Final" 1470 | }, 1471 | "io.netty:netty-codec-http2": { 1472 | "firstLevelTransitive": [ 1473 | "com.netflix.zuul:zuul-core" 1474 | ], 1475 | "locked": "4.1.21.Final" 1476 | }, 1477 | "io.netty:netty-common": { 1478 | "firstLevelTransitive": [ 1479 | "com.netflix.zuul:zuul-core" 1480 | ], 1481 | "locked": "4.1.21.Final" 1482 | }, 1483 | "io.netty:netty-handler": { 1484 | "firstLevelTransitive": [ 1485 | "com.netflix.zuul:zuul-core" 1486 | ], 1487 | "locked": "4.1.21.Final" 1488 | }, 1489 | "io.netty:netty-resolver": { 1490 | "firstLevelTransitive": [ 1491 | "com.netflix.zuul:zuul-core" 1492 | ], 1493 | "locked": "4.1.21.Final" 1494 | }, 1495 | "io.netty:netty-tcnative-boringssl-static": { 1496 | "firstLevelTransitive": [ 1497 | "com.netflix.zuul:zuul-core" 1498 | ], 1499 | "locked": "2.0.7.Final" 1500 | }, 1501 | "io.netty:netty-transport": { 1502 | "firstLevelTransitive": [ 1503 | "com.netflix.zuul:zuul-core" 1504 | ], 1505 | "locked": "4.1.21.Final" 1506 | }, 1507 | "io.netty:netty-transport-native-epoll": { 1508 | "firstLevelTransitive": [ 1509 | "com.netflix.zuul:zuul-core" 1510 | ], 1511 | "locked": "4.1.21.Final" 1512 | }, 1513 | "io.reactivex:rxjava": { 1514 | "firstLevelTransitive": [ 1515 | "com.netflix.zuul:zuul-core" 1516 | ], 1517 | "locked": "1.2.1" 1518 | }, 1519 | "junit:junit": { 1520 | "firstLevelTransitive": [ 1521 | "com.netflix.zuul:zuul-core" 1522 | ], 1523 | "locked": "4.12" 1524 | }, 1525 | "org.apache.commons:commons-lang3": { 1526 | "firstLevelTransitive": [ 1527 | "com.netflix.zuul:zuul-core" 1528 | ], 1529 | "locked": "3.4" 1530 | }, 1531 | "org.bouncycastle:bcpg-jdk15on": { 1532 | "firstLevelTransitive": [ 1533 | "com.netflix.zuul:zuul-core" 1534 | ], 1535 | "locked": "1.59" 1536 | }, 1537 | "org.bouncycastle:bcprov-jdk15on": { 1538 | "firstLevelTransitive": [ 1539 | "com.netflix.zuul:zuul-core" 1540 | ], 1541 | "locked": "1.59" 1542 | }, 1543 | "org.codehaus.groovy:groovy-all": { 1544 | "firstLevelTransitive": [ 1545 | "com.netflix.zuul:zuul-core" 1546 | ], 1547 | "locked": "2.4.4" 1548 | }, 1549 | "org.json:json": { 1550 | "firstLevelTransitive": [ 1551 | "com.netflix.zuul:zuul-core" 1552 | ], 1553 | "locked": "20090211" 1554 | }, 1555 | "org.mockito:mockito-core": { 1556 | "firstLevelTransitive": [ 1557 | "com.netflix.zuul:zuul-core" 1558 | ], 1559 | "locked": "1.9.5" 1560 | }, 1561 | "org.slf4j:slf4j-api": { 1562 | "firstLevelTransitive": [ 1563 | "com.netflix.zuul:zuul-core" 1564 | ], 1565 | "locked": "1.7.25" 1566 | } 1567 | }, 1568 | "testCompileClasspath": { 1569 | "com.google.inject.extensions:guice-assistedinject": { 1570 | "firstLevelTransitive": [ 1571 | "com.netflix.zuul:zuul-core" 1572 | ], 1573 | "locked": "4.1.0", 1574 | "requested": "4.0" 1575 | }, 1576 | "com.google.inject.extensions:guice-grapher": { 1577 | "firstLevelTransitive": [ 1578 | "com.netflix.zuul:zuul-core" 1579 | ], 1580 | "locked": "4.1.0", 1581 | "requested": "4.0" 1582 | }, 1583 | "com.google.inject.extensions:guice-multibindings": { 1584 | "firstLevelTransitive": [ 1585 | "com.netflix.zuul:zuul-core" 1586 | ], 1587 | "locked": "4.1.0", 1588 | "requested": "4.0" 1589 | }, 1590 | "com.google.inject.extensions:guice-servlet": { 1591 | "firstLevelTransitive": [ 1592 | "com.netflix.zuul:zuul-core" 1593 | ], 1594 | "locked": "4.0", 1595 | "requested": "4.0" 1596 | }, 1597 | "com.google.inject.extensions:guice-throwingproviders": { 1598 | "firstLevelTransitive": [ 1599 | "com.netflix.zuul:zuul-core" 1600 | ], 1601 | "locked": "4.0", 1602 | "requested": "4.0" 1603 | }, 1604 | "com.google.inject:guice": { 1605 | "firstLevelTransitive": [ 1606 | "com.netflix.zuul:zuul-core" 1607 | ], 1608 | "locked": "4.1.0", 1609 | "requested": "4.0" 1610 | }, 1611 | "com.netflix.archaius:archaius-core": { 1612 | "firstLevelTransitive": [ 1613 | "com.netflix.zuul:zuul-core" 1614 | ], 1615 | "locked": "0.7.5" 1616 | }, 1617 | "com.netflix.astyanax:astyanax-cassandra": { 1618 | "firstLevelTransitive": [ 1619 | "com.netflix.zuul:zuul-core" 1620 | ], 1621 | "locked": "1.56.48" 1622 | }, 1623 | "com.netflix.astyanax:astyanax-thrift": { 1624 | "firstLevelTransitive": [ 1625 | "com.netflix.zuul:zuul-core" 1626 | ], 1627 | "locked": "1.56.48" 1628 | }, 1629 | "com.netflix.blitz4j:blitz4j": { 1630 | "locked": "1.37.2", 1631 | "requested": "1.37.2" 1632 | }, 1633 | "com.netflix.eureka:eureka-client": { 1634 | "firstLevelTransitive": [ 1635 | "com.netflix.zuul:zuul-core" 1636 | ], 1637 | "locked": "1.8.6" 1638 | }, 1639 | "com.netflix.governator:governator": { 1640 | "firstLevelTransitive": [ 1641 | "com.netflix.zuul:zuul-core" 1642 | ], 1643 | "locked": "1.17.4" 1644 | }, 1645 | "com.netflix.governator:governator-archaius": { 1646 | "firstLevelTransitive": [ 1647 | "com.netflix.zuul:zuul-core" 1648 | ], 1649 | "locked": "1.17.4" 1650 | }, 1651 | "com.netflix.hystrix:hystrix-core": { 1652 | "firstLevelTransitive": [ 1653 | "com.netflix.zuul:zuul-core" 1654 | ], 1655 | "locked": "1.4.26" 1656 | }, 1657 | "com.netflix.netflix-commons:netflix-commons-util": { 1658 | "firstLevelTransitive": [ 1659 | "com.netflix.zuul:zuul-core" 1660 | ], 1661 | "locked": "0.3.0" 1662 | }, 1663 | "com.netflix.ribbon:ribbon-core": { 1664 | "firstLevelTransitive": [ 1665 | "com.netflix.zuul:zuul-core" 1666 | ], 1667 | "locked": "2.2.4" 1668 | }, 1669 | "com.netflix.ribbon:ribbon-eureka": { 1670 | "firstLevelTransitive": [ 1671 | "com.netflix.zuul:zuul-core" 1672 | ], 1673 | "locked": "2.2.4" 1674 | }, 1675 | "com.netflix.ribbon:ribbon-httpclient": { 1676 | "firstLevelTransitive": [ 1677 | "com.netflix.zuul:zuul-core" 1678 | ], 1679 | "locked": "2.2.4" 1680 | }, 1681 | "com.netflix.ribbon:ribbon-loadbalancer": { 1682 | "firstLevelTransitive": [ 1683 | "com.netflix.zuul:zuul-core" 1684 | ], 1685 | "locked": "2.2.4" 1686 | }, 1687 | "com.netflix.servo:servo-core": { 1688 | "firstLevelTransitive": [ 1689 | "com.netflix.zuul:zuul-core" 1690 | ], 1691 | "locked": "0.10.1" 1692 | }, 1693 | "com.netflix.spectator:spectator-api": { 1694 | "firstLevelTransitive": [ 1695 | "com.netflix.zuul:zuul-core" 1696 | ], 1697 | "locked": "0.59.0" 1698 | }, 1699 | "com.netflix.zuul:zuul-core": { 1700 | "project": true 1701 | }, 1702 | "commons-fileupload:commons-fileupload": { 1703 | "firstLevelTransitive": [ 1704 | "com.netflix.zuul:zuul-core" 1705 | ], 1706 | "locked": "1.3" 1707 | }, 1708 | "commons-io:commons-io": { 1709 | "firstLevelTransitive": [ 1710 | "com.netflix.zuul:zuul-core" 1711 | ], 1712 | "locked": "2.4" 1713 | }, 1714 | "io.netty:netty-buffer": { 1715 | "firstLevelTransitive": [ 1716 | "com.netflix.zuul:zuul-core" 1717 | ], 1718 | "locked": "4.1.21.Final" 1719 | }, 1720 | "io.netty:netty-codec-haproxy": { 1721 | "firstLevelTransitive": [ 1722 | "com.netflix.zuul:zuul-core" 1723 | ], 1724 | "locked": "4.1.21.Final" 1725 | }, 1726 | "io.netty:netty-codec-http": { 1727 | "firstLevelTransitive": [ 1728 | "com.netflix.zuul:zuul-core" 1729 | ], 1730 | "locked": "4.1.21.Final" 1731 | }, 1732 | "io.netty:netty-codec-http2": { 1733 | "firstLevelTransitive": [ 1734 | "com.netflix.zuul:zuul-core" 1735 | ], 1736 | "locked": "4.1.21.Final" 1737 | }, 1738 | "io.netty:netty-common": { 1739 | "firstLevelTransitive": [ 1740 | "com.netflix.zuul:zuul-core" 1741 | ], 1742 | "locked": "4.1.21.Final" 1743 | }, 1744 | "io.netty:netty-handler": { 1745 | "firstLevelTransitive": [ 1746 | "com.netflix.zuul:zuul-core" 1747 | ], 1748 | "locked": "4.1.21.Final" 1749 | }, 1750 | "io.netty:netty-resolver": { 1751 | "firstLevelTransitive": [ 1752 | "com.netflix.zuul:zuul-core" 1753 | ], 1754 | "locked": "4.1.21.Final" 1755 | }, 1756 | "io.netty:netty-tcnative-boringssl-static": { 1757 | "firstLevelTransitive": [ 1758 | "com.netflix.zuul:zuul-core" 1759 | ], 1760 | "locked": "2.0.7.Final" 1761 | }, 1762 | "io.netty:netty-transport": { 1763 | "firstLevelTransitive": [ 1764 | "com.netflix.zuul:zuul-core" 1765 | ], 1766 | "locked": "4.1.21.Final" 1767 | }, 1768 | "io.netty:netty-transport-native-epoll": { 1769 | "firstLevelTransitive": [ 1770 | "com.netflix.zuul:zuul-core" 1771 | ], 1772 | "locked": "4.1.21.Final" 1773 | }, 1774 | "io.reactivex:rxjava": { 1775 | "firstLevelTransitive": [ 1776 | "com.netflix.zuul:zuul-core" 1777 | ], 1778 | "locked": "1.2.1" 1779 | }, 1780 | "junit:junit": { 1781 | "firstLevelTransitive": [ 1782 | "com.netflix.zuul:zuul-core" 1783 | ], 1784 | "locked": "4.12" 1785 | }, 1786 | "org.apache.commons:commons-lang3": { 1787 | "firstLevelTransitive": [ 1788 | "com.netflix.zuul:zuul-core" 1789 | ], 1790 | "locked": "3.4" 1791 | }, 1792 | "org.bouncycastle:bcpg-jdk15on": { 1793 | "firstLevelTransitive": [ 1794 | "com.netflix.zuul:zuul-core" 1795 | ], 1796 | "locked": "1.59" 1797 | }, 1798 | "org.bouncycastle:bcprov-jdk15on": { 1799 | "firstLevelTransitive": [ 1800 | "com.netflix.zuul:zuul-core" 1801 | ], 1802 | "locked": "1.59" 1803 | }, 1804 | "org.codehaus.groovy:groovy-all": { 1805 | "firstLevelTransitive": [ 1806 | "com.netflix.zuul:zuul-core" 1807 | ], 1808 | "locked": "2.4.4" 1809 | }, 1810 | "org.json:json": { 1811 | "firstLevelTransitive": [ 1812 | "com.netflix.zuul:zuul-core" 1813 | ], 1814 | "locked": "20090211" 1815 | }, 1816 | "org.mockito:mockito-core": { 1817 | "firstLevelTransitive": [ 1818 | "com.netflix.zuul:zuul-core" 1819 | ], 1820 | "locked": "1.9.5" 1821 | }, 1822 | "org.slf4j:slf4j-api": { 1823 | "firstLevelTransitive": [ 1824 | "com.netflix.zuul:zuul-core" 1825 | ], 1826 | "locked": "1.7.25" 1827 | } 1828 | }, 1829 | "testRuntime": { 1830 | "com.google.inject.extensions:guice-assistedinject": { 1831 | "firstLevelTransitive": [ 1832 | "com.netflix.zuul:zuul-core" 1833 | ], 1834 | "locked": "4.1.0", 1835 | "requested": "4.0" 1836 | }, 1837 | "com.google.inject.extensions:guice-grapher": { 1838 | "firstLevelTransitive": [ 1839 | "com.netflix.zuul:zuul-core" 1840 | ], 1841 | "locked": "4.1.0", 1842 | "requested": "4.0" 1843 | }, 1844 | "com.google.inject.extensions:guice-multibindings": { 1845 | "firstLevelTransitive": [ 1846 | "com.netflix.zuul:zuul-core" 1847 | ], 1848 | "locked": "4.1.0", 1849 | "requested": "4.0" 1850 | }, 1851 | "com.google.inject.extensions:guice-servlet": { 1852 | "firstLevelTransitive": [ 1853 | "com.netflix.zuul:zuul-core" 1854 | ], 1855 | "locked": "4.0", 1856 | "requested": "4.0" 1857 | }, 1858 | "com.google.inject.extensions:guice-throwingproviders": { 1859 | "firstLevelTransitive": [ 1860 | "com.netflix.zuul:zuul-core" 1861 | ], 1862 | "locked": "4.0", 1863 | "requested": "4.0" 1864 | }, 1865 | "com.google.inject:guice": { 1866 | "firstLevelTransitive": [ 1867 | "com.netflix.zuul:zuul-core" 1868 | ], 1869 | "locked": "4.1.0", 1870 | "requested": "4.0" 1871 | }, 1872 | "com.netflix.archaius:archaius-core": { 1873 | "firstLevelTransitive": [ 1874 | "com.netflix.zuul:zuul-core" 1875 | ], 1876 | "locked": "0.7.5" 1877 | }, 1878 | "com.netflix.astyanax:astyanax-cassandra": { 1879 | "firstLevelTransitive": [ 1880 | "com.netflix.zuul:zuul-core" 1881 | ], 1882 | "locked": "1.56.48" 1883 | }, 1884 | "com.netflix.astyanax:astyanax-thrift": { 1885 | "firstLevelTransitive": [ 1886 | "com.netflix.zuul:zuul-core" 1887 | ], 1888 | "locked": "1.56.48" 1889 | }, 1890 | "com.netflix.blitz4j:blitz4j": { 1891 | "locked": "1.37.2", 1892 | "requested": "1.37.2" 1893 | }, 1894 | "com.netflix.eureka:eureka-client": { 1895 | "firstLevelTransitive": [ 1896 | "com.netflix.zuul:zuul-core" 1897 | ], 1898 | "locked": "1.8.6" 1899 | }, 1900 | "com.netflix.governator:governator": { 1901 | "firstLevelTransitive": [ 1902 | "com.netflix.zuul:zuul-core" 1903 | ], 1904 | "locked": "1.17.4" 1905 | }, 1906 | "com.netflix.governator:governator-archaius": { 1907 | "firstLevelTransitive": [ 1908 | "com.netflix.zuul:zuul-core" 1909 | ], 1910 | "locked": "1.17.4" 1911 | }, 1912 | "com.netflix.hystrix:hystrix-core": { 1913 | "firstLevelTransitive": [ 1914 | "com.netflix.zuul:zuul-core" 1915 | ], 1916 | "locked": "1.4.26" 1917 | }, 1918 | "com.netflix.netflix-commons:netflix-commons-util": { 1919 | "firstLevelTransitive": [ 1920 | "com.netflix.zuul:zuul-core" 1921 | ], 1922 | "locked": "0.3.0" 1923 | }, 1924 | "com.netflix.ribbon:ribbon-core": { 1925 | "firstLevelTransitive": [ 1926 | "com.netflix.zuul:zuul-core" 1927 | ], 1928 | "locked": "2.2.4" 1929 | }, 1930 | "com.netflix.ribbon:ribbon-eureka": { 1931 | "firstLevelTransitive": [ 1932 | "com.netflix.zuul:zuul-core" 1933 | ], 1934 | "locked": "2.2.4" 1935 | }, 1936 | "com.netflix.ribbon:ribbon-httpclient": { 1937 | "firstLevelTransitive": [ 1938 | "com.netflix.zuul:zuul-core" 1939 | ], 1940 | "locked": "2.2.4" 1941 | }, 1942 | "com.netflix.ribbon:ribbon-loadbalancer": { 1943 | "firstLevelTransitive": [ 1944 | "com.netflix.zuul:zuul-core" 1945 | ], 1946 | "locked": "2.2.4" 1947 | }, 1948 | "com.netflix.servo:servo-core": { 1949 | "firstLevelTransitive": [ 1950 | "com.netflix.zuul:zuul-core" 1951 | ], 1952 | "locked": "0.10.1" 1953 | }, 1954 | "com.netflix.spectator:spectator-api": { 1955 | "firstLevelTransitive": [ 1956 | "com.netflix.zuul:zuul-core" 1957 | ], 1958 | "locked": "0.59.0" 1959 | }, 1960 | "com.netflix.zuul:zuul-core": { 1961 | "project": true 1962 | }, 1963 | "commons-fileupload:commons-fileupload": { 1964 | "firstLevelTransitive": [ 1965 | "com.netflix.zuul:zuul-core" 1966 | ], 1967 | "locked": "1.3" 1968 | }, 1969 | "commons-io:commons-io": { 1970 | "firstLevelTransitive": [ 1971 | "com.netflix.zuul:zuul-core" 1972 | ], 1973 | "locked": "2.4" 1974 | }, 1975 | "io.netty:netty-buffer": { 1976 | "firstLevelTransitive": [ 1977 | "com.netflix.zuul:zuul-core" 1978 | ], 1979 | "locked": "4.1.21.Final" 1980 | }, 1981 | "io.netty:netty-codec-haproxy": { 1982 | "firstLevelTransitive": [ 1983 | "com.netflix.zuul:zuul-core" 1984 | ], 1985 | "locked": "4.1.21.Final" 1986 | }, 1987 | "io.netty:netty-codec-http": { 1988 | "firstLevelTransitive": [ 1989 | "com.netflix.zuul:zuul-core" 1990 | ], 1991 | "locked": "4.1.21.Final" 1992 | }, 1993 | "io.netty:netty-codec-http2": { 1994 | "firstLevelTransitive": [ 1995 | "com.netflix.zuul:zuul-core" 1996 | ], 1997 | "locked": "4.1.21.Final" 1998 | }, 1999 | "io.netty:netty-common": { 2000 | "firstLevelTransitive": [ 2001 | "com.netflix.zuul:zuul-core" 2002 | ], 2003 | "locked": "4.1.21.Final" 2004 | }, 2005 | "io.netty:netty-handler": { 2006 | "firstLevelTransitive": [ 2007 | "com.netflix.zuul:zuul-core" 2008 | ], 2009 | "locked": "4.1.21.Final" 2010 | }, 2011 | "io.netty:netty-resolver": { 2012 | "firstLevelTransitive": [ 2013 | "com.netflix.zuul:zuul-core" 2014 | ], 2015 | "locked": "4.1.21.Final" 2016 | }, 2017 | "io.netty:netty-tcnative-boringssl-static": { 2018 | "firstLevelTransitive": [ 2019 | "com.netflix.zuul:zuul-core" 2020 | ], 2021 | "locked": "2.0.7.Final" 2022 | }, 2023 | "io.netty:netty-transport": { 2024 | "firstLevelTransitive": [ 2025 | "com.netflix.zuul:zuul-core" 2026 | ], 2027 | "locked": "4.1.21.Final" 2028 | }, 2029 | "io.netty:netty-transport-native-epoll": { 2030 | "firstLevelTransitive": [ 2031 | "com.netflix.zuul:zuul-core" 2032 | ], 2033 | "locked": "4.1.21.Final" 2034 | }, 2035 | "io.reactivex:rxjava": { 2036 | "firstLevelTransitive": [ 2037 | "com.netflix.zuul:zuul-core" 2038 | ], 2039 | "locked": "1.2.1" 2040 | }, 2041 | "junit:junit": { 2042 | "firstLevelTransitive": [ 2043 | "com.netflix.zuul:zuul-core" 2044 | ], 2045 | "locked": "4.12" 2046 | }, 2047 | "org.apache.commons:commons-lang3": { 2048 | "firstLevelTransitive": [ 2049 | "com.netflix.zuul:zuul-core" 2050 | ], 2051 | "locked": "3.4" 2052 | }, 2053 | "org.bouncycastle:bcpg-jdk15on": { 2054 | "firstLevelTransitive": [ 2055 | "com.netflix.zuul:zuul-core" 2056 | ], 2057 | "locked": "1.59" 2058 | }, 2059 | "org.bouncycastle:bcprov-jdk15on": { 2060 | "firstLevelTransitive": [ 2061 | "com.netflix.zuul:zuul-core" 2062 | ], 2063 | "locked": "1.59" 2064 | }, 2065 | "org.codehaus.groovy:groovy-all": { 2066 | "firstLevelTransitive": [ 2067 | "com.netflix.zuul:zuul-core" 2068 | ], 2069 | "locked": "2.4.4" 2070 | }, 2071 | "org.json:json": { 2072 | "firstLevelTransitive": [ 2073 | "com.netflix.zuul:zuul-core" 2074 | ], 2075 | "locked": "20090211" 2076 | }, 2077 | "org.mockito:mockito-core": { 2078 | "firstLevelTransitive": [ 2079 | "com.netflix.zuul:zuul-core" 2080 | ], 2081 | "locked": "1.9.5" 2082 | }, 2083 | "org.slf4j:slf4j-api": { 2084 | "firstLevelTransitive": [ 2085 | "com.netflix.zuul:zuul-core" 2086 | ], 2087 | "locked": "1.7.25" 2088 | } 2089 | }, 2090 | "testRuntimeClasspath": { 2091 | "com.google.inject.extensions:guice-assistedinject": { 2092 | "firstLevelTransitive": [ 2093 | "com.netflix.zuul:zuul-core" 2094 | ], 2095 | "locked": "4.1.0", 2096 | "requested": "4.0" 2097 | }, 2098 | "com.google.inject.extensions:guice-grapher": { 2099 | "firstLevelTransitive": [ 2100 | "com.netflix.zuul:zuul-core" 2101 | ], 2102 | "locked": "4.1.0", 2103 | "requested": "4.0" 2104 | }, 2105 | "com.google.inject.extensions:guice-multibindings": { 2106 | "firstLevelTransitive": [ 2107 | "com.netflix.zuul:zuul-core" 2108 | ], 2109 | "locked": "4.1.0", 2110 | "requested": "4.0" 2111 | }, 2112 | "com.google.inject.extensions:guice-servlet": { 2113 | "firstLevelTransitive": [ 2114 | "com.netflix.zuul:zuul-core" 2115 | ], 2116 | "locked": "4.0", 2117 | "requested": "4.0" 2118 | }, 2119 | "com.google.inject.extensions:guice-throwingproviders": { 2120 | "firstLevelTransitive": [ 2121 | "com.netflix.zuul:zuul-core" 2122 | ], 2123 | "locked": "4.0", 2124 | "requested": "4.0" 2125 | }, 2126 | "com.google.inject:guice": { 2127 | "firstLevelTransitive": [ 2128 | "com.netflix.zuul:zuul-core" 2129 | ], 2130 | "locked": "4.1.0", 2131 | "requested": "4.0" 2132 | }, 2133 | "com.netflix.archaius:archaius-core": { 2134 | "firstLevelTransitive": [ 2135 | "com.netflix.zuul:zuul-core" 2136 | ], 2137 | "locked": "0.7.5" 2138 | }, 2139 | "com.netflix.astyanax:astyanax-cassandra": { 2140 | "firstLevelTransitive": [ 2141 | "com.netflix.zuul:zuul-core" 2142 | ], 2143 | "locked": "1.56.48" 2144 | }, 2145 | "com.netflix.astyanax:astyanax-thrift": { 2146 | "firstLevelTransitive": [ 2147 | "com.netflix.zuul:zuul-core" 2148 | ], 2149 | "locked": "1.56.48" 2150 | }, 2151 | "com.netflix.blitz4j:blitz4j": { 2152 | "locked": "1.37.2", 2153 | "requested": "1.37.2" 2154 | }, 2155 | "com.netflix.eureka:eureka-client": { 2156 | "firstLevelTransitive": [ 2157 | "com.netflix.zuul:zuul-core" 2158 | ], 2159 | "locked": "1.8.6" 2160 | }, 2161 | "com.netflix.governator:governator": { 2162 | "firstLevelTransitive": [ 2163 | "com.netflix.zuul:zuul-core" 2164 | ], 2165 | "locked": "1.17.4" 2166 | }, 2167 | "com.netflix.governator:governator-archaius": { 2168 | "firstLevelTransitive": [ 2169 | "com.netflix.zuul:zuul-core" 2170 | ], 2171 | "locked": "1.17.4" 2172 | }, 2173 | "com.netflix.hystrix:hystrix-core": { 2174 | "firstLevelTransitive": [ 2175 | "com.netflix.zuul:zuul-core" 2176 | ], 2177 | "locked": "1.4.26" 2178 | }, 2179 | "com.netflix.netflix-commons:netflix-commons-util": { 2180 | "firstLevelTransitive": [ 2181 | "com.netflix.zuul:zuul-core" 2182 | ], 2183 | "locked": "0.3.0" 2184 | }, 2185 | "com.netflix.ribbon:ribbon-core": { 2186 | "firstLevelTransitive": [ 2187 | "com.netflix.zuul:zuul-core" 2188 | ], 2189 | "locked": "2.2.4" 2190 | }, 2191 | "com.netflix.ribbon:ribbon-eureka": { 2192 | "firstLevelTransitive": [ 2193 | "com.netflix.zuul:zuul-core" 2194 | ], 2195 | "locked": "2.2.4" 2196 | }, 2197 | "com.netflix.ribbon:ribbon-httpclient": { 2198 | "firstLevelTransitive": [ 2199 | "com.netflix.zuul:zuul-core" 2200 | ], 2201 | "locked": "2.2.4" 2202 | }, 2203 | "com.netflix.ribbon:ribbon-loadbalancer": { 2204 | "firstLevelTransitive": [ 2205 | "com.netflix.zuul:zuul-core" 2206 | ], 2207 | "locked": "2.2.4" 2208 | }, 2209 | "com.netflix.servo:servo-core": { 2210 | "firstLevelTransitive": [ 2211 | "com.netflix.zuul:zuul-core" 2212 | ], 2213 | "locked": "0.10.1" 2214 | }, 2215 | "com.netflix.spectator:spectator-api": { 2216 | "firstLevelTransitive": [ 2217 | "com.netflix.zuul:zuul-core" 2218 | ], 2219 | "locked": "0.59.0" 2220 | }, 2221 | "com.netflix.zuul:zuul-core": { 2222 | "project": true 2223 | }, 2224 | "commons-fileupload:commons-fileupload": { 2225 | "firstLevelTransitive": [ 2226 | "com.netflix.zuul:zuul-core" 2227 | ], 2228 | "locked": "1.3" 2229 | }, 2230 | "commons-io:commons-io": { 2231 | "firstLevelTransitive": [ 2232 | "com.netflix.zuul:zuul-core" 2233 | ], 2234 | "locked": "2.4" 2235 | }, 2236 | "io.netty:netty-buffer": { 2237 | "firstLevelTransitive": [ 2238 | "com.netflix.zuul:zuul-core" 2239 | ], 2240 | "locked": "4.1.21.Final" 2241 | }, 2242 | "io.netty:netty-codec-haproxy": { 2243 | "firstLevelTransitive": [ 2244 | "com.netflix.zuul:zuul-core" 2245 | ], 2246 | "locked": "4.1.21.Final" 2247 | }, 2248 | "io.netty:netty-codec-http": { 2249 | "firstLevelTransitive": [ 2250 | "com.netflix.zuul:zuul-core" 2251 | ], 2252 | "locked": "4.1.21.Final" 2253 | }, 2254 | "io.netty:netty-codec-http2": { 2255 | "firstLevelTransitive": [ 2256 | "com.netflix.zuul:zuul-core" 2257 | ], 2258 | "locked": "4.1.21.Final" 2259 | }, 2260 | "io.netty:netty-common": { 2261 | "firstLevelTransitive": [ 2262 | "com.netflix.zuul:zuul-core" 2263 | ], 2264 | "locked": "4.1.21.Final" 2265 | }, 2266 | "io.netty:netty-handler": { 2267 | "firstLevelTransitive": [ 2268 | "com.netflix.zuul:zuul-core" 2269 | ], 2270 | "locked": "4.1.21.Final" 2271 | }, 2272 | "io.netty:netty-resolver": { 2273 | "firstLevelTransitive": [ 2274 | "com.netflix.zuul:zuul-core" 2275 | ], 2276 | "locked": "4.1.21.Final" 2277 | }, 2278 | "io.netty:netty-tcnative-boringssl-static": { 2279 | "firstLevelTransitive": [ 2280 | "com.netflix.zuul:zuul-core" 2281 | ], 2282 | "locked": "2.0.7.Final" 2283 | }, 2284 | "io.netty:netty-transport": { 2285 | "firstLevelTransitive": [ 2286 | "com.netflix.zuul:zuul-core" 2287 | ], 2288 | "locked": "4.1.21.Final" 2289 | }, 2290 | "io.netty:netty-transport-native-epoll": { 2291 | "firstLevelTransitive": [ 2292 | "com.netflix.zuul:zuul-core" 2293 | ], 2294 | "locked": "4.1.21.Final" 2295 | }, 2296 | "io.reactivex:rxjava": { 2297 | "firstLevelTransitive": [ 2298 | "com.netflix.zuul:zuul-core" 2299 | ], 2300 | "locked": "1.2.1" 2301 | }, 2302 | "junit:junit": { 2303 | "firstLevelTransitive": [ 2304 | "com.netflix.zuul:zuul-core" 2305 | ], 2306 | "locked": "4.12" 2307 | }, 2308 | "org.apache.commons:commons-lang3": { 2309 | "firstLevelTransitive": [ 2310 | "com.netflix.zuul:zuul-core" 2311 | ], 2312 | "locked": "3.4" 2313 | }, 2314 | "org.bouncycastle:bcpg-jdk15on": { 2315 | "firstLevelTransitive": [ 2316 | "com.netflix.zuul:zuul-core" 2317 | ], 2318 | "locked": "1.59" 2319 | }, 2320 | "org.bouncycastle:bcprov-jdk15on": { 2321 | "firstLevelTransitive": [ 2322 | "com.netflix.zuul:zuul-core" 2323 | ], 2324 | "locked": "1.59" 2325 | }, 2326 | "org.codehaus.groovy:groovy-all": { 2327 | "firstLevelTransitive": [ 2328 | "com.netflix.zuul:zuul-core" 2329 | ], 2330 | "locked": "2.4.4" 2331 | }, 2332 | "org.json:json": { 2333 | "firstLevelTransitive": [ 2334 | "com.netflix.zuul:zuul-core" 2335 | ], 2336 | "locked": "20090211" 2337 | }, 2338 | "org.mockito:mockito-core": { 2339 | "firstLevelTransitive": [ 2340 | "com.netflix.zuul:zuul-core" 2341 | ], 2342 | "locked": "1.9.5" 2343 | }, 2344 | "org.slf4j:slf4j-api": { 2345 | "firstLevelTransitive": [ 2346 | "com.netflix.zuul:zuul-core" 2347 | ], 2348 | "locked": "1.7.25" 2349 | } 2350 | } 2351 | } -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/Bootstrap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Netflix, Inc. 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 com.netflix.zuul.sample; 18 | 19 | import com.google.inject.Injector; 20 | import com.netflix.config.ConfigurationManager; 21 | import com.netflix.governator.InjectorBuilder; 22 | import com.netflix.zuul.netty.server.BaseServerStartup; 23 | import com.netflix.zuul.netty.server.Server; 24 | 25 | /** 26 | * Bootstrap 27 | * 28 | * Author: Arthur Gonigberg 29 | * Date: November 20, 2017 30 | */ 31 | public class Bootstrap { 32 | 33 | public static void main(String[] args) { 34 | new Bootstrap().start(); 35 | } 36 | 37 | 38 | public void start() { 39 | System.out.println("Zuul Sample: starting up."); 40 | long startTime = System.currentTimeMillis(); 41 | int exitCode = 0; 42 | 43 | Server server = null; 44 | 45 | try { 46 | ConfigurationManager.loadCascadedPropertiesFromResources("application"); 47 | Injector injector = InjectorBuilder.fromModule(new ZuulSampleModule()).createInjector(); 48 | injector.getInstance(FiltersRegisteringService.class); 49 | BaseServerStartup serverStartup = injector.getInstance(BaseServerStartup.class); 50 | server = serverStartup.server(); 51 | 52 | long startupDuration = System.currentTimeMillis() - startTime; 53 | System.out.println("Zuul Sample: finished startup. Duration = " + startupDuration + " ms"); 54 | 55 | server.start(true); 56 | } 57 | catch (Throwable t) { 58 | t.printStackTrace(); 59 | System.err.println("###############"); 60 | System.err.println("Zuul Sample: initialization failed. Forcing shutdown now."); 61 | System.err.println("###############"); 62 | exitCode = 1; 63 | } 64 | finally { 65 | // server shutdown 66 | if (server != null) server.stop(); 67 | 68 | System.exit(exitCode); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/FiltersRegisteringService.java: -------------------------------------------------------------------------------- 1 | package com.netflix.zuul.sample; 2 | 3 | import com.netflix.zuul.filters.FilterRegistry; 4 | import com.netflix.zuul.filters.ZuulFilter; 5 | 6 | import javax.annotation.PostConstruct; 7 | import javax.inject.Inject; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | public class FiltersRegisteringService { 13 | 14 | private final List filters; 15 | private final FilterRegistry filterRegistry; 16 | 17 | @Inject 18 | public FiltersRegisteringService(FilterRegistry filterRegistry, Set filters) { 19 | this.filters = new ArrayList<>(filters); 20 | this.filterRegistry = filterRegistry; 21 | } 22 | 23 | public List getFilters() { 24 | return filters; 25 | } 26 | 27 | @PostConstruct 28 | public void initialize() { 29 | for (ZuulFilter filter: filters) { 30 | this.filterRegistry.put(filter.filterName(), filter); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/SampleServerStartup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Netflix, Inc. 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 com.netflix.zuul.sample; 18 | 19 | import com.netflix.appinfo.ApplicationInfoManager; 20 | import com.netflix.config.DynamicIntProperty; 21 | import com.netflix.discovery.EurekaClient; 22 | import com.netflix.netty.common.accesslog.AccessLogPublisher; 23 | import com.netflix.netty.common.channel.config.ChannelConfig; 24 | import com.netflix.netty.common.channel.config.CommonChannelConfigKeys; 25 | import com.netflix.netty.common.metrics.EventLoopGroupMetrics; 26 | import com.netflix.netty.common.proxyprotocol.StripUntrustedProxyHeadersHandler; 27 | import com.netflix.netty.common.ssl.ServerSslConfig; 28 | import com.netflix.netty.common.status.ServerStatusManager; 29 | import com.netflix.spectator.api.Registry; 30 | import com.netflix.zuul.FilterLoader; 31 | import com.netflix.zuul.FilterUsageNotifier; 32 | import com.netflix.zuul.RequestCompleteHandler; 33 | import com.netflix.zuul.context.SessionContextDecorator; 34 | import com.netflix.zuul.netty.server.BaseServerStartup; 35 | import com.netflix.zuul.netty.server.DirectMemoryMonitor; 36 | import com.netflix.zuul.netty.server.Http1MutualSslChannelInitializer; 37 | import com.netflix.zuul.netty.server.ZuulServerChannelInitializer; 38 | import com.netflix.zuul.netty.server.http2.Http2SslChannelInitializer; 39 | import com.netflix.zuul.netty.ssl.BaseSslContextFactory; 40 | import io.netty.channel.ChannelInitializer; 41 | import io.netty.channel.group.ChannelGroup; 42 | import io.netty.handler.ssl.ClientAuth; 43 | 44 | import javax.inject.Inject; 45 | import javax.inject.Singleton; 46 | import java.io.File; 47 | import java.util.HashMap; 48 | import java.util.Map; 49 | 50 | /** 51 | * Sample Server Startup - class that configures the Netty server startup settings 52 | * 53 | * Author: Arthur Gonigberg 54 | * Date: November 20, 2017 55 | */ 56 | @Singleton 57 | public class SampleServerStartup extends BaseServerStartup { 58 | 59 | enum ServerType { 60 | HTTP, 61 | HTTP2, 62 | HTTP_MUTUAL_TLS, 63 | } 64 | 65 | private static final String[] WWW_PROTOCOLS = new String[]{"TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"}; 66 | private static final ServerType SERVER_TYPE = ServerType.HTTP; 67 | 68 | @Inject 69 | public SampleServerStartup(ServerStatusManager serverStatusManager, FilterLoader filterLoader, 70 | SessionContextDecorator sessionCtxDecorator, FilterUsageNotifier usageNotifier, 71 | RequestCompleteHandler reqCompleteHandler, Registry registry, 72 | DirectMemoryMonitor directMemoryMonitor, EventLoopGroupMetrics eventLoopGroupMetrics, 73 | EurekaClient discoveryClient, ApplicationInfoManager applicationInfoManager, 74 | AccessLogPublisher accessLogPublisher) { 75 | super(serverStatusManager, filterLoader, sessionCtxDecorator, usageNotifier, reqCompleteHandler, registry, 76 | directMemoryMonitor, eventLoopGroupMetrics, discoveryClient, applicationInfoManager, accessLogPublisher); 77 | } 78 | 79 | @Override 80 | protected Map choosePortsAndChannels( 81 | ChannelGroup clientChannels, 82 | ChannelConfig channelDependencies) { 83 | Map portsToChannels = new HashMap<>(); 84 | 85 | int port = new DynamicIntProperty("zuul.server.port.main", 8085).get(); 86 | 87 | ChannelConfig channelConfig = BaseServerStartup.defaultChannelConfig(); 88 | ServerSslConfig sslConfig; 89 | /* These settings may need to be tweaked depending if you're running behind an ELB HTTP listener, TCP listener, 90 | * or directly on the internet. 91 | */ 92 | switch (SERVER_TYPE) { 93 | /* The below settings can be used when running behind an ELB HTTP listener that terminates SSL for you 94 | * and passes XFF headers. 95 | */ 96 | case HTTP: 97 | channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.ALWAYS); 98 | channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, false); 99 | channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false); 100 | channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, false); 101 | 102 | portsToChannels.put(port, new ZuulServerChannelInitializer(port, channelConfig, channelDependencies, clientChannels)); 103 | logPortConfigured(port, null); 104 | break; 105 | 106 | /* The below settings can be used when running behind an ELB TCP listener with proxy protocol, terminating 107 | * SSL in Zuul. 108 | */ 109 | case HTTP2: 110 | sslConfig = ServerSslConfig.withDefaultCiphers( 111 | loadFromResources("server.cert"), 112 | loadFromResources("server.key"), 113 | WWW_PROTOCOLS); 114 | 115 | channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER); 116 | channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true); 117 | channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false); 118 | channelConfig.set(CommonChannelConfigKeys.serverSslConfig, sslConfig); 119 | channelConfig.set(CommonChannelConfigKeys.sslContextFactory, new BaseSslContextFactory(registry, sslConfig)); 120 | 121 | addHttp2DefaultConfig(channelConfig); 122 | 123 | portsToChannels.put(port, new Http2SslChannelInitializer(port, channelConfig, channelDependencies, clientChannels)); 124 | logPortConfigured(port, sslConfig); 125 | break; 126 | 127 | /* The below settings can be used when running behind an ELB TCP listener with proxy protocol, terminating 128 | * SSL in Zuul. 129 | * 130 | * Can be tested using certs in resources directory: 131 | * curl https://localhost:7001/test -vk --cert src/main/resources/ssl/client.cert:zuul123 --key src/main/resources/ssl/client.key 132 | */ 133 | case HTTP_MUTUAL_TLS: 134 | sslConfig = new ServerSslConfig( 135 | WWW_PROTOCOLS, 136 | ServerSslConfig.getDefaultCiphers(), 137 | loadFromResources("server.cert"), 138 | loadFromResources("server.key"), 139 | null, 140 | ClientAuth.REQUIRE, 141 | loadFromResources("truststore.jks"), 142 | loadFromResources("truststore.key"), 143 | false); 144 | 145 | channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER); 146 | channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true); 147 | channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false); 148 | channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, true); 149 | channelConfig.set(CommonChannelConfigKeys.serverSslConfig, sslConfig); 150 | channelConfig.set(CommonChannelConfigKeys.sslContextFactory, new BaseSslContextFactory(registry, sslConfig)); 151 | 152 | portsToChannels.put(port, new Http1MutualSslChannelInitializer(port, channelConfig, channelDependencies, clientChannels)); 153 | logPortConfigured(port, sslConfig); 154 | break; 155 | } 156 | 157 | return portsToChannels; 158 | } 159 | 160 | private File loadFromResources(String s) { 161 | return new File(ClassLoader.getSystemResource("ssl/" + s).getFile()); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/ZuulClasspathFiltersModule.java: -------------------------------------------------------------------------------- 1 | package com.netflix.zuul.sample; 2 | 3 | import com.google.inject.AbstractModule; 4 | import com.google.inject.multibindings.Multibinder; 5 | import com.netflix.zuul.BasicFilterUsageNotifier; 6 | import com.netflix.zuul.DynamicCodeCompiler; 7 | import com.netflix.zuul.FilterFactory; 8 | import com.netflix.zuul.FilterUsageNotifier; 9 | import com.netflix.zuul.filters.ZuulFilter; 10 | import com.netflix.zuul.groovy.GroovyCompiler; 11 | import com.netflix.zuul.guice.GuiceFilterFactory; 12 | import com.netflix.zuul.sample.filters.inbound.Routes; 13 | import com.netflix.zuul.sample.filters.inbound.StripPrefixFilter; 14 | 15 | import java.util.Arrays; 16 | 17 | 18 | public class ZuulClasspathFiltersModule extends AbstractModule { 19 | @Override 20 | protected void configure() { 21 | bind(DynamicCodeCompiler.class).to(GroovyCompiler.class); 22 | bind(FilterFactory.class).to(GuiceFilterFactory.class); 23 | 24 | bind(FilterUsageNotifier.class).to(BasicFilterUsageNotifier.class); 25 | 26 | Multibinder filterMultibinder = Multibinder.newSetBinder(binder(), ZuulFilter.class); 27 | filterMultibinder.addBinding().to(Routes.class); 28 | filterMultibinder.addBinding().toInstance( 29 | new StripPrefixFilter(Arrays.asList("/passthrough/.*"))); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/ZuulSampleModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Netflix, Inc. 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 com.netflix.zuul.sample; 18 | 19 | import com.google.inject.AbstractModule; 20 | import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; 21 | import com.netflix.discovery.DiscoveryClient; 22 | import com.netflix.netty.common.accesslog.AccessLogPublisher; 23 | import com.netflix.netty.common.status.ServerStatusManager; 24 | import com.netflix.spectator.api.DefaultRegistry; 25 | import com.netflix.spectator.api.Registry; 26 | import com.netflix.zuul.BasicRequestCompleteHandler; 27 | import com.netflix.zuul.FilterFileManager; 28 | import com.netflix.zuul.RequestCompleteHandler; 29 | import com.netflix.zuul.context.SessionContextDecorator; 30 | import com.netflix.zuul.context.ZuulSessionContextDecorator; 31 | import com.netflix.zuul.init.ZuulFiltersModule; 32 | import com.netflix.zuul.netty.server.BaseServerStartup; 33 | import com.netflix.zuul.netty.server.ClientRequestReceiver; 34 | import com.netflix.zuul.origins.BasicNettyOriginManager; 35 | import com.netflix.zuul.origins.OriginManager; 36 | import com.netflix.zuul.stats.BasicRequestMetricsPublisher; 37 | import com.netflix.zuul.stats.RequestMetricsPublisher; 38 | 39 | /** 40 | * Zuul Sample Module 41 | * 42 | * Author: Arthur Gonigberg 43 | * Date: November 20, 2017 44 | */ 45 | public class ZuulSampleModule extends AbstractModule { 46 | @Override 47 | protected void configure() { 48 | // sample specific bindings 49 | bind(BaseServerStartup.class).to(SampleServerStartup.class); 50 | 51 | // use provided basic netty origin manager 52 | bind(OriginManager.class).to(BasicNettyOriginManager.class); 53 | 54 | // zuul filter loading 55 | // install(new ZuulFiltersModule()); 56 | // bind(FilterFileManager.class).asEagerSingleton(); 57 | 58 | install(new ZuulClasspathFiltersModule()); 59 | // general server bindings 60 | bind(ServerStatusManager.class); // health/discovery status 61 | bind(SessionContextDecorator.class).to(ZuulSessionContextDecorator.class); // decorate new sessions when requests come in 62 | bind(Registry.class).to(DefaultRegistry.class); // atlas metrics registry 63 | bind(RequestCompleteHandler.class).to(BasicRequestCompleteHandler.class); // metrics post-request completion 64 | bind(AbstractDiscoveryClientOptionalArgs.class).to(DiscoveryClient.DiscoveryClientOptionalArgs.class); // discovery client 65 | bind(RequestMetricsPublisher.class).to(BasicRequestMetricsPublisher.class); // timings publisher 66 | 67 | // access logger, including request ID generator 68 | bind(AccessLogPublisher.class).toInstance(new AccessLogPublisher("ACCESS", 69 | (channel, httpRequest) -> ClientRequestReceiver.getRequestFromChannel(channel).getContext().getUUID())); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/filters/inbound/Routes.java: -------------------------------------------------------------------------------- 1 | package com.netflix.zuul.sample.filters.inbound; 2 | 3 | import com.netflix.zuul.context.SessionContext; 4 | import com.netflix.zuul.filters.http.HttpInboundSyncFilter; 5 | import com.netflix.zuul.message.http.HttpRequestMessage; 6 | import com.netflix.zuul.netty.filter.ZuulEndPointRunner; 7 | 8 | public class Routes extends HttpInboundSyncFilter { 9 | @Override 10 | public int filterOrder() { 11 | return 0; 12 | } 13 | 14 | @Override 15 | public boolean shouldFilter(HttpRequestMessage httpRequestMessage) { 16 | return true; 17 | } 18 | 19 | @Override 20 | public HttpRequestMessage apply(HttpRequestMessage request) { 21 | SessionContext context = request.getContext(); 22 | context.setEndpoint(ZuulEndPointRunner.PROXY_ENDPOINT_FILTER_NAME); 23 | context.setRouteVIP("api"); 24 | return request; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/java/com/netflix/zuul/sample/filters/inbound/StripPrefixFilter.java: -------------------------------------------------------------------------------- 1 | package com.netflix.zuul.sample.filters.inbound; 2 | 3 | import com.netflix.zuul.context.SessionContext; 4 | import com.netflix.zuul.filters.http.HttpInboundSyncFilter; 5 | import com.netflix.zuul.message.http.HttpRequestMessage; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | public class StripPrefixFilter extends HttpInboundSyncFilter { 12 | private final List prefixPatterns; 13 | 14 | public StripPrefixFilter(List prefixPatterns) { 15 | this.prefixPatterns = prefixPatterns; 16 | } 17 | 18 | @Override 19 | public HttpRequestMessage apply(HttpRequestMessage input) { 20 | SessionContext context = input.getContext(); 21 | String path = input.getPath(); 22 | String[] parts = path.split("/"); 23 | if (parts.length > 0) { 24 | String targetPath = Arrays.stream(parts) 25 | .skip(1).collect(Collectors.joining("/")); 26 | context.set("overrideURI", targetPath); 27 | } 28 | return input; 29 | } 30 | 31 | @Override 32 | public int filterOrder() { 33 | return 501; 34 | } 35 | 36 | @Override 37 | public boolean shouldFilter(HttpRequestMessage msg) { 38 | for (String target: prefixPatterns) { 39 | if (msg.getPath().matches(target)) { 40 | return true; 41 | } 42 | } 43 | return false; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | ### Instance env settings 2 | 3 | region=us-east-1 4 | environment=test 5 | 6 | ### Eureka instance registration for this app 7 | 8 | #Name of the application to be identified by other services 9 | eureka.name=zuul 10 | 11 | #The port where the service will be running and serving requests 12 | eureka.port=7001 13 | 14 | #Virtual host name by which the clients identifies this service 15 | eureka.vipAddress=${eureka.name}:${eureka.port} 16 | 17 | #For eureka clients running in eureka server, it needs to connect to servers in other zones 18 | eureka.preferSameZone=false 19 | 20 | # Don't register locally running instances. 21 | eureka.registration.enabled=false 22 | 23 | 24 | # Loading Filters 25 | zuul.filters.root=src/main/groovy/com/netflix/zuul/sample/filters 26 | zuul.filters.locations=${zuul.filters.root}/inbound,${zuul.filters.root}/outbound,${zuul.filters.root}/endpoint 27 | zuul.filters.packages=com.netflix.zuul.filters.common 28 | 29 | 30 | ### Load balancing backends with Eureka 31 | 32 | #eureka.shouldUseDns=true 33 | #eureka.eurekaServer.context=discovery/v2 34 | #eureka.eurekaServer.domainName=discovery${environment}.netflix.net 35 | #eureka.eurekaServer.gzipContent=true 36 | # 37 | #eureka.serviceUrl.default=http://${region}.${eureka.eurekaServer.domainName}:7001/${eureka.eurekaServer.context} 38 | #api.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 39 | #api.ribbon.DeploymentContextBasedVipAddresses=api-test.netflix.net:7001 40 | 41 | 42 | ### Load balancing backends without Eureka 43 | eureka.shouldFetchRegistry=false 44 | eureka.validateInstanceId=false 45 | 46 | api.ribbon.listOfServers=localhost:8080 47 | api.ribbon.client.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList 48 | api.ribbon.MaxConnectionsPerHost=-1 49 | zuul.origin.api.concurrency.protect.enabled=false 50 | zuul.server.netty.threads.acceptor=5 51 | zuul.server.netty.threads.worker=8 52 | 53 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 Netflix, Inc. 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 | log4j.rootLogger=INFO,stdout 18 | 19 | # raise above INFO to disable access logger 20 | log4j.logger.ACCESS=WARN 21 | 22 | # can be set to INFO for netty wire logging 23 | log4j.logger.zuul.server.nettylog=WARN 24 | log4j.logger.zuul.origin.nettylog=WARN 25 | 26 | log4j.logger.com.netflix.loadbalancer=WARN 27 | log4j.logger.com.netflix.config=WARN 28 | 29 | # stdout 30 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 31 | log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c [%t] %m%n 32 | 33 | # filter out repeating lines for Rx 34 | log4j.appender.stdout.layout=com.netflix.zuul.logging.FilteredPatternLayout 35 | log4j.appender.stdout.layout.Filters=rx.Observable,rx.internal,rx.Subscriber 36 | 37 | # async appender 38 | batcher.com.netflix.logging.AsyncAppender.stdout.waitTimeinMillis=120000 39 | log4j.logger.asyncAppenders=INFO,stdout 40 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/test/java/com/netflix/zuul/sample/filters/FiltersRegisteringServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.netflix.zuul.sample.filters; 2 | 3 | import com.google.inject.Injector; 4 | import com.netflix.governator.InjectorBuilder; 5 | import com.netflix.zuul.filters.ZuulFilter; 6 | import com.netflix.zuul.sample.FiltersRegisteringService; 7 | import com.netflix.zuul.sample.ZuulClasspathFiltersModule; 8 | import org.junit.Test; 9 | 10 | import java.util.List; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | public class FiltersRegisteringServiceTest { 15 | 16 | @Test 17 | public void testFiltersLoading() { 18 | Injector injector = InjectorBuilder.fromModule(new ZuulClasspathFiltersModule()).createInjector(); 19 | 20 | FiltersRegisteringService service = injector.getInstance(FiltersRegisteringService.class); 21 | List filters = service.getFilters(); 22 | assertThat(filters).isNotNull(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /applications/zuul2-sample/src/test/java/com/netflix/zuul/sample/filters/inbound/StripPrefixFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.netflix.zuul.sample.filters.inbound; 2 | 3 | import com.netflix.zuul.message.http.HttpRequestInfo; 4 | import com.netflix.zuul.message.http.HttpRequestMessage; 5 | import org.junit.Test; 6 | 7 | import java.util.Arrays; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static org.mockito.Mockito.mock; 11 | import static org.mockito.Mockito.when; 12 | 13 | public class StripPrefixFilterTest { 14 | 15 | @Test 16 | public void testShouldFilter() { 17 | StripPrefixFilter filter = new StripPrefixFilter(Arrays.asList("/path1/.*")); 18 | assertThat(filter.shouldFilter(sampleHttpMessage("/path1/testRemaining?query1=val1"))).isTrue(); 19 | assertThat(filter.shouldFilter(sampleHttpMessage("/path2/testRemaining?query1=val1"))).isFalse(); 20 | } 21 | 22 | private HttpRequestMessage sampleHttpMessage(String path) { 23 | HttpRequestMessage sampleRequest = mock(HttpRequestMessage.class); 24 | when(sampleRequest.getPath()).thenReturn(path); 25 | return sampleRequest; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/boot2-load-demo/d998ee0725253c224131fd0eaf1843efacb7ac8b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /images/Setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bijukunjummen/boot2-load-demo/d998ee0725253c224131fd0eaf1843efacb7ac8b/images/Setup.png -------------------------------------------------------------------------------- /monitor/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | prometheus: 4 | image: prom/prometheus:v2.2.0 5 | volumes: 6 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 7 | ports: 8 | - "9090:9090" 9 | grafana: 10 | image: grafana/grafana:5.0.1 11 | volumes: 12 | - "./grafana-datasource.yml:/etc/grafana/provisioning/datasources/grafana-datasource.yml" 13 | ports: 14 | - "3000:3000" 15 | depends_on: 16 | - prometheus 17 | -------------------------------------------------------------------------------- /monitor/grafana-datasource.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: prometheus 5 | type: prometheus 6 | access: proxy 7 | url: http://prometheus:9090 -------------------------------------------------------------------------------- /monitor/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s # By default, scrape targets every 15 seconds. 3 | scrape_configs: 4 | # - job_name: 'prometheus' 5 | # scrape_interval: 5s 6 | # static_configs: 7 | # - targets: ['localhost:9090'] 8 | - job_name: 'spring-boot-2' 9 | scrape_interval: 5s 10 | metrics_path: '/actuator/prometheus' 11 | static_configs: 12 | - targets: ["192.168.1.43:8080","192.168.1.43:8082","192.168.1.43:8083","192.168.1.43:8084"] 13 | - job_name: 'spring-boot-1' 14 | scrape_interval: 5s 15 | metrics_path: '/prometheus' 16 | static_configs: 17 | - targets: ["192.168.1.43:8081"] 18 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'applications:sample-load-target' 2 | include 'applications:boot1-load-sample' 3 | include 'applications:boot2-load-sample' 4 | include 'applications:spring-cloud-gateway-sample' 5 | include 'applications:zuul-sample' 6 | include 'applications:zuul2-sample' 7 | include 'applications:load-scripts' 8 | 9 | --------------------------------------------------------------------------------