Java RMI –分散オブジェクトの例

画像ソース:Wikimedia.org
Java RMI Hello World
exampleでは、サーバーとクライアント間の非常に基本的なString-based通信でJava Remote
Method Invocationを導入しました。 In this example we will take it one small step further and introduce Server-Client communication using Distributed Objects.
1. リモートインターフェース
最初に、サーバーが実装するすべてのメソッドを含むRemote Interfaceを開発します。 Interfaceは常にpublicであり、Remoteを拡張する必要があります。 Remote Interfaceで説明されているすべてのメソッドは、throws節にRemoteExceptionをリストする必要があります。
RMIInterface.java
package com.techfou.rmiinterface;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
public interface RMIInterface extends Remote {
Book findBook(Book b) throws RemoteException;
List allBooks() throws RemoteException;
}
2. 分散オブジェクトクラス
これは、サーバーとクライアントが交換するObjectのクラスであり、Serializable Interfaceを実装する必要があります。 また、このクラスが明示的なserialVersionUID値を宣言して、さまざまなJavaコンパイラ実装間の一貫性を保証することも非常に重要です。
これを無視した場合、またはサーバーの分散オブジェクトクラスがクライアントの分散オブジェクトクラスとは異なるserialVersionUIDを宣言した場合、逆シリアル化プロセスの結果はInvalidClassExceptionになります。
Eclipse IDEでは、次のようなserialVersionUIDを生成できます。

Book.java
package com.techfou.rmiinterface;
import java.io.Serializable;
public class Book implements Serializable {
private static final long serialVersionUID = 1190476516911661470L;
private String title;
private String isbn;
private double cost;
public Book(String isbn) {
this.isbn = isbn;
}
public Book(String title, String isbn, double cost) {
this.title = title;
this.isbn = isbn;
this.cost = cost;
}
public String getTitle() {
return title;
}
public String getIsbn() {
return isbn;
}
public double getCost() {
return cost;
}
public String toString() {
return "> " + this.title + " ($" + this.cost + ")";
}
}
3. サーバー
サーバーはUnicastRemoteObjectを拡張し、RMIInterfaceを実装します。 メインメソッドでは、localhost上のサーバーを「MyBookstore」という名前でバインドします。 簡単にするために、データベースやFileを使用する代わりに、書店が持っている本を表すBook type ObjectsでListを埋めるメソッドinitializeList()を作成しました(…はいのみ5 。 しかし、5つの素晴らしい本!)。
サーバーにもserialVersionUIDを追加する必要がありますが、この例で設計したサーバーは1台のマシンにのみ存在することを意図しているため、2回考える必要はないため、%(t1 )s。 ただし、サーバークラスも配布されている場合は、クラスのserialVersionUIDが実装されているすべてのプラットフォームで同じであることを確認する必要があります。
Bookstore.java
package com.example.rmiserver;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import com.example.rmiinterface.Book;
import com.example.rmiinterface.RMIInterface;
public class Bookstore extends UnicastRemoteObject implements RMIInterface {
private static final long serialVersionUID = 1L;
private List bookList;
protected Bookstore(List list) throws RemoteException {
super();
this.bookList = list;
}
//The client sends a Book object with the isbn information on it
//(note: it could be a string with the isbn too)
//With this method the server searches in the List bookList
//for any book that has that isbn and returns the whole object
@Override
public Book findBook(Book book) throws RemoteException {
Predicate predicate = x -> x.getIsbn().equals(book.getIsbn());
return bookList.stream().filter(predicate).findFirst().get();
}
@Override
public List allBooks() throws RemoteException {
return bookList;
}
private static List initializeList() {
List list = new ArrayList<>();
list.add(new Book("Head First Java, 2nd Edition", "978-0596009205", 31.41));
list.add(new Book("Java In A Nutshell", "978-0596007737", 10.90));
list.add(new Book("Java: The Complete Reference", "978-0071808552", 40.18));
list.add(new Book("Head First Servlets and JSP", "978-0596516680", 35.41));
list.add(new Book("Java Puzzlers: Traps, Pitfalls, and Corner Cases", "978-0321336781", 39.99));
return list;
}
public static void main(String[] args) {
try {
Naming.rebind("//localhost/MyBookstore", new Bookstore(initializeList()));
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.getMessage());
}
}
}
4. クライアント
クライアントは、パラメータとして渡した名前に関連付けられたリモートオブジェクトへの参照を「検索」するRMIInterface Objectを介してサーバーを「検索」します。 今説明したのは、Naming.lookup("//localhost/MyBookstore");が行うことです。
クライアント用の残りのコードは、うまくいけば実験できる実用的な例を作成するためのものです。
Customer.java
package com.example.rmiclient;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;
import java.util.NoSuchElementException;
import javax.swing.JOptionPane;
import com.example.rmiinterface.Book;
import com.example.rmiinterface.RMIInterface;
public class Customer {
private static RMIInterface look_up;
public static void main(String[] args) throws
MalformedURLException, RemoteException, NotBoundException {
look_up = (RMIInterface) Naming.lookup("//localhost/MyBookstore");
boolean findmore;
do {
String[] options = {"Show All", "Find a book", "Exit"};
int choice = JOptionPane.showOptionDialog(null, "Choose an action", "Option dialog",
JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE,
null, options, options[0]);
switch (choice) {
case 0:
List list = look_up.allBooks();
StringBuilder message = new StringBuilder();
list.forEach(x -> {
message.append(x.toString() + "\n");
});
JOptionPane.showMessageDialog(null, new String(message));
break;
case 1:
String isbn = JOptionPane.showInputDialog("Type the isbn of the book you want to find.");
try {
Book response = look_up.findBook(new Book(isbn));
JOptionPane.showMessageDialog(null, "Title: " +
response.getTitle() + "\n" + "Cost: $" +
response.getCost(),
response.getIsbn(), JOptionPane.INFORMATION_MESSAGE);
} catch (NoSuchElementException ex) {
JOptionPane.showMessageDialog(null, "Not found");
}
break;
default:
System.exit(0);
break;
}
findmore = (JOptionPane.showConfirmDialog(null, "Do you want to exit?", "Exit",
JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION);
} while (findmore);
}
}
5. 実行方法
5.1 After you create the four java files with your favorite IDE or Download the code below, navigate to your source folder as shown below.

5.2 First thing we need to do is compile our sources. 以下のコードをダウンロードした場合は1. compileEverything.batを実行するか、ディレクトリでコマンドウィンドウを開いて実行します。
ターミナル
$ javac src/com/example/rmiinterface/RMIInterface.java src/com/example/rmiinterface/Book.java src/com/example/rmiserver/Bookstore.java src/com/example/rmiclient/Customer.java
5.3 Confirm that your sources were compiled by accessing their respective directories:

5.4 Next we need to start the rmiregistry. 再度、2. startServer.batを実行するか、コマンドウィンドウを開いて次を実行します。
ターミナル
$ cd src $ start rmiregistry $ java com.example.rmiserver.Bookstore

5.5 If RmiRegistry started successfully, there will be another window that looks like this:

5.6 Now we are ready to run our Client:
新しいコマンドプロンプトウィンドウを開き(またはダウンロードしたファイルから3. runClient.batを実行し)、次のコマンドを実行します。
ターミナル
$ cd src $ java com.example.rmiclient.Customer
5.6.1 The Customer class runs and prompts us for action:

5.6.2 When we click “Show All” button:

5.6.3 After clicking “OK” button:

5.6.4 We click “No” button, since we don’t want to exit yet and the following dialog comes up. ISBNを入力します(例: 「978-0596009205」)、「OK」をクリックします。

5.6.5 If the book was found in the Server’s list:

5.6.6 If it wasn’t found:

5.6.7 The program will continue by asking us:

「はい」ボタンをクリックすると、プログラムは終了します。 [いいえ]をクリックすると、メインメニューに戻り、5.6.1に示すアクションを選択します。
サーバーは、ウィンドウを閉じるまで稼働し続けます。 クライアントを閉じた後でも、同時に実行する新しいクライアントまたは複数のクライアントを開くことができます。
ソースコードをダウンロード
ダウンロード–RMIObjects.zip(5 KB)
