From a18f28ca129146c654ee9f2bc02d63ce00da9543 Mon Sep 17 00:00:00 2001 From: dhaura Date: Thu, 21 Nov 2024 13:59:29 +0530 Subject: [PATCH 01/18] Introduce organization resource hierarchy traverse service with the resource resolver. --- .../pom.xml | 207 ++++++++++++++++++ .../service/OrgResourceResolverService.java | 63 ++++++ .../OrgResourceResolverServiceImpl.java | 102 +++++++++ ...OrgResourceHierarchyTraverseConstants.java | 75 +++++++ .../exception/NotImplementedException.java | 48 ++++ ...ourceHierarchyTraverseClientException.java | 127 +++++++++++ ...OrgResourceHierarchyTraverseException.java | 132 +++++++++++ ...ourceHierarchyTraverseServerException.java | 95 ++++++++ ...urceHierarchyTraverseServiceComponent.java | 104 +++++++++ ...rceHierarchyTraverseServiceDataHolder.java | 90 ++++++++ .../service/strategy/AggregationStrategy.java | 66 ++++++ .../FirstFoundAggregationStrategy.java | 81 +++++++ .../strategy/MergeAllAggregationStrategy.java | 103 +++++++++ .../OrgResourceHierarchyTraverseUtil.java | 105 +++++++++ .../src/test/resources/testng.xml | 26 +++ .../pom.xml | 5 + pom.xml | 9 +- 17 files changed, 1437 insertions(+), 1 deletion(-) create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml new file mode 100644 index 000000000..cbc3867f8 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml @@ -0,0 +1,207 @@ + + + + + + + org.wso2.carbon.identity.organization.management + identity-organization-management + 1.4.53 + ../../pom.xml + + + 4.0.0 + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service + WSO2 - Organization Resource Hierarchy Traverse Service + bundle + + + + org.wso2.carbon + org.wso2.carbon.utils + + + commons-collections.wso2 + commons-collections + + + org.ops4j.pax.logging + pax-logging-api + + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.application.mgt + + + org.wso2.carbon.identity.organization.management.core + org.wso2.carbon.identity.organization.management.service + + + + + org.testng + testng + test + + + org.jacoco + org.jacoco.agent + runtime + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-inline + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.artifactId} + ${project.artifactId} + + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.internal + + + org.apache.commons.lang; version="${org.apache.commons.lang.imp.pkg.version.range}", + org.apache.commons.logging; version="${org.apache.commons.logging.imp.pkg.version.range}", + org.apache.commons.collections; version="${org.apache.commons.collections.imp.pkg.version.range}", + + org.osgi.framework; version="${osgi.framework.imp.pkg.version.range}", + org.osgi.service.component; version="${osgi.service.component.imp.pkg.version.range}", + + org.wso2.carbon.identity.application.mgt; + version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.application.common; + version="${carbon.identity.package.import.version.range}", + + org.wso2.carbon.identity.organization.management.service; + version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}", + org.wso2.carbon.identity.organization.management.service.exception; + version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}", + org.wso2.carbon.identity.organization.management.service.util; + version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}" + + + !org.wso2.carbon.identity.organization.resource.hierarchy.traverse.internal, + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.*; + version="${project.version}" + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + + ${argLine} + --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED + --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED + + + src/test/resources/testng.xml + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + default-prepare-agent + + prepare-agent + + + + default-prepare-agent-integration + + prepare-agent-integration + + + + default-report + + report + + + + default-report-integration + + report-integration + + + + default-check + + check + + + + + BUNDLE + + + COMPLEXITY + COVEREDRATIO + + + + + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java new file mode 100644 index 000000000..604c83199 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service; + +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy.AggregationStrategy; + +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Service interface for organization resource resolver. + */ +public interface OrgResourceResolverService { + + /** + * Get resources from the organization hierarchy. + * + * @param organizationId Organization ID. + * @param resourceRetriever Function to retrieve the resource. + * @param aggregationStrategy Aggregation strategy. + * @param Type of the resource. + * @return Resolved resources. + * @throws OrgResourceHierarchyTraverseException If an error occurs while retrieving the resources. + */ + T getResourcesFromOrgHierarchy(String organizationId, + Function> resourceRetriever, + AggregationStrategy aggregationStrategy) + throws OrgResourceHierarchyTraverseException; + + /** + * Get resources from the organization and application hierarchy. + * + * @param organizationId Organization ID. + * @param applicationId Application ID. + * @param resourceRetriever Function to retrieve the resource. + * @param aggregationStrategy Aggregation strategy. + * @param Type of the resource. + * @return Resolved resources. + * @throws OrgResourceHierarchyTraverseException If an error occurs while retrieving the resources. + */ + T getResourcesFromOrgHierarchy(String organizationId, String applicationId, + BiFunction> resourceRetriever, + AggregationStrategy aggregationStrategy) + throws OrgResourceHierarchyTraverseException; +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java new file mode 100644 index 000000000..c7a9a894b --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service; + +import org.apache.commons.collections.CollectionUtils; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant.OrgResourceHierarchyTraverseConstants; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal.OrgResourceHierarchyTraverseServiceDataHolder; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy.AggregationStrategy; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util.OrgResourceHierarchyTraverseUtil; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Implementation of the OrgResourceResolverService. + */ +public class OrgResourceResolverServiceImpl implements OrgResourceResolverService { + + @Override + public T getResourcesFromOrgHierarchy(String organizationId, Function> resourceRetriever, + AggregationStrategy aggregationStrategy) + throws OrgResourceHierarchyTraverseException { + + try { + OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); + List organizationIds = organizationManager.getAncestorOrganizationIds(organizationId); + + if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { + return null; + } + + return aggregationStrategy.aggregate(organizationIds, resourceRetriever); + } catch (OrganizationManagementException e) { + throw OrgResourceHierarchyTraverseUtil.handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages + .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS, e, organizationId); + } + } + + @Override + public T getResourcesFromOrgHierarchy(String organizationId, String applicationId, + BiFunction> resourceRetriever, + AggregationStrategy aggregationStrategy) + throws OrgResourceHierarchyTraverseException { + + try { + OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); + List organizationIds = organizationManager.getAncestorOrganizationIds(organizationId); + + if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { + return null; + } + + ApplicationManagementService applicationManagementService = getApplicationManagementService(); + Map ancestorAppIds = Collections.emptyMap(); + if (applicationId != null) { + ancestorAppIds = applicationManagementService.getAncestorAppIds(applicationId, organizationId); + } + + return aggregationStrategy.aggregate(organizationIds, ancestorAppIds, resourceRetriever); + } catch (OrganizationManagementException e) { + throw OrgResourceHierarchyTraverseUtil.handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages + .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS, e, organizationId); + } catch (IdentityApplicationManagementException e) { + throw OrgResourceHierarchyTraverseUtil.handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages + .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_APPLICATIONS, + e, organizationId, applicationId); + } + } + + private ApplicationManagementService getApplicationManagementService() { + + return OrgResourceHierarchyTraverseServiceDataHolder.getInstance().getApplicationManagementService(); + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java new file mode 100644 index 000000000..ba4b09ddf --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant; + +/** + * Constants for organization resource hierarchy traverse service. + */ +public class OrgResourceHierarchyTraverseConstants { + + private static final String ORGANIZATION_RESOURCE_HIERARCHY_TRAVERSE_ERROR_CODE_PREFIX = "ORHT-"; + + private OrgResourceHierarchyTraverseConstants() { + + } + + /** + * Enum for error messages related to organization resource hierarchy traverse service. + */ + public enum ErrorMessages { + + // Server errors. + ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS( + "65001", + "Unable to resolve ancestor organizations.", + "Unexpected server error occurred " + + "while resolving ancestor organizations for organization with id: %s."), + ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_APPLICATIONS( + "65002", + "Unable to resolve ancestor applications.", + "Unexpected server error occurred while resolving ancestor applications for organization " + + "with id: %s for application with id: %s."); + + private final String code; + private final String message; + private final String description; + + ErrorMessages(String code, String message, String description) { + + this.code = code; + this.message = message; + this.description = description; + } + + public String getCode() { + + return ORGANIZATION_RESOURCE_HIERARCHY_TRAVERSE_ERROR_CODE_PREFIX + code; + } + + public String getMessage() { + + return message; + } + + public String getDescription() { + + return description; + } + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java new file mode 100644 index 000000000..bc937175b --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; + +/** + * The exception to throw when the code is not implemented. + */ +public class NotImplementedException extends RuntimeException { + + private static final long serialVersionUID = 5117918786934510964L; + + public NotImplementedException() { + + super(); + } + + public NotImplementedException(String message, Throwable cause) { + + super(message, cause); + } + + public NotImplementedException(String message) { + + super(message); + } + + public NotImplementedException(Throwable cause) { + + super(cause); + } + +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java new file mode 100644 index 000000000..00d675930 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Exception class for client side errors in organization resource hierarchy traverse. + */ +public class OrgResourceHierarchyTraverseClientException extends OrgResourceHierarchyTraverseException { + + private static final long serialVersionUID = 559143944402014381L; + + private String[] messages; + + public OrgResourceHierarchyTraverseClientException(String[] messages) { + + super(Arrays.toString(messages)); + if (messages == null) { + return; + } + List msgList = new ArrayList<>(); + for (String msg : messages) { + if (!msg.trim().isEmpty()) { + msgList.add(msg); + } + } + this.messages = msgList.toArray(new String[0]); + } + + /** + * Constructs a new exception with the specified message. + * + * @param message Detailed message + */ + public OrgResourceHierarchyTraverseClientException(String message) { + + super(message); + } + + /** + * Constructs a new exception with the specified message and cause. + * + * @param message Detailed message + * @param e Cause as {@link Throwable} + */ + public OrgResourceHierarchyTraverseClientException(String message, Throwable e) { + + super(message, e); + } + + /** + * Constructs a new exception with the specified error code and cause. + * + * @param errorCode Error code + * @param message Detailed message + */ + public OrgResourceHierarchyTraverseClientException(String errorCode, String message) { + + super(errorCode, message); + } + + /** + * Constructs a new exception with the specified error code, message and cause. + * + * @param errorCode Error code + * @param message Detailed message + * @param cause Cause as {@link Throwable} + */ + public OrgResourceHierarchyTraverseClientException(String errorCode, String message, Throwable cause) { + + super(errorCode, message, cause); + } + + /** + * Constructs a new exception with the specified error code, message and description. + * + * @param errorCode Error code. + * @param message Error message. + * @param description Error description. + */ + public OrgResourceHierarchyTraverseClientException(String errorCode, String message, String description) { + + super(errorCode, message, description); + } + + /** + * Constructs a new exception with the specified error code, message, description and cause. + * + * @param errorCode Error code + * @param message Detailed message + * @param cause Cause as {@link Throwable} + * @param description Error description. + */ + public OrgResourceHierarchyTraverseClientException(String errorCode, String message, String description, + Throwable cause) { + + super(errorCode, message, description, cause); + } + + @SuppressFBWarnings(value = "EI_EXPOSE_REP", + justification = "Client exception error messages are internally generated from the server side.") + public String[] getMessages() { + + return messages; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java new file mode 100644 index 000000000..2cc442a70 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; + +/** + * Exception class that represents exceptions thrown upon organization resource hierarchy traverse. + */ +public class OrgResourceHierarchyTraverseException extends Exception { + + private String errorCode; + private String description; + + private static final long serialVersionUID = -1982152066401023165L; + + /** + * Constructs a new exception with the specified message. + * + * @param message Detailed message + */ + public OrgResourceHierarchyTraverseException(String message) { + + super(message); + } + + /** + * Constructs a new exception with the specified message and cause. + * + * @param message Detailed message + * @param e Cause as {@link Throwable} + */ + public OrgResourceHierarchyTraverseException(String message, Throwable e) { + + super(message, e); + } + + /** + * Constructs a new exception with the specified error code and cause. + * + * @param errorCode Error code + * @param message Detailed message + */ + public OrgResourceHierarchyTraverseException(String errorCode, String message) { + + super(message); + this.errorCode = errorCode; + } + + /** + * Constructs a new exception with the specified error code, message and description. + * + * @param errorCode Error code. + * @param message Error message. + * @param description Error description. + */ + public OrgResourceHierarchyTraverseException(String errorCode, String message, String description) { + + super(message); + this.errorCode = errorCode; + this.description = description; + } + + /** + * Constructs a new exception with the specified error code, message and cause. + * + * @param errorCode Error code + * @param message Detailed message + * @param cause Cause as {@link Throwable} + */ + public OrgResourceHierarchyTraverseException(String errorCode, String message, Throwable cause) { + + super(message, cause); + this.errorCode = errorCode; + } + + /** + * Constructs a new exception with the specified error code, message, description and cause. + * + * @param errorCode Error code. + * @param message Detailed message. + * @param cause Cause as {@link Throwable}. + * @param description Error description. + */ + public OrgResourceHierarchyTraverseException(String errorCode, String message, String description, + Throwable cause) { + + super(message, cause); + this.errorCode = errorCode; + this.description = description; + } + + /** + * Returns the error code. + * + * @return Error code + */ + public String getErrorCode() { + + return errorCode; + } + + /** + * This public method is required by the stub. + * + * @return Error message. + */ + @Override + public String getMessage() { + + return super.getMessage(); + } + + public String getDescription() { + + return description; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java new file mode 100644 index 000000000..28f2c30b9 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; + +/** + * Exception class that represents server side errors in organization resource hierarchy traverse. + */ +public class OrgResourceHierarchyTraverseServerException extends OrgResourceHierarchyTraverseException { + + /** + * Constructs a new exception with the specified message. + * + * @param message Detailed message + */ + public OrgResourceHierarchyTraverseServerException(String message) { + + super(message); + } + + /** + * Constructs a new exception with the specified message and cause. + * + * @param message Detailed message + * @param e Cause as {@link Throwable} + */ + public OrgResourceHierarchyTraverseServerException(String message, Throwable e) { + + super(message, e); + } + + /** + * Constructs a new exception with the specified error code and message. + * + * @param errorCode Error code + * @param message Detailed message + */ + public OrgResourceHierarchyTraverseServerException(String errorCode, String message) { + + super(errorCode, message); + } + + /** + * Constructs a new exception with the specified error code, message and cause. + * + * @param errorCode Error code + * @param message Detailed message + * @param cause Cause as {@link Throwable} + */ + public OrgResourceHierarchyTraverseServerException(String errorCode, String message, Throwable cause) { + + super(errorCode, message, cause); + } + + /** + * Constructs a new exception with the specified error code, message and description. + * + * @param errorCode Error code. + * @param message Error message. + * @param description Error description. + */ + public OrgResourceHierarchyTraverseServerException(String errorCode, String message, String description) { + + super(errorCode, message, description); + } + + /** + * Constructs a new exception with the specified error code, message, description and cause. + * + * @param errorCode Error code. + * @param message Detailed message. + * @param cause Cause as {@link Throwable}. + * @param description Error description. + */ + public OrgResourceHierarchyTraverseServerException(String errorCode, String message, String description, + Throwable cause) { + + super(errorCode, message, description, cause); + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java new file mode 100644 index 000000000..109c26397 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.OrgResourceResolverService; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.OrgResourceResolverServiceImpl; + +/** + * OSGi declarative services component of the organization resource hierarchy traverse service. + */ +@Component( + name = "org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service", + immediate = true) +public class OrgResourceHierarchyTraverseServiceComponent { + + private static final Log log = LogFactory.getLog(OrgResourceHierarchyTraverseServiceComponent.class); + + @Activate + protected void activate(ComponentContext context) { + + try { + BundleContext bundleContext = context.getBundleContext(); + bundleContext.registerService(OrgResourceResolverService.class.getName(), + new OrgResourceResolverServiceImpl(), null); + if (log.isDebugEnabled()) { + log.debug("OrgResourceResolverService bundle is activated successfully."); + } + } catch (Exception e) { + log.error("Error while activating OrgResourceResolverService bundle.", e); + } + } + + @Deactivate + protected void deactivate(ComponentContext context) { + + if (log.isDebugEnabled()) { + log.debug("OrgResourceResolverService bundle is deactivated"); + } + } + + @Reference(name = "org.wso2.carbon.identity.organization.management.service", + service = OrganizationManager.class, + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetOrganizationManager") + protected void setOrganizationManager(OrganizationManager organizationManager) { + + OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setOrganizationManager(organizationManager); + log.debug("OrganizationManager set in OrgResourceManagementServiceComponent bundle."); + } + + protected void unsetOrganizationManager(OrganizationManager organizationManager) { + + OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setOrganizationManager(null); + log.debug("OrganizationManager unset in OrgResourceManagementServiceComponent bundle."); + } + + @Reference( + name = "org.wso2.carbon.identity.application.mgt", + service = ApplicationManagementService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetApplicationManagementService") + protected void setApplicationManagementService(ApplicationManagementService applicationManagementService) { + + OrgResourceHierarchyTraverseServiceDataHolder.getInstance() + .setApplicationManagementService(applicationManagementService); + log.debug("ApplicationManagementService set in OrgResourceManagementServiceComponent bundle."); + } + + protected void unsetApplicationManagementService(ApplicationManagementService applicationManagementService) { + + OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setApplicationManagementService(null); + log.debug("ApplicationManagementService unset in OrgResourceManagementServiceComponent bundle."); + } +} + diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java new file mode 100644 index 000000000..b4f1f58e3 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal; + +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; + +/** + * This class holds the data required for the organization resource hierarchy traverse service. + */ +public class OrgResourceHierarchyTraverseServiceDataHolder { + + private static final OrgResourceHierarchyTraverseServiceDataHolder instance = + new OrgResourceHierarchyTraverseServiceDataHolder(); + + private OrganizationManager organizationManager; + private ApplicationManagementService applicationManagementService; + + private OrgResourceHierarchyTraverseServiceDataHolder() { + + } + + /** + * Get the instance of OrgResourceManagementServiceDataHolder. + * + * @return OrgResourceManagementServiceDataHolder instance. + */ + public static OrgResourceHierarchyTraverseServiceDataHolder getInstance() { + + return instance; + } + + /** + * Get the organization manager. + * + * @return Organization manager. + */ + public OrganizationManager getOrganizationManager() { + + return organizationManager; + } + + /** + * Set the organization manager. + * + * @param organizationManager Organization manager instance. + */ + public void setOrganizationManager( + OrganizationManager organizationManager) { + + this.organizationManager = organizationManager; + } + + /** + * Get the application management service. + * + * @return Application management service. + */ + public ApplicationManagementService getApplicationManagementService() { + + return applicationManagementService; + } + + /** + * Set the application management service. + * + * @param applicationManagementService Application management service instance. + */ + public void setApplicationManagementService( + ApplicationManagementService applicationManagementService) { + + this.applicationManagementService = applicationManagementService; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java new file mode 100644 index 000000000..ef23bddde --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy; + +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.NotImplementedException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Interface for aggregation strategies. + * + * @param Type of the resource to be aggregated. + */ +public interface AggregationStrategy { + + /** + * Aggregate resolved resources of the given organization hierarchy. + * + * @param organizationHierarchy Organization hierarchy. + * @param resourceRetriever Function to retrieve the resource. + * @return Aggregated resource. + * @throws OrgResourceHierarchyTraverseException If an error occurs while aggregating the resources. + */ + default T aggregate(List organizationHierarchy, Function> resourceRetriever) + throws OrgResourceHierarchyTraverseException { + + throw new NotImplementedException("aggregate method is not implemented in " + this.getClass()); + } + + /** + * Aggregate resolved resources of the given organization and application hierarchy. + * + * @param organizationHierarchy Organization hierarchy. + * @param applicationHierarchy Application hierarchy. + * @param resourceRetriever Function to retrieve the resource. + * @return Aggregated resource. + * @throws OrgResourceHierarchyTraverseException If an error occurs while aggregating the resources. + */ + default T aggregate(List organizationHierarchy, Map applicationHierarchy, + BiFunction> resourceRetriever) + throws OrgResourceHierarchyTraverseException { + + throw new NotImplementedException("aggregate method is not implemented in " + this.getClass()); + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java new file mode 100644 index 000000000..3ee3120f1 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy; + +import org.apache.commons.collections.CollectionUtils; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util.OrgResourceHierarchyTraverseUtil; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Aggregation strategy to retrieve the first found resource in the organization hierarchy. + * + * @param Type of the resource. + */ +public class FirstFoundAggregationStrategy implements AggregationStrategy { + + @Override + public T aggregate(List organizationHierarchy, Function> resourceRetriever) + throws OrgResourceHierarchyTraverseException { + + if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + return null; + } + + for (String orgId : organizationHierarchy) { + if (OrgResourceHierarchyTraverseUtil.isMinOrgHierarchyDepthReached(orgId)) { + break; + } + + Optional resource = resourceRetriever.apply(orgId); + if (resource.isPresent()) { + return resource.get(); + } + } + return null; + } + + @Override + public T aggregate(List organizationHierarchy, Map applicationHierarchy, + BiFunction> resourceRetriever) + throws OrgResourceHierarchyTraverseException { + + if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + return null; + } + + for (String orgId : organizationHierarchy) { + if (OrgResourceHierarchyTraverseUtil.isMinOrgHierarchyDepthReached(orgId)) { + break; + } + + String appId = applicationHierarchy.get(orgId); + Optional resource = resourceRetriever.apply(orgId, appId); + if (resource.isPresent()) { + return resource.get(); + } + } + return null; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java new file mode 100644 index 000000000..648acb898 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy; + +import org.apache.commons.collections.CollectionUtils; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util.OrgResourceHierarchyTraverseUtil; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Aggregation strategy to merge all resources in the organization hierarchy with the given resource merger function. + * + * @param Type of the resource. + */ +public class MergeAllAggregationStrategy implements AggregationStrategy { + + private final BiFunction resourceMerger; + + /** + * Constructor to initialize the aggregation strategy with the resource merger function. + * + * @param resourceMerger Resource merger function. + */ + public MergeAllAggregationStrategy(BiFunction resourceMerger) { + + this.resourceMerger = resourceMerger; + } + + @Override + public T aggregate(List organizationHierarchy, Function> resourceRetriever) + throws OrgResourceHierarchyTraverseException { + + T aggregatedResource = null; + if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + return aggregatedResource; + } + + for (String orgId : organizationHierarchy) { + if (OrgResourceHierarchyTraverseUtil.isMinOrgHierarchyDepthReached(orgId)) { + break; + } + + Optional resource = resourceRetriever.apply(orgId); + if (resource.isPresent()) { + if (aggregatedResource == null) { + aggregatedResource = resource.get(); + } else { + aggregatedResource = resourceMerger.apply(aggregatedResource, resource.get()); + } + } + } + return aggregatedResource; + } + + @Override + public T aggregate(List organizationHierarchy, Map applicationHierarchy, + BiFunction> resourceRetriever) + throws OrgResourceHierarchyTraverseException { + + T aggregatedResource = null; + if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + return aggregatedResource; + } + + for (String orgId : organizationHierarchy) { + if (OrgResourceHierarchyTraverseUtil.isMinOrgHierarchyDepthReached(orgId)) { + break; + } + + String appId = applicationHierarchy.get(orgId); + Optional resource = resourceRetriever.apply(orgId, appId); + if (resource.isPresent()) { + if (aggregatedResource == null) { + aggregatedResource = resource.get(); + } else { + aggregatedResource = resourceMerger.apply(aggregatedResource, resource.get()); + } + } + } + return aggregatedResource; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java new file mode 100644 index 000000000..68adcc9d3 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util; + +import org.apache.commons.lang.ArrayUtils; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; +import org.wso2.carbon.identity.organization.management.service.util.Utils; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant.OrgResourceHierarchyTraverseConstants; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseClientException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseServerException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal.OrgResourceHierarchyTraverseServiceDataHolder; + +/** + * Utility class for organization resource hierarchy traverse service. + */ +public class OrgResourceHierarchyTraverseUtil { + + private OrgResourceHierarchyTraverseUtil() { + + } + + /** + * Get the organization manager. + * + * @return Organization manager. + */ + public static OrganizationManager getOrganizationManager() { + + return OrgResourceHierarchyTraverseServiceDataHolder.getInstance().getOrganizationManager(); + } + + /** + * Check whether the minimum organization hierarchy depth is reached. + * + * @param orgId Organization ID. + * @return True if the minimum hierarchy depth is reached. + * @throws OrgResourceHierarchyTraverseServerException If an error occurs while checking the hierarchy depth. + */ + public static boolean isMinOrgHierarchyDepthReached(String orgId) throws + OrgResourceHierarchyTraverseServerException { + + int minHierarchyDepth = Utils.getSubOrgStartLevel() - 1; + try { + int depthInHierarchy = getOrganizationManager().getOrganizationDepthInHierarchy(orgId); + return depthInHierarchy < minHierarchyDepth; + } catch (OrganizationManagementException e) { + throw new OrgResourceHierarchyTraverseServerException( + "Error occurred while getting the hierarchy depth of the organization: " + orgId, e); + } + } + + /** + * Throw an OrgResourceHierarchyTraverseClientException upon client side error while traversing organization + * resource hierarchy traverse. + * + * @param error The error enum. + * @param data The error message data. + * @return OrgResourceHierarchyTraverseClientException + */ + public static OrgResourceHierarchyTraverseClientException handleClientException( + OrgResourceHierarchyTraverseConstants.ErrorMessages error, String... data) { + + String description = error.getDescription(); + if (ArrayUtils.isNotEmpty(data)) { + description = String.format(description, data); + } + return new OrgResourceHierarchyTraverseClientException(error.getMessage(), description, error.getCode()); + } + + /** + * Throw an OrgResourceHierarchyTraverseServerException upon server side error while traversing organization + * resource hierarchy traverse. + * + * @param error The error enum. + * @param e The error. + * @param data The error message data. + * @return OrgResourceHierarchyTraverseServerException + */ + public static OrgResourceHierarchyTraverseServerException handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages error, Throwable e, String... data) { + + String description = error.getDescription(); + if (ArrayUtils.isNotEmpty(data)) { + description = String.format(description, data); + } + return new OrgResourceHierarchyTraverseServerException(error.getMessage(), description, error.getCode(), e); + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml new file mode 100644 index 000000000..5f83a467d --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/features/org.wso2.carbon.identity.organization.management.server.feature/pom.xml b/features/org.wso2.carbon.identity.organization.management.server.feature/pom.xml index 0ba6c8910..4ea7efb1b 100644 --- a/features/org.wso2.carbon.identity.organization.management.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.organization.management.server.feature/pom.xml @@ -83,6 +83,10 @@ org.wso2.carbon.identity.organization.management org.wso2.carbon.identity.organization.discovery.service + + org.wso2.carbon.identity.organization.management + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service + @@ -120,6 +124,7 @@ org.wso2.carbon.identity.organization.management:org.wso2.carbon.identity.organization.user.invitation.management org.wso2.carbon.identity.organization.management:org.wso2.carbon.identity.organization.config.service org.wso2.carbon.identity.organization.management:org.wso2.carbon.identity.organization.discovery.service + org.wso2.carbon.identity.organization.management:org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service org.wso2.carbon.core:compatible:${carbon.kernel.feature.version} diff --git a/pom.xml b/pom.xml index 0ab32ade4..3d5e203b1 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ components/org.wso2.carbon.identity.organization.config.service components/org.wso2.carbon.identity.organization.discovery.service components/org.wso2.carbon.identity.organization.management.organization.user.sharing + components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service @@ -186,6 +187,12 @@ ${project.version} provided + + org.wso2.carbon.identity.organization.management + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service + ${project.version} + provided + org.wso2.carbon.identity.framework @@ -545,7 +552,7 @@ [4.7.0,5.0.0) - 7.3.3 + 7.6.15 [5.20.0, 8.0.0) From 6cbaa3dc7943ad232e8b993a6a7992385f2eb974 Mon Sep 17 00:00:00 2001 From: dhaura Date: Thu, 21 Nov 2024 14:05:53 +0530 Subject: [PATCH 02/18] Fix traverse service pom version. --- .../pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml index cbc3867f8..cd44a8942 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.organization.management identity-organization-management - 1.4.53 + 1.4.56-SNAPSHOT ../../pom.xml From 28341aac52dda7e533936bd48113be269347983f Mon Sep 17 00:00:00 2001 From: dhaura Date: Thu, 21 Nov 2024 19:32:36 +0530 Subject: [PATCH 03/18] Improve bundle packaging and extract ancestor org retrieval to a private method. --- .../pom.xml | 12 +++++++++--- .../service/OrgResourceResolverServiceImpl.java | 15 +++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml index cd44a8942..582ed4bf8 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml @@ -89,7 +89,9 @@ ${project.artifactId} ${project.artifactId} - org.wso2.carbon.identity.organization.resource.hierarchy.traverse.internal + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant, + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal, + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util org.apache.commons.lang; version="${org.apache.commons.lang.imp.pkg.version.range}", @@ -112,8 +114,12 @@ version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}" - !org.wso2.carbon.identity.organization.resource.hierarchy.traverse.internal, - org.wso2.carbon.identity.organization.resource.hierarchy.traverse.*; + !org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant, + !org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal, + !org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util, + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service, + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception, + org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy; version="${project.version}" diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java index c7a9a894b..c41fd5997 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java @@ -47,9 +47,7 @@ public T getResourcesFromOrgHierarchy(String organizationId, Function organizationIds = organizationManager.getAncestorOrganizationIds(organizationId); - + List organizationIds = getAncestorOrganizationsIds(organizationId); if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { return null; } @@ -69,9 +67,7 @@ public T getResourcesFromOrgHierarchy(String organizationId, String applicat throws OrgResourceHierarchyTraverseException { try { - OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); - List organizationIds = organizationManager.getAncestorOrganizationIds(organizationId); - + List organizationIds = getAncestorOrganizationsIds(organizationId); if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { return null; } @@ -95,6 +91,13 @@ public T getResourcesFromOrgHierarchy(String organizationId, String applicat } } + private List getAncestorOrganizationsIds(String organizationId) + throws OrganizationManagementException { + + OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); + return organizationManager.getAncestorOrganizationIds(organizationId); + } + private ApplicationManagementService getApplicationManagementService() { return OrgResourceHierarchyTraverseServiceDataHolder.getInstance().getApplicationManagementService(); From e9667be3476a03621ecfb9c391630a6dca8558d0 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 12:15:27 +0530 Subject: [PATCH 04/18] Add unit tests and improve javadoc comments. --- .../pom.xml | 11 +- .../service/OrgResourceResolverService.java | 46 +- .../OrgResourceResolverServiceImpl.java | 11 +- ...OrgResourceHierarchyTraverseConstants.java | 42 +- ...ourceHierarchyTraverseClientException.java | 12 +- ...OrgResourceHierarchyTraverseException.java | 7 +- ...ourceHierarchyTraverseServerException.java | 5 +- ...urceHierarchyTraverseServiceComponent.java | 37 +- ...rceHierarchyTraverseServiceDataHolder.java | 23 +- .../service/strategy/AggregationStrategy.java | 51 +- .../FirstFoundAggregationStrategy.java | 6 +- .../strategy/MergeAllAggregationStrategy.java | 10 +- .../OrgResourceHierarchyTraverseUtil.java | 60 +- ...gResourceResolverHierarchyServiceTest.java | 575 ++++++++++++++++++ .../impl/MockResourceManagementService.java | 105 ++++ .../resource/impl/model/MockResource.java | 143 +++++ .../src/test/resources/testng.xml | 1 + 17 files changed, 1052 insertions(+), 93 deletions(-) create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/MockResourceManagementService.java create mode 100644 components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/model/MockResource.java diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml index 582ed4bf8..233f0df56 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml @@ -149,6 +149,15 @@ org.jacoco jacoco-maven-plugin ${jacoco.version} + + + org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/*.class + org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/*.class + org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/*.class + org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.class + org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.class + + default-prepare-agent @@ -187,7 +196,7 @@ COMPLEXITY COVEREDRATIO - + 0.60 diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java index 604c83199..cb6646d5f 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java @@ -26,19 +26,28 @@ import java.util.function.Function; /** - * Service interface for organization resource resolver. + * Provides a service interface to retrieve resources from an organization's hierarchy. + * Supports traversal of both organization and application hierarchies using customizable + * resource retrieval and aggregation strategies. + *

+ * The service is designed for extensibility, allowing clients to define their own retrieval logic + * and aggregation mechanisms via functional interfaces and strategy patterns. */ public interface OrgResourceResolverService { /** - * Get resources from the organization hierarchy. + * Retrieves resources by traversing the hierarchy of a given organization. * - * @param organizationId Organization ID. - * @param resourceRetriever Function to retrieve the resource. - * @param aggregationStrategy Aggregation strategy. - * @param Type of the resource. - * @return Resolved resources. - * @throws OrgResourceHierarchyTraverseException If an error occurs while retrieving the resources. + * @param organizationId The unique identifier of the organization. + * @param resourceRetriever A function that defines how to fetch a resource for a given organization ID. + * The function must return an {@link Optional} containing the resource if found, + * or an empty {@link Optional} if not. + * @param aggregationStrategy A strategy defining how to aggregate resources retrieved from + * different levels of the hierarchy. + * @param The type of the resource being retrieved and aggregated. + * @return An aggregated resource of type obtained from the organization hierarchy. + * @throws OrgResourceHierarchyTraverseException If any errors occur during resource retrieval + * or aggregation. */ T getResourcesFromOrgHierarchy(String organizationId, Function> resourceRetriever, @@ -46,15 +55,20 @@ T getResourcesFromOrgHierarchy(String organizationId, throws OrgResourceHierarchyTraverseException; /** - * Get resources from the organization and application hierarchy. + * Retrieves resources by traversing the hierarchy of a given organization and application. * - * @param organizationId Organization ID. - * @param applicationId Application ID. - * @param resourceRetriever Function to retrieve the resource. - * @param aggregationStrategy Aggregation strategy. - * @param Type of the resource. - * @return Resolved resources. - * @throws OrgResourceHierarchyTraverseException If an error occurs while retrieving the resources. + * @param organizationId The unique identifier of the organization. Must not be null. + * @param applicationId The unique identifier of the application within the organization. Must not be null. + * @param resourceRetriever A bi-function that defines how to fetch a resource based on the + * organization and application IDs. The function must return an + * {@link Optional} containing the resource if found, + * or an empty {@link Optional} if not. + * @param aggregationStrategy A strategy defining how to aggregate resources retrieved from + * different levels of the hierarchy. + * @param The type of the resource being retrieved and aggregated. + * @return An aggregated resource of type obtained from the organization and application hierarchy. + * @throws OrgResourceHierarchyTraverseException If any errors occur during resource retrieval + * or aggregation. */ T getResourcesFromOrgHierarchy(String organizationId, String applicationId, BiFunction> resourceRetriever, diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java index c41fd5997..b4974135a 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java @@ -22,7 +22,7 @@ import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.organization.management.service.OrganizationManager; -import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementServerException; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant.OrgResourceHierarchyTraverseConstants; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal.OrgResourceHierarchyTraverseServiceDataHolder; @@ -37,7 +37,8 @@ import java.util.function.Function; /** - * Implementation of the OrgResourceResolverService. + * Implementation of the OrgResourceResolverService interface, responsible for resolving resources within the + * given organization/ application hierarchy. */ public class OrgResourceResolverServiceImpl implements OrgResourceResolverService { @@ -53,7 +54,7 @@ public T getResourcesFromOrgHierarchy(String organizationId, Function T getResourcesFromOrgHierarchy(String organizationId, String applicat } return aggregationStrategy.aggregate(organizationIds, ancestorAppIds, resourceRetriever); - } catch (OrganizationManagementException e) { + } catch (OrganizationManagementServerException e) { throw OrgResourceHierarchyTraverseUtil.handleServerException( OrgResourceHierarchyTraverseConstants.ErrorMessages .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS, e, organizationId); @@ -92,7 +93,7 @@ public T getResourcesFromOrgHierarchy(String organizationId, String applicat } private List getAncestorOrganizationsIds(String organizationId) - throws OrganizationManagementException { + throws OrganizationManagementServerException { OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); return organizationManager.getAncestorOrganizationIds(organizationId); diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java index ba4b09ddf..ef91a2fd0 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java @@ -19,18 +19,23 @@ package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant; /** - * Constants for organization resource hierarchy traverse service. + * Constants defined for the organization resource hierarchy traverse service. */ public class OrgResourceHierarchyTraverseConstants { private static final String ORGANIZATION_RESOURCE_HIERARCHY_TRAVERSE_ERROR_CODE_PREFIX = "ORHT-"; + /** + * Private constructor to prevent instantiation of this constant class. + */ private OrgResourceHierarchyTraverseConstants() { } /** - * Enum for error messages related to organization resource hierarchy traverse service. + * Enum which provides error codes and predefined error messages related to the traversal of + * the organization resource hierarchy. It ensures that error handling within the service is consistent + * and that detailed error descriptions are available for debugging and troubleshooting. */ public enum ErrorMessages { @@ -50,6 +55,16 @@ public enum ErrorMessages { private final String message; private final String description; + /** + * Constructor for the ErrorMessages enum. + *

+ * This constructor is used to define each error message with a unique error code, a brief message, and + * a detailed description. + * + * @param code The unique error code for the message (prefixed with "ORHT-"). + * @param message A brief message describing the error. + * @param description A detailed description of the error, often including placeholders for dynamic data. + */ ErrorMessages(String code, String message, String description) { this.code = code; @@ -57,16 +72,39 @@ public enum ErrorMessages { this.description = description; } + /** + * Gets the unique error code for the error message. + *

+ * The error code is prefixed with "ORHT-" to ensure consistency in the error code system. + * + * @return The error code prefixed with "ORHT-". + */ public String getCode() { return ORGANIZATION_RESOURCE_HIERARCHY_TRAVERSE_ERROR_CODE_PREFIX + code; } + /** + * Gets the brief message for the error. + *

+ * This message provides a short description of the error, usually without context-specific details. + * It is used for logging or displaying to the user as part of the error response. + * + * @return A brief message describing the error. + */ public String getMessage() { return message; } + /** + * Gets the detailed description for the error message. + *

+ * This description provides a more detailed explanation of the error and often contains placeholders + * for dynamic data (e.g., organization or application IDs). It is typically used for logging or debugging. + * + * @return A detailed description of the error, including placeholders for dynamic data. + */ public String getDescription() { return description; diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java index 00d675930..26ac0cd0d 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java @@ -25,14 +25,20 @@ import java.util.List; /** - * Exception class for client side errors in organization resource hierarchy traverse. + * Exception class for client-side errors during organization resource hierarchy traversal. + *

+ * This class handles exceptions where client-side errors occur, capturing error codes, messages, and descriptions + * to provide detailed context for troubleshooting. */ public class OrgResourceHierarchyTraverseClientException extends OrgResourceHierarchyTraverseException { - private static final long serialVersionUID = 559143944402014381L; - private String[] messages; + /** + * Constructs a new exception with an array of specified error messages. + * + * @param messages Detailed error messages + */ public OrgResourceHierarchyTraverseClientException(String[] messages) { super(Arrays.toString(messages)); diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java index 2cc442a70..128557dc4 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java @@ -19,14 +19,17 @@ package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; /** - * Exception class that represents exceptions thrown upon organization resource hierarchy traverse. + * Custom exception for errors encountered during organization resource hierarchy traversal. + *

+ * This exception captures detailed error information, including error codes, messages, descriptions, + * and causes, to assist in troubleshooting issues related to resolving ancestor organizations or applications. */ public class OrgResourceHierarchyTraverseException extends Exception { private String errorCode; private String description; - private static final long serialVersionUID = -1982152066401023165L; + private static final long serialVersionUID = 5967152066669023668L; /** * Constructs a new exception with the specified message. diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java index 28f2c30b9..531b834e0 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java @@ -19,7 +19,10 @@ package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; /** - * Exception class that represents server side errors in organization resource hierarchy traverse. + * Exception class for server-side errors during organization resource hierarchy traversal. + *

+ * This class handles exceptions related to server-side failures, including error codes, messages, + * descriptions, and causes, to provide detailed information for debugging. */ public class OrgResourceHierarchyTraverseServerException extends OrgResourceHierarchyTraverseException { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java index 109c26397..deec43f48 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java @@ -33,7 +33,10 @@ import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.OrgResourceResolverServiceImpl; /** - * OSGi declarative services component of the organization resource hierarchy traverse service. + * OSGi component responsible for managing the activation and deactivation of the organization resource hierarchy + * traverse service. + *

+ * It manages dynamic references to necessary services required by {@link OrgResourceResolverService} as well. */ @Component( name = "org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service", @@ -42,6 +45,12 @@ public class OrgResourceHierarchyTraverseServiceComponent { private static final Log log = LogFactory.getLog(OrgResourceHierarchyTraverseServiceComponent.class); + /** + * Activates the OSGi component by registering the {@link OrgResourceResolverService} service. + * This method is called when the component is activated in the OSGi environment. + * + * @param context The ComponentContext instance that provides the OSGi environment context. + */ @Activate protected void activate(ComponentContext context) { @@ -57,6 +66,12 @@ protected void activate(ComponentContext context) { } } + /** + * Deactivates the OSGi component by cleaning up resources and logging the deactivation. + * This method is called when the component is deactivated in the OSGi environment. + * + * @param context The ComponentContext instance that provides the OSGi environment context. + */ @Deactivate protected void deactivate(ComponentContext context) { @@ -65,6 +80,11 @@ protected void deactivate(ComponentContext context) { } } + /** + * Sets the OrganizationManager instance in the OrgResourceHierarchyTraverseServiceDataHolder. + * + * @param organizationManager The OrganizationManager instance to be assigned. + */ @Reference(name = "org.wso2.carbon.identity.organization.management.service", service = OrganizationManager.class, cardinality = ReferenceCardinality.OPTIONAL, @@ -76,12 +96,22 @@ protected void setOrganizationManager(OrganizationManager organizationManager) { log.debug("OrganizationManager set in OrgResourceManagementServiceComponent bundle."); } + /** + * Unsets the OrganizationManager instance in the OrgResourceHierarchyTraverseServiceDataHolder. + * + * @param organizationManager The OrganizationManager instance to be removed. + */ protected void unsetOrganizationManager(OrganizationManager organizationManager) { OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setOrganizationManager(null); log.debug("OrganizationManager unset in OrgResourceManagementServiceComponent bundle."); } + /** + * Sets the ApplicationManagementService instance in the OrgResourceHierarchyTraverseServiceDataHolder. + * + * @param applicationManagementService The ApplicationManagementService instance to be assigned. + */ @Reference( name = "org.wso2.carbon.identity.application.mgt", service = ApplicationManagementService.class, @@ -95,6 +125,11 @@ protected void setApplicationManagementService(ApplicationManagementService appl log.debug("ApplicationManagementService set in OrgResourceManagementServiceComponent bundle."); } + /** + * Unsets the ApplicationManagementService instance in the OrgResourceHierarchyTraverseServiceDataHolder. + * + * @param applicationManagementService The ApplicationManagementService instance to be removed. + */ protected void unsetApplicationManagementService(ApplicationManagementService applicationManagementService) { OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setApplicationManagementService(null); diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java index b4f1f58e3..5a5c6ba02 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java @@ -22,7 +22,8 @@ import org.wso2.carbon.identity.organization.management.service.OrganizationManager; /** - * This class holds the data required for the organization resource hierarchy traverse service. + * Singleton class that serves as a centralized data holder for key service instances used in the organization + * resource hierarchy traversal process. */ public class OrgResourceHierarchyTraverseServiceDataHolder { @@ -37,9 +38,9 @@ private OrgResourceHierarchyTraverseServiceDataHolder() { } /** - * Get the instance of OrgResourceManagementServiceDataHolder. + * Retires the Singleton instance of the OrgResourceHierarchyTraverseServiceDataHolder class. * - * @return OrgResourceManagementServiceDataHolder instance. + * @return The singleton instance of OrgResourceHierarchyTraverseServiceDataHolder. */ public static OrgResourceHierarchyTraverseServiceDataHolder getInstance() { @@ -47,9 +48,9 @@ public static OrgResourceHierarchyTraverseServiceDataHolder getInstance() { } /** - * Get the organization manager. + * Retrieves the current instance of the OrganizationManager. * - * @return Organization manager. + * @return The current OrganizationManager instance that manages organizational data. */ public OrganizationManager getOrganizationManager() { @@ -57,9 +58,9 @@ public OrganizationManager getOrganizationManager() { } /** - * Set the organization manager. + * Sets the OrganizationManager instance. * - * @param organizationManager Organization manager instance. + * @param organizationManager The OrganizationManager instance to be assigned. */ public void setOrganizationManager( OrganizationManager organizationManager) { @@ -68,9 +69,9 @@ public void setOrganizationManager( } /** - * Get the application management service. + * Retrieves the current instance of the ApplicationManagementService. * - * @return Application management service. + * @return The current ApplicationManagementService instance responsible for managing applications. */ public ApplicationManagementService getApplicationManagementService() { @@ -78,9 +79,9 @@ public ApplicationManagementService getApplicationManagementService() { } /** - * Set the application management service. + * Sets the ApplicationManagementService instance. * - * @param applicationManagementService Application management service instance. + * @param applicationManagementService The ApplicationManagementService instance to be set. */ public void setApplicationManagementService( ApplicationManagementService applicationManagementService) { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java index ef23bddde..ef0798a84 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/AggregationStrategy.java @@ -28,19 +28,33 @@ import java.util.function.Function; /** - * Interface for aggregation strategies. + * Defines an interface for a strategy used for aggregating resources retrieved from hierarchical structures, + * such as organization and application hierarchies. This interface provides default + * methods that can be overridden to implement specific aggregation logic. + *

+ * Implementations should specify how resources are combined and may use functional + * interfaces for flexible retrieval mechanisms. * - * @param Type of the resource to be aggregated. + * @param The type of the resource to be aggregated. */ public interface AggregationStrategy { /** - * Aggregate resolved resources of the given organization hierarchy. + * Aggregates resources resolved from an organization's hierarchical structure. + *

+ * This method provides a default implementation that throws a + * {@link NotImplementedException}. Subclasses must override this method to define + * specific aggregation logic for organization hierarchies. * - * @param organizationHierarchy Organization hierarchy. - * @param resourceRetriever Function to retrieve the resource. - * @return Aggregated resource. - * @throws OrgResourceHierarchyTraverseException If an error occurs while aggregating the resources. + * @param organizationHierarchy A list representing the organization hierarchy, + * where the first element is the root organization + * and subsequent elements represent child organizations. + * @param resourceRetriever A function that retrieves a resource given an organization ID. + * Returns an {@link Optional} containing the resource, or empty + * if no resource is found for the given ID. + * @return The aggregated resource of type . + * @throws OrgResourceHierarchyTraverseException If any error occurs during resource + * retrieval or aggregation. */ default T aggregate(List organizationHierarchy, Function> resourceRetriever) throws OrgResourceHierarchyTraverseException { @@ -49,13 +63,24 @@ default T aggregate(List organizationHierarchy, Function + * This method provides a default implementation that throws a + * {@link NotImplementedException}. Subclasses must override this method to define + * specific aggregation logic for combined organization and application hierarchies. * - * @param organizationHierarchy Organization hierarchy. - * @param applicationHierarchy Application hierarchy. - * @param resourceRetriever Function to retrieve the resource. - * @return Aggregated resource. - * @throws OrgResourceHierarchyTraverseException If an error occurs while aggregating the resources. + * @param organizationHierarchy A list representing the organization hierarchy, + * where the first element is the root organization + * and subsequent elements represent child organizations. + * @param applicationHierarchy A map representing the application hierarchy, where keys + * are organization IDs, and values are application-specific + * details or IDs for each organization. + * @param resourceRetriever A bi-function that retrieves a resource based on both an + * organization ID and an application ID. Returns an {@link Optional} + * containing the resource, or empty if no resource is found. + * @return The aggregated resource of type . + * @throws OrgResourceHierarchyTraverseException If any error occurs during resource + * retrieval or aggregation. */ default T aggregate(List organizationHierarchy, Map applicationHierarchy, BiFunction> resourceRetriever) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java index 3ee3120f1..cfd473cc2 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java @@ -29,9 +29,11 @@ import java.util.function.Function; /** - * Aggregation strategy to retrieve the first found resource in the organization hierarchy. + * Aggregation strategy that can be used to traverse the organization hierarchy and retrieve the first resource found. + * This strategy is commonly applied when multiple resources might exist at different levels of the hierarchy, + * and only the first one encountered at the bottom of the hierarchy needs to be returned. * - * @param Type of the resource. + * @param The type of the resource being retrieved from the organization/ application hierarchy. */ public class FirstFoundAggregationStrategy implements AggregationStrategy { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java index 648acb898..f911b2700 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java @@ -29,9 +29,15 @@ import java.util.function.Function; /** - * Aggregation strategy to merge all resources in the organization hierarchy with the given resource merger function. + * Aggregation strategy to merge all resources in the organization hierarchy using the specified + * resource merger function. + *

+ * This strategy traverses the hierarchy and applies the provided function + * to combine the resources at each level. It ensures that the resources are merged according to the + * logic defined by the merger function, which could involve combining attributes, performing calculations, or + * resolving conflicts between resources. * - * @param Type of the resource. + * @param The type of the resources being merged in the organization/ application hierarchy. */ public class MergeAllAggregationStrategy implements AggregationStrategy { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java index 68adcc9d3..b48159dc8 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java @@ -20,26 +20,31 @@ import org.apache.commons.lang.ArrayUtils; import org.wso2.carbon.identity.organization.management.service.OrganizationManager; -import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementServerException; import org.wso2.carbon.identity.organization.management.service.util.Utils; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant.OrgResourceHierarchyTraverseConstants; -import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseClientException; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseServerException; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal.OrgResourceHierarchyTraverseServiceDataHolder; /** - * Utility class for organization resource hierarchy traverse service. + * Utility class for the Organization Resource Hierarchy Traverse Service. + *

+ * This class provides helper methods to interact with the organization hierarchy and manage traversal logic, + * such as verifying the hierarchy depth and handling server-side exceptions. */ public class OrgResourceHierarchyTraverseUtil { + /** + * Private constructor to prevent instantiation of the utility class. + */ private OrgResourceHierarchyTraverseUtil() { } /** - * Get the organization manager. + * Retrieve the organization manager instance. * - * @return Organization manager. + * @return The {@link OrganizationManager} instance used to manage organizations. */ public static OrganizationManager getOrganizationManager() { @@ -47,11 +52,14 @@ public static OrganizationManager getOrganizationManager() { } /** - * Check whether the minimum organization hierarchy depth is reached. + * Verify if the organization hierarchy depth has reached the minimum required level. + *

+ * This method obtains the depth of the specified organization in the hierarchy and compares it + * with the configured minimum depth. An exception is thrown if an error occurs during the depth calculation. * - * @param orgId Organization ID. - * @return True if the minimum hierarchy depth is reached. - * @throws OrgResourceHierarchyTraverseServerException If an error occurs while checking the hierarchy depth. + * @param orgId The ID of the organization to check. + * @return {@code true} if the hierarchy depth is less than the minimum required depth, {@code false} otherwise. + * @throws OrgResourceHierarchyTraverseServerException If an error occurs while retrieving the organization's depth. */ public static boolean isMinOrgHierarchyDepthReached(String orgId) throws OrgResourceHierarchyTraverseServerException { @@ -60,38 +68,22 @@ public static boolean isMinOrgHierarchyDepthReached(String orgId) throws try { int depthInHierarchy = getOrganizationManager().getOrganizationDepthInHierarchy(orgId); return depthInHierarchy < minHierarchyDepth; - } catch (OrganizationManagementException e) { + } catch (OrganizationManagementServerException e) { throw new OrgResourceHierarchyTraverseServerException( "Error occurred while getting the hierarchy depth of the organization: " + orgId, e); } } /** - * Throw an OrgResourceHierarchyTraverseClientException upon client side error while traversing organization - * resource hierarchy traverse. - * - * @param error The error enum. - * @param data The error message data. - * @return OrgResourceHierarchyTraverseClientException - */ - public static OrgResourceHierarchyTraverseClientException handleClientException( - OrgResourceHierarchyTraverseConstants.ErrorMessages error, String... data) { - - String description = error.getDescription(); - if (ArrayUtils.isNotEmpty(data)) { - description = String.format(description, data); - } - return new OrgResourceHierarchyTraverseClientException(error.getMessage(), description, error.getCode()); - } - - /** - * Throw an OrgResourceHierarchyTraverseServerException upon server side error while traversing organization - * resource hierarchy traverse. + * Create an {@link OrgResourceHierarchyTraverseServerException} to handle server-side errors. + *

+ * This method formats the error description using the provided data, if applicable, and constructs + * a custom exception for consistent error handling in the service. * - * @param error The error enum. - * @param e The error. - * @param data The error message data. - * @return OrgResourceHierarchyTraverseServerException + * @param error The error enumeration containing predefined error messages and codes. + * @param e The underlying cause of the error. + * @param data Optional data to format the error message description. + * @return An {@link OrgResourceHierarchyTraverseServerException} with the formatted error details. */ public static OrgResourceHierarchyTraverseServerException handleServerException( OrgResourceHierarchyTraverseConstants.ErrorMessages error, Throwable e, String... data) { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java new file mode 100644 index 000000000..1d4f38039 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service; + +import org.mockito.Mock; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementServerException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseServerException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal.OrgResourceHierarchyTraverseServiceDataHolder; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.mock.resource.impl.MockResourceManagementService; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.mock.resource.impl.model.MockResource; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy.AggregationStrategy; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy.FirstFoundAggregationStrategy; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy.MergeAllAggregationStrategy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.openMocks; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertThrows; + +/** + * Unit tests for the OrgResourceResolverHierarchyService. + */ +public class OrgResourceResolverHierarchyServiceTest { + + private static final String ROOT_ORG_ID = "10084a8d-113f-4211-a0d5-efe36b082211"; + private static final String ROOT_APP_ID = "1ee981ab-64e7-435c-ab91-e8d1e0a13b2c"; + private static final String L1_ORG_ID = "93d996f9-a5ba-4275-a52b-adaad9eba869"; + private static final String L1_APP_ID = "619d2cb1-174d-4d38-af3b-99c532dddb00"; + private static final String L2_ORG_ID = "30b701c6-e309-4241-b047-0c299c45d1a0"; + private static final String L2_APP_ID = "d04d48db-8c5a-437a-9458-4352b84db621"; + private static final String INVALID_ORG_ID = "invalid-org-id"; + private static final String INVALID_APP_ID = "invalid-app-id"; + + private OrgResourceResolverService orgResourceResolverService; + private MockResourceManagementService mockResourceManagementService; + private AggregationStrategy firstFoundAggregationStrategy; + private AggregationStrategy mergeAllAggregationStrategy; + + @Mock + OrganizationManager organizationManager; + + @Mock + ApplicationManagementService applicationManagementService; + + /** + * Initializes test data and mock services before the test class is run. + * This method sets up necessary services and aggregation strategies required for the tests. + */ + @BeforeClass + public void init() { + + // Open mock objects for the current test instance + openMocks(this); + + // Set the OrganizationManager and ApplicationManagementService to the data holder for use in tests + OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setOrganizationManager(organizationManager); + OrgResourceHierarchyTraverseServiceDataHolder.getInstance() + .setApplicationManagementService(applicationManagementService); + + // Initialize the aggregation strategies with the appropriate strategy types + firstFoundAggregationStrategy = new FirstFoundAggregationStrategy<>(); + mergeAllAggregationStrategy = new MergeAllAggregationStrategy<>(this::resourceMerger); + } + + /** + * Sets up mocks for individual test cases by initializing mock services and resource management. + * This method runs before each test method to ensure the environment is ready for testing specific scenarios. + */ + @BeforeMethod + public void setUp() throws Exception { + + // Mock responses for the organization manager with different ancestor organization chains + mockAncestorOrganizationRetrieval(Arrays.asList(L2_ORG_ID, L1_ORG_ID, ROOT_ORG_ID)); + mockAncestorOrganizationRetrieval(Arrays.asList(L1_ORG_ID, ROOT_ORG_ID)); + mockAncestorOrganizationRetrieval(Collections.singletonList(ROOT_ORG_ID)); + + // Mock responses for the application management service with corresponding application ancestor data + mockAncestorApplicationRetrieval(Arrays.asList(L2_ORG_ID, L1_ORG_ID, ROOT_ORG_ID), + Arrays.asList(L2_APP_ID, L1_APP_ID, ROOT_APP_ID)); + mockAncestorApplicationRetrieval(Arrays.asList(L1_ORG_ID, ROOT_ORG_ID), + Arrays.asList(L1_APP_ID, ROOT_APP_ID)); + mockAncestorApplicationRetrieval(Collections.singletonList(ROOT_ORG_ID), + Collections.singletonList(ROOT_APP_ID)); + + // Initialize the mock resource management service used in tests + mockResourceManagementService = new MockResourceManagementService(); + + // Instantiate the OrgResourceResolverService for testing + orgResourceResolverService = new OrgResourceResolverServiceImpl(); + } + + /** + * Resets mock services after each test method to ensure a clean state for subsequent tests. + */ + @AfterMethod + public void tearDown() { + + // Reset the mock services to their default state after each test + reset(organizationManager); + reset(applicationManagementService); + } + + @DataProvider(name = "AggregationStrategyDataProvider") + public Object[][] provideAggregationStrategies() { + + return new Object[][]{ + {firstFoundAggregationStrategy}, + {mergeAllAggregationStrategy} + }; + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetOrgLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // No resources available in the mock resource management service. + + MockResource resolvedRootResource = invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID); + assertNull(resolvedRootResource); + + MockResource resolvedL1Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L1_ORG_ID); + assertNull(resolvedL1Resource); + + MockResource resolvedL2Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID); + assertNull(resolvedL2Resource); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetOrgLevelResourcesFromOrgHierarchyWhenRootResourceAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // Add org-level resource for root organization into the mock resource management service. + List createdOrgResource = addOrgResources(Collections.singletonList(ROOT_ORG_ID)); + + MockResource resolvedRootResource = invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID); + assertResolvedResponse(resolvedRootResource, createdOrgResource.get(0)); + + MockResource resolvedL1Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L1_ORG_ID); + assertResolvedResponse(resolvedL1Resource, createdOrgResource.get(0)); + + MockResource resolvedL2Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID); + assertResolvedResponse(resolvedL2Resource, createdOrgResource.get(0)); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetOrgLevelResourcesFromOrgHierarchyWhenL1OrgResourceAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // Add org-level resources for L1 and root organizations into the mock resource management service. + List createdOrgResources = addOrgResources(Arrays.asList(ROOT_ORG_ID, L1_ORG_ID)); + + MockResource resolvedRootResource = invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID); + assertResolvedResponse(resolvedRootResource, createdOrgResources.get(0)); + + MockResource resolvedL1Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L1_ORG_ID); + assertResolvedResponse(resolvedL1Resource, createdOrgResources.get(1)); + + MockResource resolvedL2Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID); + assertResolvedResponse(resolvedL2Resource, createdOrgResources.get(1)); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetOrgLevelResourcesFromOrgHierarchyWhenL2OrgResourceAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // Add org-level resources for L2, L1 and root organizations into the mock resource management service. + List createdOrgResources = addOrgResources(Arrays.asList(ROOT_ORG_ID, L1_ORG_ID, L2_ORG_ID)); + + MockResource resolvedRootResource = invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID); + assertResolvedResponse(resolvedRootResource, createdOrgResources.get(0)); + + MockResource resolvedL1Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L1_ORG_ID); + assertResolvedResponse(resolvedL1Resource, createdOrgResources.get(1)); + + MockResource resolvedL2Resource = invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID); + assertResolvedResponse(resolvedL2Resource, createdOrgResources.get(2)); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetAppLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + MockResource resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertNull(resolvedRootAppResource); + + MockResource resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertNull(resolvedL1AppResource); + + MockResource resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertNull(resolvedL2AppResource); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetAppLevelResourcesFromOrgHierarchyWhenRootResourcesAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // Add org-level resource for root organization into the mock resource management service. + List createdOrgResource = addOrgResources(Collections.singletonList(ROOT_ORG_ID)); + + MockResource resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertResolvedResponse(resolvedRootAppResource, createdOrgResource.get(0)); + + MockResource resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertResolvedResponse(resolvedL1AppResource, createdOrgResource.get(0)); + + MockResource resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertResolvedResponse(resolvedL2AppResource, createdOrgResource.get(0)); + + // Add app-level resource for root organization into the mock resource management service. + List createdAppResource = addAppResources(Collections.singletonList(ROOT_ORG_ID), + Collections.singletonList(ROOT_APP_ID)); + + resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertResolvedResponse(resolvedRootAppResource, createdAppResource.get(0)); + + resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertResolvedResponse(resolvedL1AppResource, createdAppResource.get(0)); + + resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertResolvedResponse(resolvedL2AppResource, createdAppResource.get(0)); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetAppLevelResourcesFromOrgHierarchyWhenL1ResourcesAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // Add org-level resources for L1 and root organizations into the mock resource management service. + List createdOrgResources = addOrgResources(Arrays.asList(ROOT_ORG_ID, L1_ORG_ID)); + // Add app-level resources for root organization into the mock resource management service. + List createdAppResources = addAppResources(Collections.singletonList(ROOT_ORG_ID), + Collections.singletonList(ROOT_APP_ID)); + + MockResource resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertResolvedResponse(resolvedRootAppResource, createdAppResources.get(0)); + + MockResource resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertResolvedResponse(resolvedL1AppResource, createdOrgResources.get(1)); + + MockResource resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertResolvedResponse(resolvedL2AppResource, createdOrgResources.get(1)); + + // Add app-level resources for L1 organization into the mock resource management service. + createdAppResources.addAll(addAppResources(Collections.singletonList(L1_ORG_ID), + Collections.singletonList(L1_APP_ID))); + + resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertResolvedResponse(resolvedRootAppResource, createdAppResources.get(0)); + + resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertResolvedResponse(resolvedL1AppResource, createdAppResources.get(1)); + + resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertResolvedResponse(resolvedL2AppResource, createdAppResources.get(1)); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetAppLevelResourcesFromOrgHierarchyWhenL2ResourcesAvailable( + AggregationStrategy aggregationStrategy) throws Exception { + + // Add org-level resources for L2, L1 and root organizations into the mock resource management service. + List createdOrgResources = addOrgResources(Arrays.asList(ROOT_ORG_ID, L1_ORG_ID, L2_ORG_ID)); + // Add app-level resources for L1 and root organizations into the mock resource management service. + List createdAppResources = addAppResources(Arrays.asList(ROOT_ORG_ID, L1_ORG_ID), + Arrays.asList(ROOT_APP_ID, L1_APP_ID)); + + MockResource resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertResolvedResponse(resolvedRootAppResource, createdAppResources.get(0)); + + MockResource resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertResolvedResponse(resolvedL1AppResource, createdAppResources.get(1)); + + MockResource resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertResolvedResponse(resolvedL2AppResource, createdOrgResources.get(2)); + + // Add app-level resources for L2 organization into the mock resource management service. + createdAppResources.addAll(addAppResources(Collections.singletonList(L2_ORG_ID), + Collections.singletonList(L2_APP_ID))); + + resolvedRootAppResource = + invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID); + assertResolvedResponse(resolvedRootAppResource, createdAppResources.get(0)); + + resolvedL1AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID); + assertResolvedResponse(resolvedL1AppResource, createdAppResources.get(1)); + + resolvedL2AppResource = invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID); + assertResolvedResponse(resolvedL2AppResource, createdAppResources.get(2)); + } + + @DataProvider(name = "provideAggregationStrategiesForOrgLevelResolverWithInvalidInput") + public Object[][] provideAggregationStrategiesForOrgLevelResolverWithInvalidInput() { + + List invalidOrgIds = Arrays.asList(null, "", INVALID_ORG_ID); + + return new Object[][]{ + {firstFoundAggregationStrategy, invalidOrgIds}, + {mergeAllAggregationStrategy, invalidOrgIds}, + }; + } + + @Test(dataProvider = "provideAggregationStrategiesForOrgLevelResolverWithInvalidInput") + public void testGetOrgLevelResourcesFromOrgHierarchyForInvalidInput( + AggregationStrategy aggregationStrategy, List invalidOrgIds) throws Exception { + + for (String orgId : invalidOrgIds) { + MockResource resolvedResource = invokeOrgLevelResourceResolver(aggregationStrategy, orgId); + assertNull(resolvedResource); + } + } + + @DataProvider(name = "provideAggregationStrategiesForAppLevelResolverWithInvalidInput") + public Object[][] provideAggregationStrategiesForAppLevelResolverWithInvalidInput() { + + List invalidOrgIds = Arrays.asList(null, "", INVALID_ORG_ID); + List invalidAppIds = Arrays.asList(null, "", INVALID_APP_ID); + + return new Object[][]{ + {firstFoundAggregationStrategy, invalidOrgIds, invalidAppIds}, + {mergeAllAggregationStrategy, invalidOrgIds, invalidAppIds}, + }; + } + + @Test(dataProvider = "provideAggregationStrategiesForAppLevelResolverWithInvalidInput") + public void testGetAppLevelResourcesFromOrgHierarchyForInvalidInput( + AggregationStrategy aggregationStrategy, List invalidOrgIds, + List invalidAppIds) throws Exception { + + for (String invalidOrgId : invalidOrgIds) { + for (String invalidAppId : invalidAppIds) { + MockResource resolvedResource = + invokeAppLevelResourceResolver(aggregationStrategy, invalidOrgId, invalidAppId); + assertNull(resolvedResource); + } + } + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetOrgLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( + AggregationStrategy aggregationStrategy) throws Exception { + + when(organizationManager.getOrganizationDepthInHierarchy(anyString())) + .thenThrow(OrganizationManagementServerException.class); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, L1_ORG_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID)); + + when(organizationManager.getAncestorOrganizationIds(anyString())) + .thenThrow(OrganizationManagementServerException.class); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, L1_ORG_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID)); + } + + @Test(dataProvider = "AggregationStrategyDataProvider") + public void testGetAppLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( + AggregationStrategy aggregationStrategy) throws Exception { + + when(applicationManagementService.getAncestorAppIds(anyString(), anyString())) + .thenThrow(IdentityApplicationManagementException.class); + + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID)); + + when(organizationManager.getAncestorOrganizationIds(anyString())) + .thenThrow(OrganizationManagementServerException.class); + + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID)); + } + + /** + * Mock the retrieval of ancestor organization IDs. + * + * @param orgIds Organization IDs + * @throws OrganizationManagementException If an error occurs while retrieving ancestor organization IDs. + */ + private void mockAncestorOrganizationRetrieval(List orgIds) + throws OrganizationManagementException { + + List ancestorOrganizationIds = new ArrayList<>(orgIds); + when(organizationManager.getAncestorOrganizationIds(orgIds.get(0))).thenReturn(ancestorOrganizationIds); + } + + /** + * Mock the retrieval of ancestor application IDs. + * + * @param orgIds Organization IDs + * @param appIds Application IDs + * @throws IdentityApplicationManagementException If an error occurs while retrieving ancestor application IDs. + */ + private void mockAncestorApplicationRetrieval(List orgIds, List appIds) + throws IdentityApplicationManagementException { + + Map ancestorAppIds = new HashMap<>(); + for (String orgId : orgIds) { + ancestorAppIds.put(orgId, appIds.get(orgIds.indexOf(orgId))); + } + + when(applicationManagementService.getAncestorAppIds(appIds.get(0), orgIds.get(0))).thenReturn(ancestorAppIds); + } + + /** + * Add organization resources to the mock resource management service. + * + * @param orgIds Organization IDs + * @return List of created organization resources. + */ + private List addOrgResources(List orgIds) { + + List createdOrgResources = new ArrayList<>(); + int resourceId = 1; + for (String orgId : orgIds) { + MockResource orgResource = new MockResource(resourceId++, orgId + "Org Resource", orgId); + mockResourceManagementService.addOrgResource(orgResource); + createdOrgResources.add(orgResource); + } + return createdOrgResources; + } + + /** + * Add application resources to the mock resource management service. + * + * @param orgIds Organization IDs + * @param appIds Application IDs + * @return List of created application resources. + */ + private List addAppResources(List orgIds, List appIds) { + + List createdAppResources = new ArrayList<>(); + int resourceId = 1; + for (String orgId : orgIds) { + MockResource appResource = + new MockResource(resourceId++, orgId + "App Resource", orgId, appIds.get(orgIds.indexOf(orgId))); + mockResourceManagementService.addAppResource(appResource); + createdAppResources.add(appResource); + } + return createdAppResources; + } + + /** + * Resource resolver function used for testing MergeAllAggregationStrategy. + * + * @param aggregatedResource Aggregated resource + * @param newResource New resource + * @return Merged resource. + */ + private MockResource resourceMerger(MockResource aggregatedResource, MockResource newResource) { + + if (aggregatedResource == null) { + return newResource; + } + return aggregatedResource; + } + + /** + * Invoke the organization level resource resolver. + * + * @param aggregationStrategy Aggregation strategy + * @param organizationId Organization ID + * @return Resolved resource + * @throws OrgResourceHierarchyTraverseException If an error occurs while resolving the resource. + */ + private MockResource invokeOrgLevelResourceResolver(AggregationStrategy aggregationStrategy, + String organizationId) + throws OrgResourceHierarchyTraverseException { + + return orgResourceResolverService.getResourcesFromOrgHierarchy( + organizationId, + (orgId) -> { + MockResource resource = mockResourceManagementService.getOrgResource(orgId); + return Optional.ofNullable(resource); + }, + aggregationStrategy); + } + + /** + * Invoke the application level resource resolver. + * + * @param aggregationStrategy Aggregation strategy + * @param organizationId Organization ID + * @param applicationId Application ID + * @return Resolved resource + * @throws OrgResourceHierarchyTraverseException If an error occurs while resolving the resource. + */ + private MockResource invokeAppLevelResourceResolver(AggregationStrategy aggregationStrategy, + String organizationId, String applicationId) + throws OrgResourceHierarchyTraverseException { + + return orgResourceResolverService.getResourcesFromOrgHierarchy( + organizationId, + applicationId, + (orgId, appId) -> { + MockResource resource = mockResourceManagementService.getAppResource(orgId, appId); + return Optional.ofNullable(resource); + }, + aggregationStrategy); + } + + /** + * Assert the resolved resource with the actual resource. + * + * @param resolvedResource Resolved resource + * @param actualResource Actual resource + */ + private void assertResolvedResponse(MockResource resolvedResource, MockResource actualResource) { + + if (actualResource == null) { + assertNull(resolvedResource); + return; + } + + assertNotNull(resolvedResource); + assertEquals(resolvedResource.getId(), actualResource.getId()); + assertEquals(resolvedResource.getResourceName(), actualResource.getResourceName()); + assertEquals(resolvedResource.getOrgId(), actualResource.getOrgId()); + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/MockResourceManagementService.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/MockResourceManagementService.java new file mode 100644 index 000000000..814b010f5 --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/MockResourceManagementService.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.mock.resource.impl; + +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.mock.resource.impl.model.MockResource; + +import java.util.HashMap; +import java.util.Map; + +/** + * Service for managing mocked resources at both organization and application levels. + *

+ * This class maintains separate mappings for organization-level and application-level + * resources, providing methods to add and retrieve resources. These mappings simulate a database, + * offering a simple in-memory representation for resource storage and retrieval operations. + *

+ * This implementation is intended for testing or mocking purposes and simulates a resource management system. + */ +public class MockResourceManagementService { + + private final Map orgResources; + private final Map appResources; + + /** + * Initializes the mock resource management service with empty resource mappings + * for both organization-level and application-level resources. + */ + public MockResourceManagementService() { + + this.orgResources = new HashMap<>(); + this.appResources = new HashMap<>(); + } + + /** + * Adds an organization-level resource to the management service. + * + * @param orgResource The resource to be added. The resource's organization ID + * ({@link MockResource#getOrgId}) is used as the key for storage. + */ + public void addOrgResource(MockResource orgResource) { + + orgResources.put(orgResource.getOrgId(), orgResource); + } + + /** + * Retrieves an organization-level resource by its organization ID. + * + * @param orgId The unique identifier of the organization. + * @return The resource associated with the given organization ID, or {@code null} + * if no resource exists for the provided ID. + */ + public MockResource getOrgResource(String orgId) { + + return orgResources.get(orgId); + } + + /** + * Adds an application-level resource to the management service. + * + * @param appResource The resource to be added. The key for storage is derived + * by concatenating the resource's organization ID and + * application ID ({@link MockResource#getAppId}), separated by a colon. + */ + public void addAppResource(MockResource appResource) { + + appResources.put(appResource.getOrgId() + ":" + appResource.getAppId(), appResource); + } + + /** + * Retrieves an application-level resource by organization ID and application ID. + *

+ * If no application-level resource is found for the given organization and application IDs, + * the method falls back to returning the corresponding organization-level resource, if available. + * + * @param orgId The unique identifier of the organization. + * @param appId The unique identifier of the application within the organization. + * @return The application-level resource if found; otherwise, the organization-level + * resource associated with the organization ID. Returns {@code null} if no matching + * resource is available at either level. + */ + public MockResource getAppResource(String orgId, String appId) { + + MockResource appResource = appResources.get(orgId + ":" + appId); + if (appResource == null) { + return orgResources.get(orgId); + } + return appResource; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/model/MockResource.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/model/MockResource.java new file mode 100644 index 000000000..9b4cbb86e --- /dev/null +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/mock/resource/impl/model/MockResource.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.mock.resource.impl.model; + +/** + * Represents a mocked resource in an organization or application hierarchy. + *

+ * This class models resources that are associated either at the organization level + * or at the application level within an organization. It includes identifiers and + * metadata such as resource ID, resource name, organization ID, and optionally, + * an application ID for application-specific resources. + */ +public class MockResource { + + private int id; + private String resourceName; + private String orgId; + private String appId; + + /** + * Constructs a mocked resource associated with an organization. + * + * @param id Unique identifier of the resource. + * @param resourceName Descriptive name of the resource. + * @param orgId Identifier of the organization the resource belongs to. + */ + public MockResource(int id, String resourceName, String orgId) { + + this.id = id; + this.resourceName = resourceName; + this.orgId = orgId; + } + + /** + * Constructs a mocked resource associated with a specific application within an organization. + * + * @param id Unique identifier of the resource. + * @param resourceName Descriptive name of the resource. + * @param orgId Identifier of the organization the resource belongs to. + * @param appId Identifier of the application the resource is associated with. + */ + public MockResource(int id, String resourceName, String orgId, String appId) { + + this(id, resourceName, orgId); + this.appId = appId; + } + + /** + * Retrieves the unique identifier of the resource. + * + * @return The resource ID. + */ + public int getId() { + + return id; + } + + /** + * Sets the unique identifier of the resource. + * + * @param id The resource ID to set. + */ + public void setId(int id) { + + this.id = id; + } + + /** + * Retrieves the name of the resource. + * + * @return The resource name. + */ + public String getResourceName() { + + return resourceName; + } + + /** + * Sets the name of the resource. + * + * @param resourceName The name to assign to the resource. + */ + public void setResourceName(String resourceName) { + + this.resourceName = resourceName; + } + + /** + * Retrieves the organization ID associated with the resource. + * + * @return The organization ID. + */ + public String getOrgId() { + + return orgId; + } + + /** + * Sets the organization ID associated with the resource. + * + * @param orgId The organization ID to set. + */ + public void setOrgId(String orgId) { + + this.orgId = orgId; + } + + /** + * Retrieves the application ID associated with the resource. + * + * @return The application ID, or {@code null} if the resource is not associated with a specific application. + */ + public String getAppId() { + + return appId; + } + + /** + * Sets the application ID associated with the resource. + * + * @param appId The application ID to set. + */ + public void setAppId(String appId) { + + this.appId = appId; + } +} diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml index 5f83a467d..7ef88e30e 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml @@ -21,6 +21,7 @@ + From fc14805753bb82ff53a2bbd6fba2a5592c5de2ef Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 13:27:56 +0530 Subject: [PATCH 05/18] Add unit test comments. --- ...gResourceResolverHierarchyServiceTest.java | 121 +++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java index 1d4f38039..1f0aff680 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java @@ -147,12 +147,17 @@ public Object[][] provideAggregationStrategies() { }; } + /** + * Tests the behavior of the OrgResourceResolver when no resources are available in the organization hierarchy. + *

+ * This test ensures that the resolver correctly returns null when no resources are found at any organization level. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetOrgLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( AggregationStrategy aggregationStrategy) throws Exception { - // No resources available in the mock resource management service. - MockResource resolvedRootResource = invokeOrgLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID); assertNull(resolvedRootResource); @@ -163,6 +168,14 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( assertNull(resolvedL2Resource); } + /** + * Tests the behavior of the OrgResourceResolver when an organization-level resource is available at the root organization level. + *

+ * This test ensures that the resolver correctly returns the resource for the root organization and propagates + * the resolution to its child organizations (L1 and L2) using the given aggregation strategy. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetOrgLevelResourcesFromOrgHierarchyWhenRootResourceAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -180,6 +193,16 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenRootResourceAvailable( assertResolvedResponse(resolvedL2Resource, createdOrgResource.get(0)); } + /** + * Tests the behavior of the OrgResourceResolver when an organization-level resource is available at the + * L1 organization. + *

+ * This test ensures that when a resource is available at the L1 level, it is correctly resolved for + * L1, and L2 organizations according to the provided aggregation strategy. At the root level, + * its own resource should be returned. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetOrgLevelResourcesFromOrgHierarchyWhenL1OrgResourceAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -197,6 +220,16 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenL1OrgResourceAvailable( assertResolvedResponse(resolvedL2Resource, createdOrgResources.get(1)); } + /** + * Tests the behavior of the OrgResourceResolver when an organization-level resource is available at the + * L2 organization. + *

+ * This test ensures that when a resource is available at the L2 level, it is correctly resolved for the + * L2 organization based on the provided aggregation strategy. + * At the root and L1 level, their own resource should be returned. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetOrgLevelResourcesFromOrgHierarchyWhenL2OrgResourceAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -214,6 +247,15 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenL2OrgResourceAvailable( assertResolvedResponse(resolvedL2Resource, createdOrgResources.get(2)); } + /** + * Tests the behavior of the OrgResourceResolver when no application-level or organization-level resources + * are available in the hierarchy. + *

+ * This test ensures that when no resources are available at the organization or application levels, + * the resolver correctly returns null. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetAppLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -229,6 +271,15 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( assertNull(resolvedL2AppResource); } + /** + * Tests the behavior of the OrgResourceResolver when resources are available at both root organization and/ or + * root application levels in the organization hierarchy. + *

+ * This test verifies that when resources are available for the root level, they are correctly resolved at the + * organization and application levels across all organization levels (root, L1, and L2). + * + * @param aggregationStrategy The aggregation strategy used to resolve resources at different levels. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetAppLevelResourcesFromOrgHierarchyWhenRootResourcesAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -261,6 +312,16 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenRootResourcesAvailable( assertResolvedResponse(resolvedL2AppResource, createdAppResource.get(0)); } + /** + * Tests the behavior of the OrgResourceResolver when organization-level and/ or application-level resources + * are available for both root and L1 organizations in the hierarchy. + *

+ * This test ensures when resources are available for the L1 level, they are correctly resolved at the + * organization and application levels across both organization levels, L1, and L2. At the root level, + * its own resource should be returned. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources at different levels. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetAppLevelResourcesFromOrgHierarchyWhenL1ResourcesAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -296,6 +357,16 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenL1ResourcesAvailable( assertResolvedResponse(resolvedL2AppResource, createdAppResources.get(1)); } + /** + * Tests the behavior of the OrgResourceResolver when organization-level and/ or application-level resources + * are available for all organization levels in the hierarchy. + *

+ * This test ensures that when a resource is available at the L2 level, it is correctly resolved for the + * L2 organization based on the provided aggregation strategy. At the root and L1 level, their own resources + * should be returned. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources at different levels. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetAppLevelResourcesFromOrgHierarchyWhenL2ResourcesAvailable( AggregationStrategy aggregationStrategy) throws Exception { @@ -342,6 +413,16 @@ public Object[][] provideAggregationStrategiesForOrgLevelResolverWithInvalidInpu }; } + /** + * Tests the behavior of the OrgResourceResolver when provided with invalid organization IDs. + *

+ * This test ensures that when invalid organization IDs are passed to the resolver, it correctly returns null, + * indicating that no resources are found for the invalid input. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources at different levels. + * @param invalidOrgIds A list of invalid organization IDs to test the resolver's behavior. + * @throws Exception If an error occurs during resolution. + */ @Test(dataProvider = "provideAggregationStrategiesForOrgLevelResolverWithInvalidInput") public void testGetOrgLevelResourcesFromOrgHierarchyForInvalidInput( AggregationStrategy aggregationStrategy, List invalidOrgIds) throws Exception { @@ -364,6 +445,20 @@ public Object[][] provideAggregationStrategiesForAppLevelResolverWithInvalidInpu }; } + /** + * Tests the behavior of the OrgResourceResolver when provided with invalid organization and application IDs. + *

+ * This test verifies that the resolver correctly handles invalid input combinations by returning null, + * ensuring robustness and appropriate error handling in edge cases. The test covers scenarios where: + * - The organization ID is invalid. + * - The application ID is invalid. + * - Both the organization and application IDs are invalid. + * + * @param aggregationStrategy The aggregation strategy used to resolve resources across the hierarchy. + * @param invalidOrgIds A list of invalid organization IDs to test the resolver's behavior. + * @param invalidAppIds A list of invalid application IDs to test the resolver's behavior. + * @throws Exception If an error occurs during resolution. + */ @Test(dataProvider = "provideAggregationStrategiesForAppLevelResolverWithInvalidInput") public void testGetAppLevelResourcesFromOrgHierarchyForInvalidInput( AggregationStrategy aggregationStrategy, List invalidOrgIds, @@ -378,6 +473,17 @@ public void testGetAppLevelResourcesFromOrgHierarchyForInvalidInput( } } + /** + * Tests the behavior of the OrgResourceResolver when server-side errors occur during + * organizational hierarchy traversal. + *

+ * This test simulates server-side exceptions thrown by the `organizationManager` during the following scenarios: + * - Fetching the depth of an organization within the hierarchy. + * - Retrieving ancestor organization IDs. + * + * @param aggregationStrategy The aggregation strategy used for resolving resources. + * @throws Exception If an unexpected error occurs. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetOrgLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( AggregationStrategy aggregationStrategy) throws Exception { @@ -401,6 +507,17 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( () -> invokeOrgLevelResourceResolver(aggregationStrategy, L2_ORG_ID)); } + /** + * Tests the behavior of the OrgResourceResolver when server-side errors occur during + * application hierarchy traversal within an organization. + *

+ * This test simulates server-side exceptions thrown by the following: + * - The `applicationManagementService` while retrieving ancestor application IDs. + * - The `organizationManager` while retrieving ancestor organization IDs. + * + * @param aggregationStrategy The aggregation strategy used for resolving resources. + * @throws Exception If an unexpected error occurs. + */ @Test(dataProvider = "AggregationStrategyDataProvider") public void testGetAppLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( AggregationStrategy aggregationStrategy) throws Exception { From 15770641687e0e8f48392efbf3555944d31d7fec Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 13:31:24 +0530 Subject: [PATCH 06/18] Improve OrgResourceResolverService comments. --- .../traverse/service/OrgResourceResolverService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java index cb6646d5f..873276d05 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverService.java @@ -57,8 +57,8 @@ T getResourcesFromOrgHierarchy(String organizationId, /** * Retrieves resources by traversing the hierarchy of a given organization and application. * - * @param organizationId The unique identifier of the organization. Must not be null. - * @param applicationId The unique identifier of the application within the organization. Must not be null. + * @param organizationId The unique identifier of the organization. + * @param applicationId The unique identifier of the application within the organization. * @param resourceRetriever A bi-function that defines how to fetch a resource based on the * organization and application IDs. The function must return an * {@link Optional} containing the resource if found, From 1d653e05344a00da51c6b0d83f4d71f363474e6d Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 14:11:26 +0530 Subject: [PATCH 07/18] Fix checkstyle issues and rename test class to OrgResourceResolverServiceTest. --- ...va => OrgResourceResolverServiceTest.java} | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) rename components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/{OrgResourceResolverHierarchyServiceTest.java => OrgResourceResolverServiceTest.java} (95%) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java similarity index 95% rename from components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java rename to components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java index 1f0aff680..b65416c78 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverHierarchyServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java @@ -56,9 +56,9 @@ import static org.testng.Assert.assertThrows; /** - * Unit tests for the OrgResourceResolverHierarchyService. + * Unit tests for the OrgResourceResolverServiceTest. */ -public class OrgResourceResolverHierarchyServiceTest { +public class OrgResourceResolverServiceTest { private static final String ROOT_ORG_ID = "10084a8d-113f-4211-a0d5-efe36b082211"; private static final String ROOT_APP_ID = "1ee981ab-64e7-435c-ab91-e8d1e0a13b2c"; @@ -148,7 +148,8 @@ public Object[][] provideAggregationStrategies() { } /** - * Tests the behavior of the OrgResourceResolver when no resources are available in the organization hierarchy. + * Tests the behavior of the OrgResourceResolverService when no resources are available in the + * organization hierarchy. *

* This test ensures that the resolver correctly returns null when no resources are found at any organization level. * @@ -169,7 +170,8 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( } /** - * Tests the behavior of the OrgResourceResolver when an organization-level resource is available at the root organization level. + * Tests the behavior of the OrgResourceResolverService when an organization-level resource is available at the + * root organization level. *

* This test ensures that the resolver correctly returns the resource for the root organization and propagates * the resolution to its child organizations (L1 and L2) using the given aggregation strategy. @@ -194,7 +196,7 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenRootResourceAvailable( } /** - * Tests the behavior of the OrgResourceResolver when an organization-level resource is available at the + * Tests the behavior of the OrgResourceResolverService when an organization-level resource is available at the * L1 organization. *

* This test ensures that when a resource is available at the L1 level, it is correctly resolved for @@ -221,7 +223,7 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenL1OrgResourceAvailable( } /** - * Tests the behavior of the OrgResourceResolver when an organization-level resource is available at the + * Tests the behavior of the OrgResourceResolverService when an organization-level resource is available at the * L2 organization. *

* This test ensures that when a resource is available at the L2 level, it is correctly resolved for the @@ -248,7 +250,7 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenL2OrgResourceAvailable( } /** - * Tests the behavior of the OrgResourceResolver when no application-level or organization-level resources + * Tests the behavior of the OrgResourceResolverService when no application-level or organization-level resources * are available in the hierarchy. *

* This test ensures that when no resources are available at the organization or application levels, @@ -272,8 +274,8 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenNoResourceAvailable( } /** - * Tests the behavior of the OrgResourceResolver when resources are available at both root organization and/ or - * root application levels in the organization hierarchy. + * Tests the behavior of the OrgResourceResolverService when resources are available at both root organization + * and/ or root application levels in the organization hierarchy. *

* This test verifies that when resources are available for the root level, they are correctly resolved at the * organization and application levels across all organization levels (root, L1, and L2). @@ -313,7 +315,7 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenRootResourcesAvailable( } /** - * Tests the behavior of the OrgResourceResolver when organization-level and/ or application-level resources + * Tests the behavior of the OrgResourceResolverService when organization-level and/ or application-level resources * are available for both root and L1 organizations in the hierarchy. *

* This test ensures when resources are available for the L1 level, they are correctly resolved at the @@ -358,7 +360,7 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenL1ResourcesAvailable( } /** - * Tests the behavior of the OrgResourceResolver when organization-level and/ or application-level resources + * Tests the behavior of the OrgResourceResolverService when organization-level and/ or application-level resources * are available for all organization levels in the hierarchy. *

* This test ensures that when a resource is available at the L2 level, it is correctly resolved for the @@ -414,7 +416,7 @@ public Object[][] provideAggregationStrategiesForOrgLevelResolverWithInvalidInpu } /** - * Tests the behavior of the OrgResourceResolver when provided with invalid organization IDs. + * Tests the behavior of the OrgResourceResolverService when provided with invalid organization IDs. *

* This test ensures that when invalid organization IDs are passed to the resolver, it correctly returns null, * indicating that no resources are found for the invalid input. @@ -446,7 +448,7 @@ public Object[][] provideAggregationStrategiesForAppLevelResolverWithInvalidInpu } /** - * Tests the behavior of the OrgResourceResolver when provided with invalid organization and application IDs. + * Tests the behavior of the OrgResourceResolverService when provided with invalid organization and application IDs. *

* This test verifies that the resolver correctly handles invalid input combinations by returning null, * ensuring robustness and appropriate error handling in edge cases. The test covers scenarios where: @@ -474,7 +476,7 @@ public void testGetAppLevelResourcesFromOrgHierarchyForInvalidInput( } /** - * Tests the behavior of the OrgResourceResolver when server-side errors occur during + * Tests the behavior of the OrgResourceResolverService when server-side errors occur during * organizational hierarchy traversal. *

* This test simulates server-side exceptions thrown by the `organizationManager` during the following scenarios: @@ -508,7 +510,7 @@ public void testGetOrgLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( } /** - * Tests the behavior of the OrgResourceResolver when server-side errors occur during + * Tests the behavior of the OrgResourceResolverService when server-side errors occur during * application hierarchy traversal within an organization. *

* This test simulates server-side exceptions thrown by the following: From 22415d3011be8fb2e87c9962304baaa44ff5b3ac Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 14:14:20 +0530 Subject: [PATCH 08/18] Apply test name change in testng.xml. --- .../src/test/resources/testng.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml index 7ef88e30e..539837328 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/resources/testng.xml @@ -21,7 +21,7 @@ - + From b71a3cc569970deebeabd78654a501fc1579a9b6 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 15:05:00 +0530 Subject: [PATCH 09/18] Add missing fullstops in comments. --- .../service/OrgResourceResolverServiceTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java index b65416c78..b75f366d5 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java @@ -87,7 +87,7 @@ public class OrgResourceResolverServiceTest { @BeforeClass public void init() { - // Open mock objects for the current test instance + // Open mock objects for the current test instance. openMocks(this); // Set the OrganizationManager and ApplicationManagementService to the data holder for use in tests @@ -95,7 +95,7 @@ public void init() { OrgResourceHierarchyTraverseServiceDataHolder.getInstance() .setApplicationManagementService(applicationManagementService); - // Initialize the aggregation strategies with the appropriate strategy types + // Initialize the aggregation strategies with the appropriate strategy types. firstFoundAggregationStrategy = new FirstFoundAggregationStrategy<>(); mergeAllAggregationStrategy = new MergeAllAggregationStrategy<>(this::resourceMerger); } @@ -107,12 +107,12 @@ public void init() { @BeforeMethod public void setUp() throws Exception { - // Mock responses for the organization manager with different ancestor organization chains + // Mock responses for the organization manager with different ancestor organization chains. mockAncestorOrganizationRetrieval(Arrays.asList(L2_ORG_ID, L1_ORG_ID, ROOT_ORG_ID)); mockAncestorOrganizationRetrieval(Arrays.asList(L1_ORG_ID, ROOT_ORG_ID)); mockAncestorOrganizationRetrieval(Collections.singletonList(ROOT_ORG_ID)); - // Mock responses for the application management service with corresponding application ancestor data + // Mock responses for the application management service with corresponding application ancestor data. mockAncestorApplicationRetrieval(Arrays.asList(L2_ORG_ID, L1_ORG_ID, ROOT_ORG_ID), Arrays.asList(L2_APP_ID, L1_APP_ID, ROOT_APP_ID)); mockAncestorApplicationRetrieval(Arrays.asList(L1_ORG_ID, ROOT_ORG_ID), @@ -120,10 +120,10 @@ public void setUp() throws Exception { mockAncestorApplicationRetrieval(Collections.singletonList(ROOT_ORG_ID), Collections.singletonList(ROOT_APP_ID)); - // Initialize the mock resource management service used in tests + // Initialize the mock resource management service used in tests. mockResourceManagementService = new MockResourceManagementService(); - // Instantiate the OrgResourceResolverService for testing + // Instantiate the OrgResourceResolverService for testing. orgResourceResolverService = new OrgResourceResolverServiceImpl(); } @@ -133,7 +133,7 @@ public void setUp() throws Exception { @AfterMethod public void tearDown() { - // Reset the mock services to their default state after each test + // Reset the mock services to their default state after each test. reset(organizationManager); reset(applicationManagementService); } From 4c9316748b5baaf015d84999bc707b60a5766155 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 22 Nov 2024 15:18:18 +0530 Subject: [PATCH 10/18] Improve assertResolvedResponse method. --- .../traverse/service/OrgResourceResolverServiceTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java index b75f366d5..e9014c020 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java @@ -681,11 +681,6 @@ private MockResource invokeAppLevelResourceResolver(AggregationStrategy Date: Mon, 25 Nov 2024 12:30:41 +0530 Subject: [PATCH 11/18] Improve NotImplementedException comments. --- .../exception/NotImplementedException.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java index bc937175b..d72bf48b5 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java @@ -19,30 +19,51 @@ package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception; /** - * The exception to throw when the code is not implemented. + * A custom runtime exception to indicate that a method or functionality is not yet implemented. */ public class NotImplementedException extends RuntimeException { - private static final long serialVersionUID = 5117918786934510964L; + private static final long serialVersionUID = 5117918786934518376L; + /** + * Constructs a new NotImplementedException with no detail message or cause. + * + *

This constructor is typically used when no additional information is required + * to explain why the exception is thrown. + */ public NotImplementedException() { super(); } + /** + * Constructs a new NotImplementedException with a detailed message and the root cause. + * + * @param message A descriptive message explaining why this exception is thrown. + * @param cause The underlying cause of this exception. + */ public NotImplementedException(String message, Throwable cause) { super(message, cause); } + /** + * Constructs a new NotImplementedException with a detailed message. + * + * @param message A descriptive message explaining why this exception is thrown. + */ public NotImplementedException(String message) { super(message); } + /** + * Constructs a new NotImplementedException with the root cause. + * + * @param cause The underlying cause of this exception. + */ public NotImplementedException(Throwable cause) { super(cause); } - } From c145e9fd21a798f3ece22337ae8a8fc372fc2db5 Mon Sep 17 00:00:00 2001 From: dhaura Date: Tue, 26 Nov 2024 17:13:51 +0530 Subject: [PATCH 12/18] Handle invalid organization ids as error scenarios. --- .../OrgResourceResolverServiceImpl.java | 46 ++++++++++--------- ...OrgResourceHierarchyTraverseConstants.java | 13 +++++- .../OrgResourceHierarchyTraverseUtil.java | 20 ++++++++ .../OrgResourceResolverServiceTest.java | 13 +++--- 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java index b4974135a..689ddbec3 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java @@ -19,12 +19,14 @@ package org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.organization.management.service.OrganizationManager; import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementServerException; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.constant.OrgResourceHierarchyTraverseConstants; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseException; +import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.exception.OrgResourceHierarchyTraverseServerException; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.internal.OrgResourceHierarchyTraverseServiceDataHolder; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.strategy.AggregationStrategy; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.util.OrgResourceHierarchyTraverseUtil; @@ -47,18 +49,8 @@ public T getResourcesFromOrgHierarchy(String organizationId, Function aggregationStrategy) throws OrgResourceHierarchyTraverseException { - try { - List organizationIds = getAncestorOrganizationsIds(organizationId); - if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { - return null; - } - - return aggregationStrategy.aggregate(organizationIds, resourceRetriever); - } catch (OrganizationManagementServerException e) { - throw OrgResourceHierarchyTraverseUtil.handleServerException( - OrgResourceHierarchyTraverseConstants.ErrorMessages - .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS, e, organizationId); - } + List organizationIds = getAncestorOrganizationsIds(organizationId); + return aggregationStrategy.aggregate(organizationIds, resourceRetriever); } @Override @@ -69,9 +61,6 @@ public T getResourcesFromOrgHierarchy(String organizationId, String applicat try { List organizationIds = getAncestorOrganizationsIds(organizationId); - if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { - return null; - } ApplicationManagementService applicationManagementService = getApplicationManagementService(); Map ancestorAppIds = Collections.emptyMap(); @@ -80,10 +69,6 @@ public T getResourcesFromOrgHierarchy(String organizationId, String applicat } return aggregationStrategy.aggregate(organizationIds, ancestorAppIds, resourceRetriever); - } catch (OrganizationManagementServerException e) { - throw OrgResourceHierarchyTraverseUtil.handleServerException( - OrgResourceHierarchyTraverseConstants.ErrorMessages - .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS, e, organizationId); } catch (IdentityApplicationManagementException e) { throw OrgResourceHierarchyTraverseUtil.handleServerException( OrgResourceHierarchyTraverseConstants.ErrorMessages @@ -93,10 +78,27 @@ public T getResourcesFromOrgHierarchy(String organizationId, String applicat } private List getAncestorOrganizationsIds(String organizationId) - throws OrganizationManagementServerException { + throws OrgResourceHierarchyTraverseServerException { - OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); - return organizationManager.getAncestorOrganizationIds(organizationId); + if (StringUtils.isBlank(organizationId)) { + throw OrgResourceHierarchyTraverseUtil.handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages.ERROR_CODE_EMPTY_ORGANIZATION_ID); + } + + try { + OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); + List organizationIds = organizationManager.getAncestorOrganizationIds(organizationId); + if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { + throw OrgResourceHierarchyTraverseUtil.handleServerException(OrgResourceHierarchyTraverseConstants + .ErrorMessages.ERROR_CODE_INVALID_ANCESTOR_ORGANIZATION_ID_LIST, + organizationId); + } + return organizationIds; + } catch (OrganizationManagementServerException e) { + throw OrgResourceHierarchyTraverseUtil.handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages + .ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS, e, organizationId); + } } private ApplicationManagementService getApplicationManagementService() { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java index ef91a2fd0..3c96c658c 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/constant/OrgResourceHierarchyTraverseConstants.java @@ -40,13 +40,22 @@ private OrgResourceHierarchyTraverseConstants() { public enum ErrorMessages { // Server errors. - ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS( + ERROR_CODE_EMPTY_ORGANIZATION_ID( "65001", + "Empty organization id.", + "Organization id cannot be null or empty."), + ERROR_CODE_INVALID_ANCESTOR_ORGANIZATION_ID_LIST( + "65002", + "Invalid ancestor organization id list.", + "The ancestor organization id list cannot be empty for the organization with id: %s. " + + "At least the organization itself should be included in the list."), + ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_ORGANIZATIONS( + "65003", "Unable to resolve ancestor organizations.", "Unexpected server error occurred " + "while resolving ancestor organizations for organization with id: %s."), ERROR_CODE_SERVER_ERROR_WHILE_RESOLVING_ANCESTOR_APPLICATIONS( - "65002", + "65004", "Unable to resolve ancestor applications.", "Unexpected server error occurred while resolving ancestor applications for organization " + "with id: %s for application with id: %s."); diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java index b48159dc8..7324900a5 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/util/OrgResourceHierarchyTraverseUtil.java @@ -81,6 +81,26 @@ public static boolean isMinOrgHierarchyDepthReached(String orgId) throws * a custom exception for consistent error handling in the service. * * @param error The error enumeration containing predefined error messages and codes. + * @param data Optional data to format the error message description. + * @return An {@link OrgResourceHierarchyTraverseServerException} with the formatted error details. + */ + public static OrgResourceHierarchyTraverseServerException handleServerException( + OrgResourceHierarchyTraverseConstants.ErrorMessages error, String... data) { + + String description = error.getDescription(); + if (ArrayUtils.isNotEmpty(data)) { + description = String.format(description, data); + } + return new OrgResourceHierarchyTraverseServerException(error.getMessage(), description, error.getCode()); + } + + /** + * Create an {@link OrgResourceHierarchyTraverseServerException} to handle server-side errors. + *

+ * This method formats the error description using the provided data, if applicable, and constructs + * a custom exception including the underlying cause of the error, for consistent error handling in the service. + * + * @param error The error enumeration containing predefined error messages and codes. * @param e The underlying cause of the error. * @param data Optional data to format the error message description. * @return An {@link OrgResourceHierarchyTraverseServerException} with the formatted error details. diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java index e9014c020..825e81b03 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java @@ -56,7 +56,7 @@ import static org.testng.Assert.assertThrows; /** - * Unit tests for the OrgResourceResolverServiceTest. + * Unit tests for the OrgResourceResolverService. */ public class OrgResourceResolverServiceTest { @@ -430,8 +430,8 @@ public void testGetOrgLevelResourcesFromOrgHierarchyForInvalidInput( AggregationStrategy aggregationStrategy, List invalidOrgIds) throws Exception { for (String orgId : invalidOrgIds) { - MockResource resolvedResource = invokeOrgLevelResourceResolver(aggregationStrategy, orgId); - assertNull(resolvedResource); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeOrgLevelResourceResolver(aggregationStrategy, orgId)); } } @@ -468,9 +468,8 @@ public void testGetAppLevelResourcesFromOrgHierarchyForInvalidInput( for (String invalidOrgId : invalidOrgIds) { for (String invalidAppId : invalidAppIds) { - MockResource resolvedResource = - invokeAppLevelResourceResolver(aggregationStrategy, invalidOrgId, invalidAppId); - assertNull(resolvedResource); + assertThrows(OrgResourceHierarchyTraverseServerException.class, + () -> invokeAppLevelResourceResolver(aggregationStrategy, invalidOrgId, invalidAppId)); } } } @@ -643,7 +642,7 @@ private MockResource invokeOrgLevelResourceResolver(AggregationStrategy { + orgId -> { MockResource resource = mockResourceManagementService.getOrgResource(orgId); return Optional.ofNullable(resource); }, From b4aa7f9c143600f5ce181d2535c03f7548476aa2 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 29 Nov 2024 17:41:37 +0530 Subject: [PATCH 13/18] Remove redundant org id list empty check. --- .../traverse/service/OrgResourceResolverServiceImpl.java | 2 +- .../service/strategy/FirstFoundAggregationStrategy.java | 4 ++-- .../service/strategy/MergeAllAggregationStrategy.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java index 689ddbec3..c1fb7c19f 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceImpl.java @@ -88,7 +88,7 @@ private List getAncestorOrganizationsIds(String organizationId) try { OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager(); List organizationIds = organizationManager.getAncestorOrganizationIds(organizationId); - if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) { + if (CollectionUtils.isEmpty(organizationIds)) { throw OrgResourceHierarchyTraverseUtil.handleServerException(OrgResourceHierarchyTraverseConstants .ErrorMessages.ERROR_CODE_INVALID_ANCESTOR_ORGANIZATION_ID_LIST, organizationId); diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java index cfd473cc2..efede0cb7 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/FirstFoundAggregationStrategy.java @@ -41,7 +41,7 @@ public class FirstFoundAggregationStrategy implements AggregationStrategy public T aggregate(List organizationHierarchy, Function> resourceRetriever) throws OrgResourceHierarchyTraverseException { - if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + if (CollectionUtils.isEmpty(organizationHierarchy)) { return null; } @@ -63,7 +63,7 @@ public T aggregate(List organizationHierarchy, Map appli BiFunction> resourceRetriever) throws OrgResourceHierarchyTraverseException { - if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + if (CollectionUtils.isEmpty(organizationHierarchy)) { return null; } diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java index f911b2700..2d1ad9372 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/strategy/MergeAllAggregationStrategy.java @@ -58,7 +58,7 @@ public T aggregate(List organizationHierarchy, Function organizationHierarchy, Map appli throws OrgResourceHierarchyTraverseException { T aggregatedResource = null; - if (CollectionUtils.isEmpty(organizationHierarchy) || organizationHierarchy.isEmpty()) { + if (CollectionUtils.isEmpty(organizationHierarchy)) { return aggregatedResource; } From 3349bbdddf5aecf36ca2bc88732b07a374288385 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 29 Nov 2024 17:54:01 +0530 Subject: [PATCH 14/18] Update pom version in traverse service. --- .../pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml index 233f0df56..3efbc72e6 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.organization.management identity-organization-management - 1.4.56-SNAPSHOT + 1.4.57-SNAPSHOT ../../pom.xml From 938dc308459c20feb1fa02b2116a22ba884a80be Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 29 Nov 2024 18:08:18 +0530 Subject: [PATCH 15/18] Improve javadoc comments and variable naming. --- .../exception/NotImplementedException.java | 4 +-- ...ourceHierarchyTraverseClientException.java | 24 ++++++------- ...OrgResourceHierarchyTraverseException.java | 30 +++++++--------- ...ourceHierarchyTraverseServerException.java | 18 +++++----- ...urceHierarchyTraverseServiceComponent.java | 22 ++++++------ ...rceHierarchyTraverseServiceDataHolder.java | 10 +++--- .../OrgResourceResolverServiceTest.java | 34 +++++++++---------- 7 files changed, 67 insertions(+), 75 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java index d72bf48b5..c08cb203d 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/NotImplementedException.java @@ -27,8 +27,8 @@ public class NotImplementedException extends RuntimeException { /** * Constructs a new NotImplementedException with no detail message or cause. - * - *

This constructor is typically used when no additional information is required + *

+ * This constructor is typically used when no additional information is required * to explain why the exception is thrown. */ public NotImplementedException() { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java index 26ac0cd0d..30e459991 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseClientException.java @@ -37,7 +37,7 @@ public class OrgResourceHierarchyTraverseClientException extends OrgResourceHier /** * Constructs a new exception with an array of specified error messages. * - * @param messages Detailed error messages + * @param messages Detailed error messages. */ public OrgResourceHierarchyTraverseClientException(String[] messages) { @@ -57,7 +57,7 @@ public OrgResourceHierarchyTraverseClientException(String[] messages) { /** * Constructs a new exception with the specified message. * - * @param message Detailed message + * @param message Detailed message. */ public OrgResourceHierarchyTraverseClientException(String message) { @@ -67,8 +67,8 @@ public OrgResourceHierarchyTraverseClientException(String message) { /** * Constructs a new exception with the specified message and cause. * - * @param message Detailed message - * @param e Cause as {@link Throwable} + * @param message Detailed message. + * @param e Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseClientException(String message, Throwable e) { @@ -78,8 +78,8 @@ public OrgResourceHierarchyTraverseClientException(String message, Throwable e) /** * Constructs a new exception with the specified error code and cause. * - * @param errorCode Error code - * @param message Detailed message + * @param errorCode Error code. + * @param message Detailed message. */ public OrgResourceHierarchyTraverseClientException(String errorCode, String message) { @@ -89,9 +89,9 @@ public OrgResourceHierarchyTraverseClientException(String errorCode, String mess /** * Constructs a new exception with the specified error code, message and cause. * - * @param errorCode Error code - * @param message Detailed message - * @param cause Cause as {@link Throwable} + * @param errorCode Error code. + * @param message Detailed message. + * @param cause Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseClientException(String errorCode, String message, Throwable cause) { @@ -113,10 +113,10 @@ public OrgResourceHierarchyTraverseClientException(String errorCode, String mess /** * Constructs a new exception with the specified error code, message, description and cause. * - * @param errorCode Error code - * @param message Detailed message - * @param cause Cause as {@link Throwable} + * @param errorCode Error code. + * @param message Detailed message. * @param description Error description. + * @param cause Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseClientException(String errorCode, String message, String description, Throwable cause) { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java index 128557dc4..749498bec 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseException.java @@ -34,7 +34,7 @@ public class OrgResourceHierarchyTraverseException extends Exception { /** * Constructs a new exception with the specified message. * - * @param message Detailed message + * @param message Detailed message. */ public OrgResourceHierarchyTraverseException(String message) { @@ -44,8 +44,8 @@ public OrgResourceHierarchyTraverseException(String message) { /** * Constructs a new exception with the specified message and cause. * - * @param message Detailed message - * @param e Cause as {@link Throwable} + * @param message Detailed message. + * @param e Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseException(String message, Throwable e) { @@ -55,8 +55,8 @@ public OrgResourceHierarchyTraverseException(String message, Throwable e) { /** * Constructs a new exception with the specified error code and cause. * - * @param errorCode Error code - * @param message Detailed message + * @param errorCode Error code. + * @param message Detailed message. */ public OrgResourceHierarchyTraverseException(String errorCode, String message) { @@ -81,9 +81,9 @@ public OrgResourceHierarchyTraverseException(String errorCode, String message, S /** * Constructs a new exception with the specified error code, message and cause. * - * @param errorCode Error code - * @param message Detailed message - * @param cause Cause as {@link Throwable} + * @param errorCode Error code. + * @param message Detailed message. + * @param cause Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseException(String errorCode, String message, Throwable cause) { @@ -96,8 +96,8 @@ public OrgResourceHierarchyTraverseException(String errorCode, String message, T * * @param errorCode Error code. * @param message Detailed message. - * @param cause Cause as {@link Throwable}. * @param description Error description. + * @param cause Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseException(String errorCode, String message, String description, Throwable cause) { @@ -110,7 +110,7 @@ public OrgResourceHierarchyTraverseException(String errorCode, String message, S /** * Returns the error code. * - * @return Error code + * @return Error code. */ public String getErrorCode() { @@ -118,16 +118,10 @@ public String getErrorCode() { } /** - * This public method is required by the stub. + * Returns the error description. * - * @return Error message. + * @return Error description. */ - @Override - public String getMessage() { - - return super.getMessage(); - } - public String getDescription() { return description; diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java index 531b834e0..2b2f7ecef 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/exception/OrgResourceHierarchyTraverseServerException.java @@ -29,7 +29,7 @@ public class OrgResourceHierarchyTraverseServerException extends OrgResourceHier /** * Constructs a new exception with the specified message. * - * @param message Detailed message + * @param message Detailed message. */ public OrgResourceHierarchyTraverseServerException(String message) { @@ -39,8 +39,8 @@ public OrgResourceHierarchyTraverseServerException(String message) { /** * Constructs a new exception with the specified message and cause. * - * @param message Detailed message - * @param e Cause as {@link Throwable} + * @param message Detailed message. + * @param e Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseServerException(String message, Throwable e) { @@ -50,8 +50,8 @@ public OrgResourceHierarchyTraverseServerException(String message, Throwable e) /** * Constructs a new exception with the specified error code and message. * - * @param errorCode Error code - * @param message Detailed message + * @param errorCode Error code. + * @param message Detailed message. */ public OrgResourceHierarchyTraverseServerException(String errorCode, String message) { @@ -61,9 +61,9 @@ public OrgResourceHierarchyTraverseServerException(String errorCode, String mess /** * Constructs a new exception with the specified error code, message and cause. * - * @param errorCode Error code - * @param message Detailed message - * @param cause Cause as {@link Throwable} + * @param errorCode Error code. + * @param message Detailed message. + * @param cause Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseServerException(String errorCode, String message, Throwable cause) { @@ -87,8 +87,8 @@ public OrgResourceHierarchyTraverseServerException(String errorCode, String mess * * @param errorCode Error code. * @param message Detailed message. - * @param cause Cause as {@link Throwable}. * @param description Error description. + * @param cause Cause as {@link Throwable}. */ public OrgResourceHierarchyTraverseServerException(String errorCode, String message, String description, Throwable cause) { diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java index deec43f48..022cc1831 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceComponent.java @@ -43,7 +43,7 @@ immediate = true) public class OrgResourceHierarchyTraverseServiceComponent { - private static final Log log = LogFactory.getLog(OrgResourceHierarchyTraverseServiceComponent.class); + private static final Log LOG = LogFactory.getLog(OrgResourceHierarchyTraverseServiceComponent.class); /** * Activates the OSGi component by registering the {@link OrgResourceResolverService} service. @@ -58,11 +58,11 @@ protected void activate(ComponentContext context) { BundleContext bundleContext = context.getBundleContext(); bundleContext.registerService(OrgResourceResolverService.class.getName(), new OrgResourceResolverServiceImpl(), null); - if (log.isDebugEnabled()) { - log.debug("OrgResourceResolverService bundle is activated successfully."); + if (LOG.isDebugEnabled()) { + LOG.debug("OrgResourceResolverService bundle is activated successfully."); } } catch (Exception e) { - log.error("Error while activating OrgResourceResolverService bundle.", e); + LOG.error("Error while activating OrgResourceResolverService bundle.", e); } } @@ -75,8 +75,8 @@ protected void activate(ComponentContext context) { @Deactivate protected void deactivate(ComponentContext context) { - if (log.isDebugEnabled()) { - log.debug("OrgResourceResolverService bundle is deactivated"); + if (LOG.isDebugEnabled()) { + LOG.debug("OrgResourceResolverService bundle is deactivated"); } } @@ -87,13 +87,13 @@ protected void deactivate(ComponentContext context) { */ @Reference(name = "org.wso2.carbon.identity.organization.management.service", service = OrganizationManager.class, - cardinality = ReferenceCardinality.OPTIONAL, + cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC, unbind = "unsetOrganizationManager") protected void setOrganizationManager(OrganizationManager organizationManager) { OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setOrganizationManager(organizationManager); - log.debug("OrganizationManager set in OrgResourceManagementServiceComponent bundle."); + LOG.debug("OrganizationManager set in OrgResourceManagementServiceComponent bundle."); } /** @@ -104,7 +104,7 @@ protected void setOrganizationManager(OrganizationManager organizationManager) { protected void unsetOrganizationManager(OrganizationManager organizationManager) { OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setOrganizationManager(null); - log.debug("OrganizationManager unset in OrgResourceManagementServiceComponent bundle."); + LOG.debug("OrganizationManager unset in OrgResourceManagementServiceComponent bundle."); } /** @@ -122,7 +122,7 @@ protected void setApplicationManagementService(ApplicationManagementService appl OrgResourceHierarchyTraverseServiceDataHolder.getInstance() .setApplicationManagementService(applicationManagementService); - log.debug("ApplicationManagementService set in OrgResourceManagementServiceComponent bundle."); + LOG.debug("ApplicationManagementService set in OrgResourceManagementServiceComponent bundle."); } /** @@ -133,7 +133,7 @@ protected void setApplicationManagementService(ApplicationManagementService appl protected void unsetApplicationManagementService(ApplicationManagementService applicationManagementService) { OrgResourceHierarchyTraverseServiceDataHolder.getInstance().setApplicationManagementService(null); - log.debug("ApplicationManagementService unset in OrgResourceManagementServiceComponent bundle."); + LOG.debug("ApplicationManagementService unset in OrgResourceManagementServiceComponent bundle."); } } diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java index 5a5c6ba02..42d7729ab 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java @@ -27,7 +27,7 @@ */ public class OrgResourceHierarchyTraverseServiceDataHolder { - private static final OrgResourceHierarchyTraverseServiceDataHolder instance = + private static final OrgResourceHierarchyTraverseServiceDataHolder INSTANCE = new OrgResourceHierarchyTraverseServiceDataHolder(); private OrganizationManager organizationManager; @@ -44,7 +44,7 @@ private OrgResourceHierarchyTraverseServiceDataHolder() { */ public static OrgResourceHierarchyTraverseServiceDataHolder getInstance() { - return instance; + return INSTANCE; } /** @@ -62,8 +62,7 @@ public OrganizationManager getOrganizationManager() { * * @param organizationManager The OrganizationManager instance to be assigned. */ - public void setOrganizationManager( - OrganizationManager organizationManager) { + public void setOrganizationManager(OrganizationManager organizationManager) { this.organizationManager = organizationManager; } @@ -83,8 +82,7 @@ public ApplicationManagementService getApplicationManagementService() { * * @param applicationManagementService The ApplicationManagementService instance to be set. */ - public void setApplicationManagementService( - ApplicationManagementService applicationManagementService) { + public void setApplicationManagementService(ApplicationManagementService applicationManagementService) { this.applicationManagementService = applicationManagementService; } diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java index 825e81b03..6c732197c 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java @@ -547,7 +547,7 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( /** * Mock the retrieval of ancestor organization IDs. * - * @param orgIds Organization IDs + * @param orgIds Organization IDs. * @throws OrganizationManagementException If an error occurs while retrieving ancestor organization IDs. */ private void mockAncestorOrganizationRetrieval(List orgIds) @@ -560,8 +560,8 @@ private void mockAncestorOrganizationRetrieval(List orgIds) /** * Mock the retrieval of ancestor application IDs. * - * @param orgIds Organization IDs - * @param appIds Application IDs + * @param orgIds Organization IDs. + * @param appIds Application IDs. * @throws IdentityApplicationManagementException If an error occurs while retrieving ancestor application IDs. */ private void mockAncestorApplicationRetrieval(List orgIds, List appIds) @@ -578,7 +578,7 @@ private void mockAncestorApplicationRetrieval(List orgIds, List /** * Add organization resources to the mock resource management service. * - * @param orgIds Organization IDs + * @param orgIds Organization IDs. * @return List of created organization resources. */ private List addOrgResources(List orgIds) { @@ -596,8 +596,8 @@ private List addOrgResources(List orgIds) { /** * Add application resources to the mock resource management service. * - * @param orgIds Organization IDs - * @param appIds Application IDs + * @param orgIds Organization IDs. + * @param appIds Application IDs. * @return List of created application resources. */ private List addAppResources(List orgIds, List appIds) { @@ -616,8 +616,8 @@ private List addAppResources(List orgIds, List app /** * Resource resolver function used for testing MergeAllAggregationStrategy. * - * @param aggregatedResource Aggregated resource - * @param newResource New resource + * @param aggregatedResource Aggregated resource. + * @param newResource New resource. * @return Merged resource. */ private MockResource resourceMerger(MockResource aggregatedResource, MockResource newResource) { @@ -631,9 +631,9 @@ private MockResource resourceMerger(MockResource aggregatedResource, MockResourc /** * Invoke the organization level resource resolver. * - * @param aggregationStrategy Aggregation strategy - * @param organizationId Organization ID - * @return Resolved resource + * @param aggregationStrategy Aggregation strategy. + * @param organizationId Organization ID. + * @return Resolved resource. * @throws OrgResourceHierarchyTraverseException If an error occurs while resolving the resource. */ private MockResource invokeOrgLevelResourceResolver(AggregationStrategy aggregationStrategy, @@ -652,10 +652,10 @@ private MockResource invokeOrgLevelResourceResolver(AggregationStrategy aggregationStrategy, @@ -675,8 +675,8 @@ private MockResource invokeAppLevelResourceResolver(AggregationStrategy Date: Fri, 29 Nov 2024 18:13:54 +0530 Subject: [PATCH 16/18] Fix data holder method comment. --- .../internal/OrgResourceHierarchyTraverseServiceDataHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java index 42d7729ab..0b4fd6686 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/main/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/internal/OrgResourceHierarchyTraverseServiceDataHolder.java @@ -38,7 +38,7 @@ private OrgResourceHierarchyTraverseServiceDataHolder() { } /** - * Retires the Singleton instance of the OrgResourceHierarchyTraverseServiceDataHolder class. + * Retrieves the Singleton instance of the OrgResourceHierarchyTraverseServiceDataHolder class. * * @return The singleton instance of OrgResourceHierarchyTraverseServiceDataHolder. */ From e742138557d64d5cc325ab150827d457ff4ccc86 Mon Sep 17 00:00:00 2001 From: dhaura Date: Wed, 4 Dec 2024 10:48:34 +0530 Subject: [PATCH 17/18] Fix server error unit tests. --- .../traverse/service/OrgResourceResolverServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java index 6c732197c..311ed269c 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/src/test/java/org/wso2/carbon/identity/organization/resource/hierarchy/traverse/service/OrgResourceResolverServiceTest.java @@ -529,7 +529,7 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( assertThrows(OrgResourceHierarchyTraverseServerException.class, () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); assertThrows(OrgResourceHierarchyTraverseServerException.class, - () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); + () -> invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID)); assertThrows(OrgResourceHierarchyTraverseServerException.class, () -> invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID)); @@ -539,7 +539,7 @@ public void testGetAppLevelResourcesFromOrgHierarchyWhenServerErrorOccurs( assertThrows(OrgResourceHierarchyTraverseServerException.class, () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); assertThrows(OrgResourceHierarchyTraverseServerException.class, - () -> invokeAppLevelResourceResolver(aggregationStrategy, ROOT_ORG_ID, ROOT_APP_ID)); + () -> invokeAppLevelResourceResolver(aggregationStrategy, L1_ORG_ID, L1_APP_ID)); assertThrows(OrgResourceHierarchyTraverseServerException.class, () -> invokeAppLevelResourceResolver(aggregationStrategy, L2_ORG_ID, L2_APP_ID)); } From 0507e267d48563d7336f0be3d3cabdaaa432824c Mon Sep 17 00:00:00 2001 From: dhaura Date: Wed, 4 Dec 2024 10:51:06 +0530 Subject: [PATCH 18/18] Bump resource traverse version. --- .../pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml index 3efbc72e6..d01874f66 100644 --- a/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml +++ b/components/org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.organization.management identity-organization-management - 1.4.57-SNAPSHOT + 1.4.58-SNAPSHOT ../../pom.xml