« Back to Home

Blog

お世話になっている皆様へご挨拶

2011-03-27 05:32:01 +0900

このたび職場を移ることにしました。
お世話になっている皆様には本当に感謝しております。
これからも宜しくお願いいたします。

http://www.youtube.com/watch?v=2w12u_B7mCo

JAXBの簡単な解説(1)

2011-02-27 16:34:52 +0900

JavaとXML間のバインディングを行うJAXB

JavaオブジェクトからXMLへ変換したい、またはXMLからJavaオブジェクトへ変換したい、ということはよくあるものです。

方法はいくつか考えられますが、JavaSE6 にある標準技術 JAXB (Java Architecture for XML Binding) では、この変換を手軽に実装できるようになっています。その使い方を解説しようと思います。

JAXBの考え方

まずはJAXBの考え方を俯瞰しておきます。

図のように、JavaクラスとXML Schemaとが対応するものと考えます。言われてみればもっともな話で、実体としてJavaオブジェクト・XML文書があり、その雛形としてJavaクラス・XML Schemaがあるということですね。

ここから分かる通り、JAXBの出発点はJavaクラスかXML Schemaになります。どちらから始めても実装可能です。

JavaオブジェクトからXMLへの変換

まずはごくごく単純なデータ構造として「会社」と「従業員」を使うことにし、

会社(従業員*)
従業員(名前,給料)

とします。ありがちですいません。これをJavaクラスにするとおそらく以下のようになるでしょう。何ということはない、ごく普通のJavaクラスです。

Companyクラス

public class Company {
	private List<Employee> employees;

	public List<Employee> getEmployees() {
		return employees;
	}

	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}
}

Employeeクラス

public class Employee {
	private String name;
	private int salary;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}
}

次に、このクラスのオブジェクトをXMLに変換するプログラムがどうなるか見てみます。

※ なお、JAXB関連のクラスは javax.xml.bind 以下のパッケージに入っています。

public class Sample1 {

	public static void main(String[] args) {
		// 会社
		Company c = new Company();

		// 2人の従業員
		List<Employee> employees = new ArrayList<Employee>();

		Employee e1 = new Employee();
		e1.setName("taro");
		e1.setSalary(1000);
		employees.add(e1);

		Employee e2 = new Employee();
		e2.setName("hanako");
		e2.setSalary(800);
		employees.add(e2);

		c.setEmployees(employees);

		// マーシャル
		JAXB.marshal(c, System.out);
	}
}

特別なことは何もしていません。ただJAXB#marshal()を呼んでいるだけです。

これを実行すると、以下のような出力が得られるはずです。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <employees>
        <name>taro</name>
        <salary>1000</salary>
    </employees>
    <employees>
        <name>hanako</name>
        <salary>800</salary>
    </employees>
</company>

これで一応JavaオブジェクトからXMLへの変換はできたことになります。

次回へ

出力されたXMLをよく見ると従業員の要素名が「employees」になっています。これは少し嫌なので調整したいですね。そのためにはアノテーションを使ってバインディングを変更する必要があります。

また、JavaクラスとXML Schemaとが対応すると言っておきながら、XML Schemaが一度も登場していません。このあたりを併せて次回に解説しようと思います。

Guavaのススメ

2011-01-15 16:13:10 +0900

Guava: Google Core Libraries for Java 1.5+

GoogleのJavaユーティリティライブラリで、Apache Commons の Lang、Collectionsなどに替わる機能を提供してくれるものです。コンパクトながら、かゆいところに手が届く良質なAPIになっていると思います。

いくつかの機能を紹介します。

コレクションの全ての要素を変換したい

List<A>を基にしてList<B>を作るとします。

ライブラリを使わない場合はこんな感じになるでしょう。

List<B> blist = new ArrayList<B>(alist.size());
for (A a : alist) {
  blist.add(new B(a));
}

Guavaを使う場合は次のように書きます。

List<B> blist = Lists.transform(alist, new Function<A, B>(){
  @Override
  public B apply(A a) {
    return new B(a);
  }
});

おや? どこかで見たような・・・。そう、Commons CollectionsのListUtilsと似ています。が、あちらはジェネリクスを使わないので、ダサいキャストが必要になります。

このリスト変換の利点は、要素を使う時(リストから要素を取り出そうとした時)に初めて変換が行われるところにあります。

キャメルケースとスネークケースの相互変換

ちなみにキャメルケースとは、単語の頭文字を大文字にして結合した文字列の形式(someString)、スネークケースとは、単語間をアンダースコアで結合した文字列の形式(some_string)です。

例えばDBを扱うときに多いですね。Java内ではキャメルケース・DB内ではスネークケースを使ってる場合、変換が必要になることがありますが、自前で実装するのは結構大変で面倒です。こんな場面ではCaseFormatというenumを使います。

キャメルケースからスネークケースへの変換

String str = LOWER_CAMEL.to(LOWER_UNDERSCORE, "someString");
assert str == "some_string";

スネークケースからキャメルケースへの変換

String str = LOWER_UNDERSCORE.to(LOWER_CAMEL, "some_string");
assert str == "someString";

コレクションの文字列連結

Joinerというクラスを使います。

List<String> list = Arrays.asList("aaa", "bbb", "ccc");
String str = Joiner.on(", ").join(list);
assert str == "aaa, bbb, ccc";

Maven

セントラルリポジトリに登録されていますので、Mavenからの使用も可能です。

dependencyの記述は以下の通りです。(現時点での最新バージョンはr07)

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>r07</version>
</dependency>

公式ドキュメント

http://code.google.com/p/guava-libraries/

MySQLのレプリケーションを監視するシェルスクリプト

2010-12-30 23:35:52 +0900

SHOW SLAVE STATUSG でスレーブの状態をチェックして、問題がありそうな場合はメールを送信するスクリプトのメモです。

意図としては、

  • スレーブプロセスが走ってるか
  • エラーが起きてないか
  • 遅延が許容範囲内か(30秒)

ちなみにMySQLそのものに接続できないとかの場合はこのスクリプトでは対応できません。

#! /bin/sh
#
# watch replication
#

ALERT_TO="{mail-destination}";
ALERT_SUBJECT="[MySQL] replication alert";

CHECK_COMMAND="SHOW SLAVE STATUS\G";
ALLOW_DELAY_SECONDS=30;

echo "$CHECK_COMMAND";
slave_status=`mysql -u {user} -e "$CHECK_COMMAND"`;
echo "$slave_status";

# set variables from status
eval "`echo "$slave_status" | sed -ne 's/: (.*)/="1"/p'`";

if [ "$Slave_IO_Running" != "Yes"  ]; then
    msg="Slave_IO_Running : $Slave_IO_Runningn";
fi

if [ "$Slave_SQL_Running" != "Yes" ]; then
    msg="${msg}Slave_SQL_Running : $Slave_SQL_Runningn";
fi

if [ "$Last_Errno" != "0" ]; then
    msg="${msg}Last_Error : [${Last_Errno}] $Last_Errorn";
fi

if [ "$Seconds_Behind_Master" -gt $ALLOW_DELAY_SECONDS ]; then
    msg="${msg}Seconds_Behind_Master : $Seconds_Behind_Mastern";
fi

if [ "$msg" != "" ]; then
    echo "n-- Need alert mail --";
    echo "$msg";
    (echo "${msg}n${CHECK_COMMAND}n${slave_status}" | mailx -s "$ALERT_SUBJECT" "$ALERT_TO");
fi

JAX-RSのリファレンス実装、Jerseyの使い方(1)

2010-11-09 15:14:47 +0900

標準のAPIを使ってプログラムを書いておくと色々と都合がいいので、RESTfulなWebサービスを作成しようとするときはJAX-RSを使いたいものです。

JavaEE6には初めから入っているJAX-RSですが、現場ではTomcat5.5(もちろんJava5です)とかが頑張っているのでそのままでは使えません。Apache Tomcat 5.5 と、JAX-RSのリファレンス実装である Jersey 1.4 を使って、単純なRESTサービスを実装する手順を紹介します。

インストールする

まずはJersey1.4のインストールから。Maven2を使っている場合は、java.netのリポジトリを設定します。

(pom.xml に以下を追加)
<repositories>
    <repository>
        <id>maven2-repository.dev.java.net</id>
        <name>Java.net Repository for Maven</name>
        <url>http://download.java.net/maven/2/</url>
        <layout>default</layout>
    </repository>
</repositories>

サーバアプリケーション側のライブラリは以下です。

(pom.xml に以下を追加)
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-server</artifactId>
    <version>1.4</version>
</dependency>

jarをそのまま使いたい場合は、 http://jersey.java.net/ のDownloadからライブラリをダウンロードしてクラスパスに含めましょう。

Hello World!

入門にはありがちですが、まずは単純に"Hello World!"という文字列を返すだけのRESTサービスを構築してみます。以下のクラスを作成してください。

jerseytest.resources.HelloworldResource

package jerseytest.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/helloworld")
public class HelloworldResource {
	@GET
	public String getMessage() {
		return "Hello World!n";
	}
}

サービスの記述はこれだけです。アノテーションについては後で解説することにしましょう。

次にweb.xmlにサーブレットの設定をします。

<servlet>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>jerseytest.resources</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>JAX-RS Servlet</servlet-name>
  <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

jerseyに含まれているサーブレットクラスを指定して、初期化パラメータとしてサービスを記述したクラスのパッケージ名を与えるだけです。

それではアプリケーションをTomcatに配備して、サービスを参照してみましょう。

$ curl "http://localhost:8080/jerseytest/rest/helloworld"

Hello World!

おお!ちゃんど文字列が返ってきましたね!

アノテーションの解説

RESTサービスでは、”サービスはURLで指定されるweb上のリソースである”と考えます。それで先ほどのHelloworldResourceクラスにもResourceと名付けていました。
そのリソースクラスで使用した2つのアノテーションを説明します。

@Path
リソースとしてマークするとともに、サービスを提供するパスを示す。
@GET
HTTPのメソッドのうち、GETでサービスを提供することを示す。

パラメータを受け取る

クエリパラメータ

RESTサービスでは、サービスを提供するために必要な引数をURLのクエリパラメータとして受け取ることがあります。クエリパラメータを受け取るリソースクラスを作成してみましょう。

jerseytest.resources.SayHelloResource

package jerseytest.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

@Path("/sayhello")
public class SayHelloResource {
	@GET
	public String say(@QueryParam("name") String name) {
		return String.format("Hello %s!%n", name);
	}
}

では実際にサービスを参照してみます。

$ curl "http://localhost:8080/jerseytest/rest/sayhello?name=George"

Hello George!

確かにクエリパラメータを受け取ることができていますね。

パスパラメータ

引数をURLのパスに含めたいこともあるかもしれません。その場合には次のようなコードにします。

jerseytest.resources.SayHelloResource2

package jerseytest.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/sayhello2/{name}")
public class SayHelloResource2 {

	@PathParam("name")
	private String name;

	@GET
	public String say() {
		return String.format("Hello %s!%n", name);
	}
}

今度はプロパティにセットするようにしました。また、@Pathの指定方法にも注目してください。

サービスを参照すると以下のようになります。

$ curl "http://localhost:8080/jerseytest/rest/sayhello2/emily"

Hello emily!

アノテーションの解説

新たにパラメータを扱うアノテーションが2つ登場しました。

@QueryParam
メソッド変数あるいはプロパティに、指定した名前のクエリパラメータ値をセットすることを示す。
@PathParam
メソッド変数あるいはプロパティに、@Pathに指定したURLパス部分から値を取り出してセットすることを示す。

次回へ

ここまでで、サービスの記述とURLとのマッピング、そしてパラメータの取り出しなどが簡単にできることがお分かり頂けたと思います。

ただ、これまでのところ単純な文字列を返すサービスを構築しただけで、まったく現実的なサービスを提供できたとは言えません。次回はXMLやJSONを返すサービスを構築する手順を紹介しようと思います。