Home

sinsengumi血風録

LDRich という livedoor Reader のクライアントアプリを作りました

Android で何か作りたくて、勢いで Galaxy S を買ってしまったので、アプリを作りました。

LDRich という Android アプリで、livedoor Reader のクライアントです。
ネーミングに特に意味はなくて、思いついたものは全て使われていて、ゴロで決めました。


Android 使っている人で、livedoor Reader ユーザーは使っていただけたら嬉しいです。

Android Market
使い方の解説ページ

msysGitのGit bashで日本語を使えるようになるまで

  • Posted by: sinsengumi
  • 2011年8月8日 11:34 AM
  • Git
  • |

最近、ようやくGitを使い始めました。サクサク感があっていいですね。あとGithubの存在が大きい。

で、表題なんですが、
僕はWindows派でmsysGit使ってるわけですが、デフォルト状態(Git Bash)ではコミットログの日本語が化けて出たりと何かと不便です。
そこで、いろいろ設定して日本語が表示できるようになろうという感じです。

lessとnkfをインストール

以下を参考に、lessとnkfを導入します。
http://sourceforge.jp/magazine/09/02/12/0530242/3

inputrc

set meta-flag on
set input-meta on
set output-meta on
set convert-meta off
set kanji-code utf-8

profile

export GIT_PAGER="nkf -s | less"

GIT_EDITORの設定は~/.gitconfigで行っているのでここでは設定しません。

~/.gitconfigの設定

以下のように修正。

[user]
	name = sinsengumi
	email = tomoya.sinsengumi@gmail.com
[color]
	ui = auto
[core]
	editor = 'C:/Program Files (x86)/sakura2-0-2-0/sakura.exe' -CODE=4
	autocrlf = false
[alias]
	ci = commit
	co = checkout
	st = status
	di = diff
	sh = show
	br = branch
[i18n]
	commitencoding = UTF-8

editorの部分ではサクラエディタを起動してますが、「-CODE=4」はファイルを開く時にUTF-8で開くという起動オプションです。

ちなみにこの設定はGithubに上げてみました^^;
https://github.com/sinsengumi/Configs

参考

WTPのTomcat7.0でDataSource(PostgreSQL)からConnectionを取得する

コネクションプーリングをするために、DataSourceからコネクションを取得しようと思ったら、かなりハマってしまったので、備忘録です。

手順は以下。PostgreSQLの例ですが、大体どのDB製品でも同じだと思います。

  1. (サーバの)server.xmlにResourceを定義
  2. (アプリケーションの)web.xmlにresource-refを定義
  3. JDBCドライバを配備
  4. コネクション取得

(サーバの)server.xmlにResourceを定義

まずserver.xmlにResourceを定義します。WTPでサーバを動かしている場合は、以下のようにServersプロジェクト内にserver.xmlがあると思います。

server.xml
server.xml

この中にアプリケーションのContextタグがあると思うので、そこにResourceを追加する。
ここが、Tomcat 6.0と記述が異なっていたので、かなりハマってしまいました。しっかりマニュアルのほうを読まないといけませんね。

server.xml

<Context docBase="Sample" path="/Sample" reloadable="true" source="org.eclipse.jst.jee.server:Sample">
	<Resource name="jdbc/postgresql" auth="Container" type="javax.sql.DataSource"
		driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost/SampleDB" username="postgres"
		password="xxxxxx" maxActive="20" maxIdle="10" maxWait="-1" />
</Context>

(アプリケーションの)web.xmlにresource-refを定義

次にアプリケーション内のweb.xmlにresource-refを定義します。サーバのweb.xmlではないので注意。

web.xml

<resource-ref>
	<res-ref-name>jdbc/postgresql</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

JDBCドライバを配備

WTPでサーバを起動している場合は、サーバプログラム本体のcommon/libにいくらjarを置いてもクラスパスには追加されません。
WTPでjarを追加するには以下のようにします。

プロジェクト・エクスプローラーを右クリック → 実行(実行構成) → クラスパス → ユーザー・エントリでjarを追加

コネクション取得

これで準備ができたので、実際にServletからコネクションを取得してみます。

SampleServlet

package jp.co.njk.nems.controller.authentication;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/SampleServlet")
public class SampleServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private Connection connection;

    public void init(ServletConfig config) throws ServletException {
        try {
            InitialContext context = new InitialContext();
            DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/postgresql");
            connection = dataSource.getConnection();

        } catch (NamingException e) {
            throw new RuntimeException(e);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println(connection);
    }
}

参考

TeedaのラジオボタンにString型ではなく列挙型(Enum)を使う

Teedaのラジオボタンは通常、String型でPageクラスに定義します。
http://teeda.seasar.org/ja/extension/reverse/input.html#%E3%83%A9%E3%82%B8%E3%82%AA%E3%83%9C%E3%82%BF%E3%83%B3_%E9%9D%99%E7%9A%84
が、そこを列挙型(Enum)することができます。こちらの方が型安全になっていいかなと思います。
もちろん、静的・動的両方いけます。

以下、サンプルです。

HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:te="http://www.seasar.org/teeda/extension" xml:lang="ja"
    lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Enumのサンプル</title>
</head>
<body>
<form id="Form">
<span id="allMessages"></span>

<h1>ラジオボタン(静的)</h1>
<div id="sex">
    <label><input type="radio" name="sex" value="MALE" />男性</label>
    <label><input type="radio" name="sex" value="FEMALE" />女性</label>
</div>

<h1>ラジオボタン(動的)</h1>
<input type="hidden" id="languageItemsSave" />
<span id="language">
    <input type="radio" name="language" />
</span>

<p><input type="submit" value="送信" id="doSubmit" /></p>

</form>
</body>
</html>

列挙型

public enum Sex {
    MALE("男性"),
    FEMALE("女性");

    private String japaneseName;

    private Sex(String japaneseName) {
        this.japaneseName = japaneseName;
    }

    public String getJapaneseName() {
        return japaneseName;
    }
}
public enum Language {

    JAPANESE("日本語", "JAPANESE", "こんにちわ"),
    ENGLISH("英語", "ENGLISH", "Hello");

    private String label;
    private String value;
    private String greeting;

    private Language(String label, String value, String greeting) {
        this.label = label;
        this.value = value;
        this.greeting = greeting;
    }

    public String getLabel() {
        return label;
    }

    public String getValue() {
        return value;
    }

    public String getGreeting() {
        return greeting;
    }
}

Pageクラス

public class EnumSamplePage {

    public Sex sex;

    public Language language;
    public List<Language> languageItems;

    public Class<?> initialize() {
        // 初期値の設定
        sex = Sex.FEMALE;
        language = Language.ENGLISH;

        languageItems = new ArrayList<Language>();
        for (Language lang : Language.values()) {
            languageItems.add(lang);
        }

        return null;
    }

    public Class<?> prerender() {
        return null;
    }

    public Class<?> doSubmit() {
        System.out.println(sex.getJapaneseName());
        System.out.println(language.getGreeting());
        return null;
    }
}

注意としては、
静的なラジオボタンで使う場合は、value属性に“列挙子”を指定すること(サンプルだと「MALE」「FEMALE」)
静的なラジオボタンで使う場合は、列挙型のフィールドに“label”“value”を変数名にもつ値を定義すること。
あと、HTMLにhidden属性に”~~ItemsSave”を配置すること。これをしないとPOSTしたときにデータが消えてしまう(これはString型でも同じですが)

livedoor Reader をJavaから操作する何か作った

  • Posted by: sinsengumi
  • 2011年2月21日 12:21 AM
  • Java
  • |

追記
Github にホスティングしました。これからはGithub 使います。
https://github.com/sinsengumi/LDR4J

掲題の通り、livedoor Reader をJavaからHTTPアクセスして未読記事取ったり、ピン付けたりするライブラリ「ldr4j」を作りました。
実はAndroidでlivedoor Readerクライアントアプリを作りたくて、その前段階としてこのラッパーライブラリを作った感じです。

で、生まれてはじめて、まとまったコードをOSSとして公開してみました。
コードはSourceForge.JPでホスティングしています。
(eclipseプラグインのEGITがよさそうであれば、githubでホスティングしたいと思います。)

「ldr4j」プロジェクトページ

http://sourceforge.jp/projects/ldr4j/

以下で、Subversionからチェックアウトできます。
http://svn.sourceforge.jp/svnroot/ldr4j/

※なお、livedoor Reader API はlivedoor から正式にアナウンスされているAPIではないので、仕様変更で使えなくなる可能性はあります。

livedoor Reader が大好きで、もうこれがないとネット生活していけないくらいですね。
今回 ldr4j を作っていく過程で、livedoor Reader がどういう風に出来ているかもなんとなくですがわかりました(livedoor ReaderのOSS版である fastladder を参考にしました。)

このライブラリはこれからもちゃんとメンテナンスしていこー。テストとかもちゃんと書きたいし。

参考

よく見るClosable使ったコード

  • Posted by: sinsengumi
  • 2011年2月16日 8:23 PM
  • Java

Streamなんかを閉じる(close)時のコードなんかでよく見るパターン。
nullチェックして、closeする。さらにそのcloseはチェック例外出すからめんどいよ、ってことなのかしら。
結構有名なのかな?

private void close(Closeable stream) {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

JavaでFTPアップロードを行う。

  • Posted by: sinsengumi
  • 2011年2月1日 9:00 PM
  • Java
  • |

JavaでFTPを使用するにはいくらか方法がありますが、仕事でcommons-netのFTPを使ったのでその備忘録です。

実行環境は以下です。

  • JRE 1.6
  • commons-net-2.0.jar

はまった箇所が2点ほどあって、ひとつはエンコーディングの設定は必ずコネクトする前に行うこと。とPASVモードについてです。

commons-netのFTPClientクラスで、PASVモードにできそうな名前のメソッドが2つあって、それのどっちを使えばいいのか、もしくは違うのか結構悩みました。

  • enterLocalPassiveMode()
  • enterRemotePassiveMode()

結果的にいうと、どっちも違くて、FTPClientの親クラスであるFTPクラスのpasv()メソッドでOKでした。
これらの違いは、ソースやJavadocを見た感じ、恐らく以下のような感じだと思います。

pasv()

FTPのPASVコマンドを発行する。

enterLocalPassiveMode()

dataConnectionModeを「2」に設定する。

enterRemotePassiveMode()

内部的にpasv()を呼び出している。

以下、サンプルコードです。

public class FTPUpload {

    private static final String FTP_HOST = "127.0.0.1";
    private static final String FTP_USER = "username";
    private static final String FTP_PASSWORD = "password";

    private static final String UPLOAD_FILE = "C:\\サンプル.xls";
    private static final String UPLOADED_FILENAME = "リネーム.xls";

    public static void main(String[] args) {
        try {
            execute();
        } catch (ApplicationException e) {
            e.printStackTrace();
        }
    }

    private static void execute() throws ApplicationException {

        FTPClient ftpClient = new FTPClient();

        try {
            // エンコーディングの設定は、connectする前に行う。
            ftpClient.setControlEncoding("SJIS");

            // FTPサーバに接続
            ftpClient.connect(FTP_HOST);
            printFtpReply(ftpClient);

            // ログイン
            ftpClient.login(FTP_USER, FTP_PASSWORD);
            printFtpReply(ftpClient);

            // PASVモードに設定
            ftpClient.pasv();
            printFtpReply(ftpClient);

            // データの変換モードをバイナリに設定
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            printFtpReply(ftpClient);

            // ファイル転送
            FileInputStream fis = new FileInputStream(UPLOAD_FILE);
            ftpClient.storeFile(UPLOADED_FILENAME, fis);
            printFtpReply(ftpClient);

        } catch (NumberFormatException e) {
            throw new ApplicationException("FTPポートの値が数値ではありません。", e);
        } catch (SocketException e) {
            throw new ApplicationException("Socket通信に失敗しました。", e);
        } catch (FileNotFoundException e) {
            throw new ApplicationException("アップロードするファイルが見つかりません。", e);
        } catch (IOException e) {
            throw new ApplicationException("IOレベルで例外が発生しました。", e);
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
    }

    private static void printFtpReply(FTPClient ftpClient)throws ApplicationException {

        System.out.print(ftpClient.getReplyString());

        int replyCode = ftpClient.getReplyCode();

        if (!FTPReply.isPositiveCompletion(replyCode)) {
            throw new ApplicationException("送信したFTPコマンドは失敗しました。");
        }
    }
}

PASVモードやFTPのプロトコルに関しては、以下が大変参考になりました。
http://www.atmarkit.co.jp/fnetwork/rensai/netpro10/netpro01.html

フレームワークを調査するときにやること

仕事でSeasarプロジェクトのTeedaというフレームワークでWebアプリケーションを作ることになったので、その調査ということで、色々やったので、そのメモです。
とりあえず以下の事をやれば、一製造メンバーとしては役に立てるかな。

以下の事をやりました。

  1. チュートリアルを動かしてみる
  2. マニュアルを読む
  3. MLを眺める
  4. 課題管理(バグレポート)を眺める
  5. ブログを読む
  6. ソースを読む

以下、詳細。

1. チュートリアルを動かしてみる

大体のフレームワークには、チュートリアルがサイトに載っていたり、サンプルコードをダウンロードできたりするので、それをとりあえず動かしてみる。
Teedaの場合、html-tutorialという素晴らしいサンプルコード群が配布されているので、それをひと通り眺めると、出来ることのイメージが掴めました。

2. マニュアルを読む

もちろん、必須です。
Teedaの場合、S2やS2Daoなんかも絡んでくるので、そこらへんのマニュアルもひと通り目を通す。
分からないところがあってもとりあえず目を通す。そうすると、後で分からないことがあったときに「あそこに書いてあったような・・・」みたいな当たりが付けられるので。
あと、先にチュートリアルやっておくと実際の動きのイメージをつけながらマニュアルを読めるので、先にチュートリアルやったほうがいい。

3. MLを眺める

MLを眺める&登録しておく。
だいたい行き詰まるところは同じなので、求める答えはMLにあったりするのがほとんどだったりする。
隅から隅まで読むのは無理なので、気になるタイトルのやつだけ読んでました。
あとML登録しておくと、コミュニティの活発具合とか雰囲気がわかる気がして楽しい。

4. 課題管理(バグレポート)を眺める

フレームワークの歴史が垣間見れて面白い。
どのバージョンでこういう機能が追加されたんだ、とか分かる。
最新バージョンを使えるようなら問題ないけど、理由あって古いバージョンを使わなくちゃいけないとか言う場合に、この機能は使えないとかを調査したりする。

5. ブログを読む

これは実装してたらだいたいすると思うけど、Teedaだったら検索に引っかかったブログのTeedaカテゴリーは全部読むとか。

6. ソースを読む

これができたら最高なんだけど、、、、まだ技術力不足で無理です。。。

Windowsでどのポートが何のアプリケーションで使用されているか確認する

Eclipse内のWTPでTomcatを起動したら、以下のようなエラーメッセージが出て、起動できませんでした。

ローカル・ホスト の Tomcat v6.0 サーバー で必要なポート 8009 はすでに使用中です。サーバーはすでに別のプロセスで稼働中であるか、システム・プロセスがそのポートを使用中である可能性があります。このサーバーを始動するには、他のプロセスを停止するか、ポート番号を変更する必要があります。

どうもポートがかぶっていそうな感じだったので、ポートが何のアプリケーションで使用されているかを調べてみました。
方法は以下。

ポートのPIDを確認する

以下のコマンドで、ポートのPIDを確認する。

C:\>netstat -nao

アクティブな接続

  プロトコル  ローカル アドレス          外部アドレス        状態           PID
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       996
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:902            0.0.0.0:0              LISTENING       3632
  TCP    0.0.0.0:912            0.0.0.0:0              LISTENING       3632
  TCP    0.0.0.0:990            0.0.0.0:0              LISTENING       760
  TCP    0.0.0.0:1521           0.0.0.0:0              LISTENING       2976
  TCP    0.0.0.0:1862           0.0.0.0:0              LISTENING       2176
  TCP    0.0.0.0:2869           0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:5357           0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:5432           0.0.0.0:0              LISTENING       3400
  TCP    0.0.0.0:8009           0.0.0.0:0              LISTENING       3476
  TCP    0.0.0.0:8308           0.0.0.0:0              LISTENING       3476
  TCP    0.0.0.0:17500          0.0.0.0:0              LISTENING       4068
  TCP    0.0.0.0:49152          0.0.0.0:0              LISTENING       684

これでポート「8009」がPID「3476」で使用されていることがわかる。

PIDから使用されているアプリケーションを特定する

タスクマネージャを開いて、使用アプリケーションを特定する。

  1. 「Ctrl + Alt Delete」でタスクマネージャを開く。
  2. 「プロセス」タブを開く。
  3. デフォルトだとPIDが表示されていないので、「全ユーザーのプロセスを表示する(S)」「表示(V)→列の選択(S)→PID(プロセスID)」にそれぞれにチェックを入れる。

すると、PID「3476」がtomcat6.exeで使用されていることがわかる。
最後に該当の行を右クリックするなどして「プロパティ」などを見れば、使用されているアプリケーションが特定できる。めでたしめでたし。

Teedaでcolspanする

Teedaでcolspanするにはダイナミックプロパティを利用すればできます。

colspan.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:te="http://www.seasar.org/teeda/extension" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Teedaでcolspan</title>
</head>
<body>

<form id="Form">
<table border="1">
	<tr>
		<th>OS名</th>
		<th id="versionColspan" colspan="1">バージョン</th>
	</tr>
	<tr>
		<td><span id="osName">dummy</span></td>
		<div id="versionItems">
		<td><span id="codeName">dummy</span><br /><span id="number">dummy</span></td>
		</div>
	</tr>
</table>
</form>

</body>
</html>

ColspanPage.java

package org.sample.web.fnc;

import java.util.ArrayList;
import java.util.List;

public class ColspanPage {

	public int versionColspan;

	public List<VersionDto> versionItems;
	public String codeName;
	public String number;

	public String osName;

	public Class<?> initialize() {
		return null;
	}

	public Class<?> prerender() {
		osName = "Mac";

		// Macのバージョン
		versionItems = new ArrayList<ColspanPage.VersionDto>();

		VersionDto mac1 = new VersionDto();
		mac1.number = "10.3";
		mac1.codeName = "Panther";
		versionItems.add(mac1);

		VersionDto mac2 = new VersionDto();
		mac2.number = "10.4";
		mac2.codeName = "Tiger";
		versionItems.add(mac2);

		VersionDto mac3 = new VersionDto();
		mac3.number = "10.5";
		mac3.codeName = "Leopard";
		versionItems.add(mac3);

		VersionDto mac4 = new VersionDto();
		mac4.number = "10.6";
		mac4.codeName = "SnowLeopard";
		versionItems.add(mac4);

		return null;
	}

	class VersionDto {
		public String codeName;
		public String number;
	}

	public int getVersionColspanColspan() {
		return versionItems.size();
	}
}

Home

Search
Feeds
Meta

Return to page top