MB blog

こちらは主に自分用のメモです。

ATNDで, 気になるイベントをメールで通知させる

今年は社外の勉強会に定期的に行く、と上司と1年前に約束したことをふと思い出し、最近になって勉強会に出向くようになりました。イベント探しによく利用するのはご存知ATNDです。
しかし、たまに思い出したときに気になるキーワードで検索をかけてみると、いい感じのイベントがすでに定員オーバーになっている、ということも少なくありません。
そこで、あらかじめ登録したキーワードにマッチするイベントを、メールで通知してくれるアプリを書いてみました。
ATNDのJava APIはここから落とせました。 => http://atnd4j.sourceforge.jp/
commonsのSimpleEmailを使って、Gmailsmtpサーバーから送ってます。

汚いけど許してね...

package jp.boc.com;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.hkzo.atnd4j.Atnd;
import org.hkzo.atnd4j.Event;
import org.hkzo.atnd4j.EventsResult;

public class EventNotifier {

	public static void main( String args[] ){

		EventNotifier ntfr = new EventNotifier();

		List<String> list = new ArrayList<String>();
		list.add( "kvs" );
		list.add( "nosql" );
		list.add( "デザインパターン" );

		String query = ntfr.createQuery( list );
		ntfr.sendMail( query );

	}

	private String createQuery( List<String> keywords ){

		StringBuffer sb = new StringBuffer();
		sb.append("keyword_or=");
		for ( String s : keywords ) {
			sb.append(s + "," );
		}
		return sb.toString();
	}

	private void sendMail ( String query ) {
		org.apache.commons.mail.SimpleEmail se = new SimpleEmail();
        try {
             se.setCharset( "utf-8" );
             se.setHostName( "smtp.gmail.com" );
             se.setSmtpPort( 587 );
             se.setTLS( true );
             se.setAuthentication( "username", "password" );
             se.addTo( "送り先アドレス" );
             se.setFrom( "gmailアドレス" );
             se.setSubject( "気になるATNDイベント" );

             StringBuilder msgBldr = new StringBuilder();
             for( Event event : getEvent( query ) ) {
            	 msgBldr.append( "★ " + event.getTitle() + " " + event.getStartedAt() + " @ " + event.getAddress() + "\n"  + "	" + event.getCatch() + "\n\n");
             }
             se.setMsg(msgBldr.toString());
             se.send();

        } catch ( EmailException eme ) {
        	eme.printStackTrace();
        }
	}

	private List<Event> getEvent( String query ) {

		  Atnd atnd = new Atnd();
		  EventsResult res = null;

		  try {
			  res = atnd.getEvents( query );
		  } catch ( IOException ioe ) {
			  ioe.printStackTrace();
		  }

		  List<Event> list = res.getEvents();
		  return list;

		 }
}

とこんな感じのものを、クーロンから3日に1回くらい叩きたいわけです。
問題は置いておくサーバがないということと、たった今、"ATND Notifier"という素晴らしいChrome Extensionを見つけてしまったため、このアプリの存在価値がなくなってしまったことでしょうか。。

Excel2007で簡単ヒストグラム

Excelでびっくりするほど簡単にヒストグラムが作成できます。とても便利なのに、知らんかった・・・のでメモ。

  • 準備(アドインのインストール)
    • Officeボタン > Excelのオプション > アドイン > 設定 > 分析ツール にチェックし、インストール
    • データタブに、「分析」カテゴリが登場する
  • 実行
    • 「分析」カテゴリの「データ分析」をクリック
    • ヒストグラム」をクリック
    • 「入力範囲」に対象データ範囲を指定
    • 「データ区間」(グラフの横軸にあたる)も指定可能だが、空欄だと入力範囲に合わせて等間隔で区間が刻まれる
    • グラフ作成 にチェックして、OKをクリックすると、別シートにグラフが生成されます

ありがとう、Excelさん。

expectで対話型シェル

sshやscpなど、対話型のインプットが必要なコマンドを、スクリプト化して運用に使いづらいので、expectパッケージを利用すると便利です。
OSにあらかじめexpectのパッケージが入っていない場合、下記コマンドでインストール。

yum install expect

下記は、リモートホストにログインして ls を叩くシェルのサンプルです。

#!/bin/bash

hostname=192.168.10.12
username=hoge
password=hogehoge

expect -c "
spawn ssh -l oracle $hostname
expect \"$username@$hostname's password:\" {
  send \"$password\n\"
} \"Are you sure you want to continue connecting (yes/no)?\" {
  send \"yes\n\"
  expect \"$username@$hostname's password:\"
  send \"$password\n\"
}

expect \"\[$username@$hostname ~\]$\"
send \"ls\n\"

interact
"

ポイントはこれだけ

  • spawn 最初に投げるコマンド(別プロセスを生成)
  • expect 予想される表示内容(パターンマッチが使える)
  • send 表示内容に対して送りたいコマンド(改行文字を忘れずに。)
  • expect "A" { send "B" } "A'" { send "B'" } と場合分けが可能

このサンプルでは、はじめてssh接続するホストの場合、~/.ssh/known_hosts に公開鍵登録の可否を聞かれるので、その表示が出るときと出ないときを場合分けしてます。

ROWNUMで結果のレコード数を制限する

あるカラムでソートした結果の、上位n件だけを抽出したい・・・というときに便利な
LIMIT句というものがあります。

select * from EMPLOYEES
order by EMPLOYEE_ID asc
limit 10;

これで、EMPLOYEE_IDのトップ10件のみ取得できます。
しかし、悲しいことにOracleではLIMIT句がサポートされていない・・・

代替として ROWNUM擬似列なるものを使って取得する必要があります。
ROWNUMとは、ある結果のセットに、仮想的なレコード番号を振ったものです。
このROWNUMを条件句にセットし、結果を制限します。

上記SQLと同様のことがしたい時は、以下のような感じになります。

select * from 
  ( select rownum rn, s.* from 
    ( select * from EMPLOYEES
      order by EMPLOYEE_ID
    ) s
  ) a
where a.rn <= 10 
order by a.rn;

注意点として、rownumは、直接where句やorder by句に指定できないので、
わざわざ入れ子にして別名をつける必要あり。ジャマくさいわね。

JadClipseのインストール on Galileo

とあるライブラリの中身を解読する必要が出てきたので、Eclipse上でデコンパイラJadが使えるようにするプラグイン、JadClipseを入れました。Eclipseは3.5です。

  • jadのインストール

本家のサイトは消えてしまっているので、下記urlのInternetArchiveからダウンロードして、適当なディレクトリに解凍します。
http://web.archive.org/web/20080214075546/http://www.kpdus.com/jad.html#download
WindowsXPはNT系なので、Jad 1.5.8g for Windows 9x/NT/2000 on Intel platform のjadnt158.zipでおkです。

Eclipseの Help > Install New Softwares から、下記のアップデートサイトのurlを入力し、そのままインストールをすすめます。(ちなみに中身は3.3版といっしょ。現在は3.6版まで準備されています)
http://webobjects.mdimension.com/jadclipse/3.5/
インストール完了すると、Eclipseの再起動をすすめられるので、言われるままに再起動します。

  • JadClipseにjad.exeのパスを設定

再起動後、Window > Preference > Java > Jadclipse から、Path to decomplier に、先程解凍したjad.exeのパスを指定します。この手順は、環境変数PATHにjad.exeの場所が通っている場合は不要です。

Eclipseからjar中のclassファイルを開くと、勝手にデコンされたjadファイルが表示されちゃいます。便利!

JPA2.0のLockModeTypeについて

JPA2.0における変更点

Java EE 6仕様の一部であるJPA2.0。
JPA1.0からの変更点のひとつに、エンティティ更新時のリソースロック機能として悲観ロックをサポートするようになった、というものがあります。EntityManager # find や lock といったメソッドの引数に指定できるデータベースのロックタイプ(javax.persistence.LockModeType)が、1.0までは

  • READ
  • WRITE

の2種類だったのが、

  • OPTIMISTIC
  • OPTIMISTIC_FORCE_INCREMENT
  • PESSIMISTIC_READ
  • PESSIMISTIC_WRITE
  • PESSIMISTIC_FORCE_INCREMENT

の5種類が追加されたようです。

また、Query # setLockMode というメソッドも新たに追加され、ユーザが定義したJPQLクエリ時代に、ロックタイプ属性を持たせられるようになっています。さて、新たに追加された5種類のLockModeTypeについて、Javadocを見ただけでは動きが分からなかったので、調べてみました。

楽観ロック

既存のREADとWRITEに対応するもののようです。READ, WRITEは今後、deprecatedになっていくのでしょうか?バージョン番号/最終更新時間による更新チェックをかけるので、バージョン更新に対応したエンティティオブジェクトにのみ対応している、という点も同様です。
ここでいう"バージョン更新に対応したエンティティオブジェクト"とは、以下の条件を満たすもののことです。

  • 対象となるテーブルに、バージョン番号 or 最終更新時間をあらわすカラムがある
  • 上記カラムに対応するフィールドを、エンティティBeanが持っている
  • 上記フィールドのセッターに @Version アノテーションが付与されている

JPA2.0で指定できる楽観ロックは、以下2タイプです。

OPTIMISTIC
  • エンティティ更新のコミット時にのみ、対象データをロックし、バージョン更新がかかる
OPTIMISTIC_FORCE_INCREMENT
  • エンティティ更新のコミット時だけでなく、ただエンティティを参照しただけでデータに変更を加えていない場合も、強制的にバージョン更新がかかる

悲観ロック

DBに長時間の排他ロックをかける悲観ロックは、1.0まではJPAの標準仕様ではサポートされていませんでした(各プロバイダの実装により、ヒント句を利用して悲観ロックをかける方法は存在しました)。なお悲観ロックにおいては、楽観ロックのように、バージョン更新に対応したエンティティオブジェクトを用意する必要はありませんが、もしバージョ更ン更新に対応したエンティティオブジェクトに悲観ロックをかけた場合は、楽観ロックと同じ方法でバージョンチェックおよび更新が行われます。JPA2.0で使用できる悲観ロックは、以下3タイプです。

PESSIMISTIC_READ
  • エンティティを取得した時点から、対象データにロックがかかる
  • コミット時にロック解放される
PESSIMISTIC_WRITE
  • エンティティを更新した時点から、対象データにロックがかかる
  • エンティティを取得・参照するだけだと、
  • 取得時から更新時までのあいだに他トランザクションに介入されたとき、更新失敗やデッドロック誘発のおそれがある
  • コミット時にロック解放される
PESSIMISTIC_FORCE_UPDATE
  • バージョン更新に対応したエンティティオブジェクトにしかかけられない
  • エンティティを取得した時点から、対象データにロックがかかる
  • エンティティを参照しただけで変更を加えていない場合も、強制的にバージョン更新がかかる
  • コミット時にロック解放される

〜参考〜
JSR-000317 JavaTM Persistence 2.0(Final Release)
Locking and Concurrency in Java Persistence 2.0