Merge branch 'master' into 2.0.x

# Conflicts:
#	spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/metrics/DefaultMetricsTagProvider.java
#	spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/rx/DeferredResultSubscriber.java
#	spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/rx/ResponseBodyEmitterSubscriber.java
#	spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/rx/RxResponse.java
#	spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/support/RibbonCommandContextTest.java
#	spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/rx/ObservableReturnValueHandlerTests.java
#	spring-cloud-netflix-dependencies/pom.xml
This commit is contained in:
Spencer Gibb
2017-10-17 14:10:22 -04:00
32 changed files with 1035 additions and 989 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,9 +40,9 @@ public interface AnnotatedParameterProcessor {
/**
* Process the annotated parameter.
*
* @param context the parameter context
* @param context the parameter context
* @param annotation the annotation instance
* @param method the method that contains the annotation
* @param method the method that contains the annotation
* @return whether the parameter is http
*/
boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,37 +27,37 @@ import org.springframework.util.Assert;
*/
public abstract class BaseRequestInterceptor implements RequestInterceptor {
/**
* The encoding properties.
*/
private final FeignClientEncodingProperties properties;
/**
* The encoding properties.
*/
private final FeignClientEncodingProperties properties;
/**
* Creates new instance of {@link BaseRequestInterceptor}.
*
* @param properties the encoding properties
*/
protected BaseRequestInterceptor(FeignClientEncodingProperties properties) {
Assert.notNull(properties, "Properties can not be null");
this.properties = properties;
}
/**
* Creates new instance of {@link BaseRequestInterceptor}.
*
* @param properties the encoding properties
*/
protected BaseRequestInterceptor(FeignClientEncodingProperties properties) {
Assert.notNull(properties, "Properties can not be null");
this.properties = properties;
}
/**
* Adds the header if it wasn't yet specified.
*
* @param requestTemplate the request
* @param name the header name
* @param values the header values
*/
protected void addHeader(RequestTemplate requestTemplate, String name, String... values) {
/**
* Adds the header if it wasn't yet specified.
*
* @param requestTemplate the request
* @param name the header name
* @param values the header values
*/
protected void addHeader(RequestTemplate requestTemplate, String name, String... values) {
if (!requestTemplate.headers().containsKey(name)) {
requestTemplate.header(name, values);
}
}
if (!requestTemplate.headers().containsKey(name)) {
requestTemplate.header(name, values);
}
}
protected FeignClientEncodingProperties getProperties() {
return properties;
}
protected FeignClientEncodingProperties getProperties() {
return properties;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,8 +42,8 @@ import org.springframework.context.annotation.Configuration;
@AutoConfigureAfter(FeignAutoConfiguration.class)
public class FeignAcceptGzipEncodingAutoConfiguration {
@Bean
public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
return new FeignAcceptGzipEncodingInterceptor(properties);
}
@Bean
public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
return new FeignAcceptGzipEncodingInterceptor(properties);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,22 +28,22 @@ import feign.RequestTemplate;
*/
public class FeignAcceptGzipEncodingInterceptor extends BaseRequestInterceptor {
/**
* Creates new instance of {@link FeignAcceptGzipEncodingInterceptor}.
*
* @param properties the encoding properties
*/
protected FeignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
super(properties);
}
/**
* Creates new instance of {@link FeignAcceptGzipEncodingInterceptor}.
*
* @param properties the encoding properties
*/
protected FeignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
super(properties);
}
/**
* {@inheritDoc}
*/
@Override
public void apply(RequestTemplate template) {
/**
* {@inheritDoc}
*/
@Override
public void apply(RequestTemplate template) {
addHeader(template, HttpEncoding.ACCEPT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING,
HttpEncoding.DEFLATE_ENCODING);
}
addHeader(template, HttpEncoding.ACCEPT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING,
HttpEncoding.DEFLATE_ENCODING);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,52 +29,52 @@ import java.util.Objects;
@ConfigurationProperties("feign.compression.request")
public class FeignClientEncodingProperties {
/**
* The list of supported mime types.
*/
private String[] mimeTypes = new String[]{"text/xml", "application/xml", "application/json"};
/**
* The list of supported mime types.
*/
private String[] mimeTypes = new String[]{"text/xml", "application/xml", "application/json"};
/**
* The minimum threshold content size.
*/
private int minRequestSize = 2048;
/**
* The minimum threshold content size.
*/
private int minRequestSize = 2048;
public String[] getMimeTypes() {
return mimeTypes;
}
public String[] getMimeTypes() {
return mimeTypes;
}
public void setMimeTypes(String[] mimeTypes) {
this.mimeTypes = mimeTypes;
}
public void setMimeTypes(String[] mimeTypes) {
this.mimeTypes = mimeTypes;
}
public int getMinRequestSize() {
return minRequestSize;
}
public int getMinRequestSize() {
return minRequestSize;
}
public void setMinRequestSize(int minRequestSize) {
this.minRequestSize = minRequestSize;
}
public void setMinRequestSize(int minRequestSize) {
this.minRequestSize = minRequestSize;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FeignClientEncodingProperties that = (FeignClientEncodingProperties) o;
return Arrays.equals(mimeTypes, that.mimeTypes) &&
Objects.equals(minRequestSize, that.minRequestSize);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FeignClientEncodingProperties that = (FeignClientEncodingProperties) o;
return Arrays.equals(mimeTypes, that.mimeTypes) &&
Objects.equals(minRequestSize, that.minRequestSize);
}
@Override
public int hashCode() {
return Objects.hash(mimeTypes, minRequestSize);
}
@Override
public int hashCode() {
return Objects.hash(mimeTypes, minRequestSize);
}
@Override
public String toString() {
return new StringBuilder("FeignClientEncodingProperties{")
.append("mimeTypes=").append(Arrays.toString(mimeTypes)).append(", ")
.append("minRequestSize=").append(minRequestSize)
.append("}").toString();
}
@Override
public String toString() {
return new StringBuilder("FeignClientEncodingProperties{")
.append("mimeTypes=").append(Arrays.toString(mimeTypes)).append(", ")
.append("minRequestSize=").append(minRequestSize)
.append("}").toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,8 +42,8 @@ import org.springframework.context.annotation.Configuration;
@AutoConfigureAfter(FeignAutoConfiguration.class)
public class FeignContentGzipEncodingAutoConfiguration {
@Bean
public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
return new FeignContentGzipEncodingInterceptor(properties);
}
@Bean
public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
return new FeignContentGzipEncodingInterceptor(properties);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,84 +28,84 @@ import java.util.Map;
*/
public class FeignContentGzipEncodingInterceptor extends BaseRequestInterceptor {
/**
* Creates new instance of {@link FeignContentGzipEncodingInterceptor}.
*
* @param properties the encoding properties
*/
protected FeignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
super(properties);
}
/**
* Creates new instance of {@link FeignContentGzipEncodingInterceptor}.
*
* @param properties the encoding properties
*/
protected FeignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
super(properties);
}
/**
* {@inheritDoc}
*/
@Override
public void apply(RequestTemplate template) {
/**
* {@inheritDoc}
*/
@Override
public void apply(RequestTemplate template) {
if (requiresCompression(template)) {
addHeader(template, HttpEncoding.CONTENT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING,
HttpEncoding.DEFLATE_ENCODING);
}
}
if (requiresCompression(template)) {
addHeader(template, HttpEncoding.CONTENT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING,
HttpEncoding.DEFLATE_ENCODING);
}
}
/**
* Returns whether the request requires GZIP compression.
*
* @param template the request template
* @return true if request requires compression, false otherwise
*/
private boolean requiresCompression(RequestTemplate template) {
/**
* Returns whether the request requires GZIP compression.
*
* @param template the request template
* @return true if request requires compression, false otherwise
*/
private boolean requiresCompression(RequestTemplate template) {
final Map<String, Collection<String>> headers = template.headers();
return matchesMimeType(headers.get(HttpEncoding.CONTENT_TYPE))
&& contentLengthExceedThreshold(headers.get(HttpEncoding.CONTENT_LENGTH));
}
final Map<String, Collection<String>> headers = template.headers();
return matchesMimeType(headers.get(HttpEncoding.CONTENT_TYPE))
&& contentLengthExceedThreshold(headers.get(HttpEncoding.CONTENT_LENGTH));
}
/**
* Returns whether the request content length exceed configured minimum size.
*
* @param contentLength the content length header value
* @return true if length is grater than minimum size, false otherwise
*/
private boolean contentLengthExceedThreshold(Collection<String> contentLength) {
/**
* Returns whether the request content length exceed configured minimum size.
*
* @param contentLength the content length header value
* @return true if length is grater than minimum size, false otherwise
*/
private boolean contentLengthExceedThreshold(Collection<String> contentLength) {
try {
if (contentLength == null || contentLength.size() != 1) {
return false;
}
try {
if (contentLength == null || contentLength.size() != 1) {
return false;
}
final String strLen = contentLength.iterator().next();
final long length = Long.parseLong(strLen);
return length > getProperties().getMinRequestSize();
} catch (NumberFormatException ex) {
// ignores the exception
}
return false;
}
final String strLen = contentLength.iterator().next();
final long length = Long.parseLong(strLen);
return length > getProperties().getMinRequestSize();
} catch (NumberFormatException ex) {
// ignores the exception
}
return false;
}
/**
* Returns whether the content mime types matches the configures mime types.
*
* @param contentTypes the content types
* @return true if any specified content type matches the request content types
*/
private boolean matchesMimeType(Collection<String> contentTypes) {
if (contentTypes == null || contentTypes.size() == 0) {
return false;
}
/**
* Returns whether the content mime types matches the configures mime types.
*
* @param contentTypes the content types
* @return true if any specified content type matches the request content types
*/
private boolean matchesMimeType(Collection<String> contentTypes) {
if (contentTypes == null || contentTypes.size() == 0) {
return false;
}
if (getProperties().getMimeTypes() == null || getProperties().getMimeTypes().length == 0) {
// no specific mime types has been set - matching everything
return true;
}
if (getProperties().getMimeTypes() == null || getProperties().getMimeTypes().length == 0) {
// no specific mime types has been set - matching everything
return true;
}
for (String mimeType : getProperties().getMimeTypes()) {
if (contentTypes.contains(mimeType)) {
return true;
}
}
for (String mimeType : getProperties().getMimeTypes()) {
if (contentTypes.contains(mimeType)) {
return true;
}
}
return false;
}
return false;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,33 +23,33 @@ package org.springframework.cloud.netflix.feign.encoding;
*/
public interface HttpEncoding {
/**
* The HTTP Content-Length header.
*/
String CONTENT_LENGTH = "Content-Length";
/**
* The HTTP Content-Length header.
*/
String CONTENT_LENGTH = "Content-Length";
/**
* The HTTP Content-Type header.
*/
String CONTENT_TYPE = "Content-Type";
/**
* The HTTP Content-Type header.
*/
String CONTENT_TYPE = "Content-Type";
/**
* The HTTP Accept-Encoding header.
*/
String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
/**
* The HTTP Accept-Encoding header.
*/
String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
/**
* The HTTP Content-Encoding header.
*/
String CONTENT_ENCODING_HEADER = "Content-Encoding";
/**
* The HTTP Content-Encoding header.
*/
String CONTENT_ENCODING_HEADER = "Content-Encoding";
/**
* The GZIP encoding.
*/
String GZIP_ENCODING = "gzip";
/**
* The GZIP encoding.
*/
String GZIP_ENCODING = "gzip";
/**
* The Deflate encoding.
*/
String DEFLATE_ENCODING = "deflate";
/**
* The Deflate encoding.
*/
String DEFLATE_ENCODING = "deflate";
}

View File

@@ -1,19 +1,17 @@
/*
* Copyright 2013-2017 the original author or authors.
*
* * Copyright 2013-2016 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.ribbon;
@@ -36,88 +34,88 @@ import java.util.List;
*/
public class RibbonLoadBalancedRetryPolicy implements LoadBalancedRetryPolicy {
public static final IClientConfigKey<String> RETRYABLE_STATUS_CODES = new CommonClientConfigKey<String>("retryableStatusCodes") {};
private int sameServerCount = 0;
private int nextServerCount = 0;
private String serviceId;
private RibbonLoadBalancerContext lbContext;
private ServiceInstanceChooser loadBalanceChooser;
List<Integer> retryableStatusCodes = new ArrayList<>();
public static final IClientConfigKey<String> RETRYABLE_STATUS_CODES = new CommonClientConfigKey<String>("retryableStatusCodes") {};
private int sameServerCount = 0;
private int nextServerCount = 0;
private String serviceId;
private RibbonLoadBalancerContext lbContext;
private ServiceInstanceChooser loadBalanceChooser;
List<Integer> retryableStatusCodes = new ArrayList<>();
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
}
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
}
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser,
IClientConfig clientConfig) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
String retryableStatusCodesProp = clientConfig.getPropertyAsString(RETRYABLE_STATUS_CODES, "");
String[] retryableStatusCodesArray = retryableStatusCodesProp.split(",");
for(String code : retryableStatusCodesArray) {
if(!StringUtils.isEmpty(code)) {
try {
retryableStatusCodes.add(Integer.valueOf(code.trim()));
} catch (NumberFormatException e) {
//TODO log
}
}
}
}
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser,
IClientConfig clientConfig) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
String retryableStatusCodesProp = clientConfig.getPropertyAsString(RETRYABLE_STATUS_CODES, "");
String[] retryableStatusCodesArray = retryableStatusCodesProp.split(",");
for(String code : retryableStatusCodesArray) {
if(!StringUtils.isEmpty(code)) {
try {
retryableStatusCodes.add(Integer.valueOf(code.trim()));
} catch (NumberFormatException e) {
//TODO log
}
}
}
}
public boolean canRetry(LoadBalancedRetryContext context) {
HttpMethod method = context.getRequest().getMethod();
return HttpMethod.GET == method || lbContext.isOkToRetryOnAllOperations();
}
public boolean canRetry(LoadBalancedRetryContext context) {
HttpMethod method = context.getRequest().getMethod();
return HttpMethod.GET == method || lbContext.isOkToRetryOnAllOperations();
}
@Override
public boolean canRetrySameServer(LoadBalancedRetryContext context) {
return sameServerCount < lbContext.getRetryHandler().getMaxRetriesOnSameServer() && canRetry(context);
}
@Override
public boolean canRetrySameServer(LoadBalancedRetryContext context) {
return sameServerCount < lbContext.getRetryHandler().getMaxRetriesOnSameServer() && canRetry(context);
}
@Override
public boolean canRetryNextServer(LoadBalancedRetryContext context) {
//this will be called after a failure occurs and we increment the counter
//so we check that the count is less than or equals to too make sure
//we try the next server the right number of times
return nextServerCount <= lbContext.getRetryHandler().getMaxRetriesOnNextServer() && canRetry(context);
}
@Override
public boolean canRetryNextServer(LoadBalancedRetryContext context) {
//this will be called after a failure occurs and we increment the counter
//so we check that the count is less than or equals to too make sure
//we try the next server the right number of times
return nextServerCount <= lbContext.getRetryHandler().getMaxRetriesOnNextServer() && canRetry(context);
}
@Override
public void close(LoadBalancedRetryContext context) {
@Override
public void close(LoadBalancedRetryContext context) {
}
}
@Override
public void registerThrowable(LoadBalancedRetryContext context, Throwable throwable) {
//Check if we need to ask the load balancer for a new server.
//Do this before we increment the counters because the first call to this method
//is not a retry it is just an initial failure.
if(!canRetrySameServer(context) && canRetryNextServer(context)) {
context.setServiceInstance(loadBalanceChooser.choose(serviceId));
}
//This method is called regardless of whether we are retrying or making the first request.
//Since we do not count the initial request in the retry count we don't reset the counter
//until we actually equal the same server count limit. This will allow us to make the initial
//request plus the right number of retries.
if(sameServerCount >= lbContext.getRetryHandler().getMaxRetriesOnSameServer() && canRetry(context)) {
//reset same server since we are moving to a new server
sameServerCount = 0;
nextServerCount++;
if(!canRetryNextServer(context)) {
context.setExhaustedOnly();
}
} else {
sameServerCount++;
}
@Override
public void registerThrowable(LoadBalancedRetryContext context, Throwable throwable) {
//Check if we need to ask the load balancer for a new server.
//Do this before we increment the counters because the first call to this method
//is not a retry it is just an initial failure.
if(!canRetrySameServer(context) && canRetryNextServer(context)) {
context.setServiceInstance(loadBalanceChooser.choose(serviceId));
}
//This method is called regardless of whether we are retrying or making the first request.
//Since we do not count the initial request in the retry count we don't reset the counter
//until we actually equal the same server count limit. This will allow us to make the initial
//request plus the right number of retries.
if(sameServerCount >= lbContext.getRetryHandler().getMaxRetriesOnSameServer() && canRetry(context)) {
//reset same server since we are moving to a new server
sameServerCount = 0;
nextServerCount++;
if(!canRetryNextServer(context)) {
context.setExhaustedOnly();
}
} else {
sameServerCount++;
}
}
}
@Override
public boolean retryableStatusCode(int statusCode) {
return retryableStatusCodes.contains(statusCode);
}
@Override
public boolean retryableStatusCode(int statusCode) {
return retryableStatusCodes.contains(statusCode);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,17 +24,17 @@ import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
*/
public class RibbonLoadBalancedRetryPolicyFactory implements LoadBalancedRetryPolicyFactory {
private SpringClientFactory clientFactory;
private SpringClientFactory clientFactory;
public RibbonLoadBalancedRetryPolicyFactory(SpringClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
public RibbonLoadBalancedRetryPolicyFactory(SpringClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public LoadBalancedRetryPolicy create(String serviceId, ServiceInstanceChooser loadBalanceChooser) {
RibbonLoadBalancerContext lbContext = this.clientFactory
.getLoadBalancerContext(serviceId);
return new RibbonLoadBalancedRetryPolicy(serviceId, lbContext, loadBalanceChooser, clientFactory.getClientConfig(serviceId));
}
@Override
public LoadBalancedRetryPolicy create(String serviceId, ServiceInstanceChooser loadBalanceChooser) {
RibbonLoadBalancerContext lbContext = this.clientFactory
.getLoadBalancerContext(serviceId);
return new RibbonLoadBalancedRetryPolicy(serviceId, lbContext, loadBalanceChooser, clientFactory.getClientConfig(serviceId));
}
}

View File

@@ -21,33 +21,33 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
public class ResettableServletInputStreamWrapper extends ServletInputStream {
private final ByteArrayInputStream input;
private final ByteArrayInputStream input;
public ResettableServletInputStreamWrapper(byte[] data) {
this.input = new ByteArrayInputStream(data);
}
public ResettableServletInputStreamWrapper(byte[] data) {
this.input = new ByteArrayInputStream(data);
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return input.read();
}
@Override
public int read() throws IOException {
return input.read();
}
@Override
public synchronized void reset() throws IOException {
input.reset();
}
@Override
public synchronized void reset() throws IOException {
input.reset();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,14 +30,14 @@ import java.util.Locale;
*/
final class Invoices {
public static List<Invoice> createInvoiceList(int count) {
final List<Invoice> invoices = new ArrayList<>();
for (int ind = 0; ind < count; ind++) {
final Invoice invoice = new Invoice();
invoice.setTitle("Invoice " + (ind + 1));
invoice.setAmount(new BigDecimal(String.format(Locale.US, "%.2f", Math.random() * 1000)));
invoices.add(invoice);
}
return invoices;
}
public static List<Invoice> createInvoiceList(int count) {
final List<Invoice> invoices = new ArrayList<>();
for (int ind = 0; ind < count; ind++) {
final Invoice invoice = new Invoice();
invoice.setTitle("Invoice " + (ind + 1));
invoice.setAmount(new BigDecimal(String.format(Locale.US, "%.2f", Math.random() * 1000)));
invoices.add(invoice);
}
return invoices;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,23 +25,23 @@ import java.math.BigDecimal;
*/
public class Invoice {
private String title;
private String title;
private BigDecimal amount;
private BigDecimal amount;
public String getTitle() {
return title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public BigDecimal getAmount() {
return amount;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,27 +37,27 @@ import java.util.Locale;
@RestController
public class InvoiceResource {
@RequestMapping(value = "invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Invoice>> getInvoices() {
@RequestMapping(value = "invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Invoice>> getInvoices() {
return ResponseEntity.ok(createInvoiceList(100));
}
return ResponseEntity.ok(createInvoiceList(100));
}
@RequestMapping(value = "invoices", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<List<Invoice>> saveInvoices(@RequestBody List<Invoice> invoices) {
@RequestMapping(value = "invoices", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<List<Invoice>> saveInvoices(@RequestBody List<Invoice> invoices) {
return ResponseEntity.ok(invoices);
}
return ResponseEntity.ok(invoices);
}
private List<Invoice> createInvoiceList(int count) {
final List<Invoice> invoices = new ArrayList<>();
for (int ind = 0; ind < count; ind++) {
final Invoice invoice = new Invoice();
invoice.setTitle("Invoice " + (ind + 1));
invoice.setAmount(new BigDecimal(String.format(Locale.US, "%.2f", Math.random() * 1000)));
invoices.add(invoice);
}
return invoices;
}
private List<Invoice> createInvoiceList(int count) {
final List<Invoice> invoices = new ArrayList<>();
for (int ind = 0; ind < count; ind++) {
final Invoice invoice = new Invoice();
invoice.setTitle("Invoice " + (ind + 1));
invoice.setAmount(new BigDecimal(String.format(Locale.US, "%.2f", Math.random() * 1000)));
invoices.add(invoice);
}
return invoices;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ import static org.junit.Assert.assertTrue;
@SpringBootTest(classes = FeignRibbonClientRetryTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
"spring.application.name=feignclientretrytest", "feign.okhttp.enabled=false",
"feign.httpclient.enabled=false", "feign.hystrix.enabled=false", "localapp.ribbon.MaxAutoRetries=2",
"localapp.ribbon.MaxAutoRetriesNextServer=3"})
"localapp.ribbon.MaxAutoRetriesNextServer=3"})
@DirtiesContext
public class FeignRibbonClientRetryTests {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@ import rx.Single;
"spring.application.name=feignclienttest",
"logging.level.org.springframework.cloud.netflix.feign.valid=DEBUG",
"feign.httpclient.enabled=false", "feign.okhttp.enabled=false",
"feign.hystrix.enabled=true"})
"feign.hystrix.enabled=true"})
@DirtiesContext
public class FeignClientTests {

View File

@@ -59,19 +59,19 @@ public class RibbonClientPreprocessorOverridesIntegrationTests {
@Test
public void ruleOverridesToRandom() throws Exception {
RandomRule.class.cast(getLoadBalancer("foo").getRule());
RoundRobinRule.class.cast(getLoadBalancer("bar").getRule());
RoundRobinRule.class.cast(getLoadBalancer("bar").getRule());
}
@Test
public void pingOverridesToDummy() throws Exception {
DummyPing.class.cast(getLoadBalancer("foo").getPing());
PingConstant.class.cast(getLoadBalancer("bar").getPing());
PingConstant.class.cast(getLoadBalancer("bar").getPing());
}
@Test
public void serverListOverridesToMy() throws Exception {
FooServiceList.class.cast(getLoadBalancer("foo").getServerListImpl());
BarServiceList.class.cast(getLoadBalancer("bar").getServerListImpl());
BarServiceList.class.cast(getLoadBalancer("bar").getServerListImpl());
}
@SuppressWarnings("unchecked")
@@ -88,10 +88,10 @@ public class RibbonClientPreprocessorOverridesIntegrationTests {
}
@Configuration
@RibbonClients({
@RibbonClient(name = "foo", configuration = FooConfiguration.class),
@RibbonClient(name = "bar", configuration = BarConfiguration.class)
})
@RibbonClients({
@RibbonClient(name = "foo", configuration = FooConfiguration.class),
@RibbonClient(name = "bar", configuration = BarConfiguration.class)
})
@Import({ UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class})
protected static class TestConfiguration {
@@ -128,35 +128,35 @@ public class RibbonClientPreprocessorOverridesIntegrationTests {
}
}
@Configuration
public static class BarConfiguration {
@Configuration
public static class BarConfiguration {
@Bean
public IRule ribbonRule() {
return new RoundRobinRule();
}
@Bean
public IRule ribbonRule() {
return new RoundRobinRule();
}
@Bean
public IPing ribbonPing() {
return new PingConstant();
}
@Bean
public IPing ribbonPing() {
return new PingConstant();
}
@Bean
public ServerList<Server> ribbonServerList(IClientConfig config) {
return new BarServiceList(config);
}
@Bean
public ServerList<Server> ribbonServerList(IClientConfig config) {
return new BarServiceList(config);
}
@Bean
public ZonePreferenceServerListFilter serverListFilter() {
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.setZone("BarTestZone");
return filter;
}
}
@Bean
public ZonePreferenceServerListFilter serverListFilter() {
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.setZone("BarTestZone");
return filter;
}
}
public static class BarServiceList extends ConfigurationBasedServerList {
public BarServiceList(IClientConfig config) {
super.initWithNiwsConfig(config);
}
}
public static class BarServiceList extends ConfigurationBasedServerList {
public BarServiceList(IClientConfig config) {
super.initWithNiwsConfig(config);
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.ribbon;
import com.netflix.client.DefaultLoadBalancerRetryHandler;
@@ -43,203 +59,203 @@ import static org.mockito.Mockito.verify;
*/
public class RibbonLoadBalancedRetryPolicyFactoryTests {
@Mock
private SpringClientFactory clientFactory;
@Mock
private SpringClientFactory clientFactory;
@Mock
private BaseLoadBalancer loadBalancer;
@Mock
private BaseLoadBalancer loadBalancer;
@Mock
private LoadBalancerStats loadBalancerStats;
@Mock
private LoadBalancerStats loadBalancerStats;
@Mock
private ServerStats serverStats;
@Mock
private ServerStats serverStats;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
given(this.clientFactory.getLoadBalancerContext(anyString())).willReturn(
new RibbonLoadBalancerContext(this.loadBalancer));
given(this.clientFactory.getInstance(anyString(), eq(ServerIntrospector.class)))
.willReturn(new DefaultServerIntrospector() {
@Override
public Map<String, String> getMetadata(Server server) {
return Collections.singletonMap("mykey", "myvalue");
}
});
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
given(this.clientFactory.getLoadBalancerContext(anyString())).willReturn(
new RibbonLoadBalancerContext(this.loadBalancer));
given(this.clientFactory.getInstance(anyString(), eq(ServerIntrospector.class)))
.willReturn(new DefaultServerIntrospector() {
@Override
public Map<String, String> getMetadata(Server server) {
return Collections.singletonMap("mykey", "myvalue");
}
});
}
}
@After
public void tearDown() throws Exception {}
@After
public void tearDown() throws Exception {}
@Test
public void testGetRetryPolicyNoRetry() throws Exception {
int sameServer = 0;
int nextServer = 0;
boolean retryOnAllOps = false;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(sameServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(nextServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(retryOnAllOps).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn(retryOnAllOps).when(config).getPropertyAsBoolean(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
doReturn(server.getServiceId()).when(config).getClientName();
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.GET).when(request).getMethod();
LoadBalancedRetryContext context = new LoadBalancedRetryContext(null, request);
assertThat(policy.canRetryNextServer(context), is(true));
assertThat(policy.canRetrySameServer(context), is(false));
assertThat(policy.retryableStatusCode(400), is(false));
}
@Test
public void testGetRetryPolicyNoRetry() throws Exception {
int sameServer = 0;
int nextServer = 0;
boolean retryOnAllOps = false;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(sameServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(nextServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(retryOnAllOps).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn(retryOnAllOps).when(config).getPropertyAsBoolean(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
doReturn(server.getServiceId()).when(config).getClientName();
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.GET).when(request).getMethod();
LoadBalancedRetryContext context = new LoadBalancedRetryContext(null, request);
assertThat(policy.canRetryNextServer(context), is(true));
assertThat(policy.canRetrySameServer(context), is(false));
assertThat(policy.retryableStatusCode(400), is(false));
}
@Test
public void testGetRetryPolicyNotGet() throws Exception {
int sameServer = 3;
int nextServer = 3;
boolean retryOnAllOps = false;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(sameServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(nextServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(retryOnAllOps).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn(retryOnAllOps).when(config).getPropertyAsBoolean(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
doReturn(server.getServiceId()).when(config).getClientName();
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.POST).when(request).getMethod();
LoadBalancedRetryContext context = new LoadBalancedRetryContext(null, request);
assertThat(policy.canRetryNextServer(context), is(false));
assertThat(policy.canRetrySameServer(context), is(false));
assertThat(policy.retryableStatusCode(400), is(false));
}
@Test
public void testGetRetryPolicyNotGet() throws Exception {
int sameServer = 3;
int nextServer = 3;
boolean retryOnAllOps = false;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(sameServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(nextServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(retryOnAllOps).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn(retryOnAllOps).when(config).getPropertyAsBoolean(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
doReturn(server.getServiceId()).when(config).getClientName();
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.POST).when(request).getMethod();
LoadBalancedRetryContext context = new LoadBalancedRetryContext(null, request);
assertThat(policy.canRetryNextServer(context), is(false));
assertThat(policy.canRetrySameServer(context), is(false));
assertThat(policy.retryableStatusCode(400), is(false));
}
@Test
public void testGetRetryPolicyRetryOnNonGet() throws Exception {
int sameServer = 3;
int nextServer = 3;
boolean retryOnAllOps = true;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(sameServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(nextServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(retryOnAllOps).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn(retryOnAllOps).when(config).getPropertyAsBoolean(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
doReturn(server.getServiceId()).when(config).getClientName();
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
clientFactory.getLoadBalancerContext(server.getServiceId()).initWithNiwsConfig(config);
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.POST).when(request).getMethod();
LoadBalancedRetryContext context = new LoadBalancedRetryContext(null, request);
assertThat(policy.canRetryNextServer(context), is(true));
assertThat(policy.canRetrySameServer(context), is(true));
assertThat(policy.retryableStatusCode(400), is(false));
}
@Test
public void testGetRetryPolicyRetryOnNonGet() throws Exception {
int sameServer = 3;
int nextServer = 3;
boolean retryOnAllOps = true;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(sameServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(nextServer).when(config).getPropertyAsInteger(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(retryOnAllOps).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn(retryOnAllOps).when(config).getPropertyAsBoolean(eq(CommonClientConfigKey.OkToRetryOnAllOperations), anyBoolean());
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
doReturn(server.getServiceId()).when(config).getClientName();
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
clientFactory.getLoadBalancerContext(server.getServiceId()).initWithNiwsConfig(config);
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.POST).when(request).getMethod();
LoadBalancedRetryContext context = new LoadBalancedRetryContext(null, request);
assertThat(policy.canRetryNextServer(context), is(true));
assertThat(policy.canRetrySameServer(context), is(true));
assertThat(policy.retryableStatusCode(400), is(false));
}
@Test
public void testGetRetryPolicyRetryCount() throws Exception {
int sameServer = 3;
int nextServer = 3;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(false).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), eq(false));
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.GET).when(request).getMethod();
LoadBalancedRetryContext context = spy(new LoadBalancedRetryContext(null, request));
//Loop through as if we are retrying a request until we exhaust the number of retries
//outer loop is for next server retries
//inner loop is for same server retries
for(int i = 0; i < nextServer + 1; i++) {
//iterate once time beyond the same server retry limit to cause us to reset
//the same sever counter and increment the next server counter
for(int j = 0; j < sameServer + 1; j++) {
if(j < 3) {
assertThat(policy.canRetrySameServer(context), is(true));
} else {
assertThat(policy.canRetrySameServer(context), is(false));
}
policy.registerThrowable(context, new IOException());
}
if(i < 3) {
assertThat(policy.canRetryNextServer(context), is(true));
} else {
assertThat(policy.canRetryNextServer(context), is(false));
}
}
assertThat(context.isExhaustedOnly(), is(true));
assertThat(policy.retryableStatusCode(400), is(false));
verify(context, times(4)).setServiceInstance(any(ServiceInstance.class));
}
@Test
public void testGetRetryPolicyRetryCount() throws Exception {
int sameServer = 3;
int nextServer = 3;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(false).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), eq(false));
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
doReturn("").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.GET).when(request).getMethod();
LoadBalancedRetryContext context = spy(new LoadBalancedRetryContext(null, request));
//Loop through as if we are retrying a request until we exhaust the number of retries
//outer loop is for next server retries
//inner loop is for same server retries
for(int i = 0; i < nextServer + 1; i++) {
//iterate once time beyond the same server retry limit to cause us to reset
//the same sever counter and increment the next server counter
for(int j = 0; j < sameServer + 1; j++) {
if(j < 3) {
assertThat(policy.canRetrySameServer(context), is(true));
} else {
assertThat(policy.canRetrySameServer(context), is(false));
}
policy.registerThrowable(context, new IOException());
}
if(i < 3) {
assertThat(policy.canRetryNextServer(context), is(true));
} else {
assertThat(policy.canRetryNextServer(context), is(false));
}
}
assertThat(context.isExhaustedOnly(), is(true));
assertThat(policy.retryableStatusCode(400), is(false));
verify(context, times(4)).setServiceInstance(any(ServiceInstance.class));
}
@Test
public void testRetryableStatusCodes() throws Exception {
int sameServer = 3;
int nextServer = 3;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(false).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), eq(false));
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
doReturn("404, 418,502,foo, ,").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.GET).when(request).getMethod();
assertThat(policy.retryableStatusCode(400), is(false));
assertThat(policy.retryableStatusCode(404), is(true));
assertThat(policy.retryableStatusCode(418), is(true));
assertThat(policy.retryableStatusCode(502), is(true));
}
@Test
public void testRetryableStatusCodes() throws Exception {
int sameServer = 3;
int nextServer = 3;
RibbonServer server = getRibbonServer();
IClientConfig config = mock(IClientConfig.class);
doReturn(sameServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetries), anyInt());
doReturn(nextServer).when(config).get(eq(CommonClientConfigKey.MaxAutoRetriesNextServer), anyInt());
doReturn(false).when(config).get(eq(CommonClientConfigKey.OkToRetryOnAllOperations), eq(false));
doReturn(config).when(clientFactory).getClientConfig(eq(server.getServiceId()));
doReturn("404, 418,502,foo, ,").when(config).getPropertyAsString(eq(RibbonLoadBalancedRetryPolicy.RETRYABLE_STATUS_CODES),eq(""));
clientFactory.getLoadBalancerContext(server.getServiceId()).setRetryHandler(new DefaultLoadBalancerRetryHandler(config));
RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
RibbonLoadBalancedRetryPolicyFactory factory = new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
LoadBalancedRetryPolicy policy = factory.create(server.getServiceId(), client);
HttpRequest request = mock(HttpRequest.class);
doReturn(HttpMethod.GET).when(request).getMethod();
assertThat(policy.retryableStatusCode(400), is(false));
assertThat(policy.retryableStatusCode(404), is(true));
assertThat(policy.retryableStatusCode(418), is(true));
assertThat(policy.retryableStatusCode(502), is(true));
}
protected RibbonLoadBalancerClient getRibbonLoadBalancerClient(
RibbonServer ribbonServer) {
given(this.loadBalancer.getName()).willReturn(ribbonServer.getServiceId());
given(this.loadBalancer.chooseServer(anyObject())).willReturn(
ribbonServer.getServer());
given(this.loadBalancer.getLoadBalancerStats())
.willReturn(this.loadBalancerStats);
given(this.loadBalancerStats.getSingleServerStat(ribbonServer.getServer()))
.willReturn(this.serverStats);
given(this.clientFactory.getLoadBalancer(this.loadBalancer.getName()))
.willReturn(this.loadBalancer);
return new RibbonLoadBalancerClient(this.clientFactory);
}
protected RibbonLoadBalancerClient getRibbonLoadBalancerClient(
RibbonServer ribbonServer) {
given(this.loadBalancer.getName()).willReturn(ribbonServer.getServiceId());
given(this.loadBalancer.chooseServer(anyObject())).willReturn(
ribbonServer.getServer());
given(this.loadBalancer.getLoadBalancerStats())
.willReturn(this.loadBalancerStats);
given(this.loadBalancerStats.getSingleServerStat(ribbonServer.getServer()))
.willReturn(this.serverStats);
given(this.clientFactory.getLoadBalancer(this.loadBalancer.getName()))
.willReturn(this.loadBalancer);
return new RibbonLoadBalancerClient(this.clientFactory);
}
protected RibbonServer getRibbonServer() {
return new RibbonServer("testService", new Server("myhost", 9080), false,
Collections.singletonMap("mykey", "myvalue"));
}
protected RibbonServer getRibbonServer() {
return new RibbonServer("testService", new Server("myhost", 9080), false,
Collections.singletonMap("mykey", "myvalue"));
}
}

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -38,58 +38,58 @@ import okhttp3.Request;
*/
public class RibbonCommandContextTest {
private static final byte[] TEST_CONTENT = { 42, 42, 42, 42, 42 };
private static final byte[] TEST_CONTENT = { 42, 42, 42, 42, 42 };
private RibbonCommandContext ribbonCommandContext;
private RibbonCommandContext ribbonCommandContext;
@Test
public void testMultipleReadsOnRequestEntity() throws Exception {
givenRibbonCommandContextIsSetup();
@Test
public void testMultipleReadsOnRequestEntity() throws Exception {
givenRibbonCommandContextIsSetup();
InputStream requestEntity = ribbonCommandContext.getRequestEntity();
assertTrue(requestEntity instanceof ResettableServletInputStreamWrapper);
InputStream requestEntity = ribbonCommandContext.getRequestEntity();
assertTrue(requestEntity instanceof ResettableServletInputStreamWrapper);
whenInputStreamIsConsumed(requestEntity);
assertEquals(-1, requestEntity.read());
whenInputStreamIsConsumed(requestEntity);
assertEquals(-1, requestEntity.read());
requestEntity.reset();
assertNotEquals(-1, requestEntity.read());
requestEntity.reset();
assertNotEquals(-1, requestEntity.read());
whenInputStreamIsConsumed(requestEntity);
assertEquals(-1, requestEntity.read());
whenInputStreamIsConsumed(requestEntity);
assertEquals(-1, requestEntity.read());
requestEntity.reset();
assertNotEquals(-1, requestEntity.read());
requestEntity.reset();
assertNotEquals(-1, requestEntity.read());
whenInputStreamIsConsumed(requestEntity);
assertEquals(-1, requestEntity.read());
}
whenInputStreamIsConsumed(requestEntity);
assertEquals(-1, requestEntity.read());
}
private void whenInputStreamIsConsumed(InputStream requestEntity) throws IOException {
while (requestEntity.read() != -1) {
requestEntity.read();
}
}
private void whenInputStreamIsConsumed(InputStream requestEntity) throws IOException {
while (requestEntity.read() != -1) {
requestEntity.read();
}
}
private void givenRibbonCommandContextIsSetup() {
LinkedMultiValueMap headers = new LinkedMultiValueMap();
LinkedMultiValueMap params = new LinkedMultiValueMap();
private void givenRibbonCommandContextIsSetup() {
LinkedMultiValueMap headers = new LinkedMultiValueMap();
LinkedMultiValueMap params = new LinkedMultiValueMap();
RibbonRequestCustomizer requestCustomizer = new RibbonRequestCustomizer<Request.Builder>() {
@Override
public boolean accepts(Class builderClass) {
return builderClass == Request.Builder.class;
}
RibbonRequestCustomizer requestCustomizer = new RibbonRequestCustomizer<Request.Builder>() {
@Override
public boolean accepts(Class builderClass) {
return builderClass == Request.Builder.class;
}
@Override
public void customize(Request.Builder builder) {
builder.addHeader("from-customizer", "foo");
}
};
@Override
public void customize(Request.Builder builder) {
builder.addHeader("from-customizer", "foo");
}
};
ribbonCommandContext = new RibbonCommandContext("serviceId",
HttpMethod.POST.toString(), "/my/route", true, headers, params,
new ByteArrayInputStream(TEST_CONTENT),
Lists.newArrayList(requestCustomizer));
}
ribbonCommandContext = new RibbonCommandContext("serviceId",
HttpMethod.POST.toString(), "/my/route", true, headers, params,
new ByteArrayInputStream(TEST_CONTENT),
Lists.newArrayList(requestCustomizer));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,33 +49,33 @@ import static com.netflix.appinfo.InstanceInfo.InstanceStatus;
*/
public class EurekaHealthCheckHandler implements HealthCheckHandler, ApplicationContextAware, InitializingBean {
private static final Map<Status, InstanceInfo.InstanceStatus> STATUS_MAPPING =
new HashMap<Status, InstanceInfo.InstanceStatus>() {{
put(Status.UNKNOWN, InstanceStatus.UNKNOWN);
put(Status.OUT_OF_SERVICE, InstanceStatus.OUT_OF_SERVICE);
put(Status.DOWN, InstanceStatus.DOWN);
put(Status.UP, InstanceStatus.UP);
}};
private static final Map<Status, InstanceInfo.InstanceStatus> STATUS_MAPPING =
new HashMap<Status, InstanceInfo.InstanceStatus>() {{
put(Status.UNKNOWN, InstanceStatus.UNKNOWN);
put(Status.OUT_OF_SERVICE, InstanceStatus.OUT_OF_SERVICE);
put(Status.DOWN, InstanceStatus.DOWN);
put(Status.UP, InstanceStatus.UP);
}};
private final CompositeHealthIndicator healthIndicator;
private final CompositeHealthIndicator healthIndicator;
private ApplicationContext applicationContext;
private ApplicationContext applicationContext;
public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
this.healthIndicator = new CompositeHealthIndicator(healthAggregator);
}
public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
this.healthIndicator = new CompositeHealthIndicator(healthAggregator);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
final Map<String, HealthIndicator> healthIndicators = applicationContext.getBeansOfType(HealthIndicator.class);
@Override
public void afterPropertiesSet() throws Exception {
final Map<String, HealthIndicator> healthIndicators = applicationContext.getBeansOfType(HealthIndicator.class);
for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
//ignore EurekaHealthIndicator and flatten the rest of the composite
//otherwise there is a never ending cycle of down. See gh-643
@@ -91,23 +91,23 @@ public class EurekaHealthCheckHandler implements HealthCheckHandler, Application
else {
healthIndicator.addHealthIndicator(entry.getKey(), entry.getValue());
}
}
}
}
}
@Override
public InstanceStatus getStatus(InstanceStatus instanceStatus) {
return getHealthStatus();
}
@Override
public InstanceStatus getStatus(InstanceStatus instanceStatus) {
return getHealthStatus();
}
protected InstanceStatus getHealthStatus() {
final Status status = healthIndicator.health().getStatus();
return mapToInstanceStatus(status);
}
protected InstanceStatus getHealthStatus() {
final Status status = healthIndicator.health().getStatus();
return mapToInstanceStatus(status);
}
protected InstanceStatus mapToInstanceStatus(Status status) {
if (!STATUS_MAPPING.containsKey(status)) {
return InstanceStatus.UNKNOWN;
}
return STATUS_MAPPING.get(status);
}
protected InstanceStatus mapToInstanceStatus(Status status) {
if (!STATUS_MAPPING.containsKey(status)) {
return InstanceStatus.UNKNOWN;
}
return STATUS_MAPPING.get(status);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,47 +42,47 @@ import static org.junit.Assert.assertEquals;
*/
public class EurekaHealthCheckHandlerTests {
private EurekaHealthCheckHandler healthCheckHandler;
private EurekaHealthCheckHandler healthCheckHandler;
@Before
public void setUp() throws Exception {
@Before
public void setUp() throws Exception {
healthCheckHandler = new EurekaHealthCheckHandler(new OrderedHealthAggregator());
}
healthCheckHandler = new EurekaHealthCheckHandler(new OrderedHealthAggregator());
}
@Test
public void testNoHealthCheckRegistered() throws Exception {
@Test
public void testNoHealthCheckRegistered() throws Exception {
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.UNKNOWN, status);
}
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.UNKNOWN, status);
}
@Test
public void testAllUp() throws Exception {
@Test
public void testAllUp() throws Exception {
initialize(UpHealthConfiguration.class);
initialize(UpHealthConfiguration.class);
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.UP, status);
}
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.UP, status);
}
@Test
public void testDown() throws Exception {
@Test
public void testDown() throws Exception {
initialize(UpHealthConfiguration.class, DownHealthConfiguration.class);
initialize(UpHealthConfiguration.class, DownHealthConfiguration.class);
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.DOWN, status);
}
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.DOWN, status);
}
@Test
public void testUnknown() throws Exception {
@Test
public void testUnknown() throws Exception {
initialize(FatalHealthConfiguration.class);
initialize(FatalHealthConfiguration.class);
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.UNKNOWN, status);
}
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
assertEquals(InstanceStatus.UNKNOWN, status);
}
@Test
public void testEurekaIgnored() throws Exception {
@@ -93,50 +93,50 @@ public class EurekaHealthCheckHandlerTests {
assertEquals(InstanceStatus.UP, status);
}
private void initialize(Class<?>... configurations) throws Exception {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(configurations);
healthCheckHandler.setApplicationContext(applicationContext);
healthCheckHandler.afterPropertiesSet();
}
private void initialize(Class<?>... configurations) throws Exception {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(configurations);
healthCheckHandler.setApplicationContext(applicationContext);
healthCheckHandler.afterPropertiesSet();
}
public static class UpHealthConfiguration {
public static class UpHealthConfiguration {
@Bean
public HealthIndicator healthIndicator() {
return new AbstractHealthIndicator() {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.up();
}
};
}
}
@Bean
public HealthIndicator healthIndicator() {
return new AbstractHealthIndicator() {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.up();
}
};
}
}
public static class DownHealthConfiguration {
public static class DownHealthConfiguration {
@Bean
public HealthIndicator healthIndicator() {
return new AbstractHealthIndicator() {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.down();
}
};
}
}
@Bean
public HealthIndicator healthIndicator() {
return new AbstractHealthIndicator() {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.down();
}
};
}
}
public static class FatalHealthConfiguration {
public static class FatalHealthConfiguration {
@Bean
public HealthIndicator healthIndicator() {
return new AbstractHealthIndicator() {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.status("fatal");
}
};
}
}
@Bean
public HealthIndicator healthIndicator() {
return new AbstractHealthIndicator() {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.status("fatal");
}
};
}
}
public static class EurekaDownHealthConfiguration {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,22 +33,22 @@ import org.springframework.boot.actuate.health.Status;
*/
class LocalApplicationHealthCheckHandler implements HealthCheckHandler {
private final HealthIndicator healthIndicator;
private final HealthIndicator healthIndicator;
public LocalApplicationHealthCheckHandler(HealthIndicator healthIndicator) {
this.healthIndicator = healthIndicator;
}
public LocalApplicationHealthCheckHandler(HealthIndicator healthIndicator) {
this.healthIndicator = healthIndicator;
}
@Override
public InstanceStatus getStatus(InstanceStatus currentStatus) {
Status status = healthIndicator.health().getStatus();
if (status.equals(Status.UP)) {
return UP;
} else if (status.equals(Status.OUT_OF_SERVICE)) {
return OUT_OF_SERVICE;
} else if (status.equals(Status.DOWN)) {
return DOWN;
}
return UNKNOWN;
}
@Override
public InstanceStatus getStatus(InstanceStatus currentStatus) {
Status status = healthIndicator.health().getStatus();
if (status.equals(Status.UP)) {
return UP;
} else if (status.equals(Status.OUT_OF_SERVICE)) {
return OUT_OF_SERVICE;
} else if (status.equals(Status.DOWN)) {
return DOWN;
}
return UNKNOWN;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,39 +32,39 @@ import org.springframework.boot.actuate.health.HealthIndicator;
*/
public class LocalApplicationHealthCheckHandlerTests {
@Mock
private HealthIndicator healthIndicator;
@Mock
private HealthIndicator healthIndicator;
@Before
public void setup() {
initMocks(this);
}
@Before
public void setup() {
initMocks(this);
}
@Test
public void upMappingWorks() {
assertStatus(InstanceStatus.UP, Health.up());
}
@Test
public void upMappingWorks() {
assertStatus(InstanceStatus.UP, Health.up());
}
@Test
public void downMappingWorks() {
assertStatus(InstanceStatus.DOWN, Health.down());
}
@Test
public void downMappingWorks() {
assertStatus(InstanceStatus.DOWN, Health.down());
}
@Test
public void outOfServiceMappingWorks() {
assertStatus(InstanceStatus.OUT_OF_SERVICE, Health.outOfService());
}
@Test
public void outOfServiceMappingWorks() {
assertStatus(InstanceStatus.OUT_OF_SERVICE, Health.outOfService());
}
@Test
public void unknownMappingWorks() {
assertStatus(InstanceStatus.UNKNOWN, Health.unknown());
}
@Test
public void unknownMappingWorks() {
assertStatus(InstanceStatus.UNKNOWN, Health.unknown());
}
private void assertStatus(InstanceStatus expected, Health.Builder builder) {
given(healthIndicator.health()).willReturn(builder.build());
private void assertStatus(InstanceStatus expected, Health.Builder builder) {
given(healthIndicator.health()).willReturn(builder.build());
LocalApplicationHealthCheckHandler handler = new LocalApplicationHealthCheckHandler(healthIndicator);
InstanceStatus status = handler.getStatus(InstanceStatus.UP);
assertEquals(expected, status);
}
LocalApplicationHealthCheckHandler handler = new LocalApplicationHealthCheckHandler(healthIndicator);
InstanceStatus status = handler.getStatus(InstanceStatus.UP);
assertEquals(expected, status);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,70 +39,70 @@ import rx.subjects.PublishSubject;
@Component // needed for ServiceActivator to be picked up
public class HystrixStreamAggregator {
private static final Log log = LogFactory.getLog(HystrixStreamAggregator.class);
private static final Log log = LogFactory.getLog(HystrixStreamAggregator.class);
private ObjectMapper objectMapper;
private ObjectMapper objectMapper;
private PublishSubject<Map<String, Object>> subject;
private PublishSubject<Map<String, Object>> subject;
@Autowired
public HystrixStreamAggregator(ObjectMapper objectMapper,
PublishSubject<Map<String, Object>> subject) {
this.objectMapper = objectMapper;
this.subject = subject;
}
@Autowired
public HystrixStreamAggregator(ObjectMapper objectMapper,
PublishSubject<Map<String, Object>> subject) {
this.objectMapper = objectMapper;
this.subject = subject;
}
@ServiceActivator(inputChannel = TurbineStreamClient.INPUT)
public void sendToSubject(@Payload String payload) {
if (payload.startsWith("\"")) {
// Legacy payload from an Angel client
payload = payload.substring(1, payload.length() - 1);
payload = payload.replace("\\\"", "\"");
}
try {
if (payload.startsWith("[")) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> list = this.objectMapper.readValue(payload,
List.class);
for (Map<String, Object> map : list) {
sendMap(map);
}
}
else {
@SuppressWarnings("unchecked")
Map<String, Object> map = this.objectMapper.readValue(payload, Map.class);
sendMap(map);
}
}
catch (IOException ex) {
log.error("Error receiving hystrix stream payload: " + payload, ex);
}
}
@ServiceActivator(inputChannel = TurbineStreamClient.INPUT)
public void sendToSubject(@Payload String payload) {
if (payload.startsWith("\"")) {
// Legacy payload from an Angel client
payload = payload.substring(1, payload.length() - 1);
payload = payload.replace("\\\"", "\"");
}
try {
if (payload.startsWith("[")) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> list = this.objectMapper.readValue(payload,
List.class);
for (Map<String, Object> map : list) {
sendMap(map);
}
}
else {
@SuppressWarnings("unchecked")
Map<String, Object> map = this.objectMapper.readValue(payload, Map.class);
sendMap(map);
}
}
catch (IOException ex) {
log.error("Error receiving hystrix stream payload: " + payload, ex);
}
}
private void sendMap(Map<String, Object> map) {
Map<String, Object> data = getPayloadData(map);
if (log.isDebugEnabled()) {
log.debug("Received hystrix stream payload: " + data);
}
this.subject.onNext(data);
}
private void sendMap(Map<String, Object> map) {
Map<String, Object> data = getPayloadData(map);
if (log.isDebugEnabled()) {
log.debug("Received hystrix stream payload: " + data);
}
this.subject.onNext(data);
}
public static Map<String, Object> getPayloadData(Map<String, Object> jsonMap) {
@SuppressWarnings("unchecked")
Map<String, Object> origin = (Map<String, Object>) jsonMap.get("origin");
String instanceId = null;
if (origin.containsKey("id")) {
instanceId = origin.get("id").toString();
}
if (!StringUtils.hasText(instanceId)) {
// TODO: instanceid template
instanceId = origin.get("serviceId") + ":" + origin.get("host") + ":"
+ origin.get("port");
}
@SuppressWarnings("unchecked")
Map<String, Object> data = (Map<String, Object>) jsonMap.get("data");
data.put("instanceId", instanceId);
return data;
}
public static Map<String, Object> getPayloadData(Map<String, Object> jsonMap) {
@SuppressWarnings("unchecked")
Map<String, Object> origin = (Map<String, Object>) jsonMap.get("origin");
String instanceId = null;
if (origin.containsKey("id")) {
instanceId = origin.get("id").toString();
}
if (!StringUtils.hasText(instanceId)) {
// TODO: instanceid template
instanceId = origin.get("serviceId") + ":" + origin.get("host") + ":"
+ origin.get("port");
}
@SuppressWarnings("unchecked")
Map<String, Object> data = (Map<String, Object>) jsonMap.get("data");
data.put("instanceId", instanceId);
return data;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,58 +30,58 @@ import org.springframework.http.MediaType;
@ConfigurationProperties("turbine.stream")
public class TurbineStreamProperties {
@Value("${server.port:8989}")
private int port = 8989;
@Value("${server.port:8989}")
private int port = 8989;
private String destination = HystrixConstants.HYSTRIX_STREAM_DESTINATION;
private String destination = HystrixConstants.HYSTRIX_STREAM_DESTINATION;
private String contentType = MediaType.APPLICATION_JSON_VALUE;
private String contentType = MediaType.APPLICATION_JSON_VALUE;
public int getPort() {
return port;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public void setPort(int port) {
this.port = port;
}
public String getDestination() {
return destination;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public String getContentType() {
return contentType;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TurbineStreamProperties that = (TurbineStreamProperties) o;
return port == that.port && Objects.equals(destination, that.destination)
&& Objects.equals(contentType, that.contentType);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TurbineStreamProperties that = (TurbineStreamProperties) o;
return port == that.port && Objects.equals(destination, that.destination)
&& Objects.equals(contentType, that.contentType);
}
@Override
public int hashCode() {
return Objects.hash(port, destination, contentType);
}
@Override
public int hashCode() {
return Objects.hash(port, destination, contentType);
}
@Override
public String toString() {
return new StringBuilder("TurbineStreamProperties{").append("port=").append(port)
.append(", ").append("destination='").append(destination).append("', ")
.append("contentType='").append(contentType).append("'}").toString();
}
@Override
public String toString() {
return new StringBuilder("TurbineStreamProperties{").append("port=").append(port)
.append(", ").append("destination='").append(destination).append("', ")
.append("contentType='").append(contentType).append("'}").toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -162,8 +162,8 @@ public class CommonsInstanceDiscovery implements InstanceDiscovery {
*/
Instance marshall(ServiceInstance serviceInstance) {
String hostname = serviceInstance.getHost();
String managementPort = serviceInstance.getMetadata().get("management.port");
String port = managementPort == null ? String.valueOf(serviceInstance.getPort()) : managementPort;
String managementPort = serviceInstance.getMetadata().get("management.port");
String port = managementPort == null ? String.valueOf(serviceInstance.getPort()) : managementPort;
String cluster = getClusterName(serviceInstance);
Boolean status = Boolean.TRUE; //TODO: where to get?
if (hostname != null && cluster != null && status != null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,23 +100,23 @@ public class CommonsInstanceDiscoveryTests {
assertEquals("url is wrong", "http://"+hostName+":"+port+"/hystrix.stream", urlPath);
}
@Test
public void testUseManagementPortFromMetadata() {
CommonsInstanceDiscovery discovery = createDiscovery();
String appName = "testAppName";
int port = 8080;
int managementPort = 8081;
String hostName = "myhost";
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(appName, hostName, port, false);
serviceInstance.getMetadata().put("management.port", String.valueOf(managementPort));
Instance instance = discovery.marshall(serviceInstance);
assertEquals("port is wrong", String.valueOf(managementPort), instance.getAttributes().get("port"));
@Test
public void testUseManagementPortFromMetadata() {
CommonsInstanceDiscovery discovery = createDiscovery();
String appName = "testAppName";
int port = 8080;
int managementPort = 8081;
String hostName = "myhost";
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(appName, hostName, port, false);
serviceInstance.getMetadata().put("management.port", String.valueOf(managementPort));
Instance instance = discovery.marshall(serviceInstance);
assertEquals("port is wrong", String.valueOf(managementPort), instance.getAttributes().get("port"));
String urlPath = SpringClusterMonitor.ClusterConfigBasedUrlClosure.getUrlPath(instance);
assertEquals("url is wrong", "http://"+hostName+":"+managementPort+"/hystrix.stream", urlPath);
}
String urlPath = SpringClusterMonitor.ClusterConfigBasedUrlClosure.getUrlPath(instance);
assertEquals("url is wrong", "http://"+hostName+":"+managementPort+"/hystrix.stream", urlPath);
}
@Test
@Test
public void testGetSecurePort() {
CommonsInstanceDiscovery discovery = createDiscovery();
String appName = "testAppName";

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,17 +66,17 @@ public class ServletDetectionFilter extends ZuulFilter {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
if (!(request instanceof HttpServletRequestWrapper)
&& isDispatcherServletRequest(request)) {
ctx.set(IS_DISPATCHER_SERVLET_REQUEST_KEY, true);
&& isDispatcherServletRequest(request)) {
ctx.set(IS_DISPATCHER_SERVLET_REQUEST_KEY, true);
} else {
ctx.set(IS_DISPATCHER_SERVLET_REQUEST_KEY, false);
ctx.set(IS_DISPATCHER_SERVLET_REQUEST_KEY, false);
}
return null;
}
private boolean isDispatcherServletRequest(HttpServletRequest request) {
return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null;
}
private boolean isDispatcherServletRequest(HttpServletRequest request) {
return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,11 +26,11 @@ import org.springframework.http.client.ClientHttpResponse;
*/
public interface FallbackProvider extends ZuulFallbackProvider {
/**
* Provides a fallback response based on the cause of the failed execution.
*
* @param cause cause of the main method failure
* @return the fallback response
*/
ClientHttpResponse fallbackResponse(Throwable cause);
/**
* Provides a fallback response based on the cause of the failed execution.
*
* @param cause cause of the main method failure
* @return the fallback response
*/
ClientHttpResponse fallbackResponse(Throwable cause);
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.zuul.util;
import org.springframework.core.io.InputStreamResource;
@@ -18,80 +34,80 @@ import java.util.Map.Entry;
import java.util.Set;
public class RequestContentDataExtractor {
public static MultiValueMap<String, Object> extract(HttpServletRequest request) throws IOException {
return (request instanceof MultipartHttpServletRequest) ?
extractFromMultipartRequest((MultipartHttpServletRequest) request) :
extractFromRequest(request);
}
public static MultiValueMap<String, Object> extract(HttpServletRequest request) throws IOException {
return (request instanceof MultipartHttpServletRequest) ?
extractFromMultipartRequest((MultipartHttpServletRequest) request) :
extractFromRequest(request);
}
private static MultiValueMap<String, Object> extractFromRequest(HttpServletRequest request) throws IOException {
MultiValueMap<String, Object> builder = new LinkedMultiValueMap<>();
Set<String> queryParams = findQueryParams(request);
private static MultiValueMap<String, Object> extractFromRequest(HttpServletRequest request) throws IOException {
MultiValueMap<String, Object> builder = new LinkedMultiValueMap<>();
Set<String> queryParams = findQueryParams(request);
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
String key = entry.getKey();
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
String key = entry.getKey();
if (!queryParams.contains(key)) {
for (String value : entry.getValue()) {
builder.add(key, value);
}
}
}
if (!queryParams.contains(key)) {
for (String value : entry.getValue()) {
builder.add(key, value);
}
}
}
return builder;
}
return builder;
}
private static MultiValueMap<String, Object> extractFromMultipartRequest(MultipartHttpServletRequest request)
throws IOException {
MultiValueMap<String, Object> builder = new LinkedMultiValueMap<>();
Set<String> queryParams = findQueryParams(request);
private static MultiValueMap<String, Object> extractFromMultipartRequest(MultipartHttpServletRequest request)
throws IOException {
MultiValueMap<String, Object> builder = new LinkedMultiValueMap<>();
Set<String> queryParams = findQueryParams(request);
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
String key = entry.getKey();
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
String key = entry.getKey();
if (!queryParams.contains(key)) {
for (String value : entry.getValue()) {
HttpHeaders headers = new HttpHeaders();
String type = request.getMultipartContentType(key);
if (!queryParams.contains(key)) {
for (String value : entry.getValue()) {
HttpHeaders headers = new HttpHeaders();
String type = request.getMultipartContentType(key);
if (type != null) {
headers.setContentType(MediaType.valueOf(type));
}
if (type != null) {
headers.setContentType(MediaType.valueOf(type));
}
builder.add(key, new HttpEntity<>(value, headers));
}
}
}
builder.add(key, new HttpEntity<>(value, headers));
}
}
}
for (Entry<String, List<MultipartFile>> parts : request.getMultiFileMap().entrySet()) {
for (MultipartFile file : parts.getValue()) {
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData(file.getName(), file.getOriginalFilename());
if (file.getContentType() != null) {
headers.setContentType(MediaType.valueOf(file.getContentType()));
}
for (Entry<String, List<MultipartFile>> parts : request.getMultiFileMap().entrySet()) {
for (MultipartFile file : parts.getValue()) {
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData(file.getName(), file.getOriginalFilename());
if (file.getContentType() != null) {
headers.setContentType(MediaType.valueOf(file.getContentType()));
}
HttpEntity entity = new HttpEntity<>(new InputStreamResource(file.getInputStream()), headers);
builder.add(parts.getKey(), entity);
}
}
HttpEntity entity = new HttpEntity<>(new InputStreamResource(file.getInputStream()), headers);
builder.add(parts.getKey(), entity);
}
}
return builder;
}
return builder;
}
private static Set<String> findQueryParams(HttpServletRequest request) {
Set<String> result = new HashSet<>();
String query = request.getQueryString();
private static Set<String> findQueryParams(HttpServletRequest request) {
Set<String> result = new HashSet<>();
String query = request.getQueryString();
if (query != null) {
for (String value : StringUtils.tokenizeToStringArray(query, "&")) {
if (value.contains("=")) {
value = value.substring(0, value.indexOf("="));
}
result.add(value);
}
}
if (query != null) {
for (String value : StringUtils.tokenizeToStringArray(query, "&")) {
if (value.contains("=")) {
value = value.substring(0, value.indexOf("="));
}
result.add(value);
}
}
return result;
}
return result;
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.zuul.util;
import com.netflix.zuul.context.RequestContext;
@@ -6,18 +22,18 @@ import static org.springframework.cloud.netflix.zuul.filters.support.FilterConst
public class RequestUtils {
/**
* @deprecated use {@link org.springframework.cloud.netflix.zuul.filters.support.FilterConstants#IS_DISPATCHER_SERVLET_REQUEST_KEY}
*/
@Deprecated
public static final String IS_DISPATCHERSERVLETREQUEST = IS_DISPATCHER_SERVLET_REQUEST_KEY;
public static boolean isDispatcherServletRequest() {
return RequestContext.getCurrentContext().getBoolean(IS_DISPATCHER_SERVLET_REQUEST_KEY);
}
public static boolean isZuulServletRequest() {
//extra check for dispatcher since ZuulServlet can run from ZuulController
return !isDispatcherServletRequest() && RequestContext.getCurrentContext().getZuulEngineRan();
}
/**
* @deprecated use {@link org.springframework.cloud.netflix.zuul.filters.support.FilterConstants#IS_DISPATCHER_SERVLET_REQUEST_KEY}
*/
@Deprecated
public static final String IS_DISPATCHERSERVLETREQUEST = IS_DISPATCHER_SERVLET_REQUEST_KEY;
public static boolean isDispatcherServletRequest() {
return RequestContext.getCurrentContext().getBoolean(IS_DISPATCHER_SERVLET_REQUEST_KEY);
}
public static boolean isZuulServletRequest() {
//extra check for dispatcher since ZuulServlet can run from ZuulController
return !isDispatcherServletRequest() && RequestContext.getCurrentContext().getZuulEngineRan();
}
}