初期インストール時に「An error occurred while listing Android targets」が出てしまう場合の対処

自分用メモ。
PhoneGapインストール時に「An error occurred while listing Android targets」が出てエラーとなるケースへの対処。

PhoneGap自体はNode.js系のプロダクトなので、インストールはNode.jsさえ入っていれば以下のコマンドでOK。

npm install -g phonegap

公式サイトにある通り、サンプルアプリを作る。(ちょっとGrailsっぽい)

C:\Users\Administrator\Documents\Sources\PhoneGapTest>phonegap create HelloWorld
[phonegap] missing library phonegap/www/3.3.0
[phonegap] downloading https://github.com/phonegap/phonegap-app-hello-world/archive/3.3.0.tar.gz...
[phonegap] created project at C:\Users\Administrator\Documents\Sources\PhoneGapTest\HelloWorld

C:\Users\Administrator\Documents\Sources\PhoneGapTest>cd HelloWorld

で、run androidを実行するところでエラー。

C:\Users\Administrator\Documents\Sources\PhoneGapTest\HelloWorld>phonegap run android
[phonegap] detecting Android SDK environment...
[phonegap] using the local environment
[phonegap] adding the Android platform...
[phonegap] missing library cordova/android/3.3.0
[phonegap] downloading https://git-wip-us.apache.org/repos/asf?p=cordova-android.git;a=snapshot;h=3.3.0;sf=tgz...
   [error] An error occured during creation of android sub-project.

C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:126
                    throw e;
                          ^
Error: An error occurred while listing Android targets
    at C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\lib\check_reqs.js:87:29
    at _rejected (C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:808:24)
    at C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:834:30
    at Promise.when (C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:1079:31)
    at Promise.promise.promiseDispatch (C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:752:41)
    at C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:574:44
    at flush (C:\Users\Administrator\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:108:17)
    at process._tickCallback (node.js:415:13)

発生している対象のjsを確認すると、「android list target」でエラーが出てるみたい。
Android SDKをダウンロードして展開しただけだと以下のようにパスが通ってないので当たり前ですね。
(Android SDKのインストール先にカレントディレクトリ移せばコマンド通る)

C:\Users\Administrator\Documents\Sources\PhoneGapTest\HelloWorld>android list targets
'android' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

cd C:\Program Files\adt-bundle-windows-x86-20131030\sdk\tools

C:\Program Files\adt-bundle-windows-x86-20131030\sdk\tools>android list target
Available Android targets:
----------
id: 1 or "android-19"
     Name: Android 4.4
     Type: Platform
     API level: 19
     Revision: 1
     Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
     ABIs : armeabi-v7a

環境変数PATHに通してあげればとりあえず解決。
(デバイスの設定してないからエラーになるけど、それはまた別の問題。)

C:\Users\Administrators\Documents\Sources\PhoneGapTest\HelloWorld>phonegap run android
[phonegap] detecting Android SDK environment...
[phonegap] using the local environment
[phonegap] adding the Android platform...
[phonegap] compiling Android...
[phonegap] successfully compiled Android app
[phonegap] trying to install app onto device
[phonegap] no device was found
[phonegap] trying to install app onto emulator
   [error] An error occurred while emulating/deploying the android project.

昔のAndroid SDKってPATHにも勝手に足してくれてたような記憶あるけど記憶違いかな・・・。
まあ、解決したので良しとします。

Visual Studioを使わずにVBSをデバッグする方法

個人的にはあまり好きじゃないですが、やむなくWindows Serverでサーバ環境を構築する場合、いろんなスクリプトを作らざるを得なくなるのが常というものですが、最大の難点はデバッグがしづらい!という事だと思います。

Visual Studioとか使えばデバッグ出来るんですが、もう少しシンプルなツールだけでデバッグする方法についてまとめてみました。

まずは、テスト用にVBSスクリプト LoopScript.vbsを作成。5秒おきにテキストに1行ログを書いていくだけのシンプルなスクリプトです。

Dim objFso
Dim file
Dim loopCount
Wscript.Echo("ループ処理の開始")
Set objFso = CreateObject("Scripting.FileSystemObject")
Set file = objFso.OpenTextFile("LoopScriptLog.log", 8, True)
loopCount = 0
Do Until loopCount = 120
	file.Writeline(now & " : " & loopCount)
	Wscript.Echo(now & " : ループ" & loopCount & "回目")
	WScript.Sleep(5000)
	loopCount = loopCount + 1
	Stop
Loop
Wscript.Echo("ループ処理の終了")
file.Close()
Wscript.Echo("ファイルのクローズ")

(1) Windows Script Debuggerのインストール

上記のスクリプトをステップ実行する場合や実行中の変数の中身を見たい場合は、Windows Script Debugger が必要になります。まずはMicrosoft公式からダウンロード。

Windows Script Debugger
http://www.microsoft.com/ja-jp/download/details.aspx?id=23992

scd10jp.exeをダウンロードして、「管理者権限で」実行します。

インストールが完了したら再起動を要求されるので、再起動しましょう。

(2) Windows Script Debuggerの起動

インストールが終了していれば、「C:\Program Files\Microsoft Script Debugger」(デフォルトの場合)に「msscrdbg.exe」という実行ファイルが出来ているはずなので、起動しましょう。

(3) VBSスクリプトの実行

VBSを起動する際に、以下のようにオプションを付けて起動します。

C:\Users\Administrator>wscript C:\Users\Administrator\Desktop\LoopScript.vbs //x

すると、Microsoft Script Debugger側の「実行中のドキュメント」に「Windows Script Host」⇒「LoopScript.vbs」が出て来ますので、ダブルクリックすると以下のようにスクリプト内容が表示された状態になります。

EclipseVisual Studioのように、ブレークポイントを指定してステップ実行、みたいな事が出来ます。

(4) 実行中の変数の確認

ウォッチウィンドウみたいな便利機能はないので、実行中の変数が知りたい場合はコマンドウィンドウにて「?変数名」で問い合わせる必要があります。

?loopCount
3

インスタンスに対してもアクセス可能ですが、対象のインスタンスが持っているメソッドやプロパティを指定する必要があります。

?file.Line
376
?objFso.GetFile(WScript.ScriptFullname).DateCreated
2013/12/10 14:13:10

インスタンス指定しただけで配下のプロパティ全部出してくれたりとか、そういう便利機能はないのが残念。

バイトコードインジェクションツール Byteman

試験の過程で特定処理が呼び出された時に何かログを出す必要性が出てきたんですが、試験のためだけにソース変更するのも美しくないから何か手がないかな〜と探していたところ、AOPのような仕組みをJavaだけで実現できるプロダクトがあるという情報を会社の先輩から教えていただきました。

JBossコミュニティのBytemanというツールです。
https://www.jboss.org/byteman

これはオープンソースJavaバイトコード操作ツールで、GNU LGPL 2.1でライセンスされている。Bytemanはコードのテスト、トレース、モニタリングを支援するJavaエージェントであり、開発者はこれを使って、ロード時や実行中にJavaアプリケーションの動作を変更することができる。これはアプリケーションの書き直しや再コンパイルをすることなく動作し、StringやThreadといったJavaプラットフォームクラスを修正することまで可能だ。

Byteman 2.0.0: バイトコード操作、テスティング、フォールトインジェクション、ロギング

Bytemanを使うとこんな風にスクリプトでランタイム上のバイトコードを自由に操作することができます。AOPを知っている人は、それをかなり自由に適用できるもの、と思ってもらえばわかりやすいかな。今回はデバッガとしてのユースケースを説明しましたが、デバッガとして使うにしてもソースコードを用意する必要がないという点と、ログベースのデバッグができるのでマニュアルインタラクティブGUIデバッガではできないマルチスレッド系や「たまにしか起きない」系の問題のデバッグもできるという面で通常のデバッガより優れてます。また、他にも実行統計機能を追加したり(例はsamplesにいっぱい入ってる)、モニタリングツールですという名目でByteman有効化しておいて、小さい単純なバグが発見されたときにBytemanでこっそり直したり、などとより黒いことも可能になります。

nekopの日記 BytemanによるJava黒魔術

9月26日のJJUG主催ナイトセミナー JJUG ナイトセミナー - torutkの日記 で、「イマドキの現場で使えるJavaライブラリ事情」の紹介にあったBytemanをJUnitから使い、モック的に利用する流れを簡単に記述しました。

[http://d.hatena.ne.jp/torutk/20121001/p1:title=torutkの日記 [Java]JBoss Bytemanを使ってAOP]

SpringやSesar2などのフレームワーク使った事がある方は馴染みがあるかと思いますが、Javaのクラス名やメソッドを指定してログ出力を差し込んだりする機能で使ってみるとかなり便利。何よりソースの中に本来のビジネスロジックではない部分を減らせるのでS/N比の向上になります。
ただ、上記のフレームワークたちは基本的にはWebアプリケーションのフレームワークのため、画面を持たないようなプロダクト(常駐プロセス系とか)ではあまり利用されていないんじゃないかと思います。実際、今回もそうでしたしね。

常駐プロセスの中で子スレッドを作成してひたすら処理をループさせるメソッドがあるので、Thread.run()された後に開始されるそのループ処理メソッド名を指定すれば、ロジックの一回転毎にログを吐ける、はず。

Groovy 2.1.3 + IBM J9 JDK 1.7.0 でコマンドラインからGroovyが呼び出せない

ま、ここに書いてある事象と同じではありますが・・・・。

http://groovy.329449.n5.nabble.com/Startup-problems-possible-to-specify-javahome-through-command-line-td5716159.html

IBM J9 JDK 1.7.0をインストールして、JAVA_HOMEに設定している環境で、コマンドラインからgroovyを呼ぶとエラーになり、groovy.batからならいけるという謎の事象。
これ、Windows7環境だけじゃなくて、Windows Server 2008 R2環境でも同じですね。

C:\Users\Administrator>set JAVA_HOME=IBM JDKのインストールパス

C:\Users\Administrator>groovy.bat -v
Groovy Version: 2.1.3 JVM: 1.7.0 Vendor: IBM Corporation OS: Windows Server 2008 R2

C:\Users\Administrator>groovy -version
error: could not find client or server jvm under IBM JDKのインストールパス
please check that it is a valid jdk / jre containing the desired type of jvm

まあ、果たしてIBM J9 JDKとGroovyを合わせて使う人がどれだけいるかどうか疑問ではありますが・・・。
細かいところはさておき、Oracle JDKでは持っていないメインフレーム向けの文字コードIBM J9 JDKでは持っていたりするんですよね。
メインフレームDB2JDBC接続するときのNEC機種依存文字の文字化け防止にも必須っぽい。


2013/9/17追記

とまあ、上記の感じでbat経由で起動すればいいやとか思ってたら、頂いたコメントで疑問氷解。

nobusuenobusue 2013/09/16 09:51
http://d.hatena.ne.jp/orangeclover/20130914/1379115966 でもコメントいただいていますが、Windowsインストーラー版で導入したgroovy.exeにはJREのパスがハードコードされていて、かつOracleJDKしか対応していないというのが原因です。
groovy.batはgroovy.exeを経由せずに直接Groovyのブートストラップクラスを実行するので、このような現象は起きないです。
ですので対策としては、「Windowsインストーラー版を使わずにzipを直接展開する(こちらにはgroovy.exeが入っていません)」もしくは「goovy.batを明示的に指定する」ということになります。

なんでこうなるのかよくわからん・・・と思ってたらまさかのハードコーディングなのですね。
そういやWindows2008R2でJAVA_HOMEなしでインストーラ動かすと似たような事象が起きてたのでそれも似たような感じかもしれません。

ドメインで文字列のキーをIDにする その2

ドメインで文字列のキーをIDにする
http://d.hatena.ne.jp/kkz_tech/20130606/1370609690

上の続きで、レガシーDBを使ってGrailsドメインクラスを作る場合のお話です。
※前提条件としては、テーブル定義は変更できないもの、としています。

いくらレガシーといえど、テーブルの親子関係くらいはありますよね。
前回の例だとユーザーを作りましたから、今度はさらにユーザーを親とする子テーブル、ユーザーのログイン履歴に相当するものを作ってみました。

何個か引っかかるポイントはあったのですが、まずは親のインスタンスをどう持たせるか、です。適当に指定したら親テーブルとの外部キーであるユーザーIDが2個出来てしまう(;´∀`)

ログイン履歴はタイムスタンプ型のログイン日付とユーザーIDの複合主キーなわけですが、これはstatic mappingに以下のような指定をする事で思った通りのレコードになりました。

class LoginHistory {
	LoginUser loginUser
	Date loginDate
	static mapping = {
		id generator: 'assigned', composite: ['loginUser', 'loginDate']
		loginUser column: 'user_id'
	}

ただ、このままではrun-app時にエラーが出てしまう。どうやら、ドメインクラスを比較する際にComparatorを使っているようなのですが、id列を持たせないようにしてしまった場合、そのためのメソッドが無いとダメみたいです。hashCode()とequals()を実装してあげると以下のような感じです。
コメントで教えて頂いたのですが、ドメインクラス自体にアノテーションで@EqualsAndHashCodeを指定するやり方もある模様。今度試したらまたエントリ作りますね。


hashCode、equalsともに「何を持って一意とするか(=主キー相当のプロパティは何か)」をきちんと意識する必要があります。って当たり前か。

class LoginHistory  implements Serializable {

	boolean equals(other) {
		if (!(other instanceof LoginHistory)) {
			return false
		}
		return (other.loginUser.userId == loginUser.userId && other.loginDate == loginDate)
	}

	int hashCode() {
		def builder = new HashCodeBuilder()
		builder.append loginUser.userId
		builder.append loginDate
		builder.toHashCode()
	}
}

とりあえず上記を踏まえて出来上がったのは、以下のような感じです。
レコードの作成日、更新日のカラムは既に持っていましたが、名前がGORMのデフォルトと違うので、自分で指定しています。

import java.util.Date;
import org.apache.commons.lang.builder.HashCodeBuilder;

class LoginHistory  implements Serializable {
	LoginUser loginUser
	Date loginDate
	Date dateCreated
	Date lastUpdated
	
	String toString() {
		return loginUser.userId + toString(loginDate)
	}
	
	boolean equals(other) {
		if (!(other instanceof LoginHistory)) {
			return false
		}
		return (other.loginUser.userId == loginUser.userId && other.loginDate == loginDate)
	}

	int hashCode() {
		def builder = new HashCodeBuilder()
		builder.append loginUser.userId
		builder.append loginDate
		builder.toHashCode()
	}
	
    static constraints = {
		loginDate blank:false, nullable:false
		ip blank:true, nullable:true, maxSize:19
    }
	
	static mapping = {
		table 'login_history'
		version false
		id generator: 'assigned', composite: ['loginUser', 'loginDate']
		loginUser column: 'user_id'
		dateCreated column: 'insert_date'
		lastUpdated column: 'update_date'
	}
}

実際のテーブルがどう出来ているかと言うとログイン履歴はこんな感じ。

 \d login_history
            テーブル "public.login_history"
   カラム    |             型              |  修飾語
                                                                                                          • -
user_id | character varying(64) | not null login_date | timestamp without time zone | not null insert_date | timestamp without time zone | not null update_date | timestamp without time zone | not null インデックス: "login_history_pkey" PRIMARY KEY, btree (user_id, login_date) 外部キー制約: "fkf4700b1e89c762ba" FOREIGN KEY (user_id) REFERENCES login_user(user_id)

親テーブルのユーザーマスタはこんな感じ。

# \d login_user
                 テーブル "public.login_user"
        カラム        |             型              |  修飾語
                                                                                                                            • -
user_id | character varying(64) | not null insert_date | timestamp without time zone | not null update_date | timestamp without time zone | not null name | character varying(64) | not null password | bytea | not null インデックス: "login_user_pkey" PRIMARY KEY, btree (user_id) 参照元: TABLE "login_history" CONSTRAINT "fkf4700b1e89c762ba" FOREIGN KEY (user_id) REFERENCES login_user(user_id)

DB2のJDBCでデフォルトスキーマ設定

Jenkinsで外注さんから上がってきたソースをビルドしてたのですが、ばりばりとSQL発行するところでエラー。どうやら全部のテーブルをSYSTEMスキーマ(正確にはDB2だとSYSIBM)につっこんでしまってるようです(;´∀`)。

アプリ的には機能ごとに複数のDBユーザ、スキーマを使い分けている関係上、propertiesファイルでスキーマを指定できるようになってるのですが、テストコードだからか、その仕様はあまり気にせずSQL発行してしまってる模様。

テスト用のJDBC接続文字列を渡してるところでスキーマ指定すればいけるかな?ってことで以下を参考に設定。

jdbc:db2://server:port/dbname:currentSchema=hoge;

http://d.hatena.ne.jp/digo/20090612

最後のセミコロン忘れたり、逆にコロンの部分にセミコロン入れたりして失敗してましたが、そのへんはご愛嬌、ってことで!

最初はGoogoleで検索してヒットしたここ見てて失敗してましたが、これはWebLogicのデータソース設定だからそりゃそうだ(笑)。

Redmine 1.3.xにバーンダウンチャートを表示させるまで

いろいろあって新人教育という限定的なタスクながらもスクラム開発をする事になり、いろいろと準備をしております。
開発する内容の整理や環境の準備、加えて自分もある程度スクラム開発やらGrailsやらに詳しくならなければならない上に、業務は通常通りのボリュームのままというなかなかステキな状況になっております(笑)。

まあ、とはいうもののやりたいことをやりたいようにやれてるんで、体力的にはともかく精神的にはまだまだモチベーション高い感じです。

スクラム開発用のプラグインは入っているものの、バーンダウンチャートが表示できてないんでいろいろと設定を。
(結局バーンダウンチャートについては手書きの方がよい、という話もあるんですが。)

まずは http://www.redmine.org/projects/redmine/wiki/PluginCharts を参考に、PluginChartプラグインのダウンロード。

cd
git clone https://github.com/cou2jpn/redmine_charts.git vendor/plugins/redmine_charts

次はRedmineで利用しているDBの設定。

For Redmine 1.x:
rake db:migrate_plugins RAILS_ENV=production

For Redmine 2.x:
rake redmine:plugins:migrate RAILS_ENV=production

これでプラグインをインストールしてサーバを再起動したものの、うまくプラグインが表示できてないのでおかしいなと思ったのですが、Redmineの再起動は別手順なんですね。

cd
touch ./tmp/restart.txt

http://kkkw.hatenablog.jp/entry/2012/10/04/094539