Tutorial
本チュートリアルではS2Directory単体での基本的な使い方を紹介します。
本チュートリアルでは紹介しませんが、JDK 5以降の環境でS2DirectoryにS2DirectoryTigerを併用すると、エンティティとDirectoryDaoでTigerアノテーションを利用することができます。
S2Directoryを使用して開発を進める基本的な手順は次のようになります。
- Setupに従い必要なライブラリをあなたのプロジェクトに配置する
- S2Directoryを使うための設定を行う
- エンティティを作成する (POJO, Entity, Java Beansなどいろいろな呼び名があります)
- Daoインタフェースを作成する
- 必要なロジックを記述し、開発を進めていく
- サンプルの実行結果
作成するサンプルアプリケーション
本Tutorialでは、ユーザエントリ user1 (dn: uid=user1,ou=Users,dc=seasar,dc=org)を取得し、値を読み書きするサンプルアプリケーションを紹介します。
作成するサンプルアプリケーションのためのディレクトリインフォメーションツリー
サンプルアプリケーションで扱うディレクトリインフォメーションツリー(Directory Information Tree: DIT)は次のようになっているとします。
- ディレクトリインフォメーションツリー
dc=seasar,dc=org
|-ou=Users
| |-uid=user1
| |-...
| \-uid=user99
|
\-ou=Groups
|-ou=group1
|-...
\-ou=group99
- ユーザエントリ user1 (dn: uid=user1,ou=Users,dc=seasar,dc=org)
dn: uid=user1,ou=Users,dc=seasar,dc=org
cn: user1
uid: user1
uidNumber: 10001
gidNumber: 1000
homeDirectory: /home/users/user1
userPassword: {SHA}/FnHO2r9STv93ciakMWsL5K7EJM= (secretのSHAハッシュ)
loginShell: /bin/bash
gecos: System User
description: (empty)
S2Directoryを使うための設定を行う
S2DirectoryはS2Containerに付属するDIやAOPなどの様々な機能を利用してその機能を実現していますが、それらのDIやAOPなどの設定方法には複数種類あります。本Tutorialでは、AutoRegisterを利用した例を紹介します。
より実践的なアプリケーションを開発する場合、SMART Deployによる設定を行った方がHOT Deployなどの便利な機能が使えるため、その際はそちらを使用することを推奨します。
- See Also: [S2Directory] S2DirectoryでのSMART Deploy利用方法 (S2Container 2.4.x以降のみ利用可能)
app.dicon
アプリケーションを構成するルートとなるdiconファイルです。S2Directoryの基本機能を提供するためのシステム設定(DI設定、AOP定義)を有効にするためにdirectorydao.diconファイルをincludeします。また、DaoインタフェースにS2DirectoryのAOPのためのインタセプターを適用する設定を記述したalldao.diconをincludeします。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.4//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include path="alldao.dicon" />
</components>
alldao.dicon
S2Directoryのインタセプターのためのインタセプタチェインの定義とその適用先とするDaoインタフェースを指定します。下記の設定では、org.seasar.directory.examples.directorydaoパッケージ以下にある*DirectoryDaoクラスに適用しています。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.4//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include path="directorydao.dicon"/>
<!-- DirectoryDaoインタセプターチェイン定義 -->
<component name="directoryDaoInterceptorChain" class="org.seasar.framework.aop.interceptors.InterceptorChain">
<initMethod name="add"><arg>directorydao.interceptor</arg></initMethod>
</component>
<!-- DirectoryDao定義 -->
<component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
<property name="autoNaming">
<component class="org.seasar.framework.container.autoregister.DefaultAutoNaming"/>
</property>
<initMethod name="addClassPattern">
<arg>"org.seasar.directory.examples.directorydao"</arg>
<arg>".*DirectoryDao"</arg>
</initMethod>
</component>
<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
<property name="interceptor">directoryDaoInterceptorChain</property>
<initMethod name="addClassPattern">
<arg>"org.seasar.directory.examples.directorydao"</arg>
<arg>".*DirectoryDao"</arg>
</initMethod>
</component>
</components>
directory.dicon
ディレクトリサーバに接続するための各種設定情報を定義するdiconファイルです。詳細については、Configurationのdirectory.diconについての説明を読んでください。
- See Also: [S2Directory] Configuration
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components.dtd"> <components namespace="directory"> <!-- # Directory Configuration --> <component name="directoryControlProperty" class="org.seasar.directory.impl.DirectoryControlPropertyImpl" instance="prototype"> <property name="initialContextFactory"> "com.sun.jndi.ldap.LdapCtxFactory" </property> <!-- # PermissiveSSLSocketFactory is not strictly secure. # But, it can connect to the server having the SSL certificate signed by own CA. # default value: <property name="sslSocketFactory"> "javax.net.ssl.SSLSocketFactory" </property> --> <property name="sslSocketFactory"> "org.seasar.directory.impl.PermissiveSSLSocketFactory" </property> <property name="enableTLS">false</property> <property name="url"> "ldap://localhost:389" </property> <property name="baseDn">"dc=seasar,dc=org"</property> <property name="bindDn">"cn=Manager,dc=seasar,dc=org"</property> <property name="password">"secret"</property> <property name="passwordAlgorithm">"SHA"</property> <!-- # Other options and each default value. <property name="authentication">"simple"</property> <property name="user"></property> <property name="passwordAlgorithm">"SSHA"</property> <property name="passwordSaltLength">"4"</property> <property name="userSuffix">"ou=Users"</property> <property name="userAttributeName">"uid"</property> <property name="groupSuffix">"ou=Groups"</property> <property name="groupAttributeName">"memberUid"</property> <property name="multipleValueDelimiter">"DEFAULT_MULTIPLE_VALUE_DELIMITER"</property> --> </component> </components>
エンティティを作成する (POJO, Entity, Java Beansなどいろいろな呼び名があります)
ディレクトリのエントリを写像するエンティティを作成します。エンティティはフィールドとsetter/getterメソッドを定義した単純なPOJO(Plain Old Java Object)で構成されます。また、エンティティにS2Directoryのための情報を定義しておきたい場合はアノテーションを書くことが出来ます。
- See Also: [S2Directory] Entity
* 現在提供しているアノテーションはフィールドアノテーションのみです。
なお、下記のPOJOは、Directory POJO Generatorを使用して稼働中のディレクトリサーバから自動的に生成したものにpackageを加えただけのエンティティクラスです。
package org.seasar.directory.examples.entity;
import java.io.Serializable;
public class PosixAccount implements Serializable {
private String dn;
private String cn;
private String uid;
private String uidNumber;
private String gidNumber;
private String homeDirectory;
private String userPassword;
private String loginShell;
private String gecos;
private String description;
public PosixAccount() {
super();
}
public PosixAccount(String cn, String uid, String uidNumber, String gidNumber, String homeDirectory) {
super();
this.cn = cn;
this.uid = uid;
this.uidNumber = uidNumber;
this.gidNumber = gidNumber;
this.homeDirectory = homeDirectory;
}
public void setDn(String dn) {
this.dn = dn;
}
public String getDn() {
return dn;
}
public void setCn(String cn) {
this.cn = cn;
}
public String getCn() {
return cn;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getUid() {
return uid;
}
public void setUidNumber(String uidNumber) {
this.uidNumber = uidNumber;
}
public String getUidNumber() {
return uidNumber;
}
public void setGidNumber(String gidNumber) {
this.gidNumber = gidNumber;
}
public String getGidNumber() {
return gidNumber;
}
public void setHomeDirectory(String homeDirectory) {
this.homeDirectory = homeDirectory;
}
public String getHomeDirectory() {
return homeDirectory;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserPassword() {
return userPassword;
}
public void setLoginShell(String loginShell) {
this.loginShell = loginShell;
}
public String getLoginShell() {
return loginShell;
}
public void setGecos(String gecos) {
this.gecos = gecos;
}
public String getGecos() {
return gecos;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("DN: ");
buf.append("dn=").append(dn).append(", ");
buf.append("MUST: ");
buf.append("cn=").append(cn).append(", ");
buf.append("uid=").append(uid).append(", ");
buf.append("uidNumber=").append(uidNumber).append(", ");
buf.append("gidNumber=").append(gidNumber).append(", ");
buf.append("homeDirectory=").append(homeDirectory).append(", ");
buf.append("MAY: ");
buf.append("userPassword=").append(userPassword).append(", ");
buf.append("loginShell=").append(loginShell).append(", ");
buf.append("gecos=").append(gecos).append(", ");
buf.append("description=").append(description);
return buf.toString();
}
public int hashCode() {
return dn.hashCode();
}
}
Daoインタフェースを作成する
ディレクトリにアクセスするためのインタフェース(以下、Daoインタフェースと呼ぶ)を作成します。Daoインタフェースにメソッドを書いておくだけで、データアクセスのロジックはS2Directoryにより自動生成されるため、実装部分を作る必要はありません。下記のDaoインタフェースはオブジェクトクラスposixAccountを持ったエントリのためのサンプルです。
- See Also: [S2Directory] DirectoryDao
package org.seasar.directory.examples.directorydao;
import org.seasar.directory.DirectoryControlProperty;
import org.seasar.directory.examples.entity.PosixAccount;
public interface PosixAccountDirectoryDao {
/** エンティティクラスを指定します。 */
public Class BEAN = PosixAccount.class;
/** ユーザ認証を行います。 */
public boolean authenticate(DirectoryControlProperty user);
/** uidで検索し、結果をエンティティで取得します。 */
public static final String getUserByUid_ARGS = "uid";
public PosixAccount getUserByUid(String uid);
/** ユーザモードでuidを検索し、結果をエンティティで取得します。 */
public static final String getUserByUidWithUser_ARGS = "user, uid";
public PosixAccount getUserByUidWithUserMode(DirectoryControlProperty user, String uid);
/** uidとuidNumberで検索し、結果をエンティティで取得します。 */
public static final String getUserByUidAndUidNumber_ARGS = "uid, uidNumber";
public PosixAccount getUserByUidAndUidNumber(String uid, int uidNumber);
/** エンティティからフィルタを組み立てて検索し、結果をエンティティで取得します。 */
public PosixAccount getUser(PosixAccount account);
/** エンティティからフィルタを組み立ててユーザモードで検索し、結果をエンティティで取得します。 */
public PosixAccount getUserWithUserMode(DirectoryControlProperty user, PosixAccount account);
/** objectclass=posixAccountを持つすべてのエントリを取得します。 */
public List getAllUser();
/** エントリを新規に追加します。 */
public int insert(PosixAccount account);
/** エントリを新規にユーザモードで追加します。 */
public int insertWithUserMode(DirectoryControlProperty user, PosixAccount account);
/** エントリを更新します。 */
public int update(PosixAccount account);
/** エントリをユーザモードで更新します。 */
public int updateWithUserMode(DirectoryControlProperty user, PosixAccount account);
/** エントリを削除します。 */
public int delete(PosixAccount account);
/** エントリをユーザモードで削除します。 */
public int deleteWithUserMode(DirectoryControlProperty user, PosixAccount account);
}
必要なロジックを記述し、開発を進めていく
下記はサンプルアプリケーションの例です。
package org.seasar.directory.examples.client;
import java.util.List;
import org.seasar.directory.DirectoryControlProperty;
import org.seasar.directory.examples.directorydao.PosixAccountDirectoryDao;
import org.seasar.directory.examples.entity.PosixAccount;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public class PosixAccountExample {
public static void main(String[] args) {
/** S2Containerの初期化 */
S2Container container = S2ContainerFactory.create("app.dicon");
container.init();
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container
.getComponent(PosixAccountDirectoryDao.class);
/** 処理開始 */
System.out.println("### ユーザ一覧を表示します。");
List users = posixAccountDao.getAllUser();
int size = users.size();
for (int i = 0; i < size; i++) {
PosixAccount user = (PosixAccount)users.get(i);
System.out.println(i + ": " + user);
}
System.out.println("### user1のパスワード認証を行います。");
DirectoryControlProperty property = (DirectoryControlProperty)container
.getComponent(DirectoryControlProperty.class);
property.setUser("user1");
property.setPassword("secret");
System.out.println(posixAccountDao.authenticate(property));
System.out.println("### user1を検索し、エンティティで取得します。(Filter: uid=user1)");
PosixAccount search = new PosixAccount();
search.setUid("user1");
PosixAccount user1 = posixAccountDao.getUser(search);
System.out.println(user1);
System.out.println("### user1のloginShellを/bin/zshに変更します。");
user1.setLoginShell("/bin/zsh");
System.out.println(posixAccountDao.update(user1));
System.out.println("### user1を検索し直し、変更の反映を確認します。");
user1 = posixAccountDao.getUser(search);
System.out.println(user1);
System.out.println("### user1のuserPasswordをsecret2にユーザモードで変更します。");
user1.setUserPassword("secret2");
System.out.println(posixAccountDao.updateWithUserMode(property, user1));
System.out.println("### user1を検索し直し、変更の反映を確認します。");
property.setPassword("secret2");
System.out.println(posixAccountDao.authenticate(property));
System.out.println("### user1のエントリを削除します。");
System.out.println(posixAccountDao.delete(user1));
System.out.println("### user1を検索し直し、削除の反映を確認します。");
user1 = posixAccountDao.getUser(search);
System.out.println(user1);
}
}
実行結果
下記はサンプルアプリケーションの実行結果です。
### ユーザ一覧を表示します。
DN: dn=uid=user1,ou=Users,dc=seasar,dc=org, MUST: cn=user1, uid=user1, uidNumber=10001, gidNumber=1000, homeDirectory=/home/users/user1, MAY: userPassword={SHA}/FnHO2r9STv93ciakMWsL5K7EJM=, loginShell=/bin/bash, gecos=System User, description=null
... snip ...
DN: dn=uid=user99,ou=Users,dc=seasar,dc=org, MUST: cn=user99, uid=user99, uidNumber=10099, gidNumber=1000, homeDirectory=/home/users/user99, MAY: userPassword={SHA}bFWAPW8dehd6DbPrSzQ7DVD5wRE=, loginShell=/bin/bash, gecos=System User, description=null
### user1のパスワード認証を行います。
true
### user1を検索し、エンティティで取得します。(Filter: uid=user1)
DN: dn=uid=user1,ou=Users,dc=seasar,dc=org, MUST: cn=user1, uid=user1, uidNumber=10001, gidNumber=1000, homeDirectory=/home/users/user1, MAY: userPassword={SHA}/FnHO2r9STv93ciakMWsL5K7EJM=, loginShell=/bin/bash, gecos=System User, description=null
### user1のloginShellを/bin/zshに変更します。
1
### user1を検索し直し、変更の反映を確認します。
DN: dn=uid=user1,ou=Users,dc=seasar,dc=org, MUST: cn=user1, uid=user1, uidNumber=10001, gidNumber=1000, homeDirectory=/home/users/user1, MAY: userPassword={SHA}/FnHO2r9STv93ciakMWsL5K7EJM=, loginShell=/bin/zsh, gecos=System User, description=null
### user1のuserPasswordをsecret2にユーザモードで変更します。
1
### user1を検索し直し、変更の反映を確認します。
DN: dn=uid=user1,ou=Users,dc=seasar,dc=org, MUST: cn=user1, uid=user1, uidNumber=10001, gidNumber=1000, homeDirectory=/home/users/user1, MAY: userPassword={SHA}xjbo4jj9evl+LlAPjG8PTAvtr7A=, loginShell=/bin/zsh, gecos=System User, description=null
### user1のエントリを削除します。
1
### user1を検索し直し、削除の反映を確認します。
null
S2Directoryの実際の動作と詳細を学ぶには、Demonstrationを読んでください。
