
問題の本質
長い間開発されているJavaアプリケーションに出会ったことのある人なら誰でも、その多くが非常にゆっくりとビルドして起動することを知っています。 これが起こる理由については説明しません。 これは別の記事のトピックです。
勤務中、私は巨大なコードベースを持つ非常に古いアプリケーションをサポートする必要がありました。 最悪の場合、1分から7分、さらに3分に始まります。 繰り返しになりますが、すべてのプログラマーが特定の量のコードを書くために地獄を想像し、そのような長いサイクルで外部サービスからNullPointerExceptionをキャッチすることは難しくありません。
別のオプションも可能です。 クラスには、すでに実行していることに近いタスクを実行するために適合させる必要がある一定量のコードがあります。 ここで、このクラスがJava 1.4の一部として実装されていると想像してください。 GenericはJava 1.5でのみ追加されたため、Genericでは機能しません。 さらに、以前システムをサポートしていたプログラマーは積極的にこれを使用し、他のクラスのメソッドによって返されるコレクションにポップします。これは、匿名のjava.lang.Object実装にはなりません。
数日間サボテンを食べた後、私は1日に5〜20行の作業コードを書いているという事実に夢中になり始めていると感じました。
このような野barな状況で開発を加速できる唯一の方法は、動的言語のインタープリターをアプリケーションにねじ込んで、そのような状況に脆弱なコードを最初にプロトタイプ化し、次にJavaでアルゴリズムを実装することです。 もちろん、ソリューションのフレームワーク内では、この言語のインタラクティブコンソールも必要でした。 これがないダイナミクスは何ですか? FreeBSDでアプレットが非常に貧弱に動作するという事実のために、コンソールをアプレットに入れたくありませんでした(最近は慣れてきました)。
既存のソリューションを検索する
「フォーク」サイプを発明することはうまくいかないという意見の支持者として(多くの場合、そこからピッチフォークのみが残るため)、私は週末にこの問題に対する既存の解決策を掘り下げることにしました。 本当にPythonが欲しかった。 しかし、最初の選択肢に戻る前に、何とか目をそらしました。
- Beanshell-telnetコンソールの悲惨さのために破棄され、そのままの状態でインタープリターとともに配信されます。 アプレットが収まりません。
- JRuby-人気の最初の発生時にRailsで遊んで以来、この言語を安全に忘れることができたことを発見したからではなく、破棄されました。 クイックグーグルでは、一部のCorbaモンスター以外の結果は得られませんでした。 おびえて閉め......
- グルーヴィー
wantedで見つけたものに似たもの。 Spring Beanとして実装され、ブラックジャックと売春婦を備えた独自のDependecy Injectionフレームワークがあります。 試したことがありません。
ジソン
Pythonプログラマーは、その概念の1つである「バッテリーを含む」をよく知っています。これは、標準パッケージであっても、さまざまなおいしいライブラリを意味します。 Javaのみが独自のバッテリーを持っています。 JVMのPython実装は単なる参考ですが、ライブラリはまだ完全に移植されていないため(たとえば、最近Jython環境にインストールツールがインストールされ始めたため)、ネイティブPythonソリューションを取得できませんでした。
JythonのさまざまなバージョンでRPyCを試しました (夜は気付かれませんでした)。 ツイストマンホールについて読みました。 Jythonとの統合のためにテストブランチのソースコードをマージしないことにしました。JythonのTwistedの修正を開始し、その後学士になる危険性があるためです。
github.com/EnigmaCurry/jython-shell-serverを収集し、実現しました。readlineはなく、幸せはありません。 開発者がサーバー側でこの機能を実装していない限り、Telnetはreadlineをサポートしません。 長さ80文字の文字列を記述し、最初のオブジェクトが異なる方法で呼び出されることを思い出してください。 もちろん、マウスをコンソールに刺すこともできますが、ネイティブのbashのような環境が必要でした。
私の実装
サーバー
5分で、彼はサーバーインターフェイスとしてXMLRPCを選択しました。 次の5分間、彼は心を変えませんでした。 次の20分間で実現しました。
Jythonサーバーコード:
from SimpleXMLRPCServer import * <br/>
from os import path<br/>
from code import InteractiveConsole as BaseInteractiveConsole<br/>
<br/>
class Stdout ( object ) :<br/>
""" stdout """ <br/>
def __init__ ( self ) :<br/>
self . buffer = '' <br/>
<br/>
def get_buffer ( self ) :<br/>
""" """ <br/>
bc = self . buffer <br/>
self . buffer = '' <br/>
return bc<br/>
<br/>
def write ( self , bs ) :<br/>
""" """ <br/>
self . buffer += bs<br/>
return len ( bs ) <br/>
<br/>
class InteractiveConsole ( BaseInteractiveConsole ) :<br/>
""" , """ <br/>
<br/>
def __init__ ( self , locals ) :<br/>
""" """ <br/>
BaseInteractiveConsole. __init__ ( self , locals ) <br/>
# <br/>
self . stdout = sys . stdout = sys . stderr = Stdout ( ) <br/>
<br/>
def push ( self , line ) :<br/>
result = BaseInteractiveConsole. push ( self , line ) <br/>
return ( result, self . stdout . get_buffer ( ) ) # <br/>
<br/>
<br/>
<br/>
class Server ( SimpleXMLRPCServer ) :<br/>
"""XMLRPC-, """ <br/>
<br/>
def __init__ ( self , ls, * args, ** kwargs ) :<br/>
SimpleXMLRPCServer . __init__ ( self , * args, ** kwargs ) <br/>
self . register_introspection_functions ( ) <br/>
# <br/>
self . register_instance ( InteractiveConsole ( ls ) )
お客様
基本的なインターフェースとしてCmdが選択されました。このインターフェースはすぐにreadlineをサポートしますが、これが必要です。
今回のサーバーコードはPython(JythonのCmdはreadlineをサポートしていないようです):
from cmd import Cmd as BaseCmd<br/>
from code import InteractiveConsole as BaseInteractiveConsole<br/>
import re , sys <br/>
from xmlrpclib import ServerProxy<br/>
<br/>
class Cmd ( BaseCmd ) :<br/>
""" -""" <br/>
reg = re . compile ( '^ \s *' ) <br/>
def __init__ ( self , host, port ) : <br/>
BaseCmd. __init__ ( self ) <br/>
self . s = ServerProxy ( 'http://%s:%d' % ( host, int ( port ) ) ) # <br/>
self . prompt = '>>> ' # <br/>
self . leading_ws = '' # <br/>
self . is_empty = False # <br/>
<br/>
def precmd ( self , line ) :<br/>
""" ,<br/>
""" <br/>
# , .. default <br/>
self . leading_ws = self . reg . match ( line ) . group ( 0 ) <br/>
# , .. <br/>
self . is_empty = ( line == '' ) <br/>
return line # , <br/>
<br/>
def default ( self , line ) : <br/>
if ( self . is_empty ) : # y <br/>
line = '' <br/>
line = self . leading_ws + line # <br/>
( result, output ) = self . s . push ( line ) # <br/>
# <br/>
self . prompt = ( '... ' if result else '>>> ' ) <br/>
sys . stdout . write ( output ) # :) <br/>
<br/>
if __name__ == '__main__' :<br/>
HOST, PORT = sys . argv [ 1 : ] <br/>
Cmd ( HOST, PORT ) . cmdloop ( )
サーバー用のJavaラッパー
サーバーを実行するシンプルなBean。 どこでも簡単です。
package net.rjyc ; <br/>
<br/>
import org.python.util.PythonInterpreter ; <br/>
import java.util.* ; <br/>
<br/>
public class Server { <br/>
private PythonInterpreter i ; <br/>
public PythonInterpreter getInterpreter ( ) { <br/>
return i ; <br/>
} <br/>
public Server ( String host, int port ) { <br/>
this ( host, port, new HashMap < String, Object > ( ) ) ; <br/>
} <br/>
public Server ( String host, int port, Map < String, Object > locals ) { <br/>
i = new PythonInterpreter ( ) ; <br/>
// <br/>
i. set ( "host" , host ) ; <br/>
i. set ( "port" , port ) ; <br/>
i. set ( "ls" , locals ) ; <br/>
} <br/>
<br/>
public void start ( ) { <br/>
// <br/>
i. exec ( "from rjyc import Server; Server(dict(ls), (host, port), logRequests = False).serve_forever()" ) ; <br/>
} <br/>
}
使用する
フィールドからのリンクのリストを表示する架空のサーブレットを想像してください。
import javax.servlet.http.* ; <br/>
import java.util.* ; <br/>
import java.io.* ; <br/>
<br/>
public class Hello extends HttpServlet { <br/>
public final Map < String, String > links = new HashMap < String, String > ( ) ; <br/>
{ <br/>
links. put ( "Python" , "http://python.org" ) ; <br/>
links. put ( "Java" , "http://java.net" ) ; <br/>
} <br/>
@ Override protected void doGet ( HttpServletRequest request, HttpServletResponse response ) <br/>
throws IOException { <br/>
PrintWriter writer = response. getWriter ( ) ; <br/>
for ( Map . Entry < String, String > e: links. entrySet ( ) ) <br/>
writer. println ( "<a href= \" " +e. getValue ( ) + " \" >" +e. getKey ( ) + "</a>" ) ; <br/>
writer. close ( ) ; <br/>
} <br/>
}
Webサーバーの回答は次のとおりです。
siasia@siasia ~ % wget http://localhost:8080 -O - 2>/dev/null <a href="http://python.org">Python</a> <a href="http://java.net">Java</a>
次に、コンソールを紹介します。
import javax.servlet.http.* ; <br/>
import java.util.* ; <br/>
import java.io.* ; <br/>
import net.rjyc.Server ; <br/>
<br/>
public class Hello extends HttpServlet { <br/>
public final Map < String, String > links = new HashMap < String, String > ( ) ; <br/>
{ <br/>
links. put ( "Python" , "http://python.org" ) ; <br/>
links. put ( "Java" , "http://java.net" ) ; <br/>
Thread t = new Thread ( ) { <br/>
@ Override public void run ( ) { <br/>
Map < String, Object > locals = new HashMap < String, Object > ( ) ; <br/>
locals. put ( "this" , Hello. this ) ; <br/>
new Server ( "localhost" , 8081 , locals ) . start ( ) ; <br/>
} <br/>
} ; <br/>
t. start ( ) ; <br/>
} <br/>
@ Override protected void doGet ( HttpServletRequest request, HttpServletResponse response ) <br/>
throws IOException { <br/>
PrintWriter writer = response. getWriter ( ) ; <br/>
for ( Map . Entry < String, String > e: links. entrySet ( ) ) <br/>
writer. println ( "<a href= \" " +e. getValue ( ) + " \" >" +e. getKey ( ) + "</a>" ) ; <br/>
writer. close ( ) ; <br/>
} <br/>
}
そしてそれに接続します:
siasia@siasia ~ % python client.py localhost 8081 >>> this examples.Hello@13ebc5c >>> this.links {Python=http://python.org, Java=http://java.net} >>> this.links['Scala'] = 'http://scala-lang.org' >>> this.links {Scala=http://scala-lang.org, Python=http://python.org, Java=http://java.net}
結果を確認します。
siasia@siasia ~ % wget http://localhost:8080 -O - 2>/dev/null <a href="http://scala-lang.org">Scala</a> <a href="http://python.org">Python</a> <a href="http://java.net">Java</a>
メイヴン
Mavenを使用する場合に備えて、Mavenアーティファクトを準備しました。
- リポジトリをpom.xmlに追加します。
<リポジトリ> <id> Rjycリポジトリ</ id> <url> http://siasia.github.com/maven2 </ url> </ repository>
- rjycに依存関係を追加します。
<依存性> <groupId> org.python </ groupId> <artifactId> rjyc </ artifactId> <バージョン> 1.0-SNAPSHOT </バージョン> </ dependency>
- サーバーをコードにインポートします。
import net.rjyc.Server;
- 上記のように実行します。
- クライアントをダウンロードhttp://github.com/siasia/rjyc/raw/master/client.py
-
python client.py [host] [port]
- 利益!!!
この記事が他の誰かを少し幸せにすることを願っています。
github http://github.com/siasiaでフォークしてください 。