/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.servicecomb.loadbalance;

import java.io.IOException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
import org.springframework.stereotype.Component;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.netflix.client.DefaultLoadBalancerRetryHandler;
import com.netflix.client.RetryHandler;

import io.vertx.core.VertxException;

@Component
public class DefaultRetryExtensionsFactory implements ExtensionsFactory {
  private static final Collection<String> ACCEPT_KEYS = Lists.newArrayList(
      Configuration.PROP_RETRY_HANDLER);

  private static final String RETRY_DEFAULT = "default";

  private static final Collection<String> ACCEPT_VALUES = Lists.newArrayList(
      RETRY_DEFAULT);

  @Override
  public boolean isSupport(String key, String value) {
    return ACCEPT_KEYS.contains(key) && ACCEPT_VALUES.contains(value);
  }

  public RetryHandler createRetryHandler(String retryName, String microservice) {
    return new DefaultLoadBalancerRetryHandler(
        Configuration.INSTANCE.getRetryOnSame(microservice),
        Configuration.INSTANCE.getRetryOnNext(microservice), true) {
      private List<Class<? extends Throwable>> retriable = Lists
          .newArrayList(ConnectException.class, SocketTimeoutException.class);

      Map<Class<? extends Throwable>, List<String>> strictRetriable =
          ImmutableMap.<Class<? extends Throwable>, List<String>>builder()
              .put(ConnectException.class, Lists.newArrayList())
              .put(SocketTimeoutException.class, Lists.newArrayList())
              /*
               * deal with some special exceptions caused by the server side close the connection
               */
              .put(IOException.class, Lists.newArrayList(new String[] {"Connection reset by peer"}))
              .put(VertxException.class, Lists.newArrayList(new String[] {"Connection was closed"}))
              .put(NoRouteToHostException.class, Lists.newArrayList(new String[]{"Host is unreachable"}))
              .build();

      @Override
      public boolean isRetriableException(Throwable e, boolean sameServer) {
        boolean retriable = isPresentAsCause(e);
        if (!retriable) {
          if (e instanceof InvocationException) {
            if (((InvocationException) e).getStatusCode() == 503) {
              return true;
            }
          }
        }
        return retriable;
      }

      @Override
      protected List<Class<? extends Throwable>> getRetriableExceptions() {
        return this.retriable;
      }

      public boolean isPresentAsCause(Throwable throwableToSearchIn) {
        int infiniteLoopPreventionCounter = 10;
        while (throwableToSearchIn != null && infiniteLoopPreventionCounter > 0) {
          infiniteLoopPreventionCounter--;
          for (Entry<Class<? extends Throwable>, List<String>> c : strictRetriable.entrySet()) {
            Class<? extends Throwable> key = c.getKey();
            if (key.isAssignableFrom(throwableToSearchIn.getClass())) {
              if (c.getValue() == null || c.getValue().isEmpty()) {
                return true;
              } else {
                String msg = throwableToSearchIn.getMessage();
                for (String val : c.getValue()) {
                  if (val.equals(msg)) {
                    return true;
                  }
                }
              }
            }
          }
          throwableToSearchIn = throwableToSearchIn.getCause();
        }
        return false;
      }
    };
  }
}

@@ -974,32 +974,57 @@
 meoutException;%0A
+import java.util.Arrays;%0A
 import java.util
@@ -1833,559 +1833,28 @@
 %0A%0A  
-@Override%0A  public boolean isSupport(String key, String value) %7B%0A    return ACCEPT_KEYS.contains(key) && ACCEPT_VALUES.contains(value);%0A  %7D%0A%0A  public RetryHandler createRetryHandler(String retryName, String microservice) %7B%0A    return new DefaultLoadBalancerRetryHandler(%0A        Configuration.INSTANCE.getRetryOnSame(microservice),%0A        Configuration.INSTANCE.getRetryOnNext(microservice), true) %7B%0A      private List%3CClass%3C? extends Throwable%3E%3E retriable = Lists%0A          .newArrayList(ConnectException.class, SocketTimeoutException.class);%0A%0A     
+private static final
  Map
@@ -1914,20 +1914,16 @@
 iable =%0A
-    
       Im
@@ -1991,28 +1991,24 @@
 )%0A          
-    
 .put(Connect
@@ -2024,38 +2024,33 @@
 .class, 
-Lists.new
 Array
+s.as
 List())%0A
         
@@ -2033,36 +2033,32 @@
 rrays.asList())%0A
-    
           .put(S
@@ -2082,38 +2082,33 @@
 tion.class, 
-Lists.new
 Array
+s.as
 List())%0A    
@@ -2117,19 +2117,11 @@
     
-    /*%0A    
+/*%0A
     
@@ -2221,20 +2221,16 @@
         
-    
 */%0A     
@@ -2230,28 +2230,24 @@
 /%0A          
-  
-  
 .put(IOExcep
@@ -2254,38 +2254,33 @@
 tion.class, 
-Lists.new
 Array
+s.as
 List(new Str
@@ -2322,28 +2322,24 @@
 )%0A          
-  
-  
 .put(VertxEx
@@ -2349,38 +2349,33 @@
 tion.class, 
-Lists.new
 Array
+s.as
 List(new Str
@@ -2414,28 +2414,24 @@
 )%0A          
- 
-   
 .put(NoRoute
@@ -2453,30 +2453,25 @@
 .class, 
-Lists.new
 Array
+s.as
 List(new
@@ -2515,20 +2515,16 @@
         
-    
 .build()
@@ -2524,16 +2524,420 @@
 build();
+%0A%0A  @Override%0A  public boolean isSupport(String key, String value) %7B%0A    return ACCEPT_KEYS.contains(key) && ACCEPT_VALUES.contains(value);%0A  %7D%0A%0A  public RetryHandler createRetryHandler(String retryName, String microservice) %7B%0A    return new DefaultLoadBalancerRetryHandler(%0A        Configuration.INSTANCE.getRetryOnSame(microservice),%0A        Configuration.INSTANCE.getRetryOnNext(microservice), true) %7B
 %0A%0A      
@@ -3318,140 +3318,8 @@
  %7D%0A%0A
-      @Override%0A      protected List%3CClass%3C? extends Throwable%3E%3E getRetriableExceptions() %7B%0A        return this.retriable;%0A      %7D%0A%0A
     

use static strictRetriable and use Arrays.asList()