<?xml version="1.0" encoding="UTF-8" ?><rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xml:lang="ja">
  <channel rdf:about="http://www19.atwiki.jp/heppokoact/">
    <title>heppokoactの技術メモ</title>
    <link>http://www19.atwiki.jp/heppokoact/</link>
    <description>heppokoactの技術メモ</description>

    <dc:language>ja</dc:language>
    <dc:date>2009-12-22T03:31:39+09:00</dc:date>

    <items>
      <rdf:Seq>
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/25.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/23.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/22.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/24.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/2.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/16.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/21.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/20.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/18.html" />
                <rdf:li rdf:resource="http://www19.atwiki.jp/heppokoact/pages/17.html" />
              </rdf:Seq>
    </items>
	
		
    
  </channel>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/25.html">
    <title>コミット内容をCSVにする</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/25.html</link>
    <description>
      @ECHO OFF

set HOOKDIR=&quot;E:\repository\hooks&quot;
set TMPDIR=&quot;%HOOKDIR%\.svnhook&quot;
set SVNLOOKDIR=&quot;E:\subversion\bin&quot;

set REPOS=%1
set TXN=%2
set RET=1

set LOG=%TMPDIR%\%TXN%.log
set CHANGED=%TMPDIR%\%TXN%.changed

if not exist %TMPDIR% mkdir %TMPDIR%

call %SVNLOOKDIR%\svnlook log -t %TXN% %REPOS% &gt;&gt; %LOG%
call %SVNLOOKDIR%\svnlook changed -t %TXN% %REPOS% &gt;&gt; %CHANGED%

cd %HOOKDIR%
java -classpath %HOOKDIR% SvnToCsv %LOG% %CHANGED%
set RET=%ERRORLEVEL%

del %LOG%
del %CHANGED%

exit %RET%



import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * svn logの実行結果からCSVを作成します。
 *
 */
public class SvnToCsv {

	private String log;
	private String changed;

	public static void main(String[] args) {
		if (args.length != 2) {
			System.err.println(&quot;引数の数が変ですよ。（&quot; + args.length + &quot;個）&quot;);
			System.exit(1);
		}

		int result;
		try {
			result = new SvnToCsv(args[0], args[1]).toCsv();
		} catch (Exception e) {
			System.err.print(e.getMessage());
			result = 1;
		}

		System.exit(result);
	}

	public SvnToCsv(String logPath, String changedPath) throws IOException {
		log = read(logPath);
		changed = read(changedPath);
	}

	public int toCsv() throws IllegalFormatException, IOException {
		// 特定のディレクトリへの変更をしなければスルー
		if (!needToCsv()) {
			return 0;
		}

		String bugNo = getFirstGroup(log, &quot;課題管理番号：(\\d+)&quot;);
		String comment = getFirstGroup(log, &quot;コメント：(.+)&quot;);
		String[] changedPathes = getChangdPathes();
		write(toCsvString(bugNo, comment, changedPathes));

		return 0;
	}

	private void write(String csv) throws IOException {
		FileOutputStream out = null;
		PrintWriter writer = null;
		try {
			out = new FileOutputStream(new File(&quot;C:/release.log&quot;), true);
			FileChannel channel = out.getChannel();
			FileLock lock = getLock(channel);

			writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out)));
			writer.print(csv);

			lock.release();

		} finally {
			if (writer != null) writer.close();
			if (out != null) out.close();
		}
	}

	private FileLock getLock(FileChannel channel) throws IOException {
		for (int i=0; i&lt;5; i++) {
			FileLock lock = channel.tryLock();
			if (lock == null) {
				try {
					Thread.sleep(1000);
					continue;
				} catch (InterruptedException e) {}
			}
			return lock;
		}

		throw new IOException(&quot;C:/release.logのロックが取得できませんでした。&quot;);
	}

	private String toCsvString(String bugNo, String comment, String[] changedPathes) {
		StringBuilder builder = new StringBuilder();
		for (String path: changedPathes) {
			builder.append(bugNo).append(&quot;,&quot;).append(path).append(&quot;,&quot;).append(comment).append(&quot;\r\n&quot;);
		}
		return builder.toString();
	}

	private String[] getChangdPathes() throws IllegalFormatException {
		String[] changedArray = changed.split(&quot;\\r\\n&quot;);
		String[] changedPathes = new String[changedArray.length];
		for (int i=0; i&lt;changedArray.length; i++) {
			String changedElement = changedArray[i];
			changedPathes[i] = getFirstGroup(changedElement, &quot;.+/ほげ/(ふが/.+)&quot;);
		}
		return changedPathes;
	}

	private String getFirstGroup(String target, String regexp) throws IllegalFormatException {
		Pattern pattern = Pattern.compile(regexp);
		Matcher matcher = pattern.matcher(target);
		if (!matcher.find()) {
			throw new IllegalFormatException(&quot;正規表現「&quot; + regexp + &quot;」が見つかりません。\r\n対象：&quot; + target);
		}
		return matcher.group(1);
	}

	private boolean needToCsv() {
		Pattern pattern = Pattern.compile(&quot;/ほげ/&quot;);
		return pattern.matcher(changed).find();
	}

	private String read(String path) throws IOException {
		BufferedReader reader = null;
		StringBuilder builder = new StringBuilder();

		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(path), &quot;MS932&quot;));
			while (true) {
				String line = reader.readLine();
				if (line == null) break;
				builder.append(line).append(&quot;\r\n&quot;);
			}

		} finally {
			if (reader != null) reader.close();
		}

		return builder.toString();
	}

	private class IllegalFormatException extends Exception {
		IllegalFormatException(String message) {
			super(message);
		}
	}

}    </description>
    <dc:date>2009-12-22T03:31:39+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/23.html">
    <title>プロジェクト管理ツール</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/23.html</link>
    <description>
      -機能比較
--http://forza.cocolog-nifty.com/blog/2009/05/redminetrac-905.html
-redmineのExcelからの一括登録ツール
--http://d.hatena.ne.jp/kaorun55/20090524/1243177625
-[[コミット内容をCSVにする]]    </description>
    <dc:date>2009-12-22T03:28:20+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/22.html">
    <title>ひとりごと</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/22.html</link>
    <description>
      -だめコード集をつくる。
--JSPで案外DRY原則が守られないかも
-プロジェクトの終了条件を明確にする。
-一括は成果物責任。過程に口を出されるならSES。
-例外処理基準が必要。
--日付のパース例外やnewInstanceしたときの例外などはPGが処理に困るだろう。
--e.printStackTrace()禁止。チェッカーを作れ！
-ログ出力基準が必要。
--例外処理時とデバッグ用のログ。
--ToStringBuilder#reflectionToString()を活用。
-assertしまくって規約違反をすべて例外に！
-ActionとServiceの分け方
--Action
---データベースに依存しないチェック
--Service
---データベースに依存するチェック
-一括更新で1件1件ロールバックおよびコミットをする場合、件数が多くなりすぎないかどうかに気をつける。
-セッション中のデータのライフサイクルを図にする。
--できればフレームワーク側で対応する。
-「機能」とは何かを定義する必要がある。
--でないと…
---機能の粒度がまちまちになる。
---機能IDを振る時に一貫性のない機能IDになる。
---など。
--帳票なら出力された帳票が機能なのか、帳票を作成する過程を含めて機能なのか。
--各機能のサブ機能はどのように表現すればよいのか。
-命名規約
--booleanはtrue/falseの意味が明確にならないような命名を避ける。
---だめな例…check（trueがチェックOKなのかfalseがチェックOKなのかわからない）
---良い例…isValid
---isやhasで始めるとよいかも。
--クラス名やファイル名で各画面固有のものは「画面ID + 機能名」にした方が管理しやすい。
-HTML
--1行当たりの高さを決めておく。
---ラベルと入力項目の高さが異なるとめんどう。
--右寄せ、左寄せを決めておく。
---おもに数値と日付が問題になる。
---中央寄せにする項目があるかどうかも問題。
--上寄せ、中寄せ、下寄せを決めておく。
---DIVだと中寄せは辛い。
-更新日付をDBからAPに持ってきてDBにINSERT、UPDATEする場合はThreadLocalに入れておいた方がよさげ。    </description>
    <dc:date>2009-12-03T20:28:46+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/24.html">
    <title>WEB全般</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/24.html</link>
    <description>
      -IEではwindow.openやwindow.showModalDialogではリファラが飛ばない。
-window.showModalDialogはレスポンスを受け取ってからでないとポップアップが開かないっぽい。
--重い画面を開けるとしばらく何も表示されないのでユーザビリティが悪くなる。    </description>
    <dc:date>2009-12-03T14:34:31+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/2.html">
    <title>メニュー</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/2.html</link>
    <description>
      **メニュー
-[[トップページ]]

-[[Wicket]]
-[[VBA]]
-[[Hibernate]]
-[[Struts2]]
-[[その他]]
-[[UNIX]]
-[[ツール]]
-[[WEB全般]]
-[[ひとりごと]]
-[[プロジェクト管理ツール]]

----

**リンク
-[[プラグイン紹介&gt;プラグイン]]
-[[まとめサイト作成支援ツール]]
-[[@wiki&gt;&gt;http://atwiki.jp]]
-[[@wikiご利用ガイド&gt;&gt;http://atwiki.jp/guide/]]

// リンクを張るには &quot;[&quot; 2つで文字列を括ります。
// &quot;&gt;&quot; の左側に文字、右側にURLを記述するとリンクになります


//**更新履歴
//#recent(20)

&amp;link_editmenu(text=ここを編集)    </description>
    <dc:date>2009-12-03T14:32:58+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/16.html">
    <title>その他</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/16.html</link>
    <description>
      -include-preludeに指定するJSPのパスを間違えても例外が出ない。その後パスを正しく直しても、JSPのタイムスタンプが変わるまでJSPのクラスファイルが更新されない。
-javaメモリチューニング
http://d.hatena.ne.jp/learn/20090218/p1
-統計学入門
--http://d.hatena.ne.jp/hiroyukikojima/20080724
-JPAとS2JDBC比較、ドメインモデルにからめて
--http://d.hatena.ne.jp/higayasuo/20071029/1193635026    </description>
    <dc:date>2009-11-28T12:58:56+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/21.html">
    <title>ツール</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/21.html</link>
    <description>
      -PDFを編集
http://www.moongift.jp/2009/11/pdf_xchange_viewer/
-定期的に自動実行する
http://www.express.nec.co.jp/linux/distributions/knowledge/system/crond.html
-分散メモリキャッシュサーバ
memcached    </description>
    <dc:date>2009-11-16T11:11:56+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/20.html">
    <title>フリーソフト</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/20.html</link>
    <description>
      -PDFを編集
http://www.moongift.jp/2009/11/pdf_xchange_viewer/    </description>
    <dc:date>2009-11-14T12:59:17+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/18.html">
    <title>UNIX</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/18.html</link>
    <description>
      **sed
Stream Editorの略。
文字列を読み込んで編集できる。
sed &#039;s/正規表現/置換後/フラグ&#039; ソース 出力先
ls | sed &#039;s/正規表現/置換後/フラグ&#039;
置換以外にも指定した行のみの読み込みや削除など。    </description>
    <dc:date>2009-11-05T08:14:52+09:00</dc:date>
  </item>
    <item rdf:about="http://www19.atwiki.jp/heppokoact/pages/17.html">
    <title>Struts2</title>
    <link>http://www19.atwiki.jp/heppokoact/pages/17.html</link>
    <description>
      *あれこれ
-バリデーションエラーが発生すると勝手にname=&quot;input&quot;で登録したresultに遷移してしまう。
--自画面に遷移させるならばname=&quot;input&quot;に自画面を登録しておく必要がある。
-reset,back,clear,browseはValidationが働かない。
--struts-defaults.xmlで定義されている。
-URLを/struts/hogeとするとクラスパスから静的リソースhogeを探すらしい。
--未確認。
-Action#prepare()で前処理ができる。
--Action#hoge()の前処理はAction#prepareHoge()でできる。
-RolesInterceptorで認可が可能だが、403を返すだけなので、403用ページが必要。
-TokenInterceptorには&lt;s:tokenTag&gt;。
-バリデーションエラーメッセージを動的に変えたい場合はプロパティファイルを次のようにする。
--ActionにuserNameというプロパティがあり、それの必須チェックをする場合。
 error.required=%{getText(fieldName)}は必須です。
 userName=ユーザ名
-共通遷移先が定義できるらしい。
--未確認。
-ExceptionInterceptorにはメッセージ表示処理はないので、例外クラスにメッセージを返すメソッドを作成して${exception.message}で取得。
-chainでActionにフォワードしていればActionの属性値を引き継げる。
--両方のActionに同じプロパティが必要。
-actionErrorとfieldErrorは別物らしい…

*参考
-http://hamasyou.com/archives/Engineer-Soul/struts2_ue_xwork.php
-http://www.h3.dion.ne.jp/~alpha-pz/info14.html    </description>
    <dc:date>2009-05-25T09:12:17+09:00</dc:date>
  </item>
  </rdf:RDF>

