<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>reality &#187; rmi</title>
	<atom:link href="http://www.reality.hk/articles/tag/rmi/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.reality.hk</link>
	<description>Reality is merely an illusion, albeit a very persistent one.</description>
	<lastBuildDate>Sun, 05 Sep 2010 14:37:02 +0000</lastBuildDate>
	<language>zh-tw</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>用 JRuby 整合 Ruby 和 Java (2) &#8211; DRb 和 RMI</title>
		<link>http://www.reality.hk/articles/2008/02/16/782/</link>
		<comments>http://www.reality.hk/articles/2008/02/16/782/#comments</comments>
		<pubDate>Sat, 16 Feb 2008 14:27:50 +0000</pubDate>
		<dc:creator>小影</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[distributed-computing]]></category>
		<category><![CDATA[DRb]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[rmi]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.reality.hk/articles/2008/02/16/782/</guid>
		<description><![CDATA[DRb (Distributed Ruby) 是 Ruby 的 RPC。使用 DRb 我們可以經 TCP/IP 去使用遠端的物件。DRb 的運作方式跟傳統的 RPC 差不多，只是定義 Stub 和 Skeleton 都交給 Ruby 負責，遠端的客戶甚至不需任何有關類的定義，一切都動態地由 Ruby 完成了。 DRb 其中一個重要用處就是分隔和連接不同的服務。如 BackgrounDRb 就是一個使用 DRb 的 Rails plugin，它讓 Web Server 可以把一些繁重的工作交給另一個 Process (本地的或者其他的主機也可)。 前文試驗過怎樣在 JRuby 呼叫 RMI ，用同樣的方法，我們可以用 JRuby 作 proxy ，讓其他的 Ruby Process 可以如普通 Java 軟件一樣使用 RMI。 以下 Ruby 的源碼就會連接 RMI Service [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://chadfowler.com/ruby/drb.html">DRb</a> (Distributed Ruby) 是 Ruby 的 RPC。使用 DRb 我們可以經 TCP/IP 去使用遠端的物件。DRb 的運作方式跟傳統的 RPC 差不多，只是定義 Stub 和 Skeleton 都交給 Ruby 負責，遠端的客戶甚至不需任何有關類的定義，一切都動態地由 Ruby 完成了。</p>
<p><span id="more-782"></span><br />
DRb 其中一個重要用處就是分隔和連接不同的服務。如 <a href="http://backgroundrb.rubyforge.org/">BackgrounDRb</a> 就是一個使用 DRb 的 Rails plugin，它讓 Web Server 可以把一些繁重的工作交給另一個 Process (本地的或者其他的主機也可)。</p>
<p>前文試驗過<a href="http://www.reality.hk/articles/2008/02/13/780/">怎樣在 JRuby 呼叫 RMI </a>，用同樣的方法，我們可以用 JRuby 作 proxy ，讓其他的 Ruby Process 可以如普通 Java 軟件一樣使用 RMI。</p>
<p>以下 Ruby 的源碼就會連接 RMI Service 並開啟一個 DRb 服務：<br />
<code>
<pre>
module DRb
  def start_rmi_service(rmiuri=nil, drburi=nil, config=nil)
    DRb.start_service(drburi, RbRmi::Rmi.new(rmiuri), config)
  end
  module_function :start_rmi_service
end
</pre>
<p></code></p>
<p>接著我們可以如常使用 DRb ：</p>
<p><code>
<pre>
DRb.start_rmi_service "//0.0.0.0:5555/HelloServer", "druby://0.0.0.0:8888"
DRb.thread.join
</pre>
<p></code></p>
<p>這樣一個 DRb RMI 服務就完成了！試試在另一部電腦使用 irb ：</p>
<p><code>
<pre>
core:java siuying$ irb
irb(main):001:0> require 'drb'
irb(main):002:0> DRb.start_service
irb(main):003:0> rmi = DRbObject.new(nil, 'druby://:8888')
irb(main):004:0> rmi.sayHello
</pre>
<p></code></p>
<p>成功！我們可以把這包裝成一個指令，這樣只要在作整合的 server 輸入指令：</p>
<p><code>
<pre>
jruby rmi-drb.rb '//0.0.0.0:5555/HelloServer' 'druby://0.0.0.0:8888' "../hello.jar"
</pre>
<p></code></p>
<p>即可連接 Java 和 Ruby 的世界了！JRuby 還支援把 JRuby compile 成 Java Class，把這 package 後可以直接把 binary deploy，在任何支援 Java 的系統上執行！</p>
<p>有興趣試試這個程式可以到 svn 下載<a href="http://svn.reality.hk/ruby/rb-rmi/">源碼</a>。</p>
<h3>引申閱讀：</h3>
<ul>
<li><a href="http://chadfowler.com/ruby/drb.html">Intro to DRb</a></li>
<li><a href="http://backgroundrb.rubyforge.org/">BackgrounDRb</a></li>
<li><a href="http://www.reality.hk/articles/2008/02/13/780/">用 JRuby 整合 Ruby 和 Java</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.reality.hk/articles/2008/02/16/782/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用 JRuby 整合 Ruby 和 Java</title>
		<link>http://www.reality.hk/articles/2008/02/13/780/</link>
		<comments>http://www.reality.hk/articles/2008/02/13/780/#comments</comments>
		<pubDate>Tue, 12 Feb 2008 17:02:31 +0000</pubDate>
		<dc:creator>小影</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jruby]]></category>
		<category><![CDATA[rmi]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.reality.hk/articles/2008/02/13/780/</guid>
		<description><![CDATA[JRuby 是一個純 Java 下的 Ruby 實現。在 JVM 下執行的 Ruby 的移植性更好，而且可以讓 Ruby 直接使用 Java 的庫。今次我會介紹如何安裝和設定 JRuby ，並用它去呼叫現有的 Java RMI 。 安裝 JRuby 假設你己安裝了 Java ，那安裝 JRuby 很簡單： 到 JRuby 的網頁並選 &#8216;Download!&#8217;，選擇一個版本 ( jruby-bin-&#60;version&#62;.zip ) ，現在最新的是 JRuby 1.1RC1 ( jruby-bin-1.1RC1.zip ) 把檔案解壓到一個位置，如 /usr/local/jruby，並把 bin 加到 PATH 中 執行 jruby 即可使用 JRuby！ 通常我們用指令 jruby file.rb 去執行 ruby 程式 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://jruby.codehaus.org/">JRuby</a> 是一個純 Java 下的 <a href="http://www.ruby-lang.org/en/">Ruby</a> 實現。在 JVM 下執行的 Ruby 的移植性更好，而且可以讓 Ruby 直接使用 Java 的庫。今次我會介紹如何安裝和設定 JRuby ，並用它去呼叫現有的 Java RMI 。</p>
<p><span id="more-780"></span></p>
<h3>安裝 JRuby</h3>
<p>假設你己安裝了 Java ，那安裝 JRuby 很簡單：</p>
<ul>
<li>到 <a href="http://jruby.codehaus.org/">JRuby 的網頁</a>並選 &#8216;Download!&#8217;，選擇一個版本 ( jruby-bin-<em>&lt;version&gt;</em>.zip ) ，現在最新的是 JRuby 1.1RC1 ( <a href="http://dist.codehaus.org/jruby/jruby-bin-1.1RC1.zip">jruby-bin-1.1RC1.zip</a> )</li>
<li>把檔案解壓到一個位置，如 /usr/local/jruby，並把 bin 加到 PATH 中 </li>
<li>執行 jruby 即可使用 JRuby！</li>
</ul>
<p>通常我們用指令 jruby file.rb 去執行 ruby 程式 (file.rb)，也可以使用 jruby -S command 去執行一些內置的指令 (如 <a href="http://www.rubygems.org/">gem</a>)。詳細的用法可以用 jruby &#8211;help 看到。</p>
<h3>設定 Java RMI</h3>
<p>這個例子中我們假設已有一個 Hello World RMI Service。它的源碼很簡單：</p>
<h4>Hello.java</h4>
<p><code>
<pre>
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
	String sayHello() throws RemoteException;
}
</pre>
<p></code></p>
<h4>Hello.java</h4>
<p><code>
<pre>
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements Hello {
    public HelloImpl() throws RemoteException {
		super();
    }

    public String sayHello() {
		return "Hello World!";
    }

    public static void main(String args[]) {
		// Create and install a security manager
		if (System.getSecurityManager() == null) {
		    System.setSecurityManager(new RMISecurityManager());
		}

		try {
		    HelloImpl obj = new HelloImpl();
		    Naming.rebind("//0.0.0.0:5555/HelloServer", obj);
		} catch (Exception e) {
		    e.printStackTrace();
		}
    }
}
</pre>
<p></code></p>
<p>這個 RMI 服務只提供一個方法：String sayHello()。詳細的 RMI 設定我不重覆了，請參考 <a href="http://java.sun.com/j2se/1.3/docs/guide/rmi/getstart.doc.html">Sun 的介紹</a>。總之這裡我們假設 rmiregistry 和 HelloImpl 己經執行了，欠的只是一個 RMI Client。</p>
<h3>JRuby 中呼叫 Java RMI</h3>
<p>把相關的 RMI Stub 放在 JRuby 的 Class Path 中 (JRuby 也是一個 Java 程式啊！)，接著在 Jruby 中就可以使用有開的 RMI 了。這裡我們用 irb (Interactive Ruby Shell) 示範：</p>
<p><code>
<pre>
core:ruby siuying$ jruby -S irb
irb(main):001:0&gt; <strong>include Java </strong>
=&gt; Object
irb(main):002:0&gt; <strong>remote = java.rmi.Naming.lookup '//127.0.0.1:5555/HelloServer'</strong>
=&gt; #&lt;Java::Default::HelloImpl_Stub:0x2e62e @java_object=HelloImpl_Stub[UnicastRef [liveRef: [endpoint:[192.168.11.7:49661](remote),objID:[a96e08c:1180df7b735:-8000, 0]]]]&gt;
irb(main):003:0&gt; <strong>remote.sayHello</strong>
=&gt; "Hello World!"
</pre>
<p></code></p>
<p>include Java 是 JRuby 的魔法，只要使用它就可以直接在 JRuby 中用 package 指定 Java 的 class (也可以用 import 把特定的 class 或 package 全包括進來) 。</p>
<p>接著兩行就是 JRuby 在用 Naming 去找主機上的 HelloServer 服務，並使用它的 sayHello 方法。這和在 Java 上使用 RMI 沒有甚麼分別 &#8212; 除了源碼短少和動態的特性之外。</p>
<h4>rm_rmi.rb</h4>
<p><code>
<pre>
import 'hello.jar'
class RbRmi
  attr_reader :url
  attr_reader :classpath

  def initialize(url)
    @url = url
    self.init
  end

  protected
    def init
      @remote = java.rmi.Naming.lookup(url)
      @remote.java_class.declared_instance_methods.each() { |method|
        self.class.send(:define_method, method.name){ |*args|
          @remote.send(method.name.to_sym, *args)
        }
      }
    end
end</pre>
<p></code></p>
<p>接著輸入以下指令：<br />
<code>
<pre>
irb(main):047:0&gt; <strong>rmi = RbRmi.new "//127.0.0.1:5555/HelloServer"</strong>
=> #&lt;RbRmi:0x67ed25
@url="//127.0.0.1:5555/HelloServer", @remote=#&lt;Java::Default::HelloImpl_Stub:0x22631
@java_object=HelloImpl_Stub[UnicastRef [liveRef: [endpoint:[192.168.11.7:49661](remote),objID:[a96e08c:1180df7b735:-8000, 0]]]]&gt;,
@classpath="../hello.jar"&gt;
irb(main):048:0&gt; <strong>rmi.sayHello</strong>
=> "Hello World!"
</pre>
<p></code></p>
<p>rmi 明明只是個 Ruby RbRmi object，怎樣卻自動新增了 RMI stub 裡的方法！？這就是 Ruby 的動態特性的厲害之處。在執行中 (init 方法) 我們為 RbRmi 物件加入了新的 method！這是在程式碼或者在 command line 的 irb 中進行，完全沒有 compile 的過程！</p>
<p>當然，這個粗略的實作未必是 industrial strength 的解決方案，但這己可以看見在 JRuby 中使用 Java 物件(包括 RMI) 是如此的簡單。以後即使有沉重的遺留應用，我們還是可以好好利用 Ruby 的強大生產力了。</p>
<p><strong>Update@13 Feb</strong>: 原本的程式只支援沒有 argument 的 method，改良為支援任意數目的 arguments 。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.reality.hk/articles/2008/02/13/780/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
