2011年10月21日金曜日

Java jadでjarをGrepするバッチ(bat)

jar内のclassをjadコマンドで逆コンパイルして
文字列検索する簡単なバッチスクリプトを作りました。

jargrep.bat
@echo off

if "%1"=="" ( 
goto error

) 

for %%i in (*.*) do  (
    jar xf %%i
)

jad -r -o **/*.class 2>nul


for /R .. %%i in (*.jad) do  (
 echo "%%i"
    type "%%i" | find "%1"
)
goto end

:error
echo エラー:引数が指定されていません 

:end



検索したいjarを一箇所に集めて、同じディレクトリに
batファイルを持ってきて下記のように実行。
jargrep.bat xxxx > grepresult.txt

jarを解凍したファイルも消してないし、全然汎用的には作ってませんが、
時間がないのでとりあえずいいか。

findstrの方が正規表現とかもできるけど、
1行が長いとエラーになるっぽいので、とりあえずfindにしてます(めちゃ重い)。
ここは自分でGrepクラスでも作った方がよいかも。。

2011年7月29日金曜日

Java class依存関係 jar依存関係 解析ツール

class依存関係やjar依存関係を調べるのによいツールはないかと
思って調べたのですが、いくつかあった中でこのツールが非常に
便利だったので紹介します。
tattletale
http://www.jboss.org/tattletale
2011/07/29現在 最新は1.1.2

▼使い方
java -jar tattletale.jar [ターゲットディレクトリ] [レポート出力ディレクトリ] 
▼ex)
java -Xmx512m -jar tattletale.jar C:/dir ./report

[ターゲットディレクトリ]はEclipseのworkspaceを指定してOK


レポート結果はHTMLで出力され、
classの依存関係、jarの依存関係など様々の情報を出力してくれてかなり便利です!

2011年6月24日金曜日

javaで円マークとバックスラッシュ

はまったのでメモ

円マークのwiki
Unihan Database

円マークとバックスラッシュ
Shift_JIS
  0x5c 円マーク
  0xa5 なし
  
UTF-8
  0x5c   バックスラッシュ
  0xc2a5 円マーク

UTF-16
  0x005c バックスラッシュ
  0x00a5 円マーク
  

ISO-8859-1
  0x5c バックスラッシュ
  0xa5 円マーク


Unicodeエスケープで確認
●画面出力
  日本語フォント  MS ゴシック
  "\\"              →  円マーク
  "\u005c\u005c"    →  円マーク
  "\u00a5"          →  円マーク

  英語フォント    Arial
  "\\"              →  バックスラッシュ
  "\u005c\u005c"    →  バックスラッシュ
  "\u00a5"          →  円マーク

●JasperReportでPDF出力
  "\\"              →  バックスラッシュ
  "\u005c\u005c"    →  バックスラッシュ
  "\u00a5"          →  円マーク

ブラウザからの入力時に、円マークとバックスラッシュを入力・区別できるのかというと、
とりあえずファイルで作成したものをコピペで両方入力可能でした。
円マークもバックスラッシュも両方画面上は円マークとして表示される(日本語フォント)が、
サーバ側で取得すると判別可能なためString.replaceAll等で置換可能ですね。

2011年6月16日木曜日

eclipseでリモートデバッグ

eclipseでリモートデバッグ方法メモ

▼リモートのJVM起動オプションに下記を追加
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address
=12345


▼eclipse
「eclipseメニューの実行」→「構成及びデバッグ」→「リモートjava
アプリケーション」→右クリックして新規→
・「プロジェクト」 デバッグするプロジェクトを指定
・「接続タイプ」 標準(ソケット接続)
・「ホスト」 ホストを指定
・「ポート」 JVMオプションで指定したportを指定(上記の例だと12345)
→「適用」→「デバッグ」

JVMのリモートメモリ監視(jconsole)

JDK5.0以降、監視ツールなど有用なものがけっこう含まれています。
※JDK6.0で試しています

メモリはjconsoleが一番見やすいと思います。

JVM起動オブションに下記を追加
-Dcom.sun.management.jmxremote.port=ポート番号
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false    

portはwellknownポートでなければなんでもOK。
デフォルトでSSLとパスワード認証が有効になっているので無効にする。
jconsoleを起動して、リモートプロセスタブに[ホスト名:port]を入力して「接続」
でリモートJVMの監視ができます。

ここに色々のっていますね。
http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/management/agent.html#auth_disabled

2011年5月18日水曜日

JSF(Teeda) フェーズリスナでセッション存在チェック

JSFを用いたWEBアプリケーションの作成において、
セッションの存在チェックをどのタイミングで行うのが
正解なのか。

まず、Actionにインターセプターを設定してセッション存在チェックを
行おうと考えたが、rendererやConverter、Validatorを
拡張実装してスコープやセッションから値を取得している場合に、
チェックより前なので、ヌルポ等の予期せぬエラーが発生する可能性がある。

次に、filterでセッションチェックを行おうと考えていたが、
filterはTeeda管理外なので、エラー発生の場合Teedaで設定した
エラー画面とならず、HTTPステータスエラー画面になってしまう
(web.xmlのerror-pageで設定していれば別)。

今回はrendererのdecode処理でもセッションを使用する拡張等を
行っていたので、リクエスト適応フェーズ前にチェックを
行う必要があるため、フェーズリスナーでセッション存在チェックを
実装しようと思います。

JSFではフェーズごとにリスナーで処理をいれることができ、
フェーズリスナーの下記タイミングでチェックを行うことで
renderer、Converter、Validatorより前にチェックできる。

POST
1.RESTORE_VIEW(Page状態復元 スコープ管理機能中間モデルの復元)
→→→ ここでセッションチェック ←←←
2.APPLY_REQUEST_VALUES(中間モデルにリクエスト値の適応)※renderer(decode)
3.PROCESS_VALIDATIONS(バリデーション) ※Converter、Validator実行
4.UPDATE_MODEL_VALUES(Pageクラスのプロパティ更新)
5.INVOKE_APPLICATIONS(アクション実行)
GET
6.RENDER_RESPONSE(レンダリング)※renderer(encode)→initialize(初回)→prerender



 <lifecycle>
  <phase-listener>
   test.listener.SessionCheckListener
  </phase-listener>
 </lifecycle>


package test.listener;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpSession;
・・・

public class SessionCheckListener implements PhaseListener {

    public void beforePhase(PhaseEvent event) {
        //リクエスト適応フェーズ前にセッションチェック処理
        ・・・
    }
    
    //リクエスト適応フェーズ後は何もしない
    public void afterPhase(PhaseEvent event) {}

    public PhaseId getPhaseId() {
        //リクエスト適応フェーズ
        return PhaseId.APPLY_REQUEST_VALUES;
    }
}    


あと、リクエストが違うので念のため
「6.RENDER_RESPONSE(レンダリング)」前
にもセッション存在チェックを入れました。

JPA(Kuina-Dao) リレーション関係を持ったテーブルの更新、追加時の注意点

例)
親テーブル(1)と関係する子テーブル(N)を関係性を持たせ新規登録

// 親テーブル用Dao
private ParentDao parentDao;
// 子テーブル用Dao
private ChildDao childDao;

protected void doLogic() {
    // 親テーブルを登録
    Parent parent = new Parent();
    parent.setParentid("999");
    parentDao.persist(parent);

    // 子テーブルを登録 数分繰り返し処理
    for (int i = 0; i < 10; i++) {
       Child child = new Child();
       child.setChildid("ABC" + i);
       
       // 親テーブルPkeyを直に設定しない
       // child.seParent_pkey(11111);
       
       // 親entitiyをセット
       child.setParentt(parent);
       childDao.persist(child);                                                        
    }                                                         
}                                                         
子entity(N側)の親entityPkeyは、個別に設定しないようにする。 個別に設定しないように制約を付けるには、Columnアノテーションで insertable、updatableにfalseを設定することによって、 リレーションentitiyによる追加、更新以外を防ぐことが可能。
@javax.persistence.Entity
@javax.persistence.Table(name = "child")
public class Child {

・・・

@javax.persistence.ManyToOne(targetEntity = Parent.class ,fetch = FetchType.LAZY)
private Parent parent;


@javax.persistence.Column(name = "parent_pkey", insertable = false, updatable = false)
private Integer parent_pkey;

・・・
}

2011年2月16日水曜日

Kuina-Daoで行ロック、テーブルロック

Kuina-DaoはS2ファミリーでJavaEE5のO/Rマッピング標準です。
JPA上で利用可能なDAOフレームワークで、インタフェースを定義する
だけで動的な問い合わせを生成してくれます。
SQLファイルを利用した問い合わせもできます。
http://kuina.seasar.org/ja/


今回はKuina-Daoで行ロック、テーブルロックはどのようにやるかのメモです。


行ロック
■javax.persistence.EntitiyManagerを使用する場合
TestEntitiy entity = testDao.find(pkey);
EntityManager em = SingletonS2Container.getComponent(EntityManager.class);
em.lock(entity, LockModeType.WRITE); //またはem.lock(entity, LockModeType.READ);
em.flush();

■org.seasar.kuina.dao.GenericDaoを継承したDaoを使用する場合
TestEntity entity = testDao.find(1);
testDao.writeLock(entity); //またはtestDao.readLock(entity);

LockModeType.READはreadLock、LockModeType.WRITEはwriteLockに対応しています。
LockModeTypeとしてLockModeType.WRITEを指定すると、エンティティの状態変更がない場合でもバージョン列は強制的に更新されます。
バージョン列の更新はflushまたはコミットのタイミング。


テーブルロック
テーブルロックはざっと見たところ、Entityを使用してはできなさそうなので、
SQLファイルを利用した方法しかなさそうです。

■Daoインターフェース
public interface  LockTableDao {
    void deleteLockTable();
}

■SQL(LockTableDao_deleteLockTable.sql)
LOCK TABLE appparam IN EXCLUSIVE MODE;

■実行
lockTableDao.deleteLockTable();


Kuina-Daoはメソッドの名前や引数・戻り値から実行すべき操作を判断するので、
戻り値をvoidにする場合は(insert|update|delete|remove)が先頭に付けないと駄目ですね。
http://kuina.seasar.org/ja/user_guide/dao.html#メソッド



Kuina-Daoはあまり人気ないようですが、使いやすくていいですね。
でも複雑な問い合わせはSQLにならざるをえない。。

S2Dao後継のDomaそろそろさわってみようかな。
AnnotationProcessingTool(apt)を利用したJava6(JDBC4.0)対応のO/Rマッパーとその開発支援ツール。
http://doma.seasar.org/
Seasar2への依存なしってのがいいですね!

2011年2月3日木曜日

java synchronized 排他の相互関係まとめ

synchronizedの排他関係について気になったので整理しました。

staticメソッドのsynchronized
Classオブジェクトのロックを取得します。

class HogeClass {
  synchronized static public void hogeMethod() {
     // 処理
  }
}

上記は以下のsynchronizedブロックと同様になります。

static public void hogeMethod() {
  synchronized(Class.forName("HogeClass")) {
    // 処理
  }
}


以下のようなsynchronizedがついてるメソッドとついていないメソッドが混在するクラスの場合。

class HogeClass {
  synchronized static public void methodA() {
     // 処理
  }
  
  synchronized static public void methodB() {
     // 処理
  }
  
  static public void methodC() {
     // 処理
  }
}

methodA自身、methodB自身、methodAとmethodBは互いに排他的に実行されますが、
methodAとmethodC、methodBとmethodCは排他的に実行されません。
staticなのでJVM上で排他制御されます。



インスタンスメソッドのsynchronized
インスタンスオブジェクトのロックを取得します。

synchronized public void hogeMethod() {
     // 処理
}

上記は以下のsynchronizedブロックと同様になります。

public void hogeMethod() {
  synchronized(this) {
    // 処理
  }
}


以下のようなsynchronizedがついてるメソッドとついていないメソッドが
混在する場合はどうなるでしょう。

class HogeClass {
  synchronized public void methodA() {
     // 処理
  }
  
  synchronized public void methodB() {
     // 処理
  }
  
  public void methodC() {
     // 処理
  }
}

methodA自身、methodB自身、methodAとmethodBは同じインスタンス内で互いに排他的に実行されますが、
methodAとmethodC、methodBとmethodCは排他的に実行されません。
この排他関係はstaticの場合と同様ですが、インスタンスメソッドなので
いちインスタンスに対してで排他制御されますね。

また、synchronizedメソッド内からsynchronizedメソッドを呼び出すことは可能です。
オブジェクトのロックを取得しているので当然ですね。
(もちろんstaticの場合も同様)
class HogeClass {
  synchronized public void methodA() {
     methodB();
  }
  
  synchronized public void methodB() {
     // 処理
  }
  
}



あまりないとは思いますが、JVM上でスレッド間をまたいでインスタンスメソッドの
排他制御を行いたい場合は、以下のような方法があります。
class HogeClass {
  private static Object lock = new Object();
  
  public void methodA() {
     synchronized (lock) {
      // 処理
     } 
  }
  
  public void methodB() {
    synchronized (lock) {
      // 処理
     }
  }
  
}


排他制御は、相互作用を理解して誤動作やデッドロック等が起きないように
必要最低限に限定して使用するのがよいですね。

2011年1月13日木曜日

WindowsでTomcatをコマンド起動

VisualVMを使用してプロファイリングしようと思ったけど、WindowsサービスでTomcatをあげると認識してくれないのでコマンドでTomcatを起動。

JVMオプションはそれぞれの環境によって違うと思います。
※p6spy使ってるんで、spy.propertiesの環境変数を追加

java 
-Xms256m 
-Xmx512m 
-XX:PermSize=256m 
-XX:MaxPermSize=512m 
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 
-Djava.util.logging.config.file="C:\Program Files\Apache Software Foundation\Tomcat 6.0\conf\logging.properties" 
-Dspy.properties="C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\myapp\WEB-INF\classes\spy.properties" 
-Dcatalina.home="C:\Program Files\Apache Software Foundation\Tomcat 6.0" 
-Dcatalina.base="C:\Program Files\Apache Software Foundation\Tomcat 6.0" 
-Djava.endorsed.dirs="C:\Program Files\Apache Software Foundation\Tomcat 6.0\endorsed" 
-Djava.io.tmpdir="C:\Program Files\Apache Software Foundation\Tomcat 6.0\temp" 
-classpath "C:\Program Files\Apache Software Foundation\Tomcat 6.0\bin\bootstrap.jar" 
org.apache.catalina.startup.Bootstrap start


Tomcatのバージョンは6.0.16です。
わざわざコマンド起動しないでも、サービスを監視する方法ありそうだけどとりあえず。