2017-02-17 53 views
0

我的項目簡要描述: 我正在寫一個名爲「GreetingsNode」的java類,它在分佈式環境中工作,其中有一個「managementNode」作爲服務存儲庫並接收和存儲其他節點的信息(主機端口號和所提供的服務),並分發由註冊服務提供的方法的RPC。如果一個節點可以回答RPC,則打開一個節點套接字並在主叫節點和應答節點之間建立連接,並且應答節點返回結果。Apache Thrift RPC在分佈式環境中的Java方法實現

我使用Apache thrift作爲IDL和RPC的框架。

現在的問題。 My GreetingsNodeHandler類實現了一個包含單個方法「getHello(user)」(用戶是包含節點名稱的結構,它是GreetingsNode類的構造函數的參數)的簡單節點接口。 當連接到管理節點的GreetingsNode X創建該方法的RPC時,另一個註冊的GreetingsNode必須回答消息「hello X」。

我不明白如何實現返回結果的處理程序部分,因此我無法理解應該如何編寫junit測試來檢查方法實現是否正常工作。

斷言像 的assertEquals(client.getHello(用戶).getMessage(), 「John Doe:您好」)

會的工作,但我不明白怎麼回事,在我的情況,我應該把客戶端部分...

爲GreetingService的節儉服務代碼:

struct Message { 
    1: string message 
} 

struct User { 
    1: string name 
} 

service GreetingsService { 
    Message getHello(1: User user) 
} 

代碼GreetingsServiceHandler必須實現GreetingsService方法getHello()

public class GreetingsServiceHandler implements GreetingsService.Iface { 

private static Random random = new Random(10); 
private ManagementService.Client managementClient; 
private GreetingsService.Client helloClient; 

@Override 
public Message getHello(User user) throws TException { 
    Message answer = null; 
    // class ServiceProvider is generated by thrift, part of ManagementService thrift service 
    ServiceProvider provider = null; 
    List<ServiceProvider>providers = managementClient.getProvidersForService(user.name); 

    if (providers.isEmpty()) 
     throw new NoProviderAvailableException(); //separate file contains Exception 
    else { 
     provider = providers.get(random.nextInt(providers.size())); 
     //connection between nodes is established here 
     TTransport helloTransport = new TSocket(provider.getHostName(), provider.getPort()); 
     TProtocol helloProtocol = new TBinaryProtocol(helloTransport); 
     helloClient = new GreetingsService.Client(helloProtocol); 
     helloTransport.open(); 

     // here lies my problem 
     answer = helloClient.getHello(user); 
     //if I use this instead, then helloClient variable is clearly not used, but of course I need it to answer the method call 
     answer = answer.setMessage("Ciao " + user.getName() + ", welcome among us!"); 

    } 
    return answer; 

} 

和GreetingsNode代碼如下:

public class GreetingsNode implements NodeIface { 

private ThriftServer helloServer; 
private ManagementService.Client managementClient; 
private NodeManifest nodeManifest; 
private User user; 
private String name; 

public GreetingsNode(NodeManifest nodeManifest, String name) { 
    this.nodeManifest = nodeManifest; 
    this.helloServer = new ThriftServer(GreetingsServiceHandler.class); 
    this.name = name; 
} 

@Override 
public void turnOn() throws TException { 

    helloServer.start(); 

    TSocket helloServerTransport = new TSocket("localhost", Constants.SERVER_PORT); 
    TBinaryProtocol helloServerProtocol = new TBinaryProtocol(helloServerTransport); 
    managementClient = new ManagementService.Client(helloServerProtocol); 
    this.setUser(new User(name)); 
    helloServerTransport.open(); 

    helloServer = new ThriftServer(GreetingsServiceHandler.class); 
    //portNegotiator is a class described in a separate file, that handles the registration of other nodes to the managementNode. NodeManifest is a file generated by thrift, part of managementService thrift file, describing a struct that contains hostname and port number of nodes. 
    PortNegotiator negotiator = new PortNegotiator(managementClient); 
    negotiator.negotiate(nodeManifest, helloServer); 

} 

@Override 
public void turnOff() { 
    helloServer.stop(); 
} 

public User getUser() { 
    return user; 
} 

public void setUser(User user) { 
    this.user = user; 
} 
+0

你有看過[教程代碼](https:// thrift。apache.org/tutorial/java)? – JensG

+0

當然我做了,我已經實現了一個函數算術計算器,其中「算法節點」應答由另一個節點所做的「executeOperation」方法的調用。 當我使用字符串時,我無法翻譯這種行爲...不知道爲什麼實際上因爲這個概念應該是非常相似,如果不相同 – Gaspare79

回答

1

的基本方法在處理IMPL是非常簡單的,類似下面應該做的(免責聲明:未測試):

@Override 
public Message getHello(User user) throws TException { 
    Message answer = new Message(); 
    answer = answer.setMessage("Ciao " + user.getName() + ", welcome among us!"); 
    return answer; 
} 

如果我用這個代替,那麼helloClient變量顯然沒有用,但我當然需要它來回答方法調用

當連接到管理節點的GreetingsNode X創建該方法的RPC時,另一個註冊的GreetingsNode必須回答消息「hello X」。

如果這意味着我們要像客戶端=>服務器A =>服務器B調用序列則這也是可能的,只需要稍作修改。從我們的基本出發例如上面,我們相應提高了代碼:

private Message callTheOtherNode(User user) { 
    // class ServiceProvider is generated by Thrift, 
    // part of ManagementService Thrift service 
    ServiceProvider provider = null; 
    List<ServiceProvider>providers = managementClient.getProvidersForService(user.name); 

    if (providers.isEmpty()) 
     throw new NoProviderAvailableException(); //separate file contains Exception 

    provider = providers.get(random.nextInt(providers.size())); 
    //connection between nodes is established here 
    TTransport helloTransport = new TSocket(provider.getHostName(), provider.getPort()); 
    TProtocol helloProtocol = new TBinaryProtocol(helloTransport); 
    helloClient = new GreetingsService.Client(helloProtocol); 
    helloTransport.open(); 
    return helloClient.getHello(user); 
} 

@Override 
public Message getHello(User user) throws TException { 
    Message answer = callTheOtherNode(user); 
    return answer; 
} 

當然,「其他節點」被稱爲需求真正做到與請求的東西,而不是簡單地轉發一遍又一節點。

+0

我懷疑我過於複雜:( 非常感謝您的先生 – Gaspare79

+0

兩個疑問:1)我不知道應該在哪裏放置私人CallOtherNode方法的代碼,它會在Handler文件中,我猜。這樣做會使eclipse發出警告,「來自GreetingsServiceHandler類型的方法CallOtherNode(User)從不在本地使用」2)第二個getHello()應該以不同的方式命名和/或包含在我的thrift服務文件中,否則eclipse會一直告訴我(正確)「的GreetingsServiceHandler類型的方法sayHello(用戶)必須覆蓋或實現超類型方法」(因爲它不包含在生成的節儉文件中)。 – Gaspare79

+0

是的,呼叫序列將是Client(它是一個GreetingsNode)==> Server A(它是managementNode)==> Server B(它是另一個Greetings節點)。然後,服務器B與客戶建立連接並接聽電話。 – Gaspare79