- ユーザにアサインしたロールを取得する
- ユーザの所属組織を取得する
- ユーザの所属サイトを取得する
- 組織に所属するユーザを取得する
- サイトのサイトメンバーを取得する
- など...
みなさまはこのような処理を行う時、userLocalService.getGroupUsers(グループのユーザを取る)、organizationLocalService.getUserOrganizations(ユーザが所属する組織を取得)などのメソッドをよく利用しますか?実は、これは間違っています。
その原因は、Liferayのサービスから取得できるものは、データベースの中に直接存在するレコードのみです。ただし、組織、サイトは階層構造のため、ユーザがサイトに所属する際、ユーザ-サイトに直接関連するデータベースレコードが存在しないこともできます(例えば、ユーザが所属するユーザグループがサイトメンバとしてサイトにアサインすることができます)。
そのため、データベース上直接関連がないエンティティを取るため、再帰的に階層構造をトラバースしないといけません。そこで、Liferayは階層構造を配慮した便利なツールを提供しています。
今回はユーザからユーザの所属サイト、ユーザグループ、組織またはユーザにアサインしたロールを取るツールを紹介したいと思います。次回は逆方向でサイト、ユーザグループ、組織から所属ユーザを取るツールです。
UserBag
以下のコードでUserBagが作成できます。UserBag userBag = UserBagFactoryUtil.create(userId);
作成されたUserBagを利用し、以下の処理を行えます。
- userBag.getRoles()
- ユーザにアサインしたロールを取得する。
- userBag.getUserUserGroupIds()
- ユーザが所属するユーザグループのIDを取得する
- userBag.getUserOrgs()
- ユーザが所属する組織を取得する。
- userBag.getUserGroups()
- ユーザが所属するサイトを取得する。
- userBag.getGroups()
- ユーザが所属するグループを取得する。
※ 実に、ユーザグループと組織に繋がるgroupは、ユーザグループまたは組織のプロファイルページと見られます。
検証
さて、Liferayを起動してUserBagの効果を検証しましょう。ひとまず、検証用モジュールを作りましょう。@Component( property = { "osgi.command.scope=liferay", "osgi.command.function=checkUserOrganizations", "osgi.command.function=checkUserSites", "osgi.command.function=checkUserRoles" }, service = SiteUserOrgCmd.class ) public class SiteUserOrgCmd { private static final long companyId = PortalUtil.getDefaultCompanyId(); public void checkUserOrganizations(String screenName) throws Exception { User user = UserLocalServiceUtil.getUserByScreenName(companyId, screenName); UserBag userBag = UserBagFactoryUtil.create(user.getUserId()); System.out.println("User's organizations in userBag: "); for (Organization org : userBag.getUserOrgs()) { System.out.println(" " + org.getName()); } System.out.println("User's organizations in service: "); for (Organization org : OrganizationLocalServiceUtil.getUserOrganizations(user.getUserId())) { System.out.println(" " + org.getName()); } } public void checkUserSites(String screenName) throws Exception { User user = UserLocalServiceUtil.getUserByScreenName(companyId, screenName); UserBag userBag = UserBagFactoryUtil.create(user.getUserId()); System.out.println("User's sites: "); for (Group grp : userBag.getUserGroups()) { System.out.println(" " + grp.getName(Locale.getDefault())); } System.out.println("User's sites in service: "); for (Group grp : GroupLocalServiceUtil.getUserGroups(user.getUserId(), true)) { System.out.println(" " + grp.getName(Locale.getDefault())); } } public void checkUserRoles(String screenName) throws Exception { User user = UserLocalServiceUtil.getUserByScreenName(companyId, screenName); UserBag userBag = UserBagFactoryUtil.create(user.getUserId()); System.out.println("User's roles: "); for (Role r : userBag.getRoles()) { System.out.println(" " + r.getName()); } System.out.println("User's roles in service: "); for (Role r : RoleLocalServiceUtil.getUserRoles(user.getUserId())) { System.out.println(" " + r.getName()); } } }
※ Liferayユーザグループが階層構造になれないため、検証内容から外します。
続いて、検証用エンティティを用意します。
- ユーザ: ub_user
- ユーザグループ: ub_grp
- 組織: ub_org
- 階層組織: ub_org/ub_org1
- サイト: ub_site
- 一般ロール: ub_role
それては、gogo shellでUserBagの効果を検証しましょう。
※ 検証中、明記以外の場合、「検証の度にユーザ、ロール、サイトと組織の関係を元に戻す」を前提として検証操作をします。
組織
以下の状況を考えてみましょう。- ub_org <- ub_user
- ub_orgは階層構造中一番トップな組織ため、UserBagとOrganizationLocalServiceの戻り値は同じです。
g! checkUserOrganizations ub_user User's organizations in userBag: ub_org User's organizations in service: ub_org
- ub_org1 <- ub_user
- ub_org1はub_orgの一個下の階層の組織のため、ユーザが直接にub_org1のユーザとして追加すると、OrganizationLocalServiceはDBに直接存在するレコードub_org1をリターンします。それに対して、UserBagは階層構造の上の組織ub_orgもリターンします。
g! checkUserOrganizations ub_user User's organizations in userBag: ub_org ub_org1 User's organizations in service: ub_org1
サイト
以下の状況を考えてみましょう。- ub_site <- ub_user
- ユーザが直接にサイトメンバーとしてサイトへ登録すると、UserBagとGroupLocalServiceの出力が同じです。
User's sites: ub_site User's sites in service: ub_site
- ub_site <- ub_grp, ub_grp <- ub_user
- ユーザが直接にサイトへ登録ではなく、ユーザグループに通じでサイトメンバーへ登録際、UserBagとGroupLocalServiceの出力が同じです。
- 最初に「あれ?」と思う方がいらっしゃいませんか?
- 実は、GroupLocalServiceUtil.getUserGroups(long userId, boolean inherit))のパラメーターとしてinherit=trueを指定したら、GroupLocalServiceでもUserBagのような出力ができます。
g! checkUserSites ub_user User's sites: ub_site User's sites in service: ub_site
- ub_site <- ub_org, ub_org <- ub_user
- ユーザが直接にサイトへ登録ではなく、ユーザグループに通じでサイトメンバーへ登録際、UserBagとGroupLocalServiceの出力が同じです。
- 理由はユーザグループの場合と同じです。
- ちなみに、組織サイトも結果に入りました。
g! checkUserSites ub_user User's sites: ub_org ub_site User's sites in service: ub_org ub_site
- ※ ub_site <- ub_org, ub_org1 <- ub_user
- ちょっと変な結果ですが、ub_userを直接に組織ub_orgの下に置かなくて、ub_org下のub_org1にアサインしたとき、ub_userはub_siteのサイトメンバーとして認識されないようです。
- これはLiferayの仕様(liferay-7.1-sp2, dxp-14-7110まで)だそうです(サイトメンバー管理画面にも同じ結果が確認できます)。
g! checkUserSites ub_user User's sites: ub_org1 User's sites in service: ub_org1
ロール
以下の状況を考えてみましょう。- ub_role <- ub_user
- ユーザが直接にロールをアサインするとき、UserBagとRoleLocalServiceの出力が同じです。
g! checkUserRoles ub_user User's roles: User ub_role User's roles in service: User ub_role
- ub_role <- ub_grp, ub_grp <- ub_user
- ユーザがユーザグループを通じてユub_roleにアサインされるとき、データベースにレコードがいないため、UserBagとRoleLocalServiceの出力が違います。
g! checkUserRoles ub_user User's roles: User ub_role User's roles in service: User
- ub_role <- ub_org, ub_org1 <- ub_user
- ユーザが組織を通じてユub_roleにアサインされるとき、データベースにレコードがいないため、UserBagとRoleLocalServiceの出力が違います。
- ub_org1は階層構造上ub_orgの下の階層のため、ユーザはub_roleを持っています。
g! checkUserRoles ub_user User's roles: User ub_role User's roles in service: User
まとめ
今回は、Liferayが提供したUserBagを利用し、ユーザから当該ユーザの所属とロールを取得する方法を紹介しました。UserBagはLiferayの階層構造を配慮して結果をリターンするため、カスタマイズの際役に立つでしょう。また、公式github上のソースコードを参考すると、UserBagをより深く理解できますので(UserBagImpl, UserBagFactoryImpl)、ぜひおすすめします。ちなみに、UserBagの定義はLiferayのkernelモジュールであるcom.liferay.portal.security.permissionの中にあり、LiferayのpermissionCheckerはよくこのクラスを利用しています。これは本来UserBagを開発する理由でしょう。
No comments:
New comments are not allowed.