Category Archives: Java - Page 2

[SAStruts][Interceptor]セッションによるログイン認証を可能にする

Webアプリケーションだと、セッション(Session)でログイン情報を保持する方法をよくとる。
今回は、SAStrutsでログイン処理+セッション保持を紹介する。
たぶん、このやり方が一般的かと思う。

■はじめに
今回、Eclipse→Dolteng→SAStruts→S2JDBCで開発するので、その辺を注意。
プロジェクト名が「LoginSample」とする。
ベースURLが「http://localhost:8080/LoginSample/」とする。
ベースパッケージが「biz.mikuriya」とする。

■大まかな手順
いくつかのプログラム開発、設定ファイル編集を行なうと、
ログイン処理+セッション保持が可能になる。
以下の手順で作業を進める。

・ユーザーデータクラスを作成
・アクションフォームクラスを作成
・アクション(ページ構成)を作成
・アクションに合ったJSPを作成
・ログイン処理+セッション保持処理用のクラスを作成
・customizer.diconを編集
・動作確認

■ユーザーデータクラスを作成
メールアドレスだけをセッションに保持しておきたいので、
ユーザーデータクラスは、以下のように作成。

biz.mikuriya.dto.UserDto.java

package biz.mikuriya.dto;

import java.io.Serializable;

import org.seasar.framework.container.annotation.tiger.Component;
import org.seasar.framework.container.annotation.tiger.InstanceType;

@Component(instance = InstanceType.SESSION)
public class UserDto implements Serializable {
	private static final long serialVersionUID = 1L;

	public String email;
}

■アクションフォームクラスを作成
メールアドレスとパスワードの入力によるログイン処理が行なわれるため、
それ用の入力チェックデータクラスを作成。

biz.mikuriya.form.UserForm.java

package biz.mikuriya.form;

import org.seasar.struts.annotation.EmailType;
import org.seasar.struts.annotation.Maxlength;
import org.seasar.struts.annotation.Minlength;
import org.seasar.struts.annotation.Required;

public class UserForm {
	@Required
	@EmailType
	public String email;

	@Required
	@Minlength(minlength = 6)
	@Maxlength(maxlength = 32)
	public String password;
}

■アクション(ページ構成)を作成
今回は3ページ作成する。
トップページ、ログインページ、マイページの3種類を作成。

biz.mikuriya.action.IndexAction.java(トップページ)

※ログインの必要がないページ

package biz.mikuriya.action;

import javax.annotation.Resource;

import org.seasar.struts.annotation.Execute;

import biz.mikuriya.dto.UserDto;

public class IndexAction {
	@Resource
	public UserDto userDto;

    @Execute(validator = false)
	public String index() {
        return "index.jsp";
	}
}

biz.mikuriya.action.LoginAction.java(ログインページ)

※ログインの必要がないページ

package biz.mikuriya.action;

import javax.annotation.Resource;

import org.seasar.framework.beans.util.Beans;
import org.seasar.struts.annotation.ActionForm;
import org.seasar.struts.annotation.Execute;

import biz.mikuriya.dto.UserDto;
import biz.mikuriya.form.UserForm;

public class LoginAction {
	@Resource
	@ActionForm
	public UserForm userForm;

	@Resource
	protected UserDto userDto;

	@Execute(validator = true, input = "/login/index.jsp")
	public String index() {
		// セッションへの保存処理
		// userDtoに値を入れるだけでSessionに保存される
		Beans.copy(this.userForm, this.userDto).execute();

		return "/mypage/?redirect=true";
	}
}

biz.mikuriya.action.MypageAction.java(マイページ)

※ログインが必要なページ

package biz.mikuriya.action;

import javax.annotation.Resource;

import org.seasar.struts.annotation.Execute;

import biz.mikuriya.dto.UserDto;

public class MypageAction {
	@Resource
	public UserDto userDto;

	@Execute(validator = false)
	public String index() {
		return "index.jsp";
	}
}

■アクションに合ったJSPを作成
前項で作成したActionに一致したJSPファイルを作成。

/WEB-INF/view/index.jsp

<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>トップページ</title>
</head>
<body>
	<h1>トップページ</h1>

	メールアドレス<br/>
	ここに表示「<b>${userDto.email}</b>」<br/>

	<br/>

	<a href="<c:url value="/"/>">トップページ</a>|<a href="<c:url value="/login/"/>">ログインページ</a>|<a href="<c:url value="/mypage/"/>">マイページ</a>
</body>
</html>

/WEB-INF/view/login/index.jsp

<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>ログインページ</title>
</head>
<body>
	<h1>ログインページ</h1>

	<html:errors/>

	<s:form action="/login/">
		メールアドレス<html:text property="email" /><br/>
		パスワード<html:password property="password" /><br/>
		<br/>
		<html:submit value="ログイン"/>
	</s:form>

	<br/>

	<a href="<c:url value="/"/>">トップページ</a>|<a href="<c:url value="/login/"/>">ログインページ</a>|<a href="<c:url value="/mypage/"/>">マイページ</a>
</body>
</html>

/WEB-INF/view/mypage/index.jsp

<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>マイページ</title>
</head>
<body>
	<h1>マイページ</h1>

	<b>これがマイページ</b><br/>

	メールアドレス<br/>
	ここに表示「<b>${userDto.email}</b>」<br/>

	<br/>

	<a href="<c:url value="/"/>">トップページ</a>|<a href="<c:url value="/login/"/>">ログインページ</a>|<a href="<c:url value="/mypage/"/>">マイページ</a>
</body>
</html>

■ログイン処理+セッション保持処理用のクラスを作成
重要ポイントとなるログイン処理クラスを作成。

biz.mikuriya.interceptor.LoginConfirmInterceptor.java

package biz.mikuriya.interceptor;

import javax.annotation.Resource;

import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
import org.seasar.struts.annotation.Execute;

import biz.mikuriya.dto.UserDto;

public class LoginConfirmInterceptor extends AbstractInterceptor {
	private static final long serialVersionUID = 1L;

	@Resource
	protected UserDto userDto;

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// ここの条件がtrueであればログイン済みと判断
		// ここの条件がfalseであればログインページへ移動
		return (!isExecuteMethod(invocation) || isLoggedIn()) ? invocation
				.proceed() : "/login/";
	}

	private boolean isExecuteMethod(MethodInvocation invocation) {
		return invocation.getMethod().isAnnotationPresent(Execute.class);
	}

	private boolean isLoggedIn() {
		// Sessionにユーザー情報が登録されているかチェック
		return (userDto != null && userDto.email != null);
	}
}

■customizer.diconを編集
これも重要ポイントとなるログイン処理を有効にするための設定ファイル
これを編集する。
MypageActionだけをセッションチェックしたいので、addClassPatternで登録する

customizer.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
	"http://www.seasar.org/dtd/components24.dtd">
<components>
	<include path="default-customizer.dicon"/>
	<component name="formCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain"/>

	<component name="actionCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain">
		<initMethod name="addAspectCustomizer">
			<arg>"aop.traceInterceptor"</arg>
			<!-- ここ重要(追加必須) -->
			<arg>true</arg>
		</initMethod>

		...(中略)...

		<!-- SESSIONのチェック設定はここから -->
		<initMethod name="addCustomizer">
			<arg>
				<component class="org.seasar.framework.container.customizer.AspectCustomizer">
					<property name="interceptorName">"loginConfirmInterceptor"</property>
					<!-- ここ重要(追加必須) -->
					<property name="useLookupAdapter">true</property>

					<!-- このActionだけセッションチェックを行なう -->
					<initMethod name="addClassPattern">
						<arg>"biz.mikuriya.action"</arg>
						<arg>"MypageAction"</arg>
					</initMethod>
				</component>
			</arg>
		</initMethod>
		<!-- SESSIONのチェック設定はここまで -->
	</component>

	...(省略)...
</components>

「ここ重要」とコメントにした部分は、とても重要。
以下のURLに書かれているように、HotDeploy時とCoolDeploy時では、
動作が違うので、注意すべし。

[S2Container][SAStruts] セッション格納の値について

■動作確認
実際に動作を確認する。

http://localhost:8080/LoginSample/

セッションがない状態でマイページへ接続

http://localhost:8080/LoginSample/mypage/

[SAStruts]S2JDBCでJOINのやり方をいつも忘れるからメモ

SAStrutsでJOINを行なう際、どう書くか毎回忘れてしまう。

単純なテストを以下に記す。



■データベースのスキーマ

CREATE DATABASE db_test;
USE db_test;

CREATE TABLE channels (
	channel_id INTEGER NOT NULL AUTO_INCREMENT
	, title TEXT NOT NULL
	, PRIMARY KEY (channel_id)
);

CREATE TABLE items (
	item_id INTEGER NOT NULL AUTO_INCREMENT
	, title TEXT NOT NULL
	, url VARCHAR(255) NOT NULL
	, channel_id INTEGER NOT NULL
	, PRIMARY KEY (item_id)
	, UNIQUE (url)
);

INSERT INTO channels (title) VALUES("情報考学 Passion For The Future");
INSERT INTO channels (title) VALUES("RwJ");

INSERT INTO items (title,url,channel_id) VALUES("無趣味のすすめ","http://www.ringolab.com/note/daiya/2009/07/post-1021.html",1);
INSERT INTO items (title,url,channel_id) VALUES("アイデア・スイッチ 次々と発想を生み出す装置","http://www.ringolab.com/note/daiya/2009/07/post-1023.html",1);
INSERT INTO items (title,url,channel_id) VALUES("ベガーズ・イン・スペイン","http://www.ringolab.com/note/daiya/2009/07/post-1022.html",1);
INSERT INTO items (title,url,channel_id) VALUES("psコマンドはオプションに「-」がいらないみたい","http://blog.mikuriya.biz/archives/310",2);
INSERT INTO items (title,url,channel_id) VALUES("[SAStruts]Tomcat起動時に初回のみ呼び出す独自のクラスでデータベース接続","http://blog.mikuriya.biz/archives/171",2);
INSERT INTO items (title,url,channel_id) VALUES("[PHP]フレームワーク「CakePHP」のインストールと設定","http://blog.mikuriya.biz/archives/7",2);




■jdbc.diconを編集

今回は、MySQLを使用するので、そのあたりを編集する。

<components namespace="jdbc">
	...

	<component name="xaDataSource"
		class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
		<property name="driverClassName">
			"com.mysql.jdbc.Driver"
		</property>
		<property name="URL">
			"jdbc:mysql://localhost:3306/db_test"
		</property>
		<property name="user">"root"</property>
		<property name="password">""</property>
	</component>
	...
</components>




■channelsテーブルのクラス

package biz.mikuriya.entity;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "channels")
public class Channel {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int channelId;

	public String title;

	@OneToMany(mappedBy = "parent") // Itemに定義する変数名がparentになる
	public List<Item> childs;
}




■itemsテーブルのクラス

package biz.mikuriya.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "items")
public class Item {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int itemId;

	public String title;

	public String url;

	public int channelId;

	@ManyToOne
	@JoinColumn(name = "channel_id")
	public Channel parent; // Channel.itemsのmappedByの値と変数名を合わせる
}




■動作テスト用実行クラス

package biz.mikuriya;

import java.util.List;

import org.seasar.extension.jdbc.JdbcManager;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

import biz.mikuriya.entity.Channel;
import biz.mikuriya.entity.Item;

public class DBTest {
	private JdbcManager jdbcManager;

	/**
	 * データベース接続
	 */
	public DBTest() {
		SingletonS2ContainerFactory.init();
		S2Container container = SingletonS2ContainerFactory.getContainer();
		this.jdbcManager = (JdbcManager) container
				.getComponent(JdbcManager.class);
	}

	/**
	 * 普通にSELECT
	 */
	public void selectChannel() {
		System.out.println("CHANNELS************************************");

		List<Channel> channels = this.jdbcManager.from(Channel.class)
				.getResultList();

		for (Channel channel : channels) {
			System.out.println("\t" + channel.channelId + "\t" + channel.title);
			System.out.println("\t--------");
		}
	}

	/**
	 * 普通にSELECT
	 */
	public void selectItem() {
		System.out.println("ITEMS************************************");

		List<Item> items = this.jdbcManager.from(Item.class).getResultList();

		for (Item item : items) {
			System.out.println("\t" + item.itemId + "\t" + item.channelId
					+ "\t" + item.title + "\t" + item.url);
			System.out.println("\t--------");
		}
	}

	/**
	 * 一対多の構造で取得する場合
	 */
	public void joinOneToMany() {
		System.out.println("JOIN************************************");

		List<Channel> channels = this.jdbcManager.from(Channel.class)
				.innerJoin("childs").getResultList(); // JOINには、変数名を指定する

		for (Channel channel : channels) {
			System.out.println("\t" + channel.channelId + "\t" + channel.title);

			for (Item item : channel.childs) {
				System.out.println("\t\t" + item.itemId + "\t" + item.channelId
						+ "\t" + item.title + "\t" + item.url);
				System.out.println("\t\t--------");
			}

			System.out.println("\t--------");
		}
	}

	/**
	 * 一対一の構造で取得する場合
	 */
	public void joinOneToOne() {
		System.out.println("JOIN************************************");

		List<Item> items = this.jdbcManager.from(Item.class)
				.innerJoin("parent").getResultList(); // JOINには、変数名を指定する

		for (Item item : items) {
			System.out.println("\t" + item.itemId + "\t" + item.channelId
					+ "\t" + item.title + "\t" + item.url + "\t"
					+ item.parent.channelId + "\t" + item.parent.title);
			System.out.println("\t--------");
		}
	}

	public static void main(String[] args) {
		DBTest test = new DBTest();

		test.selectChannel();
		test.selectItem();

		test.joinOneToMany();
		test.joinOneToOne();
	}
}

[SAStruts]Tomcat起動時に初回のみ呼び出す独自のクラスでデータベース接続

SAStruts(Super Agile Struts)の開発、設定方法に苦戦した。



やりたいことは以下。

1.WebサーバTomcat起動時に独自に作成したクラスを呼び出したい。

2.呼び出したクラス内でデータベースにSELECTを発行し、取得したレコードをメモリに読み込みたい。



1点目の解決法は、customizer.diconにinitializeServiceを設定すれば解決できる。

(customizer.diconへの設定例)
<components>
...(中略)
    <component name="initializeService" class="jp.mikuriya.Init">
        <initMethod name="init">
            <arg>"/home/hoge/sample/property/sys.properties"</arg>
        </initMethod>
    </component>
<components>


(クラスの記述例)
package jp.mikuriya;

import org.seasar.extension.jdbc.JdbcManager;

public class Init {
    public JdbcManager jdbcManager;

    public void init(String propertyFile) {
        /* -------------------- */
        /* 適当な処理内容を記述 */
        /* -------------------- */
        System.out.println("Tomcat起動時に呼ばれたよ。[propertyFile=" + propertyFile + "]");
    }
}

Tomcatを起動すればこれでSystem.outは実行される。


しかし、上記の「クラスの記述例」で記述している「JdbcManager jdbcManager」に注目してもらいたい。

フィールドに設定しておくと、勝手にデータベースに接続してくれる

SAStrutsの特徴であるJdbcManagerが記述されている。

これがどうにも上手くいかない。

うまくいかないとはデータベースに接続できないってこと。



Tomcatのログ(catalina.out)を確認すると、以下のようなメッセージが出力されている。

「...プロパティ(jdbcManager)が見つからないので設定をスキップします」

Tomcatのログをもっと確認してみると、customizer.diconを呼び出しているようなログが

s2jdbc.diconを呼び出しているようなログよりも前の行に表示されている。

ってことは、s2jdbc.diconを呼び出してから、例題のプログラムを起動させればよいと考えた。



そこで先ほどcustomizer.diconに設定していた内容を切り取って、

s2jdbc.diconに追加する。

(s2jdbc.diconへの設定例)
<components>
...(中略)
    <component name="initializeService" class="jp.mikuriya.Init">
        <initMethod name="init">
            <arg>"/home/hoge/sample/property/sys.properties"</arg>
        </initMethod>
    </component>
</components>



これで再度Tomcatのログを確認してみると、s2jdbc.diconを呼び出した後に

System.outが出力されているのがわかる。



他にやり方がありそうなのだが、わかんねぇ。

Javaオープンソース「Nutch」はクロール→インデクシング→検索までいける

Nutchというクローラ、インデクサ、検索を行なうオープンソースがあったので、

軽く触ってみた。

Nutch内部ではLucene、Hadoopが動作してるようなので、勉強にはちょうどいいかと思う。

早速、インストールから動作までの解説をする。



■クローラ

1.Nutch本体ダウンロード、解凍

# tar -xvzf nutch-0.9.tar.gz
# mv nutch-0.9 /usr/local/nutch



2.環境変数にパスを通す

# vi /etc/bashrc

export NUTCH_HOME=/usr/local/nutch
export PATH=${NUTCH_HOME}/bin:${PATH}

# source /etc/bashrc



3.クロール先を決める

クロール先URLリストを作成する。

今回は2サイトをクロールする予定。

# cd ${NUTCH_HOME}
# mkdir crawl_urls
# vi crawl_urls/corporate_sites

http://www.datasection.co.jp/

# vi crawl_urls/blogs

http://blog.mikuriya.biz/



要は作成したディレクトリcrawl_urls以下に1行1URLで

クロールしたいサイトの開始位置をどんどん記述するってことみたい。



4.クロールのフィルタ設定

今回のクロール対象は2サイトなので、それ以外はクロールしたくない。

以下のファイルに正規表現でフィルタリングを行なう。(正規表現はJava仕様)

# cd ${NUTCH_HOME}
# vi conf/crawl-urlfilter.txt

(修正前)
+^http://([a-z0-9]*\.)*MY.DOMAIN.NAME/
(修正後)
+^http://www\.datasection\.co\.jp/
+^http://blog\.mikuriya\.biz/

※よく見ると先頭に「+」とか「-」が入ってる。

クロールしたいURLパターンは「+」、クロールしたくないURLパターンは「-」を

このファイルに追加していくようだ。



5.クロール設定

クロール用の設定ファイルは初期段階では何も書かれていないので、

nutch-default.xmlをそのままコピーしてくる。

# cat conf/nutch-default.xml > nutch-site.xml

nutch-site.xmlの「http.agent.name」は必須っぽい。適当な名前をつけて。

私の場合は、クロールしたデータを「/usr/local/nutch/crawl_data」に

格納したいので以下を編集した。

# vi conf/nutch-site.xml
<property>
  <name>searcher.dir</name>
  <value>/usr/local/nutch/crawl_data</value> ← ここを編集した
  <description>
    ...
  </description>
</property>

nutch-site.xmlには、propertyのdescription属性に

設定の説明が書いてあるので、各自適当に読んで設定してもらいたい。



6.クロール開始

# /usr/local/nutch/bin/nutch crawl /usr/local/nutch/crawl_urls -dir /usr/local/nutch/crawl_data -depth 3 -topN 50 &

※なおcrawl_dataは勝手に作成されるので、いちいち作らなくてよい。



■WEBアプリケーション

Tomcatからクロールしたデータを検索表示することができるので、その設定を行なう。

${NUTCH_HOME}/nutch-0.9.warがその実体。

# cd ${NUTCH_HOME}
# mkdir nutch_web
# cp nutch-0.9.war nutch_web/
# cd nutch_web
# unzip nutch-0.9.war



解凍したアプリケーションの設定ファイルには、何も書かれていないので

クロール用で使用した設定ファイルを上書きしてやる。

# cp conf/nutch-site.xml nutch_web/WEB-INF/classes/nutch-site.xml



Tomcatで見れるようにシンボリックリンクを貼る。

# cd /usr/local/tomcat/webapps
# ln -s /usr/local/nutch/nutch_web nutch



Tomcat起動

# /usr/local/tomcat/bin/startup.sh



■検索結果のウェブ画面







形態素解析器Senの導入(日本語対応)、Hadoopによる分散(複数のサーバで運用)、

その他パフォーマンスなどは、もったいないから教えない。



■参考URL:

http://dev.team-lab.com/index.php?itemid=120

http://kazuhiro.ty.land.to/blog/2007/01/nutch.html

Railsのパクリ「Grails」は本当にパクリだった

Ruby on RailsのパクリGrailsをちょっとだけ触ってみた。

基本的にRuby on Railsをパクっているので、

結果的に必要ないかな、というのが率直な感想。



■Grailsのインストール

以下の解説で分からなかったら本家を見ろ。



1.grails-bin-1.0.2.zipをダウンロード

http://grails.codehaus.org/Download

2.解凍し、適当なディレクトリに設置。

3.設置したディレクトリを環境変数にGRAILS_HOMEとして設定する。

4.環境変数PATHにGRAILS_HOME/binも設定する。

5.コマンドプロンプトを開き、以下のコマンドを実行してみる。

grails help

※ヘルプが表示されればインストール完了。



■サンプルアプリケーションを作成

まぁこれも本家を見れば出来るけど解説。



1.コマンドプロンプトを開く。

2.アプリケーションを作成する。

アプリケーションの名前を聞かれたら「fuck」を入力し、完了。

※作成中のログに作成したアプリケーションのパスが表示される。

grails create-app
Please enter: fuck



3.作成したアプリケーションのディレクトリまで移動する。

cd C:/Users/UserName/fuck

※私の場合はWindows Vistaなのでこのパス



4.Youというクラスを作成する。

作成するとgrails-app/domainにYou.groovyというファイルが出来上がる。

grails create-domain-class
Please enter: You



5.You.groovyを編集する。

idとversionは必須項目なのかな?

class You {
    Long id
    Long version

    String yourname
}



6.コントローラを作成すればあとはサーバを起動するだけ。

以下のコマンドを実行するとgrails-app/controllersに

YouController.groovyが出来上がる。

grails generate-all
Please enter: you



7.YouController.groovyを編集する。

class YouController {
    def scaffold = You
}



8.サーバを起動する。

grails run-app
...
...
Server running. Browse to http://localhost:8080/fuck
2008-04-19 11:10:33.791:/fuck:INFO:  GSP servlet initialized



9.ブラウザからhttp://localhost:8080/fuckへ接続する。





10.それからhttp://localhost:8080/fuck/youに接続。





わざわざJavaベースではなく、Ruby on railsでいいんじゃん?

形態素解析器MeCabでJava Binding(バインディング)を使用してみた

理想的にはWindows上でJava Bindingを動作させたかったが、
dllファイルを作成しなくてはいけないようで、これは私の専門外。
これだけを調査すると、多分一日かかりそうなので、Linuxのみ動作させる。

以下の手順がすでに完了済みであることを前提にすすめる。
1.すでにMecabをインストールしていることを前提に解説
2.MeCabで使用する文字コードはUTF-8のみに固定(その他文字コードでは不明)
3.試したMeCabのバージョンは「0.96」

■Java Bindingのパッケージをダウンロード
http://sourceforge.net/project/showfiles.php?group_id=177856&package_id=205296
この時、MeCab、Java Bindingのバージョンを合わせなければいけない。

■解凍、コンパイル

$ tar -xvzf mecab-java-0.xx.tar.gz
$ cd mecab-java-0.xx
$ make

make中に以下のエラーが発生する時があるが、無視して結構。

test.java:24: 警告:この文字は、エンコーディング UTF8 にマップできません。

コンパイルが終了すると、新規に2つのファイルが作成されている。
・MeCab.jar(実行時のクラスパスに通す)
・libMeCab.so(loadLibraryで読み込むライブラリ)

■サンプルソース
パッケージ内に存在するtest.javaを見ていただければ分かると思うが、
一応サンプルソースを書く。

try {
    System.loadLibrary("MeCab");
} catch (UnsatisfiedLinkError e) {
    e.printStackTrace();
}

Tagger tagger = new Tagger();

/* Nodeが無くなるまで処理を続ける */
for (Node node = tagger.parseToNode(text); node != null; node = node.getNext()) {
    System.out.println(node.getSurface());
    System.out.println(node.getFeature());
}

■注意点
スレッドで使用すると、エラーが発生する。
「Taggerを毎回インスタンス化すればスレッド内でも使用できる」と書いてはあるが、
エラーが発生するので、微妙。

エラー文は、こんな感じ。

java.lang.RuntimeException:
        tagger.cpp(149) [tokenizer_.open(*param)]
        tokenizer.cpp(114) [sysdic->open (create_filename(prefix, SYS_DIC_FILE).c_str())]
        dictionary.cpp(73) [ptr == dmmap_->end()]
        dictionary file is broken: /usr/local/lib/mecab/dic/ipadic/sys.dic
        at org.chasen.mecab.MeCabJNI.new_Tagger__SWIG_1(Native Method)
        at org.chasen.mecab.Tagger.(Tagger.java:94)
        at MeCabThreadTest.analyze(MeCabThreadTest.java:38)
        at MeCabThreadTest.run(MeCabThreadTest.java:36)

終いには、これ。

./mecab_test.sh: line 5: 31692 アボートしましたjava -classpath ...

スレッドにする必要性は、今のところそこまでないけど、
いつか必要になった時に困るよねぇ。

[Java]Java標準クラスを使用して、環境変数を取得

/etc/bashrcに設定した値を取れないかと思ってみた。
そして、取得できることが分かった。

虎の穴 環境変数

public static void main(String[] args) {
    Map p = System.getenv();
    Iterator ite = p.keySet().iterator();
    while (ite.hasNext()) {
        String key = (String) ite.next();
        System.out.println(key + " - " + p.get(key));
    }
}

Java標準クラスって結構便利なのね。
自分で作る前に、とりあえずJava標準クラスをチェックだな。
反省。

[Java]JavaFX Scriptを軽く試すが、基本はマイコミジャーナルのパクリ

JavaFX Scriptが出たということで試す。

■実行環境
環境は、こんな感じ。

>java -version
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)

■JavaFX Script用パッケージのダウンロード
以下のURLからライブラリをダウンロード
https://openjfx.dev.java.net/servlets/ProjectDocumentList

解凍して、trunk/lib以下のjarファイルをクラスパスに通す。

■サンプルプログラム作成
サンプルソースを以下のURLからコピーしてくる。
http://journal.mycom.co.jp/articles/2007/05/11/javafx/001.html

■実行
そんで実行する際は、net.java.javafx.FXShellをmainとするみたい。
引数にfxファイルを指定して実行する。
この時、実行するfxファイルは、拡張子をはずして引数に渡す。

まぁ、基本的にマイコミジャーナルをコピペしているに近いんだが・・・。

■参考URL
http://journal.mycom.co.jp/articles/2007/05/11/javafx/001.html

[Java]リダイレクトされたURLを取得する

Yahoo!とかgooでは、ログをとるためにか?リンクに変な文字列がついてる。

http://rd.search.goo.ne.jp/click?...http://www.sun.com/

リダイレクトされたURLがほしかったので、プログラムで取得する。

URL url = new URL("http://rd.search.goo.ne.jp/click?...http://www.sun.com/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int responseCode = connection.getResponseCode();
String redirectUrl = connection.getURL().toString();
connection.dicconnect();

変数redirectUrlには、「http://www.sun.com」が取得できているはず。

[Java]Vista、普通にTomcat起動でエラー発生の注意点

Windows Vistaで普通にTomcatをインストールし、

SysdeoのTomcat PluginからTomcatを起動してみる。



なぜかこんなエラーが発生。

http://d.hatena.ne.jp/cloneko/20050430/1114830190



よく見ると、Tomcat起動時のtomcat-users.xmlバックアップ処理中に

現在ログインしているユーザでは権限が無いため変更できない、

というエラー。



この状況は以下のような時に起きるっぽい。

・インストーラでTomcatをインストールした。

・現在ログインしているユーザでは権限が無い



tomcat-users.xmlに対して、現在ログインしているユーザの権限を

最強にしたらTomcatが正常に起動した。





インストーラでのインストールの際、普段と違った動きをした場合は、

Windows Vistaを疑うべきかも。