RMIのサンプルコード その2
再度RMIを使ったサンプルコードを書いてみました。
プログラム全体の説明
今回のサンプルコードの全体図を描いてみました。
1.スタブはリモートオブジェクト(BookSearchServiceImpl)と同じメソッド(以後リモートメソッドと略)を持っています。クライアントプログラム(BookSearchServiceClient)は、スタブが持っているリモートメソッドを呼び出します。
2.スタブはスケルトンにリモートメソッドが呼ばれた事を伝えます。
3.スケルトンはリモートオブジェクトのメソッドを呼び出します。
4.リモートオブジェクトは書籍データベースに対してデータ検索を依頼します。
5.書籍データベースは検索結果をリモートオブジェクトへ返します。
6.リモートオブジェクトはスケルトンに対して、戻り値(検索結果)を返します。
7.スケルトンはスタブに対して戻り値を返します。
8.スタブはスケルトンから受け取った戻り値をクライアントプログラムに渡します。
データベースの準備
1.HSQLDB(hsqldb_1_8_0_1.zip)をここからダウンロードして、Dドライブの直下に解凍するとD:\hsqldb_1_8_0_1\hsqldbというフォルダが出来たかと思います。
2.D:\hsqldb_1_8_0_1\hsqldb直下に以下の内容のHSQLDB起動用バッチファイルを作成します。
- StartupDBServer.bat(サーバー起動用バッチファイル)
rem HSQLDBのサーバー起動バッチ cd .\lib java -cp hsqldb.jar org.hsqldb.Server
- StartupDBClient.bat(HSQL Database Manager起動用バッチファイル)
rem HSQL Database Managerの起動 rem HSQL Database Manager起動後、Typeプルダウンメニューより rem HSQL Database Engin Serverを選択してください。 cd .\lib java -cp hsqldb.jar org.hsqldb.util.DatabaseManager
3.D:\hsqldb_1_8_0_1\hsqldb\StartupDBServer.batをダブルクリックしてHSQLDBサーバーを起動します。
次にD:\hsqldb_1_8_0_1\hsqldb\StartupDBClient.batをダブルクリックして、HSQL Database Managerを起動します。HSQL Database Manager起動後、TypeのプルダウンメニューよりHSQL Database Engin Serverを選択してOKボタンを押して下さい。
4.テーブルを作成とサンプルデータの挿入を行ないます。
適当なフォルダにcreateTable.sqlというファイルを作り、以下のSQL文をコピーしてcreateTable.sqlを保存して下さい。
/* bookテーブルの作成 */ CREATE TABLE book( book_id INTEGER, title VARCHAR NOT NULL, isbn VARCHAR NOT NULL, price INTEGER NOT NULL, publisher VARCHAR NOT NULL, PRIMARY KEY(book_id) ); /* authorテーブルの作成 */ CREATE TABLE author( author_id INTEGER, name VARCHAR NOT NULL, PRIMARY KEY(author_id) ); /* author_bookテーブルの作成 */ CREATE TABLE author_book( author_id INTEGER NOT NULL, book_id INTEGER NOT NULL, FOREIGN KEY(author_id) REFERENCES book(book_id), FOREIGN KEY(book_id) REFERENCES author(author_id) ); /* サンプルデータの挿入 */ INSERT INTO book(book_id,title,isbn,price,publisher) VALUES(1,'東欧チャンス','4093875855',1470,'小学館'); INSERT INTO book(book_id,title,isbn,price,publisher) VALUES(2,'考える技術','4062124920',1680,'講談社'); INSERT INTO book(book_id,title,isbn,price,publisher) VALUES(3,'Hibernate 開発者ノートシリーズ','487311215X',2520,'オライリー・ジャパン'); INSERT INTO author(author_id,name) VALUES(1,'大前研一'); INSERT INTO author(author_id,name) VALUES(2,'James Elliott'); INSERT INTO author(author_id,name) VALUES(3,'佐藤 直生'); INSERT INTO author_book(author_id,book_id) VALUES(1,1); INSERT INTO author_book(author_id,book_id) VALUES(1,2); INSERT INTO author_book(author_id,book_id) VALUES(2,3); INSERT INTO author_book(author_id,book_id) VALUES(3,3);
5.HSQL Database ManagerのFileメニューよりOpenScriptを選択して、作成したcreateTable.sqlを開いて下さい。次にExecuteボタンを押して下さい。
必要なテーブルとサンプルデータが挿入されているはずですので、SELECT文を使って確かめて下さい。
以上でデータベースの準備は終わりです。
サンプルコードの内容
以下のサンプルコードを全てD:\rmi_book\examples\rmi\book以下に作成します。
BookSearchService.java
package examples.rmi.book; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.List; /** * * リモートインターフェイスは以下二つの条件を満たさなくてはいけません。 * * 1.java.rmi.Remoteインターフェイスを継承します。 * * 2.定義したメソッドはRemoteExceptionをスローするようにします。 * */ public interface BookSearchService extends Remote { /** * 全検索処理 * * @return * @throws RemoteException */ public List<Book> searchByAll() throws RemoteException; /** * 著者名で検索 * * @return * @throws RemoteException */ public List<Book> searchByAuthor(String name) throws RemoteException; /** * タイトル名で検索 * * @return * @throws RemoteException */ public List<Book> searchByTitle(String title) throws RemoteException; }
BookSearchServiceImpl.java
package examples.rmi.book; import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.List; /** * * 本の検索サービスを提供するサーバー側プログラム * * リモートオブジェクトは以下四つの条件を満たす必要があります。 * * 1.BookSearchServiceインターフェイスを実装する。 * * 2.java.rmi.server.UnicastRemoteObjectを継承する。 * * 3.RemoteExceptionをスローするためにコンストラクタを用意する。 * * 4.BookSearchServiceインターフェイスで用意したメソッドを実装する。 */ @SuppressWarnings("serial") public class BookSearchServiceImpl extends UnicastRemoteObject implements BookSearchService { private BookDao bookDao = new BookDaoImpl(); protected BookSearchServiceImpl() throws RemoteException { super(); } /** * 全検索 * */ public List<Book> searchByAll() throws RemoteException { return this.bookDao.searchByAll(); } /** * 著者名で検索 * */ public List<Book> searchByAuthor(String name) throws RemoteException { return this.bookDao.searchByAuthor(name); } /** * タイトル名で検索 * */ public List<Book> searchByTitle(String title) throws RemoteException { return this.bookDao.searchByTitle(title); } public static void main(String[] args) { if (args.length != 2) { System.out.println("実行例:BookSearchServiceImpl ホスト名 ポート番号"); System.exit(0); } if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { BookSearchService service = new BookSearchServiceImpl(); StringBuffer url = new StringBuffer(); String hostname = args[0]; String portNumber = args[1]; url.append("rmi://"); url.append(hostname); url.append("/BookSearchService:"); url.append(portNumber); Naming.rebind(new String(url), service); } catch (RemoteException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } } }
BookDao.java
package examples.rmi.book; import java.util.List; /** * BookDaoインターフェイス * */ public interface BookDao { /** * 全検索処理 * * @return */ public List<Book> searchByAll(); /** * 著者名で検索 * * @return */ public List<Book> searchByAuthor(String name); /** * タイトル名で検索 * * @return */ public List<Book> searchByTitle(String title); }
BookDaoImpl.java
package examples.rmi.book; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * BookDaoインターフェイスの実装クラス * */ @SuppressWarnings("serial") public class BookDaoImpl implements BookDao { /** * 全検索処理 * * @return */ public List<Book> searchByAll() { String selectSql = "SELECT title,name,isbn,price,publisher FROM author as a,book as b,author_book as ab where a.author_id = ab.author_id and b.book_id = ab.book_id"; Connection con = null; PreparedStatement prst = null; ResultSet rset = null; List<Book> lists = new ArrayList<Book>(); con = BookDaoImpl.getConnection(); try { prst = con.prepareStatement(selectSql); rset = prst.executeQuery(); while (rset.next()) { Book book = new Book(); Author author = new Author(); author.setName(rset.getString("name")); book.setTitle(rset.getString("title")); book.addAuthor(author); book.setPrice(rset.getInt("price")); book.setIsbn(rset.getString("isbn")); book.setPublisher(rset.getString("publisher")); lists.add(book); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (rset != null) { rset.close(); } if (prst != null) { prst.close(); } if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } } return lists; } /** * 著者名で検索 * * @return */ public List<Book> searchByAuthor(String name) { String selectSql = "SELECT title,name,isbn,price,publisher FROM author as a,book as b,author_book as ab where a.author_id = ab.author_id and b.book_id = ab.book_id and name like ?"; Connection con = null; PreparedStatement prst = null; ResultSet rset = null; List<Book> lists = new ArrayList<Book>(); con = BookDaoImpl.getConnection(); try { prst = con.prepareStatement(selectSql); String string = BookDaoImpl.addPercent(name); prst.setString(1, string); rset = prst.executeQuery(); while (rset.next()) { Book book = new Book(); Author author = new Author(); author.setName(rset.getString("name")); book.setTitle(rset.getString("title")); book.addAuthor(author); book.setIsbn(rset.getString("isbn")); book.setPrice(rset.getInt("price")); book.setPublisher(rset.getString("publisher")); lists.add(book); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (rset != null) { rset.close(); } if (prst != null) { prst.close(); } if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } } return lists; } /** * タイトル名で検索 * * @return */ public List<Book> searchByTitle(String title) { String selectSql = "SELECT title,name,isbn,price,publisher FROM author as a,book as b,author_book as ab where a.author_id = ab.author_id and b.book_id = ab.book_id and title like ?"; Connection con = null; PreparedStatement prst = null; ResultSet rset = null; List<Book> lists = new ArrayList<Book>(); con = BookDaoImpl.getConnection(); try { prst = con.prepareStatement(selectSql); String string = BookDaoImpl.addPercent(title); prst.setString(1, string); rset = prst.executeQuery(); while (rset.next()) { Book book = new Book(); Author author = new Author(); author.setName(rset.getString("name")); book.setTitle(rset.getString("title")); book.addAuthor(author); book.setIsbn(rset.getString("isbn")); book.setPrice(rset.getInt("price")); book.setPublisher(rset.getString("publisher")); lists.add(book); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (rset != null) { rset.close(); } if (prst != null) { prst.close(); } if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } } return lists; } /** * コネクションを生成するメソッド * * @return */ private static Connection getConnection() { Connection con = null; String url = "jdbc:hsqldb:hsql://localhost/"; String user = "sa"; String password = ""; try { Class.forName("org.hsqldb.jdbcDriver"); con = DriverManager.getConnection(url, user, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return con; } /** * 文字列の前後に%を付加するメソッド * * @param string * @return */ private static String addPercent(String string) { StringBuffer sb = new StringBuffer(); sb.append("%"); sb.append(string); sb.append("%"); return new String(sb); } }
Author.java
package examples.rmi.book; import java.io.Serializable; import java.util.HashSet; import java.util.Set; /** * AuthorテーブルのデータをセットするJavaBeans * */ @SuppressWarnings("serial") public class Author implements Serializable { private int author_id; private String name; private Set<Book> books = new HashSet<Book>(); public int getAuthor_id() { return this.author_id; } public void setAuthor_id(int author_id) { this.author_id = author_id; } public Set<Book> getBooks() { return this.books; } public void setBooks(Set<Book> books) { this.books = books; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public void addBook(Book book) { this.books.add(book); } }
Book.java
package examples.rmi.book; import java.io.Serializable; import java.util.HashSet; import java.util.Set; /** * BookテーブルのデータをセットするJavaBeans * */ @SuppressWarnings("serial") public class Book implements Serializable { private int book_id; private String title; private int price; private String isbn; private String publisher; private Set<Author> authors = new HashSet<Author>(); public Set<Author> getAuthors() { return this.authors; } public void setAuthors(Set<Author> authors) { this.authors = authors; } public int getBook_id() { return this.book_id; } public void setBook_id(int book_id) { this.book_id = book_id; } public String getIsbn() { return this.isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public int getPrice() { return this.price; } public void setPrice(int price) { this.price = price; } public String getPublisher() { return this.publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public void addAuthor(Author author) { this.authors.add(author); } }
BookSearchServiceClient.java
package examples.rmi.book; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.util.List; /** * 本の検索サービスを利用するクライアント側プログラム * * @author osabek * */ public class BookSearchServiceClient { public static void main(String[] args) { if (args.length != 3) { System.out.println("実行例:BookSearchServiceClient ホスト名 ポート番号 処理内容"); System.out.println("処理内容:"); System.out.println("allを指定した場合:全検索を行ないます。"); System.out.println("authorを指定した場合:著者名で検索出来ます。"); System.out.println("titleを指定した場合:タイトル名で検索出来ます。"); System.exit(0); } BookSearchService service = null; List<Book> list = null; String hostname = args[0]; String portNumber = args[1]; StringBuffer url = new StringBuffer(); url.append("rmi://"); url.append(hostname); url.append("/BookSearchService:"); url.append(portNumber); try { service = (BookSearchService) Naming.lookup(new String(url)); if (args[2].equals("all")) { try { list = service.searchByAll(); } catch (RemoteException e) { e.printStackTrace(); } } else if (args[2].equals("author")) { System.out.print("検索したい著者名を入力して下さい。===> "); try { String authorName = inputKeyword(); list = service.searchByAuthor(authorName); } catch (IOException e) { e.printStackTrace(); } } else if (args[2].equals("title")) { System.out.print("検索したいタイトル名を入力して下さい。===> "); String title; try { title = inputKeyword(); list = service.searchByTitle(title); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("all、author、titleの何れかを選択して下さい。"); System.out.println("プログラムを終了します。"); System.exit(0); } printList(list); } catch (MalformedURLException e1) { e1.printStackTrace(); } catch (RemoteException e1) { e1.printStackTrace(); } catch (NotBoundException e1) { e1.printStackTrace(); } } /** * リストの内容を表示するメソッド * * @param list */ private static void printList(List<Book> list) { if (list.size() != 0) { for (Book book : list) { for (Author author : book.getAuthors()) { System.out.printf("タイトル:%s 著者名:%s 価格:%d ISBN:%s\n", book.getTitle(), author.getName(), book.getPrice(),book.getIsbn()); } } } else { System.out.println("検索結果は0件です。"); } } /** * 検索語句の入力処理を行なうメソッド * * @return * @throws IOException */ private static String inputKeyword() throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String keyword = reader.readLine(); return keyword; } }
コンパイル方法
上記のサンプルコードを全てコンパイルします。
D:\rmi_book>javac examples\rmi\book\*.java
次にrmicコマンドを使用しスタブとスケルトンを作ります。
D:\rmi_book>rmic examples.rmi.book.BookSearchServiceImpl
実行前の準備
1.D:\rmi_book\examples\rmi\book以下にpolicy.txtを作成します。policy.txtの内容は以下の通りです。
grant { permission java.security.AllPermission; };
2.D:\hsqldb_1_8_0_1\hsqldb\lib\hsqldb.jarをD:\rmi_book\examples\rmi\book以下へコピーします。
実行方法
1.StartupDBServer.batをダブルクリックしてHSQLDBサーバーを起動します。次にStartupDBClient.batをダブルクリックしてHsql Database Managerを起動します。
2.コマンドプロンプトを起動し、D:\rmi_bookディレクトリーに移動して以下のコマンドを実行します。
D:\rmi_book>start rmiregistry
3.サーバー側で以下のコマンドを実行します。その際、第一引数にはホスト名を、第二引数にはポート名を指定して下さい。
D:\rmi_book>java -classpath .\examples\rmi\book\hsqldb.jar;. -Djava.rmi.server.c odebase=file:///D:\rmi_book\examples\rmi\book\ -Djava.security.policy=.\examples \rmi\book\policy.txt examples.rmi.book.BookSearchServiceImpl localhost 15000
4.クライアント側で以下のコマンドを実行します。その際、第一引数にサーバーのホスト名、第二引数に上記で指定したポート番号を、そして第三引数にはall、author又はtitleを指定します。
allを指定した場合は全検索を行ないます。
authorを指定した場合は著者名で検索を行ないます。
titleを指定した場合は本のタイトルで検索を行ないます。
全検索を行なった場合のコマンド例と実行結果
D:\rmi_book>java -Djava.security.policy=policy.txt examples.rmi.book.BookSearchServiceClient localhost 15000 all タイトル:東欧チャンス 著者名:大前研一 価格:1470 ISBN:4093875855 タイトル:考える技術 著者名:大前研一 価格:1680 ISBN:4062124920 タイトル:Hibernate 開発者ノートシリーズ 著者名:James Elliott 価格:2520 ISBN:487311215X タイトル:Hibernate 開発者ノートシリーズ 著者名:佐藤 直生 価格:2520 ISBN:487311215X
著者名で検索を行なった場合のコマンド例と実行結果
D:\rmi_book>java -Djava.security.policy=policy.txt examples.rmi.book.BookSearchS erviceClient localhost 15000 author 検索したい著者名を入力して下さい。===> 大前 タイトル:東欧チャンス 著者名:大前研一 価格:1470 ISBN:4093875855 タイトル:考える技術 著者名:大前研一 価格:1680 ISBN:4062124920
タイトル名で検索を行なった場合のコマンド例と実行結果
D:\rmi_book>java -Djava.security.policy=policy.txt examples.rmi.book.BookSearchS erviceClient localhost 15000 title 検索したいタイトル名を入力して下さい。===> 考える タイトル:考える技術 著者名:大前研一 価格:1680 ISBN:4062124920