如何以递归和有效的方式调用服务器,直到我得到正确的响应?

时间:2014-01-14 03:03:00

标签: java recursion

我目前有两面旗帜。一个是remoteFlag,另一个是secondaryFlag。默认情况下,如果他们想要在我们的应用程序调用时更改它们,则客户可以更改它们。所以可能发生的组合是 -

remoteFlag       secondaryFlag

true             true
true             false
false            false
false            true

默认情况下,它始终为真。

我应该对我们的服务器进行HTTP调用(所有服务器都是Ubunutu机器)。假设下面是我的服务器,其中完全限定的主机名对应于unix中的hostname -f

String hostname1 = hostname1;
String hostname2 = hostname2;

String hostname3 = hostname3;
String hostname4 = hostname4;

我有几个我应该按照以下描述做的案例 -

  1. 假设remoteFlagsecondaryFlag两者都是true,那么我 我应该一个接一个地击中所有上述服务器,直到我们得到 从服务器回复。意思是假设hostname1已关闭 所以我们不会从那些服务器得到任何响应,它会 抛出异常然后我们将转到hostname2来获取 相同的数据,但假设如果hostname2也失效,那么我们就会去 hostname3获取数据,但假设hostname3也是 然后我们将转到hostname4来获取数据。但如果有的话 服务器能够给出响应然后我们将返回 通过做出适当的回应说我们已经得到了数据。 如果没有一台服务器能够回复那么我们 将发出错误回复,说明所有服务器都已关闭。
  2. 现在,如果remoteFlagtruesecondaryFlagfalse,则 我们只会转到hostname1hostname3。如果是hostname1 然后我们将转到hostname3以获得回复。如果两者都有 他们失败了,然后我们会做一个ERROR响应说服务器 落下了。
  3. 现在,如果remoteFlagfalsesecondaryFlagfalse,则 我们只会去hostname1,这就是全部。如果hostname1失效, 那么我们将做出一个ERROR响应,说服务器已关闭。
  4. 现在,如果remoteFlagfalsesecondaryFlagtrue,则 我们只会转到hostname1hostname2,这就是全部。如果 hostname1已关闭,然后我们会转到hostname2获取 响应。如果两者都失效,那么我们将犯一个错误 响应说服务器已关闭。
  5. 下来我的意思是服务器没有启动,所以这就是他们没有响应的原因。我尝试了其中一个已关闭的服务器,如果我尝试命中该服务器,RestTemplate会抛出异常。

    以下是我的代码到目前为止仅适用于remoteFlagsecondaryFlag两者都是真的但是它再次看起来不是很好的代码,因为我只是在下面的代码中重复一下。我不知道如果其中任何一个服务器关闭,我如何继续递归调用服务器。但是,如果其中任何一个已经启动并得到正确的响应,那么通过使用我获得的实际数据进行SUCCESS响应来返回调用。

    下面是

    public class ClientTask implements Callable<ClientResponse> {
    
        public ClientTask(ClientKey clientKeys) {
            this.clientKeys = clientKeys;
        }
    
        @Override
        public ClientResponse call() throws Exception {
            ....
    
            boolean remoteFlag = clientKeys.isRemoteFlag();
            boolean secondaryFlag = clientKeys.isSecondaryFlag();
    
            RestTemplate restTemplate = new RestTemplate();
            String response = null;
            ...
    
            String hostname1 = hostname1;
            String hostname2 = hostname2;
    
            String hostname3 = hostname3;
            String hostname4 = hostname4;
    
            // first use case when both are true
            if(remoteFlag && secondaryFlag) {
                if(hostname1 != null) {
                    try {
                        String url = generateURL(hostname1);            
                        response = restTemplate.getForObject(url, String.class);
    
                        return new ClientResponse(response, ClientError.NONE, ClientStatus.SUCCESS);
                    } catch(Exception ex) {
                        ex.printStackTrace(); // use logger
                    }
                }            
                // hostname1 is down
                if(response == null && hostname2 != null) {
                    try {
                        String url = generateURL(hostname2);            
                        response = restTemplate.getForObject(url, String.class);
    
                        return new ClientResponse(response, ClientError.NONE, ClientStatus.SUCCESS);
                    } catch(Exception ex) {
                        ex.printStackTrace(); // use logger
                    }
                }
                // hostname1 and 2 both are down
                if(response == null && hostname3 != null) {
                    try {
                        String url = generateURL(hostname3);            
                        response = restTemplate.getForObject(url, String.class);
    
                        return new ClientResponse(response, ClientError.NONE, ClientStatus.SUCCESS);
                    } catch(Exception ex) {
                        ex.printStackTrace(); // use logger
                    }
                }
                // hostname1, 2, 3 are down
                if(response == null && hostname4 != null) {
                    try {
                        String url = generateURL(hostname4);            
                        response = restTemplate.getForObject(url, String.class);
    
                        return new ClientResponse(response, ClientError.NONE, ClientStatus.SUCCESS);
                    } catch(Exception ex) {
                        ex.printStackTrace(); // use logger
                    }
                }
            }
    
            // not sure how to add other use case logic here as well properly
        }
    
        /**
         * Method to generate the url to hit the servers. 
         * 
         */ 
        private String generateURL(final String hostname) {
            StringBuffer url = new StringBuffer();
            url.append("http://" + hostname + ":8080/user?userId=" + clientKeys.getUserId() + "&page_id=" + clientKeys.getPageId());
    
            Set<Entry<String, String>> params = clientKeys.getAttributeMap().entrySet();
    
            for(Entry<String, String> e : params){
                url.append("&" + e.getKey());
                url.append("=" + e.getValue());
            }
    
            return url.toString();
        }
    }
    

    ProblemStatement: -

    在上面的代码中,我只是一直在重复内容,不知道在收到响应之前我如何递归地继续调用服务器。以及如何在上面的代码中也适合其他用例。最初我想为其他用例添加相同的if块。然后我认为我的整个代码将填充if if only。

    任何想法如何有效地解决这个问题?

2 个答案:

答案 0 :(得分:2)

您的代码中有很多样板。只需填写if语句中的主机列表,即可轻松避免它们。然后迭代该列表:

List<String> hostnames = new ArrayList<>();
if(remoteFlag && secondaryFlag) {
    hostnames.add(hostname1);
    hostnames.add(hostname2);

} else if …

for (String hostname : hostnames) {
    if(hostname == null) {
        continue;

    }
    try {
        String url = generateURL(hostname1);            
        response = restTemplate.getForObject(url, String.class);
        break;

    } catch(Exception ex) {
        ex.printStackTrace(); // use logger

    }
}
if (response == null) {
    // do error handling

}
return new ClientResponse(response, ClientError.NONE, ClientStatus.SUCCESS);

我个人更喜欢另一种解决方案。构建一个表达状态转换并链接这些组件的组件:

public class FallbackCall() {

    private String hostname;

    private String secondaryHostname;

    private FallbackQuery next;

    public ClientResponse call(boolean remote, boolean secondary) {
        ClientResponse response = getResponse(hostname);
        if (response == null && secondary) {
            reponse = getResponse(secondaryHostname);

        }
        if (response == null && remote) {
            reponse = next.call(remote, secondary);

        }
        return response;
    }

    private ClientResponse getResponse(String hostname) {
        // your boiler plate
    }

}

答案 1 :(得分:0)

一个想法是将检索提取到另一种方法(甚至可能是“静态”),如此

// I don't recognize your library...
public ClientResponse call(String hostname) throws Exception {
  if (hostname == null) {
    return null;
  }
  // You might also make generateURL static 
  String url = generateURL(hostname);
  String response = restTemplate.getForObject(url,
      String.class);
  if (response == null) { // add more logic here to test your response.
     return null;
  }
  return new ClientResponse(response,
      ClientError.NONE, ClientStatus.SUCCESS);
}

然后你可以逐个传递你的网址,直到你得到一个好的回应。像这样,

// String hostname1 = hostname1;
// String hostname2 = hostname2;
// String hostname3 = hostname3;
// String hostname4 = hostname4;
if(remoteFlag && secondaryFlag) {
  ClientResponse response = call(hostname1);
  // != null is one test. However you test the response is valid.
  if (response != null) return response;
  response = call(hostname2);
  if (response != null) return response;
  response = call(hostname3);
  if (response != null) return response;
  return call(hostname4);
}