Menu

Documentation

Tutorial

本チュートリアルではS2Directory単体での基本的な使い方を紹介します。
本チュートリアルでは紹介しませんが、JDK 5以降の環境でS2DirectoryにS2DirectoryTigerを併用すると、エンティティDirectoryDaoでTigerアノテーションを利用することができます。

S2Directoryを使用して開発を進める基本的な手順は次のようになります。

  1. Setupに従い必要なライブラリをあなたのプロジェクトに配置する
  2. S2Directoryを使うための設定を行う
  3. エンティティを作成する (POJO, Entity, Java Beansなどいろいろな呼び名があります)
  4. Daoインタフェースを作成する
  5. 必要なロジックを記述し、開発を進めていく
  6. サンプルの実行結果

作成するサンプルアプリケーション

本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などの便利な機能が使えるため、その際はそちらを使用することを推奨します。

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についての説明を読んでください。

<?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を持ったエントリのためのサンプルです。

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を読んでください。