DirectoryDao
S2Direcotryでは、ディレクトリにアクセスするDao(Data Access Object)として、インタフェース(以下、Daoインタフェースと呼ぶ)を利用します。Daoインタフェースにメソッドを書いておくだけで、データアクセスのロジックはS2Directoryにより自動生成されるため、実装部分を作る必要はありません。ディレクトリに対しての読み出し、書き込み、認証といった処理は、規約に従ってメソッドを定義することで機能が組み込まれます。Daoインタフェースを作成するには、次のことが必要になります。
- Entityとの関連付けの定数宣言 (BEANアノテーション)
- 規約に従ったメソッドの定義
また、メソッドの引数を検索フィルタをで参照したり、自動的に生成される検索フィルタに条件を追加したい場合、次のアノテーションを定義することで、それぞれの処理に対して追加情報を与えることができます。
リレーショナルデータベースを永続化するS2Daoと大きく異なる点は、ディレクトリに特化した次の点です。
- 認証処理の規約がある
- ユーザモード実行
アノテーション
S2Directoryで使用するDaoインタフェースに定義可能なフィールドによるアノテーション(フィールドアノテーション)の一覧です。
BEANアノテーション
Daoがどのエンティティに関連付けられるのかを指定します。BEANアノテーションは1Daoインタフェースに対して必ず1つ定義する必要があります。
フィールドアノテーションの場合
- BEANアノテーションの形式
public static final Class BEAN = エンティティクラス名.class;
- posixAccountの例 (エンティティがPosixAccountの場合、省略可)
public interface PosixAccountDirectoryDao { public static final Class BEAN = PosixAccount.class; ... 省略 ... }
Tigerアノテーションの場合 (S2DirectoryTiger必須)
- BEANアノテーションの形式
@S2Directory(bean = エンティティクラス名.class)
- posixAccountの例 (エンティティがPosixAccountの場合、省略可)
@S2Directory(bean = PosixAccount.class) public interface PosixAccountDirectoryDao { ... 省略 ... }
ARGSアノテーション
メソッドの引数を検索フィルタで参照できるようにするアノテーションです。これはメソッドの引数名は、通常リフレクションAPIで取得できないためです。ARGSアノテーションは、エンティティを使用しないで引数のあるメソッドを定義する場合、必要になります。
フィールドアノテーションの場合
- ARGSアノテーションの形式
public static final String メソッド名_ARGS = "引数名"; public static final String メソッド名_ARGS = "引数名1, 引数名2, ...";
- public PosixAccountDto getUserByUid(String uid);というメソッドがDaoインタフェースに定義されていた場合
public static final String getUserByUid_ARGS = "uid"; public PosixAccountDto getUserByUid(String uid);
- public PosixAccountDto getUserByUidAndUidNumber(String uid, int uidNumber);というメソッドがDaoインタフェースに定義されていた場合
public static final String getUserByUidAndUidNumber_ARGS = "uid, uidNumber"; public PosixAccountDto getUserByUidAndUidNumber(String uid, int uidNumber);
Tigerアノテーションの場合 (S2DirectoryTiger必須)
- ARGSアノテーションの形式
@Arguments("引数名") @Arguments( {"引数名1", "引数名2", ... })
- public PosixAccountDto getUserByUid(String uid);というメソッドがDaoインタフェースに定義されていた場合
@Arguments("uid") public PosixAccountDto getUserByUid(String uid);
- public PosixAccountDto getUserByUidAndUidNumber(String uid, int uidNumber);というメソッドがDaoインタフェースに定義されていた場合
@Arguments( { "uid", "uidNumber" }) public PosixAccountDto getUserByUidAndUidNumber(String uid, int uidNumber);
QUERYアノテーション
自動的に生成される検索フィルタに条件を追加するアノテーションです。多くの場合、QUERYアノテーションは必要ありません。
フィールドアノテーションの場合
- QUERYアノテーションの形式
public static final String メソッド名_QUERY = "検索フィルタ";
- public List getUserByFilter();というメソッドに検索条件uid=user2,ou=Users,dc=seasar,dc=orgを追加する場合
public static final String getUserByFilter_QUERY = "uid=user2,ou=Users,dc=seasar,dc=org"; public List getUserByFilter();
Tigerアノテーションの場合 (S2DirectoryTiger必須)
- QUERYアノテーションの形式
@Query("検索フィルタ")
- public List getUserByFilter();というメソッドに検索条件uid=user2,ou=Users,dc=seasar,dc=orgを追加する場合
@Query("uid=user2,ou=Users,dc=seasar,dc=org") public List getUserByFilter();
OBJECTCLASSESアノテーション
エンティティとオブジェクトクラスとの関連付けを明示的に指定する場合はOBJECTCLASSESアノテーションを使用します。OBJECTCLASSESアノテーションを明示的に指定しなかった場合、エンティティクラス名をオブジェクトクラス名として使用します。ここで登場するオブジェクトクラスは、DaoインタフェースのARGSアノテーションが定義されていない検索関数を実行される場合に使用するフィルタとなります。
フィールドアノテーションの場合
- posixAccountの例 (クラス名がPosixAccountの場合、省略可)
public static final String OBJECTCLASSES = "オブジェクトクラス名"; public static final String OBJECTCLASSES = "オブジェクトクラス名1, オブジェクトクラス名2, ... ";
- posixAccountとinetOrgPersonのオブジェクトクラスを指定する例
public interface PosixAccountDirectoryDao { public static final Class BEAN = PosixAccount.class; public static final String OBJECTCLASSES = "posixAccount, inetOrgPerson"; ... 省略 ... }
Tigerアノテーションの場合 (S2DirectoryTiger必須)
OBJECTCLASSESアノテーション
エンティティとオブジェクトクラスとの関連付けを明示的に指定する場合はOBJECTCLASSESアノテーションを使用します。OBJECTCLASSESアノテーションを明示的に指定しなかった場合、エンティティクラス名をオブジェクトクラス名として使用します。ここで登場するオブジェクトクラスは、DaoインタフェースのARGSアノテーションが定義されていない検索関数を実行される場合に使用するフィルタとなります。
- posixAccountの例 (クラス名がPosixAccountの場合、省略可)
@ObjectClasses("オブジェクトクラス名") @ObjectClasses( { "オブジェクトクラス名1", "オブジェクトクラス名2", ... } )
- posixAccountとinetOrgPersonのオブジェクトクラスを指定する例
@S2Directory(bean = PosixAccount.class) @ObjectClasses( { "posixAccount", "inetOrgPerson" }) public interface PosixAccountDirectoryDao { ... 省略 ... }
規約に従ったメソッドの定義
Daoインタフェースに定義するメソッド名とディレクトリに対しての処理の規約は次の表のとおりです。
機能 | メソッド定義の規約 |
---|---|
認証処理 | auth で始まるメソッド名 |
挿入処理 | insert, create, add のいずれかで始まるメソッド名 |
更新処理 | update, modify, store のいずれかで始まるメソッド名 |
削除処理 | delete, remove のいずれかで始まるメソッド名 |
検索、読み込み処理 | 上記規約以外すべて |
認証処理
ディレクトリサーバの持つSimple Authentication and Security Layer (SASL)機構を用いて、ディレクトリの保持するユーザエントリに保存されたユーザ名とパスワードに対して認証処理を行いたい場合、メソッド名をauthで始めるメソッド名で定義し、引数にDirectoryControlPropertyを指定します。DirectoryControlPropertyは、認証に使うユーザ名やパスワードなどのサーバ接続情報を保持するオブジェクトです。認証処理はDirectoryControlPropertyの保持する値のみを参照し、BEANアノテーションで指定されたエンティティとは無関係に処理を実行します。
- 認証処理のためのメソッド定義例
/** ユーザ認証を行います。 */ public boolean authenticate(DirectoryControlProperty user); public boolean authenticateByUserMode(DirectoryControlProperty user);
- ユーザ名: user1 パスワード: secret で認証する例
- S2Container: container (初期化済みであること)
- Daoインタフェース: posixAccountDirectoryDao
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container .getComponent(PosixAccountDirectoryDao.class); DirectoryControlProperty property = (DirectoryControlProperty)container .getComponent(DirectoryControlProperty.class); property.setUser("user1"); property.setPassword("secret"); if (posixAccountDao.authenticate(property)) { // succeed authentication } else { // failed authentication }
挿入処理
挿入処理を行いたい場合は、insert, create, add のいずれかで始まるメソッド名をもつメソッドを定義します。引数には、挿入するエントリ情報を持つエンティティを指定します。この時、このエントリをディレクトリインフォメーションツリー上のどこにエンティティを挿入するかを指し示すために、必ずdnフィールドにそのエントリを挿入する位置を指し示すDNを設定しておく必要があります。戻り値には、voidあるいはintを指定できます。intにした場合、挿入した行数が戻り値となります。
標準設定の場合、userPassword属性に対応する値は自動的にdirectory.diconで設定した暗号化ハッシュ形式に変換され保存されます。この挙動を変更したい、もしくは、属性に応じて保存する値を変換したい場合は、専用のAttributeHandlerを作成し、directorydao.diconで定義することで実現できます。
- See Also: [S2Directory] Configuration
- 挿入処理のためのメソッド定義例
/** エントリを新規に追加します。 */ public int insert(PosixAccount account); public int createUser(PosixAccount user); public void addUser(PosixAccount user);
- ユーザエントリ user1 を挿入する例
- S2Container: container (初期化済みであること)
- Daoインタフェース: posixAccountDirectoryDao
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container .getComponent(PosixAccountDirectoryDao.class); PosixAccount account = new PosixAccount(); // 挿入する位置を指定 account.setDn("uid=user1,ou=Users,dc=seasar,dc=org"); // エントリの持つ属性値を設定 account.setUid("user1"); account.setUserPassword("secret"); account.setLoginShell("/bin/bash"); account.setUid("user1"); account.setUidNumber("10001"); account.setGidNumber("1000"); account.setGecos("System User"); account.setHomeDirectory("/home/users/user1"); account.setDescription("System User"); // 挿入 posixAccountDao.insert(account);
更新処理
更新処理を行いたい場合は、update, modify, store のいずれかで始まるメソッド名をもつメソッドを定義します。引数には、更新するエントリ情報を持つエンティティを指定します。この時、エンティティは既にディレクトリサーバから更新対象のエントリの値を取得した永続化された状態であり、その状態に対して更新する値をセットしてある必要があります。また、このエントリがディレクトリインフォメーションツリー上のどのエンティティを永続化しているかを指し示しているdnフィールドを更新することは出来ません。戻り値には、voidあるいはintを指定できます。intにした場合、更新した行数が戻り値となります。なお、エンティティの特定のフィールドにnull, 空文字列を指定した場合、そのフィールドに対応する属性は削除されます。
標準設定の場合、userPassword属性に対応する値は自動的にdirectory.diconで設定した暗号化ハッシュ形式で検証され、値が更新されている場合のみ保存されます。この挙動を変更したい、もしくは、属性に応じて保存する値を変換したい場合は、専用のAttributeHandlerを作成し、directorydao.diconで定義することで実現できます。
- See Also: [S2Directory] Configuration
- 更新処理のためのメソッド定義例
/** エントリを更新します。 */ public int update(PosixAccount account); public int modifyUser(PosixAccount account); public void storeUser(PosixAccount user);
- ユーザエントリ user1 を追加する例
- S2Container: container (初期化済みであること)
- Daoインタフェース: posixAccountDirectoryDao
- エントリの取得方法については後述
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container .getComponent(PosixAccountDirectoryDao.class); // user1エントリを取得 PosixAccount account = posixAccountDao.getUserByUid("user1"); // 更新したい属性値を設定 account.setUserPassword("secret2"); account.setLoginShell("/bin/zsh"); account.setGecos(""); account.setDescription(null); // 挿入 posixAccountDao.update(account);
削除処理
削除処理を行いたい場合は、delete, remove のいずれかで始まるメソッド名をもつメソッドを定義します。引数には、削除するエントリのDN情報を持つエンティティを指定します。戻り値には、voidあるいはintを指定できます。intにした場合、更新した行数が戻り値となります。なお、Daoインタフェースで指定されているBEANアノテーションのエンティティが対応するオブジェクトクラスを持つエントリと削除したいエントリが一致する必要はありません。
- 削除処理のためのメソッド定義例
/** エントリを削除します。 */ public int delete(PosixAccount account); public void removeUser(PosixAccount user);
- ユーザエントリ user1 を追加する例
- S2Container: container (初期化済みであること)
- Daoインタフェース: posixAccountDirectoryDao
- エントリの取得方法については後述
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container .getComponent(PosixAccountDirectoryDao.class); // user1エントリを取得 PosixAccount account = posixAccountDao.getUserByUid("user1"); // 削除 posixAccountDao.delete(account); // 直接DNを指定して削除 account = new PosixAccount(); account.setDn("uid=group1,ou=Groups,dc=seasar,dc=org"); posixAccountDao.delete(account);
検索、読み込み処理
検索、読み込み処理を行いたい場合は、認証処理、挿入処理、更新処理、削除処理のメソッド定義の規約に当てはまらないメソッド名をもつメソッドを定義します。引数には、検索条件となる任意の型の変数を任意の数、もしくは、エンティティを指定します。戻り値には、エンティティの型あるいはjava.util.Listを指定できます。エンティティの型にしたメソッドの検索結果が複数ある場合、1つのエントリの値が返ります。java.utilListにした場合、複数の検索結果を追加された状態が返ります。なお、Daoインタフェースで指定されているBEANアノテーションのエンティティが対応するオブジェクトクラスを持つエントリと削除したいエントリが一致する必要はありません。
- 検索、読み込み処理のためのメソッド定義例
/** uidで検索し、結果をエンティティで取得します。 */ public static final String getUserByUid_ARGS = "uid"; public PosixAccount getUserByUid(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 List getUserList(PosixAccount account); /** OBJECTCLASSESアノテーションで指定したオブジェクトクラスを持つすべてのエントリを取得します。 */ public List getAllUser();
- ユーザエントリ user1 を検索する例
- S2Container: container (初期化済みであること)
- Daoインタフェース: posixAccountDirectoryDao
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container .getComponent(PosixAccountDirectoryDao.class); // uidで検索し、結果をエンティティで取得 PosixAccount account1 = posixAccountDao.getUserByUid("user1"); // uidとuidNumberで検索し、結果をエンティティで取得 PosixAccount account2 = posixAccountDao.getUserByUidAndUidNumber("user1", 1000); // エンティティからフィルタを組み立てて検索し、結果をエンティティで取得 PosixAccount search1 = new PosixAccount(); search1.setUid("user1"); PosixAccount account3 = posixAccountDao.getUser(search1); // エンティティからフィルタを組み立てて検索し、結果をエンティティのリストで取得 PosixAccount search2 = new PosixAccount(); search2.setGidNumber("1000"); List list1 = posixAccountDao.getUserList(search2); // OBJECTCLASSESアノテーションで指定したオブジェクトクラスを持つすべてのエントリを取得 List list2 = posixAccountDao.getAllUser();
ユーザモード実行
多くのディレクトリサーバではそのディレクトリインフォメーションツリーのエントリに対してACLを設定することで細かいアクセス制御を設定することが出来、より安全なデータ管理を行うことが可能です。S2Direcotryでは、ディレクトリサーバの保持するユーザエントリに保存されたユーザ名とパスワードを利用してACLに従ったユーザモードでの処理実行を行うことができます。ユーザモードで実行したい場合、メソッド定義の第一引数にDirectoryControlPropertyを指定します。DirectoryControlPropertyは認証処理で利用したものと同じ型です。第一引数にDirectoryControlPropertyを指定する以外、各処理の定義、実行の仕方は同じです。
- 各処理をユーザモードで実行するための実行例
/** ユーザモードでuidを検索し、結果をエンティティで取得します。 */ public static final String getUserByUidWithUser_ARGS = "user, uid"; public PosixAccount getUserByUidWithUserMode(DirectoryControlProperty user, String uid); /** エンティティからフィルタを組み立ててユーザモードで検索し、結果をエンティティで取得します。 */ public PosixAccount getUserWithUserMode(DirectoryControlProperty user, PosixAccount account); /** エントリを新規にユーザモードで追加します。 */ public int insertWithUserMode(DirectoryControlProperty user, PosixAccount account); /** エントリをユーザモードで更新します。 */ public int updateWithUserMode(DirectoryControlProperty user, PosixAccount account); /** エントリをユーザモードで削除します。 */ public int deleteWithUserMode(DirectoryControlProperty user, PosixAccount account);
- ユーザエントリ user1 を検索する例
- S2Container: container (初期化済みであること)
- Daoインタフェース: posixAccountDirectoryDao
- ユーザモード: user1 で実行 (ユーザエントリ user1 が既にあること)
PosixAccountDirectoryDao posixAccountDao = (PosixAccountDirectoryDao)container .getComponent(PosixAccountDirectoryDao.class); DirectoryControlProperty property = (DirectoryControlProperty)container .getComponent(DirectoryControlProperty.class); property.setUser("user1"); property.setPassword("secret"); ... 以降このpropertyを第一引数に指定し、各処理の実行の仕方と同じ ...