diff --git a/components/identity-event/org.wso2.carbon.identity.event/src/main/java/org/wso2/carbon/identity/event/IdentityEventConstants.java b/components/identity-event/org.wso2.carbon.identity.event/src/main/java/org/wso2/carbon/identity/event/IdentityEventConstants.java index 600b4076acb0..dcda266bcc26 100644 --- a/components/identity-event/org.wso2.carbon.identity.event/src/main/java/org/wso2/carbon/identity/event/IdentityEventConstants.java +++ b/components/identity-event/org.wso2.carbon.identity.event/src/main/java/org/wso2/carbon/identity/event/IdentityEventConstants.java @@ -234,6 +234,8 @@ private Event(){} public static final String POST_GET_ROLES_V2_EVENT = "POST_GET_ROLES_V2_EVENT"; public static final String PRE_GET_ROLES_V2_COUNT_EVENT = "PRE_GET_ROLES_V2_COUNT_EVENT"; public static final String POST_GET_ROLES_V2_COUNT_EVENT = "POST_GET_ROLES_V2_COUNT_EVENT"; + public static final String PRE_GET_ROLES_V2_FILTERED_COUNT_EVENT = "PRE_GET_ROLES_V2_COUNT_EVENT"; + public static final String POST_GET_ROLES_V2_FILTERED_COUNT_EVENT = "POST_GET_ROLES_V2_COUNT_EVENT"; public static final String PRE_GET_ROLE_V2_EVENT = "PRE_GET_ROLE_V2_EVENT"; public static final String POST_GET_ROLE_V2_EVENT = "POST_GET_ROLE_V2_EVENT"; public static final String PRE_UPDATE_ROLE_V2_NAME_EVENT = "PRE_UPDATE_ROLE_V2_NAME_EVENT"; @@ -393,6 +395,7 @@ private EventProperty(){} public static final String SORT_ORDER = "SORT_ORDER"; public static final String USER = "USER"; public static final String FILTER = "FILTER"; + public static final String SEARCH_FILTER = "SEARCH_FILTER"; public static final String USER_CLAIM_SEARCH_ENTRIES = "USER_CLAIM_SEARCH_ENTRIES"; public static final String LOGIN_IDENTIFIERS = "LOGIN_IDENTIFIERS"; public static final String CONTEXT = "context"; diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementEventPublisherProxy.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementEventPublisherProxy.java index d0ab2fe2ff7a..9d10fdced4cb 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementEventPublisherProxy.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementEventPublisherProxy.java @@ -788,6 +788,23 @@ public void publishPreGetRolesCountWithException(String tenantDomain) throws Ide doPublishEvent(event); } + /** + * Publish event before retrieving the count of roles within a specified tenant domain for a filter. + * + * @param searchFilter The filter value. + * @param tenantDomain The domain in which the operation is being performed. + * @throws IdentityRoleManagementException If an error occurs during the pre-retrieval phase. + */ + public void publishPreGetRolesCountWithException(String searchFilter, String tenantDomain) + throws IdentityRoleManagementException { + + Map eventProperties = new HashMap<>(); + eventProperties.put(IdentityEventConstants.EventProperty.TENANT_DOMAIN, tenantDomain); + eventProperties.put(IdentityEventConstants.EventProperty.SEARCH_FILTER, searchFilter); + Event event = createEvent(eventProperties, IdentityEventConstants.Event.PRE_GET_ROLES_V2_FILTERED_COUNT_EVENT); + doPublishEvent(event); + } + /** * Publish event after retrieving the count of roles within a specified tenant domain. * @@ -855,6 +872,25 @@ public void publishPostAddMainRoleToSharedRoleRelationship(String mainRoleUUID, } } + /** + * Publish event after retrieving the count of roles within a specified tenant domain for a filter. + * + * @param searchFilter The filter value. + * @param tenantDomain The domain in which the operation is being performed. + */ + public void publishPostGetRolesCount(String searchFilter, String tenantDomain) { + + Map eventProperties = new HashMap<>(); + eventProperties.put(IdentityEventConstants.EventProperty.TENANT_DOMAIN, tenantDomain); + eventProperties.put(IdentityEventConstants.EventProperty.SEARCH_FILTER, searchFilter); + Event event = createEvent(eventProperties, IdentityEventConstants.Event.POST_GET_ROLES_V2_FILTERED_COUNT_EVENT); + try { + doPublishEvent(event); + } catch (IdentityRoleManagementException e) { + log.error(e.getMessage(), e); + } + } + private Event createEvent(Map eventProperties, String eventName) { return new Event(eventName, eventProperties); diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementService.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementService.java index f4e9677722ba..eaa756e1932e 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementService.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementService.java @@ -310,6 +310,15 @@ boolean isExistingRoleName(String roleName, String audience, String audienceId, */ int getRolesCount(String tenantDomain) throws IdentityRoleManagementException; + /** + * Retrieve available total roles count in a tenant for a given specific search filter. + * + * @param tenantDomain Tenant domain. + * @return The list count of roles. + * @throws IdentityRoleManagementException IdentityRoleManagementException. + */ + int getRolesCount(String searchFilter, String tenantDomain) throws IdentityRoleManagementException; + /** * Get role without users. * diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementServiceImpl.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementServiceImpl.java index a0b8b65e903a..4148f2dbe0dc 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementServiceImpl.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/RoleManagementServiceImpl.java @@ -695,6 +695,34 @@ public int getRolesCount(String tenantDomain) throws IdentityRoleManagementExcep return count; } + @Override + public int getRolesCount(String searchFilter, String tenantDomain) throws IdentityRoleManagementException { + + List roleManagementListenerList = RoleManagementServiceComponentHolder.getInstance() + .getRoleManagementListenerList(); + for (RoleManagementListener roleManagementListener : roleManagementListenerList) { + if (roleManagementListener.isEnable()) { + roleManagementListener.preGetRolesCount(searchFilter, tenantDomain); + } + } + RoleManagementEventPublisherProxy roleManagementEventPublisherProxy = + RoleManagementEventPublisherProxy.getInstance(); + roleManagementEventPublisherProxy.publishPreGetRolesCountWithException(searchFilter, tenantDomain); + List expressionNodes = getExpressionNodes(searchFilter); + int count = roleDAO.getRolesCount(expressionNodes, tenantDomain); + roleManagementEventPublisherProxy.publishPostGetRolesCount(searchFilter, tenantDomain); + for (RoleManagementListener roleManagementListener : roleManagementListenerList) { + if (roleManagementListener.isEnable()) { + roleManagementListener.postGetRolesCount(count, searchFilter, tenantDomain); + } + } + if (log.isDebugEnabled()) { + log.debug(String.format("Get roles count for the filter %s & tenant domain %s is successful.", + searchFilter, tenantDomain)); + } + return count; + } + @Override public Role getRoleWithoutUsers(String roleId, String tenantDomain) throws IdentityRoleManagementException { diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAO.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAO.java index 1a00b867f31a..acfb9cfb3b7e 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAO.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAO.java @@ -334,6 +334,16 @@ boolean isExistingRoleName(String roleName, String audience, String audienceId, */ int getRolesCount(String tenantDomain) throws IdentityRoleManagementException; + /** + * Retrieve available total roles count in a tenant for a given specific search filter. + * + * @param expressionNodes List of expressionNodes. + * @param tenantDomain Tenant domain. + * @return The list count of roles. + * @throws IdentityRoleManagementException IdentityRoleManagementException. + */ + int getRolesCount(List expressionNodes, String tenantDomain) throws IdentityRoleManagementException; + /** * Get role without users. * diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOImpl.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOImpl.java index c5b708e5e997..a7c12941f469 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOImpl.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOImpl.java @@ -344,6 +344,46 @@ public List getRoles(List expressionNodes, Intege return getFilteredRolesBasicInfo(expressionNodes, limit, offset, sortBy, sortOrder, tenantDomain); } + @Override + public int getRolesCount(List expressionNodes, String tenantDomain) + throws IdentityRoleManagementException { + + return getFilteredRolesCount(expressionNodes, tenantDomain); + } + + private int getFilteredRolesCount(List expressionNodes, String tenantDomain) + throws IdentityRoleManagementException { + + int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); + FilterQueryBuilder filterQueryBuilder = new FilterQueryBuilder(); + appendFilterQuery(expressionNodes, filterQueryBuilder); + Map filterAttributeValue = filterQueryBuilder.getFilterAttributeValue(); + + try (Connection connection = IdentityDatabaseUtil.getUserDBConnection(false)) { + String query = String.format(SQLQueries.GET_ROLES_COUNT_BY_TENANT_AND_FILTER, + filterQueryBuilder.getFilterQuery()); + try (NamedPreparedStatement statement = new NamedPreparedStatement(connection, query, + RoleConstants.RoleTableColumns.UM_ID)) { + statement.setInt(RoleConstants.RoleTableColumns.UM_TENANT_ID, tenantId); + if (filterAttributeValue != null) { + for (Map.Entry entry : filterAttributeValue.entrySet()) { + statement.setString(entry.getKey(), entry.getValue()); + } + } + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + return resultSet.getInt(1); + } + } + } + } catch (SQLException e) { + throw new IdentityRoleManagementServerException(RoleConstants.Error.UNEXPECTED_SERVER_ERROR.getCode(), + String.format("Error while getting the role list count in tenantDomain: %s with filter %s.", + tenantDomain, filterQueryBuilder.getFilterQuery()), e); + } + return 0; + } + private List getFilteredRolesBasicInfo(List expressionNodes, Integer limit, Integer offset, String sortBy, String sortOrder, String tenantDomain) throws IdentityRoleManagementException { diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/SQLQueries.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/SQLQueries.java index 0b04889ec383..a326cc710d4d 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/SQLQueries.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/SQLQueries.java @@ -356,6 +356,10 @@ public class SQLQueries { "UM_HYBRID_ROLE_AUDIENCE.UM_AUDIENCE_ID, UM_AUDIENCE_REF_ID FROM UM_HYBRID_ROLE INNER JOIN " + "UM_HYBRID_ROLE_AUDIENCE ON UM_HYBRID_ROLE.UM_AUDIENCE_REF_ID = UM_HYBRID_ROLE_AUDIENCE.UM_ID WHERE "; + public static final String GET_ROLES_COUNT_BY_TENANT_AND_FILTER = "SELECT COUNT(UM_ROLE_NAME) FROM " + + "UM_HYBRID_ROLE INNER JOIN UM_HYBRID_ROLE_AUDIENCE ON UM_HYBRID_ROLE.UM_AUDIENCE_REF_ID = " + + "UM_HYBRID_ROLE_AUDIENCE.UM_ID WHERE %s UM_TENANT_ID=:UM_TENANT_ID;"; + public static final String GET_ROLES_BY_TENANT_AND_ROLE_NAME_TAIL_MYSQL = " UM_TENANT_ID=:UM_TENANT_ID; ORDER BY " + "UM_HYBRID_ROLE.UM_ID DESC LIMIT :OFFSET;, :LIMIT;"; diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/listener/RoleManagementListener.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/listener/RoleManagementListener.java index b430f76efa5e..225227596b2b 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/listener/RoleManagementListener.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/main/java/org/wso2/carbon/identity/role/v2/mgt/core/listener/RoleManagementListener.java @@ -492,6 +492,18 @@ void postUpdatePermissionsForRole(String roleId, List addedPermissio */ void preGetRolesCount(String tenantDomain) throws IdentityRoleManagementException; + /** + * Invoked before retrieving available total roles count in a tenant for a given specific search filter. + * + * @param searchFilter The search filter. + * @param tenantDomain The domain in which the operation is being performed. + * @throws IdentityRoleManagementException If an error occurs during the pre-retrieval phase. + */ + default void preGetRolesCount(String searchFilter, String tenantDomain) throws IdentityRoleManagementException { + + // Implement the method if required. + } + /** * Invoked after retrieving the count of roles within a specified tenant domain. * @@ -501,6 +513,20 @@ void postUpdatePermissionsForRole(String roleId, List addedPermissio */ void postGetRolesCount(int count, String tenantDomain) throws IdentityRoleManagementException; + /** + * Invoked after retrieving available total roles count in a tenant for a given specific search filter. + * + * @param count The number of roles retrieved from the specified tenant domain. + * @param searchFilter The search filter. + * @param tenantDomain The domain in which the operation was performed. + * @throws IdentityRoleManagementException If an error occurs during the post-retrieval phase. + */ + default void postGetRolesCount(int count, String searchFilter, String tenantDomain) + throws IdentityRoleManagementException { + + // Implement the method if required. + } + /** * Invoked before retrieving the list of roles associated with a specific user in the given tenant domain. * diff --git a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/test/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOTest.java b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/test/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOTest.java index 69739368b0f8..7c130f5d7b0f 100644 --- a/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/test/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOTest.java +++ b/components/role-mgt/org.wso2.carbon.identity.role.v2.mgt.core/src/test/java/org/wso2/carbon/identity/role/v2/mgt/core/dao/RoleDAOTest.java @@ -617,6 +617,30 @@ public void testCountRoles() throws Exception { assertEquals(rolesCount, 3); } + @Test + public void testCountRolesForAFilter() throws Exception { + + RoleDAOImpl roleDAO = spy(new RoleDAOImpl()); + mockCacheClearing(roleDAO); + identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getUserDBConnection(anyBoolean())) + .thenAnswer(invocation -> getConnection()); + identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean())) + .thenAnswer(invocation -> getConnection()); + identityUtil.when(IdentityUtil::getPrimaryDomainName).thenReturn(USER_DOMAIN_PRIMARY); + identityUtil.when(() -> IdentityUtil.extractDomainFromName(anyString())).thenCallRealMethod(); + identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())).thenReturn(SAMPLE_TENANT_ID); + userCoreUtil.when(() -> UserCoreUtil.isEveryoneRole(anyString(), any(RealmConfiguration.class))) + .thenReturn(false); + userCoreUtil.when(() -> UserCoreUtil.removeDomainFromName(anyString())).thenCallRealMethod(); + addRole(roleNamesList.get(0), APPLICATION_AUD, SAMPLE_APP_ID, roleDAO); + addRole(roleNamesList.get(1), APPLICATION_AUD, SAMPLE_APP_ID, roleDAO); + addRole(roleNamesList.get(2), APPLICATION_AUD, SAMPLE_APP_ID, roleDAO); + + List expressionNodes = getExpressionNodes("audienceId ne undefined"); + int rolesCount = roleDAO.getRolesCount(expressionNodes, SAMPLE_TENANT_DOMAIN); + assertEquals(rolesCount, 3); + } + @Test public void testUpdateRoleName() throws Exception {