スポンサー広告 - スポンサーサイト

--/--/-- (--) --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【プログラミング】JAVA - WinMerge用プラグイン - INIファイルの比較

2013/11/17 (日) 22:44

プロパティファイルに引き続き、INIファイルの比較が必要になりました。
具体的には、php.ini の設定の違いを洗い出したかったのですが、
同じ流れでWinMerge用のプラグインを作ってみました。
もしかしたら世の中に需要があるかもしれないのでソースを公開します。
適当に書き換えて使ってください。

package tak.tools;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.TreeMap;

/**
* INIファイルを読み込んで、セクションごとにキーの値でソートして出力します。
* コメント行は無視されます。
* 実行可能JARを生成してください。
*
* @author tak
*
*/
public class IniOutput {

/**
* メイン
*
* @param args INIファイルのフルパス
*/
public static void main(String[] args) {

try {
outputList(System.out, createIniMap(args[0]));
} catch (Exception e) {
e.printStackTrace();
}

}

/**
* INIファイルを読み込んでMAPを生成
*
* @param path INIファイルのパス
* @return セクションごとに纏めたMAP
* @throws IOException 例外発生時
*/
private static TreeMap<String, TreeMap<String, ArrayList<String>>> createIniMap(String path) throws IOException {

TreeMap<String, TreeMap<String, ArrayList<String>>> map = new TreeMap<String, TreeMap<String, ArrayList<String>>>();

BufferedReader br = null;

try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(path), "Windows-31J"));

String line;
String section = "";
while ((line = br.readLine()) != null) {

// 前後の空白を除去
line = line.trim();

// コメントアウトを除去
if (line.indexOf(";") >= 0) {
line = line.replaceFirst(";.*$", "");
}

// 空行なので飛ばす
if (line.length() == 0) {
continue;
}

if (line.matches("^\\[.*\\]$")) {
// セクション
section = line;

// 初回登場時は器を用意
if (!map.containsKey(section)) {
map.put(section, new TreeMap<String, ArrayList<String>>());
}

} else {
// 設定
int hoge = line.indexOf("=");
String key = line.substring(0, hoge).trim();
String value = line.substring(hoge + 1).trim();

// 同一のキーがあるかもしれないのでリストで保持する
if(!map.get(section).containsKey(key)){
ArrayList<String> list = new ArrayList<String>();
list.add(value);
map.get(section).put(key, list);
}else{
map.get(section).get(key).add(value);
}

}

}

} finally {
if (br != null) {
br.close();
}
}

return map;
}

/**
* INIファイルマップの出力
*
* @param out 出力先
* @param ini 対象INIファイル
*/
private static void outputList(PrintStream out, TreeMap<String, TreeMap<String, ArrayList<String>>> ini) {

for (String section : ini.keySet()) {
out.println(section);
for (String key : ini.get(section).keySet()) {
ArrayList<String> list = ini.get(section).get(key);

// 昇順でソート
Collections.sort(list);
for (String value : list) {
out.println(key + "=" + value);
}
}
}

}
}


続いて、WinMerge用のプラグインファイルです。
MergePlugins ディレクトリに配置します。
※64Bit版では動かないかもしれません。
<scriptlet>

<implements type="Automation" id="dispatcher">
<property name="PluginEvent"><get/></property>
<property name="PluginDescription"><get/></property>
<property name="PluginFileFilters"><get/></property>
<property name="PluginIsAutomatic"><get/></property>
<method name="UnpackFile"/>
<method name="PackFile"/>
</implements>

<script language="VBS">

Option Explicit

'環境に応じて変更してください
Const jarPath = "C:\Program Files\WinMerge\MergePlugins\iniOutput.jar"

Function get_PluginEvent()
get_PluginEvent = "FILE_PACK_UNPACK"
End Function

Function get_PluginDescription()
get_PluginDescription = "Compare Ini Files"
End Function

Function get_PluginFileFilters()
get_PluginFileFilters = "\.ini$"
End Function

Function get_PluginIsAutomatic()
get_PluginIsAutomatic = True
End Function

Function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode)
Dim fso
Dim fo
Dim ws
Dim exec

Set fso = CreateObject("Scripting.FileSystemObject")
Set fo = fso.CreateTextFile(fileDst, True)
Set ws = CreateObject("WScript.Shell")
Set exec = ws.Exec("java -jar """ + jarPath + """ """ + fileSrc + """")
fo.Write(exec.StdOut.ReadAll())

Set exec = Nothing
Set ws = Nothing
fo.Close
Set fo = Nothing
Set fso = Nothing

pbChanged = True
pSubcode = 0
UnpackFile = True

End Function

Function PackFile(fileSrc, fileDst, pbChanged, pSubcode)
PackFile = False
End Function

</script>
</scriptlet>

スポンサーサイト

【プログラミング】JAVA - WinMerge用プラグイン - プロパティファイルの比較

2013/11/17 (日) 22:36

仕事でプロパティファイルの比較をする必要があったのですが、
一方はコメントあり、もう一方はコメントなし、設定値の記述順もばらばら。
という状況で、有効な設定行だけを抽出して差を確認したかったのです。
単純に「WinMerge」で比較しても、当然上手く比較できません。
そこで、「WinMerge」用のプラグインを作ることにしました。
どんな動作にするかというと、Javaの「java.util.Properties」で読み込み、
キーでソートして出力するという単純な物です。
このAPIで読み込むと、コメント行が除去されます。ついでにUnicode コード変換された文字も元に戻ります。
読み込んだ後に「java.util.TreeMap」に詰め直してソートします。
もしかしたら世の中に需要があるかもしれないのでソースを公開します。
適当に書き換えて使ってください。

package tak.tools;

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Enumeration;
import java.util.Properties;
import java.util.TreeMap;

/**
* プロパティファイルを読み込んで、キーの値でソートして出力します。
* コメント行は無視されます。
* 実行可能JARを生成してください。
*
* @author tak
*
*/
public class PropertiesOutput {

/**
* メイン
*
* @param args プロパティファィルのフルパス
*/
public static void main(String[] args) {

final Properties prop = new Properties();

try {
prop.load(new InputStreamReader(new FileInputStream(args[0]), "UTF-8"));
outputList(System.out, prop);
} catch (Exception e) {
e.printStackTrace();
}

}

/**
* プロパティの出力
*
* @param out 出力先
* @param prop 対象プロパティファイル
*/
private static void outputList(PrintStream out, Properties prop) {

// キーでソート
TreeMap<String, String> map = new TreeMap<String, String>();

// プロパティの抽出
for (Enumeration<?> e = prop.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
map.put(key, (String) prop.getProperty(key));
}

// プロパティの出力
for (String key : map.keySet()) {
out.println(key + "=" + map.get(key));
}

}

}


続いて、WinMerge用のプラグインファイルです。
MergePlugins ディレクトリに配置します。
※64Bit版では動かないかもしれません。
<scriptlet>

<implements type="Automation" id="dispatcher">
<property name="PluginEvent"><get/></property>
<property name="PluginDescription"><get/></property>
<property name="PluginFileFilters"><get/></property>
<property name="PluginIsAutomatic"><get/></property>
<method name="UnpackFile"/>
<method name="PackFile"/>
</implements>

<script language="VBS">

Option Explicit

'環境に応じて変更してください
Const jarPath = "上記JAVAをJAR化して配置したフルパス"

Function get_PluginEvent()
get_PluginEvent = "FILE_PACK_UNPACK"
End Function

Function get_PluginDescription()
get_PluginDescription = "Compare Propertis Files"
End Function

Function get_PluginFileFilters()
get_PluginFileFilters = "\.properties$;\.conf$"
End Function

Function get_PluginIsAutomatic()
get_PluginIsAutomatic = True
End Function

Function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode)
Dim fso
Dim fo
Dim ws
Dim exec

Set fso = CreateObject("Scripting.FileSystemObject")
Set fo = fso.CreateTextFile(fileDst, True)
Set ws = CreateObject("WScript.Shell")
Set exec = ws.Exec("java -jar """ + jarPath + """ """ + fileSrc + """")
fo.Write(exec.StdOut.ReadAll())

Set exec = Nothing
Set ws = Nothing
fo.Close
Set fo = Nothing
Set fso = Nothing

pbChanged = True
pSubcode = 0
UnpackFile = True

End Function

Function PackFile(fileSrc, fileDst, pbChanged, pSubcode)
PackFile = False
End Function

</script>
</scriptlet>

【プログラミング】JAVA - setCharacterEncoding

2013/02/17 (日) 21:48

久々にJavaのネタです。

先日仕事で遭遇したことをメモ。
仕事でStruts2をベースをしたフレームワークを使用しています。
そこでこんなことが起こりました。

画面からの入出力、ソース共にShift_JIS(Windows-31J)でという要件でした。
というわけでstruts.xmlに以下の設定を追加。
<constant name="struts.i18n.encoding" value="Windows-31J"/>
これでStruts2の内部ではリクエスト情報に対して
request.setCharacterEncoding("Windows-31J")
を実行してくれます。

んで、さらにちょっと特殊な要件が発生しました。
リクエスト毎に、とある名前のパラメータが存在したら値を取り出してログに出力してほしい。
これを実現するために、サーブレットフィルタを作成しました。
そのフィルタはStruts2のコントローラーが動く前に仕込み、処理としては
request.getParameter("とある名前");
をして、取り出せるかを試していました。

このフィルタを仕込んでみたところ、なんと入力データが文字化けするようになってしまいました。
調査すること数時間。原因が判明しました。
なんと「request.setCharacterEncoding()」は、事前に「request.getParameter()」を実行されていると、無効になるんだそうです。
つーかJavadocに書いてありました(汗)
---
Overrides the name of the character encoding used in the body of this request. This method must be called prior to reading request parameters or reading input using getReader(). Otherwise, it has no effect.

【Google翻訳】
この要求の本体で使用される文字エンコーディングの名前をオーバーライドします。このメソッドは、リクエストパラメータの読み取り、またはgetReader()を使用して入力を読み取る前に呼び出す必要があります。それ以外の場合は、効果がありません。
---
なんという事でしょう。文字コードをセットする前にパラメータを読みだしてしまうと、文字コードがセットできないんだそうです。
最初に読みだしたときに、文字コードが何も指定されていないのでデフォルトの「UTF-8」と決めてしまうのでしょう。
まぁ言われてみれば、分からないでもないですよねぇ。
対策としては、自前で「request.setCharacterEncoding()」を実行してしまうか、Struts2のコントローラーが動いた後でパラメータを読みだすかですね。
後者の場合はインターセプタを使用するという手も考えられます。
そもそものサーブレットの仕様であり、Struts2固有の現象ではないので注意です。

意外と盲点というか、知っていればあっという間に解決ですが、知らないと答えを知るまでにそれなりに時間がかかりそうな出来事でした。
二度目が起こらないように書き記しておきます。

【プログラミング】JAVA - うるう年

2012/02/26 (日) 23:43

今年はうるう年です。
2月の29日が存在するので、仕事でも影響調査がありました。
その時にちょっと気になったことがあったのでメモ。

■お試しソース

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Calendar cal = Calendar.getInstance();

System.out.println("----------");
System.out.println("うるう年から1年引いてみる");

cal.set(Calendar.YEAR, 2012);
cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 29);
cal.add(Calendar.YEAR, -1);
System.out.println(sdf.format(cal.getTime()));

System.out.println("----------");
System.out.println("うるう年の前日から1年引いてみる");

cal.set(Calendar.YEAR, 2012);
cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 28);
cal.add(Calendar.YEAR, -1);
System.out.println(sdf.format(cal.getTime()));

System.out.println("----------");
System.out.println("うるう年の翌年の2月末日から1年引いてみる");

cal.set(Calendar.YEAR, 2013);
cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 28);

cal.add(Calendar.YEAR, -1);
System.out.println(sdf.format(cal.getTime()));

System.out.println("----------");
System.out.println("うるう年の翌年の3月1日から1年引いてみる");

cal.set(Calendar.YEAR, 2013);
cal.set(Calendar.MONTH, 2);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.YEAR, -1);
System.out.println(sdf.format(cal.getTime()));

System.out.println("----------");

■実行結果
----------
うるう年から1年引いてみる
2011/02/28
----------
うるう年の前日から1年引いてみる
2011/02/28
----------
うるう年の翌年の2月末日から1年引いてみる
2012/02/28
----------
うるう年の翌年の3月1日から1年引いてみる
2012/03/01
----------

何が言いたいのかというと、
・2月29日から1年引いた場合と、2月28日から1年引いた場合の『日』は28になる。
・1年引くと2月29日になる日というのは存在しない。
ということです。
経緯は考えないとして、もし月末の処理で1年前の末日を求める処理をしていた場合、単純に1年引く処理をしていると、うるう年の翌年に誤動作を起こすかもしれない!
とか。
cal.getActualMaximum(Calendar.DATE)
とかすると、月末の日付が取れるのでこれでなんとかするか、
1年引く⇒1ヵ月足す⇒その月の1日にする⇒1日引く
とかでも取れるっちゃ取れるかねぇ。

とにかく、4年に一度のイベントだけども、その年に限らず前後の年のことも考慮して調査しないと、忘れたころに障害とかが起きそうな予感です。

【プログラミング】JAVA - TomcatでCGI

2011/06/18 (土) 21:56

自宅でPHPでの開発(ほぼ趣味)を行いたいと考えたときに、ApacheやIISを導入するのはなんとなく躊躇われた。
レジストリとか汚したくないし、サービスが登録されてもうざいし。
できるだけ綺麗に美しく、エレガントにできないだろうかと。
そこで、Eclipse(Pleiadesの3.6)は既にインストールしてあったので、同胞のTomcat上でCGIを動かすことにした。

実は、以前に仕事でTomcat上で動くwebアプリケーションをJAVAで作成する案件があり、同時にPerlで書かれたCGIも動かす必要があったので同じ設定をしたことがある。
なので実現可能であることは知っていたのでした。
とりあえず備忘録として記録しておくことにします。

まずはCGIを何で書くのか。
今時だとPHPが主流かしら?一昔前はPerl一色だった気もするが。

言語を決めたらその言語をインストールする。
WindowsでもLinuxでもどっちでも良いけど、まぁとりあえずWindowsにしておこう。

Tomcat全体に設定することも可能だけども、ここはとある任意のコンテキストにだけ設定を施そう。

各webappの web.xml に設定を記述する。
以下はPHPの場合。
<web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<!-- CGI用のサーブレット定義 -->
<servlet>
<servlet-name>php</servlet-name>

<!-- TomcatでCGIを動かすためのサーブレット -->
<servlet-class>
org.apache.catalina.servlets.CGIServlet
</servlet-class>

<!-- パラメータ:デバッグレベル -->
<init-param>
<param-name>debug</param-name>
<param-value>6</param-value>
</init-param>

<!-- パラメータ:PHPスクリプトを配備するフォルダのパス docrootが基点 -->
<init-param>
<param-name>cgiPathPrefix</param-name>
<param-value>php</param-value>
</init-param>

<!-- パラメータ:PHPを実行するためのコマンド -->
<init-param>
<param-name>executable</param-name>
<param-value>C:/php/php-4.4.9/php.exe</param-value>
</init-param>

<load-on-startup>5</load-on-startup>
</servlet>

<!-- CGI用のサーブレットマッピング -->
<servlet-mapping>
<servlet-name>php</servlet-name>
<url-pattern>/php/*</url-pattern>
</servlet-mapping>

</web-app>


で、ここからはTomcatのバージョンによって異なる設定。

■Tomcat5.xの場合
$CATALINA_HOME/server/lib/servlets-cgi.renametojar

$CATALINA_HOME/server/lib/servlets-cgi.jar
にリネームする。
要するに、先の web.xml で指定したサーブレット「org.apache.catalina.servlets.CGIServlet」がこのjarの中にあるということ。

■Tomcat6の場合
サーブレットクラス「org.apache.catalina.servlets.CGIServlet」は、
$CATALINA_HOME/lib/catalina.jar
に引っ越しした模様。
なので特に設定の必要はなくなったのだけど、別の設定が必要なようです。

該当のコンテキスト設定タグの要素(Context)に、
privileged="true"
というのが必要。
$CATALINA_HOME/conf/Catalina/localhost
に置くファイルか、
$CATALINA_HOME/conf/Catalina/localhost/server.xml
に書くものですね。

この privileged 要素の意味するところは以下のような感じ。
---
このWebアプリケーションに特権を与えるかどうかを指定します。
true にすると、コンテナ・サーブレットを使うことが可能になります。
コンテナ・サーブレットとは、org.apache.catalina.ContainerServletインターフェイスを
実装したサーブレットの事を指します。
---
だそうだ。

PHP以外にもPerlも同時に使いたいんだぁ!という場合は、web.xmlにサーブレットとマッピングの設定を追加すれば共存が可能と思われます。

Eclipseだけで開発したいときには便利だと思ふ。

検索フォーム
RSSリンクの表示
カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
月別アーカイブ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。