2010-01-24

C++の参照渡しは Javaと違うのか?

Java の参照と C++ の参照の違い

これって未だに誰も突っ込んでいないようなんだけど、
C++版の f() にある

dest = Foo(message);

で何が実際に行われるかを勘違いしておられるように見えるのだけれど。
(ヒント:暗黙の operator=)
それとも私の知らないうちにC++が変わったんだろうか。最近滅多に使わないから・・・

【追記】
ちゃんとコメントで指摘されていた(コメント承認までのラグ)みたいです。
私なんぞが出る幕ではなかったですね。

2010-01-17

ApacheとWebDAVとPHP

WebDAVを使って PHPファイルなどのスクリプトファイルを編集しようとすると、DAVクライアントから PHPスクリプトへの要求が発生したときに中身がわざわざ実行されてその結果が返ってきてしまう。

それを避けるには、適当な Locationなりに
ForceType text/plain
を入れてやればいいのだが、なにかの拍子でこれが効かなくなった。
Apache 2.2.14で何か変わったのだろうか。バグかな。

仕方ないので
<FilesMatch "\.ph(p5?|tml)$">
SetHandler None
</FilesMatch>
も入れてしのいだ。

nss-myhostnameで、自ホスト名を常に引けるようにする

Javaで自ホストの名前を調べようとしたら、下記のようになる。
java.net.InetAddress.getLocalHost().getHostName()

のだが、getLocalHost()の呼び出し時点で UnknownHostException が出てしまう場合がある。
Javaランタイムは getLocalHost()の中でまず自ホスト名を調べた後にそのIPアドレスを解決しようとするのだが、するとホスト名からIPアドレスを解決できない場合には当然この例外が送出されることになる。

ホスト名からIPアドレスを引けない理由をいろいろ端折って一言でいうと、/etc/hosts に載っていないからだ。
OSのインストーラが気を利かせて /etc/hostsにホスト名を追記してくれていればこういう問題は起こらないのだが、その場合にせよ手動でホスト名を後で変更するさいに /etc/hostsにも変更を加えるのを忘れるというのは容易に起こりうる。
何を言いたいかというと、ホスト名の変更ごときのために設定を2カ所も変えなければならないというのはスマートさに欠けるということだ。

長い能書きの後に結論を手短に言うと、libnss_myhostname.so というnssモジュールを /lib に入れて /etc/nsswitch.conf の hosts: 行に myhostname を追加しておけば /etc/hostsにわざわざ自ホスト名を記述しなくても IPアドレスが引けるようになる。よって java.net.InetAddress.getLocalHost()は成功する。

但し期待したネットワークインターフェイスにバインドされたIPアドレスではなくローカルループバックのアドレス(127.0.0.2)が返ることに注意すること。(他のホストからも到達可能な、まっとうなIPアドレスをホスト名から得たいのであれば、nss-myhostnameを使うのは適切ではない)

nss-myhostname: http://0pointer.de/lennart/projects/nss-myhostname/

2009-12-19

Debian lennyに Aipoを入れる

aipoは国産のグループウェア。Javaでできており Tomcat上で動作する。バックエンドDBとしては PostgreSQLを使用する。
公式に配布されているインストーラは CentOSでしか動作しないのと、また既存環境を壊さないように独自に JREを持っていてかつ自前でPostgreSQLをビルドするなどのつつましやかな動作をする。が、今は仮想化の時代なので aipo専用に環境を用意するなどたやすい。
というわけで最小のディスク容量で aipoサーバを構築するため debootstrapで作成したミニマム構成の Debian上で、apt-getでインストール出来る標準の PostgreSQL/Tomcat/JavaVM/Apacheを使って aipoを動作させてみる。

apt-getするものはこれだけ。Macや Windowsから動的に名前解決をしたければ avahi-daemonや sambaも入れると良い。

apt-get install postgresql tomcat5.5 apache2 openjdk-6-jre-headless

postgresql上に aipo用のデータベースを作成する。

su - postgres で postgresユーザになる。

createuser -SDRP aipo_postgres
パスワードを聞かれるので aipo に設定
createdb org001 -O aipo_postgres

exit で元のユーザに戻る

/etc/postgresql/8.3/main/pg_hba.conf を開いて編集する。
local all all password sameuser
のように、local行にある ident の部分を passwordに変更する。

PostgreSQLを再起動する
/etc/init.d/postgresql-8.3 restart

aipoを展開する
tar zxvf aipo5000.tar.gz

スキーマ定義とサンプルデータの投入
psql -U aipo_postgres -d org001 -W -f aipo/backup/postgresql/sample_dump/aipo_db_sql.dump
パスワードを聞かれるので aipo と入力

PostgreSQLの JDBCドライバを Tomcatに追加
mv aipo/src/postgresql-8.1-407.jdbc3.jar /usr/share/tomcat5.5/common/lib/

aipo本体を Tomcatに追加
mv aipo/src/webapps/aipo /var/lib/tomcat5.5/webapps/

aipoの設定ファイル /var/lib/tomcat5.5/webapps/aipo/WEB-INF/conf/AipoResources.properties を編集
aipo.webappserver.port=80
のように変更する(元の値は8080)

サンプルデータに所属する各種リソースファイルをコピー
cp -rf aipo/backup/postgresql/sample_dump/psml /var/lib/tomcat5.5/webapps/aipo/WEB-INF
cp -rf aipo/backup/postgresql/sample_dump/files /var/lib/tomcat5.5/webapps/aipo/WEB-INF
cp -rf aipo/backup/postgresql/sample_dump/mail /var/lib/tomcat5.5/webapps/aipo/WEB-INF

aipo関連ファイルの所有権を全て tomcat55 に変更
chown -R tomcat55 /var/lib/tomcat5.5/webapps/aipo

/etc/default/tomcat5.5 ファイルを編集

JAVA_HOME=/usr/lib/jvm/java-6-openjdk
TOMCAT5_SECURITY=no

のように JAVA_HOMEと TOMCAT_SECURITY行を変更

/aipo/へリダイレクトするためのトップページを TomcatのROOTアプリケーションとして配置
mv aipo/src/webapps/ROOT /var/lib/tomcat5.5/webapps/

Tomcatを再起動
/etc/init.d/tomcat5.5 restart

Apacheの Proxy, AJPモジュールを有効化する
a2enmod proxy
a2enmod proxy_ajp

/etc/apache2/mods-enabled/proxy.conf を編集し、/aipo へのアクセスを Tomcatへ転送するよう設定する

<IfModule mod_proxy.c>
ProxyPass / ajp://localhost/
</IfModule>


Apacheの再起動
/etc/init.d/apache2 restart

上記完了後、ブラウザからHTTPでアクセスすると aipoが利用できる。

Spring 3.0が出た

ので、Webアプリケーションから ContextLoaderListenerを使って普通に Springを利用するケースで最低限どの jarファイルが必要かだけ調べて置いた。

commons-logging-*.jar
org.springframework-asm-3.0.0.RELEASE.jar
org.springframework-beans-3.0.0.RELEASE.jar
org.springframework-context-3.0.0.RELEASE.jar
org.springframework-core-3.0.0.RELEASE.jar
org.springframework-expression-3.0.0.RELEASE.jar
org.springframework-web-3.0.0.RELEASE.jar

applicationContext.xml が空ならこれで Webアプリケーションが起動出来る。

Hibernateの SessionFactoryやら TransactionManagerやらを使おうとしたら更に下記が必要だった。

aopalliance.jar
org.springframework-aop-3.0.0.RELEASE.jar
org.springframework-jdbc-3.0.0.RELEASE.jar
org.springframework-orm-3.0.0.RELEASE.jar
org.springframework-transaction-3.0.0.RELEASE.jar

langは何処に行ってしまったのか今捜索中。まさかディスコンなんてことは・・・

2009-12-15

すぐに動かす Struts2.1と Convention Plugin

ずっと前に Struts2.0の ZeroConfプラグインベースで色々調べてブログのエントリを起こしたんだけど、しばらく Struts2から離れてて久しぶりに見てみたらバージョンが 2.1になってて、ZeroConfが廃止されて Conventionなるものに置き換わってるじゃないですか。

まあいいや。Struts2.1をダウンロードしてきたら、

struts2-core-*.jar
struts2-convention-plugin-*.jar
xwork-core-*.jar
commons-fileupload-*.jar
freemarker-*.jar
ognl-*.jar

あたりを WEB-INF/lib に放り込む。DIは Springにさせたいんじゃという場合は struts2-spring-plugin-*.jarも。
で前回は struts.xml無しでどれだけ行けるかってことでやってたにも関わらず今回はのっけからギブアップ。
Eclipseから自前の Mainクラスで Jettyを起動してるような場合、親クラスローダーに属するクラスを除外してしまうとアクションクラスが探し出せない。仕方ないので下記のような struts.xmlを Javaソースディレクトリのトップに配置。


<struts>
<constant
name=
"struts.convention.exclude.parentClassLoader"
value=
"false"/>
<constant
name=
"struts.convention.package.locators.basePackage"
value=
"your.package.name.here"/>
</struts>


WEB-INF/web.xmlに書き入れるのはこんな風

<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


で、actionとか actions って名前のパッケージ内にアクションクラスを配置する。アクションクラスは名前が "なんとかAction"であること。/hoge というURIにマッピングされるアクションは HogeActionだし、/ で終わるURIにアクションをマッピングしたいならIndexActionという名前にする。アクションクラスにはそれぞれ execute()メソッドを作る。

ブラウザからリクエストが送信されると、パラメータ群が setterメソッドにより Actionクラスのオブジェクトにセットされて、execute() メソッドが実行される。executeメソッドはアクションの実行結果を示す文字列を返す。典型的に、通常の戻り値は "success" である。

例で説明すると、Webアプリケーションのコンテキストパスが /struts2test で、そこのルート URI ( e.g. http://hogehoge/struts2test/ ) に対応するアクションを作りたいなら、net.stbbs.actions.IndexAction という名前のクラスを作る。net.stbbs の部分はなんでもいいが、struts.xmlに struts.convention.package.locators.basePackage プロパティを指定したならそのパッケージに含まれていること。

URIに階層を設けるなら(例えば http://hogehoge/struts2test/user/ )、パッケージもそれに対応する名前の階層を作って net.stbbs.actions.user.IndexAction のようにすれば良い。

IndexActionの exeucte()が "success"を返すと、処理は WEB-INF/content/index.jsp にフォワードされる。execute()が "fail" を返したなら、WEB-INF/content/index-fail.jsp である。というかむしろ Struts1を考えた時点でこういう規約を何故用意してくれなかったんだろう。

対応するアクションクラスが無い場合、(例えばリクエストされたURI /hoge に対して HogeActionが見つからない場合)、処理は WEB-INF/content/hoge.jsp にそのまま転送されることに注意。hoge.jspもない場合は容赦なく 404となる。

/ に対して IndexAction, /hoge に対して HogeActionをそれぞれ作るのは面倒なので、差し支えない範囲でアクションクラスをまとめてしまうこともできる。例えば IndexActionに hoge() メソッドを追加して @Action("hoge") というアノテーションを付けておけば、IndexAction#hoge()は /hoge へのリクエストにマッピングされてくれるので HogeActionを作らなくて済む。入出力パラメータの似通ったアクションをひとつのクラスにまとめるにはこの方法がいいだろう。

規約とアノテーションで URIにアクションクラス(とメソッド)をマッピングする方法の概略終わり。
続くかどうかは不明。

2009-12-11

コマンドプロンプトから MS SQLServerのバックアップを取る

sqlcmd -Q "backup database データベース名 to disk='c:\backup\mybackup.bak' with init"

これをバッチファイルか何かにしてタスクスケジューラにでも食わせておけば良い。