Java を使って画面コピーを取得する

タイトルの通り。
環境はこちら。

C:\Documents and Settings\user1>java -version
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)

C:\Documents and Settings\user1>

コードはこれ。

// $Id$
package test;

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public class Capture {

	public static void main(String[] args) throws Exception {
		Capture self = new Capture();
		self.screenCapture(new URL("http://www.akky.org/"),new File("test.png"));
	}
	/**
	 * IEを使ってキャプチャーする
	 * @param url 対象URL
	 * @param saveFile 保存ファイル名
	 * @throws AWTException java.awt.Robotクラスからの例外
	 * @throws IOException 画面イメージの保存中にエラー
	 * @throws InterruptedException ブラウザの描画待ちの間に割り込みが発生した
	 */
	private void screenCapture(URL url,File saveFile) throws AWTException, IOException, InterruptedException{
		// IEを起動
		String command = "C:\Program Files\Internet Explorer\IEXPLORE.EXE " + url.toString();
		Process process = Runtime.getRuntime().exec(command);
		// ブラウザの描画が終るであろう、30秒程度待つ
		Thread.sleep(1000 *10);
		// 画面キャプチャーを取得
		Robot robot = new Robot();
		Rectangle rect = new Rectangle(1024, 768);
		BufferedImage captured = robot.createScreenCapture(rect);
		// ConvolveOpを使ってボカシを掛ける
		float scale = 0.2f; // 縮小する比率
		int size = (int)(1.0/scale);
		float[] kernelData = new float[size*size];
		for (int i = 0; i > size * size; i++) {
			kernelData[i] = 1.0f / size / size;
		}
		Kernel kernel = new Kernel(size, size, kernelData);
		ConvolveOp coOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
		BufferedImage inter = new BufferedImage(captured.getWidth(), captured.getHeight(), captured.getType());
		coOp.filter(captured, inter);
             // ぼかした画像を縮小
                AffineTransformOp atOp = new AffineTransformOp(
                    AffineTransform.getScaleInstance(scale, scale), null);
                BufferedImage dest = new BufferedImage((int)(captured.getWidth() * scale),
                     (int)(captured.getHeight() * scale),
                    captured.getType());
                atOp.filter(inter, dest);
                // 保存
		saveFile.delete();
		ImageIO.write(dest, "png", saveFile);
		// IEを終了
		process.destroy();
	}

cakePHPのAjaxヘルパーがGETメソッドを呼ぶ前に検査を行なう

AjaxヘルパーのobserveFormを用いた更新を行なう前に、フォームの値を検査して画面の更新を制御したい時の方法です。具体的には、フォームの値がない(空白)の場合は更新をしたくなかった。

実装はHTMLのformタグのonSubmitイベントでfalseを返却してsubmitを中断させる動きのcakePHP版。view部分のソースがこれで、

   $opt = array(
        "url" => "/hogeapli/result", // 反映するURL
        "update" => "result", // 反映先のdivタグのID
        "frequency" => "1", // 値変更の監視間隔
        "with" => "document.searchForm.serialize()", // 送信するフォーム
        "condition" => "searchFormSubmit()" // 検査を行なうJavaScriptのメソッド
      ); // 送信するフォーム
  echo $ajax->observeForm("searchForm",$opt);

optionのconditionに検査を実装したJavaScriptの関数を指定しておく。JavaScriptでは画面を更新したいときはtrueを返し、更新したくないときはfalseを返す実装をしておく。コードがこれ。

function searchFormSubmit(){
  var ret = false;
  for each( var e in document.forms.searchForm.elements ){
    if ( e.nodeName =="INPUT" ){
      if ( e.value != "" ){
        ret = true;
      }
    }
  }

  return ret;

こうすることで、フォーム内の値の変更を検知し、画面更新をする前に、JavaScriptのsearchFormSubmitが実行され、戻り値に従って更新の継続/中断を制御する。

LinuxからWindowsのファイル共有をmountする。 cifsで。

smbmountでWindowsXPの共有をmountしようとしたけど、漢字の文字化けを解決できなかった。コマンドはこんなん。ちなみに、smbmountを実行しているのは、CentOS4.5。localeはja_JP.UTF-8。

smbmount ‘//WindowsXPのIPアドレス/共有名’ /media/smb -o username=WindowsXPのユーザ,password=WindowsXPのパスワード,codepage=cp932,iocharset=utf8

マウント自体はできるものの、漢字を含む文字化けを解消できない。

でぐるぐるして、cifsにたどり着く。Windows上のファイルにLinuxからアクセスするには(mount.cifs編)を参考にして、cifsでマウントする。

mount -t cifs ‘//WindowsXPのIPアドレス/共有名’ /media/smb -o username=WindowsXPのユーザ,password=WindowsXPのパスワード

Oracle Secure Enterprise Search 10g Release 1 (10.1.6) のインストール

RedHat entrtpiese Linux 4にOracle Secure Enterprise Search 10g Release 10g(ses)をインストールしたのでそのときのメモ。

  • 足りなかったパッケージ「openmotif-2.2.3-10.RHEL4.5」をrpmでインストール
  • /etc/sysctl.confにカーネルパラメータを追加

    fs.file-max=65566
    kernel.sem=250 32000 100 128
    kernel.shmmax=2147483648
    net.ipv4.ip_local_port_range= 1024 65000

  • /etc/security/limits.confにユーザ制限の上限変更を追加

    * soft nproc 2047
    * hard nproc 16384
    * soft nofile 1024
    * hard nofile 65536

  • /etc/pam.d/loginにモジュール読み込みを追加

    session required /lib/security/pam_limits.so

  • /etc/profileに追加

    if [ $USER = "oracle" ]; then
    if [ $SHELL = "/bin/ksh" ]; then
    ulimit -p 16384
    ulimit -n 65536
    else
    ulimit -u 16384 -n 65536
    fi
    fi

  • CDからrunInstallerを起動
  • OIUに従ってインストール。

起動/停止は$ORACLE_HOME/bin/searhctl [startall|stopall]を実行する。管理者パスワードを聞かれるので、インストール時に指定した管理者パスワードを入力する。DBのsysユーザのパスワードがこれになっている

PostgreSQLとHibernateとトランザクション

DBアクセスにHiberanteをつかったJavaアプリを作ったときに発生した悩ましい問題。検索だけの画面の実装において、一連の処理が終わった後にはHibernateのセッションを閉じるためにfinallyでSession.close()を実行している。けど、pgAdminでPostgreSQLのロックの状態をみると、検索したテーブルの索引を排他ロックしたままになっている。明示的にトランザクションの開始をしていないけど、セッションを終了させているのだからトランザクションも終了させてロックを解除して欲しい。けど、ロックしたままになっている。poolしていないけどセッションも残っているが若干気になるが、ロックが残っているもが解せない。

試行錯誤の結果、検索だけであっても明示的にトランザクションを開始し、セッションを閉じる前にcommitする。そうすることで、ロックの残骸はなくなったけどすっきりしないな。これまでの開発ではセッションを閉じるタイミングで暗黙的に開始されているトランザクションであればロールバックされ、ロックも開放されるのだけどな。

PostgreSQLとHibernateとの相性が良くないのか、Hiernateの使い方が間違っているのか。

Oracle ORA-00600 keltnfy-ldmInit エラー

インスタンスが起動しないと思ったら、alertにエラーが出ていた。

Errors in file /usr/local/oracle10g2/admin/orcl/udump/orcl_ora_4375.trc:
ORA-00600: internal error code, arguments: [keltnfy-ldmInit], [46], [1], [], [], [], [], []
USER: terminating instance due to error 600
Instance terminated by USER, pid = 4375

どうやら、自分自身のホスト名が解決できないのが原因。はて?と思いつつも、/etc/hostsを編集しようとすると中身がからっぽ。0バイトになっている。orz
hostsに記述を追加して無事に起動

起動スクリプト

インストール後に、OS自体を再起動してSQL*Plusで接続しようとすると、インスタンスが起動していない。SQL*Plusから起動してみると、HDDを激しくアクセスしつづけているので、はて?。と考えてみると、起動/停止スクリプトの準備をしていなかったので、リカバリーが動き出しているんだ。orz。という訳で、まずはrcを使った起動/停止から。

ググッてみると、dboraなる起動スクリプトがあるらしく、ORACLE_BASEの下をfindしてみるが、見つけられず。要はdbstartとdbshutを呼び出せばいいんでしょ。とはいいつつも、ゼロから作るのは面倒なので、sugimuraさんのサイトから頂きました。

ここまでで、つまずいたこと。

dbshutで停止できない。
dbstartした場合でないとdbshutで停止できなかった。一度は手動で停止して、dbstartを使って起動されるのを確認
DBユーザscottがロックされている
sysdbaで接続して、alter user scott account unlock;を実行してアカウント解除。最初のログイン時に新しいパスワードを要求される。

解決できなかったこと。環境変数ORACLE_SIDを設定して、SQL*PlusからDBへ接続ようとするが

[oracle@localhost ~]$ sqlplus scott/tiger

SQL*Plus: Release 10.2.0.1.0 - Production on Wed Dec 5 00:17:19 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

ERROR:
ORA-01034: ORACLE not available
ORA-27101: shared memory realm does not exist
Linux Error: 2: No such file or directory

Enter user-name: [oracle@localhost ~]$

となってしまう。リスナー経由での接続はOK

oracle11gがリリースされたけど、いまさらながらoracle10gにチャレンジ

最近はMySQLとPostgreSQLの案件が多いものの、かつてはOracle Master Platinum 8iまで取得したOracleの勉強を始めてようと思います。Platinum 8iを取得したころは最前線のDBAであったものの、最近はOracle自体から遠ざかってしまい新機能の事を知らないし、EBSに手を出しそうなので余裕があるときに勉強をしようと思います。

極力、実環境ベースでやっていきたいので、CentOSを使った環境を用意しました。

    OS
    CentOS 4.5
    kernel
    2.6.9-55
    Oracle
    10.2.0.1.0

app/views/pages/home.thtml で helperを使う方法

home.thtmlでJavaScriptヘルパーを使おうとおもったら、

Notice: Undefined variable: javascript in /usr/local/corpjoin/app/views/pages/home.thtml

とエラーになってしまった。

ぐぐって、CakePHPではまったこと 10(home)にあった。

home.thtmlでヘルパー(html以外の)とか使いたい場合は、 cake/libs/controller/pages_controller.phpを app/controller/pages_controller.phpにコピーしてvar $helpers;を定義すればよいです。

らしい。

hiberanteとPostgreSQL

仕事が忙しくて一月の間放置。久しぶりです。

で、忙しかった仕事はPostgreSQLのDBにHibernateを使ってDBアクセスする方式。初めてのHibernateであったけど、使い方は概ね障害となることもなく進んだのだが、いまだに解決できていない問題がある。それは、Hibernateのセッションはcloseしているのだけど、PostgreSQLから見るとトランザクションの途中で排他ロックしているオブジェクトが残ってしまう。PGの意図としてはセッションをcloseしたのだからトランザクションも終了して欲しいのだが、現実は残っている。

事象をもう少し説明すると、SELECTだけを実行しているのにトランザクションの途中になっている。まあ、暗黙的にトランザクションを開始しているのだろうけど、セッションを終了させたのだから暗黙的に開始されたトランザクションも終了して欲しいな。と。半月近く悩み続けているこの問題。ちょっと余裕が出てきたので考え直し。
これまでは、JDBC(というかjava.sql.*のクラスを直接実行する方式だけでしか業務アプリを作成したことがなく、これまではSELECTだけであればfinallyでjava.sql.Connectionをcloseすることでトランザクションも終了させていた。が、今回はそうもいかない。

余裕があることで、Hierbateのソースを持ってきてeclipseからふにふにとデバック実行ですよ。org.hibernate.impl.SessionImpl#Close()を追っていくと、java.sql.Connectionのセッションをクローズする分岐に入っていかないな。なんでだろう・・・

試しに明示的にトランザクションを開始させ、セッションをcloseするためにトランザクションをcommitするとPostgreSQLにトランザクション途中のものはなくなっている。

Webの記事を見ていると、Hibernate + PostgreSQLの例があるが、SELECTだけでも明示的にとトランザクションを開始/終了している記事は見つけられず。なにか、設定が足りないのか外れを引いてしまったのか・・・