Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Generic Organization Resource Resolver #415

Merged
merged 21 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a18f28c
Introduce organization resource hierarchy traverse service with the r…
dhaura Nov 21, 2024
6cbaa3d
Fix traverse service pom version.
dhaura Nov 21, 2024
941a2ae
Merge remote-tracking branch 'upstream/main' into DP-add-b2b-resource…
dhaura Nov 21, 2024
28341aa
Improve bundle packaging and extract ancestor org retrieval to a priv…
dhaura Nov 21, 2024
e9667be
Add unit tests and improve javadoc comments.
dhaura Nov 22, 2024
fc14805
Add unit test comments.
dhaura Nov 22, 2024
1577064
Improve OrgResourceResolverService comments.
dhaura Nov 22, 2024
1d653e0
Fix checkstyle issues and rename test class to OrgResourceResolverSer…
dhaura Nov 22, 2024
22415d3
Apply test name change in testng.xml.
dhaura Nov 22, 2024
b71a3cc
Add missing fullstops in comments.
dhaura Nov 22, 2024
4c93167
Improve assertResolvedResponse method.
dhaura Nov 22, 2024
7f071c1
Improve NotImplementedException comments.
dhaura Nov 25, 2024
c145e9f
Handle invalid organization ids as error scenarios.
dhaura Nov 26, 2024
b4aa7f9
Remove redundant org id list empty check.
dhaura Nov 29, 2024
3349bbd
Update pom version in traverse service.
dhaura Nov 29, 2024
938dc30
Improve javadoc comments and variable naming.
dhaura Nov 29, 2024
beca634
Fix data holder method comment.
dhaura Nov 29, 2024
e742138
Fix server error unit tests.
dhaura Dec 4, 2024
1a8702a
Merge branch 'main' into DP-add-b2b-resource-resolver
dhaura Dec 4, 2024
0507e26
Bump resource traverse version.
dhaura Dec 4, 2024
d2107a1
Merge remote-tracking branch 'origin/DP-add-b2b-resource-resolver' in…
dhaura Dec 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<parent>
<groupId>org.wso2.carbon.identity.organization.management</groupId>
<artifactId>identity-organization-management</artifactId>
<version>1.4.56-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service</artifactId>
<name>WSO2 - Organization Resource Hierarchy Traverse Service</name>
<packaging>bundle</packaging>

<dependencies>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId>
</dependency>
<dependency>
<groupId>commons-collections.wso2</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
<dependency>
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-api</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.application.mgt</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.organization.management.core</groupId>
<artifactId>org.wso2.carbon.identity.organization.management.service</artifactId>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<classifier>runtime</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Name>${project.artifactId}</Bundle-Name>
<Private-Package>
org.wso2.carbon.identity.organization.resource.hierarchy.traverse.internal
</Private-Package>
<Import-Package>
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}"
</Import-Package>
<Export-Package>
!org.wso2.carbon.identity.organization.resource.hierarchy.traverse.internal,
org.wso2.carbon.identity.organization.resource.hierarchy.traverse.*;
version="${project.version}"
darshanasbg marked this conversation as resolved.
Show resolved Hide resolved
</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<!--suppress UnresolvedMavenProperty -->
<argLine>
${argLine}
--add-opens java.xml/jdk.xml.internal=ALL-UNNAMED
--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED
</argLine>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-report-integration</id>
<goals>
<goal>report-integration</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
<limit implementation="org.jacoco.report.check.Limit">
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<!--<minimum>0.60</minimum>-->
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -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 {
dhaura marked this conversation as resolved.
Show resolved Hide resolved

/**
* Get resources from the organization hierarchy.
*
* @param organizationId Organization ID.
* @param resourceRetriever Function to retrieve the resource.
* @param aggregationStrategy Aggregation strategy.
* @param <T> Type of the resource.
* @return Resolved resources.
* @throws OrgResourceHierarchyTraverseException If an error occurs while retrieving the resources.
*/
<T> T getResourcesFromOrgHierarchy(String organizationId,
Function<String, Optional<T>> resourceRetriever,
AggregationStrategy<T> 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 <T> Type of the resource.
* @return Resolved resources.
* @throws OrgResourceHierarchyTraverseException If an error occurs while retrieving the resources.
*/
<T> T getResourcesFromOrgHierarchy(String organizationId, String applicationId,
BiFunction<String, String, Optional<T>> resourceRetriever,
AggregationStrategy<T> aggregationStrategy)
throws OrgResourceHierarchyTraverseException;
}
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we introduce OrganizationManager as a constructor ? This will make writing unit tests easy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our usual practice with OSGI services is to store all the required services/ managers by the component in the data holder of the component.


@Override
public <T> T getResourcesFromOrgHierarchy(String organizationId, Function<String, Optional<T>> resourceRetriever,
AggregationStrategy<T> aggregationStrategy)
throws OrgResourceHierarchyTraverseException {

try {
OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager();
List<String> organizationIds = organizationManager.getAncestorOrganizationIds(organizationId);
dhaura marked this conversation as resolved.
Show resolved Hide resolved

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> T getResourcesFromOrgHierarchy(String organizationId, String applicationId,
BiFunction<String, String, Optional<T>> resourceRetriever,
AggregationStrategy<T> aggregationStrategy)
throws OrgResourceHierarchyTraverseException {

try {
OrganizationManager organizationManager = OrgResourceHierarchyTraverseUtil.getOrganizationManager();
List<String> organizationIds = organizationManager.getAncestorOrganizationIds(organizationId);

if (CollectionUtils.isEmpty(organizationIds) || organizationIds.isEmpty()) {
return null;
}

ApplicationManagementService applicationManagementService = getApplicationManagementService();
Map<String, String> 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();
}
}
Loading
Loading