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