From c3cc8f878187f5759cdd624b1dc5cc1b536dee1e Mon Sep 17 00:00:00 2001 From: Thamindu Aluthwala Date: Mon, 30 Oct 2023 11:05:56 +0530 Subject: [PATCH] Introduce caching --- .../AuthorizedAPIManagementServiceImpl.java | 3 +- .../mgt/cache/AuthorizedAPICache.java | 52 ++++++ .../mgt/cache/AuthorizedAPICacheEntry.java | 46 +++++ .../mgt/cache/AuthorizedAPICacheKey.java | 58 +++++++ .../impl/CacheBackedAuthorizedAPIDAOImpl.java | 158 ++++++++++++++++++ 5 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICache.java create mode 100644 components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheEntry.java create mode 100644 components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheKey.java create mode 100644 components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/CacheBackedAuthorizedAPIDAOImpl.java diff --git a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/AuthorizedAPIManagementServiceImpl.java b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/AuthorizedAPIManagementServiceImpl.java index 580571841fa1..b097001f79e8 100644 --- a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/AuthorizedAPIManagementServiceImpl.java +++ b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/AuthorizedAPIManagementServiceImpl.java @@ -30,6 +30,7 @@ import org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants; import org.wso2.carbon.identity.application.mgt.dao.AuthorizedAPIDAO; import org.wso2.carbon.identity.application.mgt.dao.impl.AuthorizedAPIDAOImpl; +import org.wso2.carbon.identity.application.mgt.dao.impl.CacheBackedAuthorizedAPIDAOImpl; import org.wso2.carbon.identity.application.mgt.internal.ApplicationManagementServiceComponentHolder; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; @@ -44,7 +45,7 @@ */ public class AuthorizedAPIManagementServiceImpl implements AuthorizedAPIManagementService { - private final AuthorizedAPIDAO authorizedAPIDAO = new AuthorizedAPIDAOImpl(); + private final AuthorizedAPIDAO authorizedAPIDAO = new CacheBackedAuthorizedAPIDAOImpl(new AuthorizedAPIDAOImpl()); @Override public void addAuthorizedAPI(String applicationId, AuthorizedAPI authorizedAPI, String tenantDomain) diff --git a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICache.java b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICache.java new file mode 100644 index 000000000000..126b79bf45d6 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICache.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 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.application.mgt.cache; + +import org.wso2.carbon.identity.core.cache.BaseCache; + +/** + * Cache for authorized API. + */ +public class AuthorizedAPICache extends BaseCache { + + private static final String CACHE_NAME = "AuthorizedAPICache"; + private static volatile AuthorizedAPICache instance; + + public AuthorizedAPICache(String cacheName) { + + super(cacheName); + } + + /** + * Get instance of AuthorizedAPICache. + * + * @return Instance of AuthorizedAPICache. + */ + public static AuthorizedAPICache getInstance() { + + if (instance == null) { + synchronized (AuthorizedAPICache.class) { + if (instance == null) { + instance = new AuthorizedAPICache(CACHE_NAME); + } + } + } + return instance; + } +} diff --git a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheEntry.java b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheEntry.java new file mode 100644 index 000000000000..2773cdc6e074 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheEntry.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023, 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.application.mgt.cache; + +import org.wso2.carbon.identity.application.common.model.AuthorizedAPI; + +import java.io.Serializable; + +/** + * Cache entry for authorized API. + */ +public class AuthorizedAPICacheEntry implements Serializable { + + private AuthorizedAPI authorizedAPI; + + public AuthorizedAPICacheEntry(AuthorizedAPI authorizedAPI) { + + this.authorizedAPI = authorizedAPI; + } + + public AuthorizedAPI getAuthorizedAPI() { + + return authorizedAPI; + } + + public void setAuthorizedAPI(AuthorizedAPI authorizedAPI) { + + this.authorizedAPI = authorizedAPI; + } +} diff --git a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheKey.java b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheKey.java new file mode 100644 index 000000000000..3d810279b4e3 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/cache/AuthorizedAPICacheKey.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023, 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.application.mgt.cache; + +import java.io.Serializable; + +/** + * Cache key for authorized API. + */ +public class AuthorizedAPICacheKey implements Serializable { + + private static final long serialVersionUID = 3112605038259278777L; + + private String appId; + private String apiId; + + public AuthorizedAPICacheKey(String appId, String apiId) { + + this.appId = appId; + this.apiId = apiId; + } + + public String getAppId() { + + return appId; + } + + public void setAppId(String appId) { + + this.appId = appId; + } + + public String getApiId() { + + return apiId; + } + + public void setApiId(String apiId) { + + this.apiId = apiId; + } +} diff --git a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/CacheBackedAuthorizedAPIDAOImpl.java b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/CacheBackedAuthorizedAPIDAOImpl.java new file mode 100644 index 000000000000..cc6c0ac90751 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/CacheBackedAuthorizedAPIDAOImpl.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023, 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.application.mgt.dao.impl; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.common.model.AuthorizedAPI; +import org.wso2.carbon.identity.application.common.model.AuthorizedScopes; +import org.wso2.carbon.identity.application.common.model.Scope; +import org.wso2.carbon.identity.application.mgt.cache.AuthorizedAPICache; +import org.wso2.carbon.identity.application.mgt.cache.AuthorizedAPICacheEntry; +import org.wso2.carbon.identity.application.mgt.cache.AuthorizedAPICacheKey; +import org.wso2.carbon.identity.application.mgt.dao.AuthorizedAPIDAO; + +import java.util.List; + +/** + * Cache backed implementation of {@link AuthorizedAPIDAO}. + */ +public class CacheBackedAuthorizedAPIDAOImpl implements AuthorizedAPIDAO { + + private final AuthorizedAPIDAO authorizedAPIDAO; + + private static AuthorizedAPICache authorizedAPICache; + + private static final Log LOG = LogFactory.getLog(CacheBackedAuthorizedAPIDAOImpl.class); + + public CacheBackedAuthorizedAPIDAOImpl(AuthorizedAPIDAO authorizedAPIDAO) { + + this.authorizedAPIDAO = authorizedAPIDAO; + authorizedAPICache = AuthorizedAPICache.getInstance(); + } + + @Override + public void addAuthorizedAPI(String applicationId, String apiId, String policyId, List scopes, int tenantId) + throws IdentityApplicationManagementException { + + + authorizedAPIDAO.addAuthorizedAPI(applicationId, apiId, policyId, scopes, tenantId); + } + + @Override + public List getAuthorizedAPIs(String applicationId, int tenantId) + throws IdentityApplicationManagementException { + + return authorizedAPIDAO.getAuthorizedAPIs(applicationId, tenantId); + } + + @Override + public void patchAuthorizedAPI(String appId, String apiId, List addedScopes, List removedScopes, + int tenantId) throws IdentityApplicationManagementException { + + clearAuthorizedAPIFromCache(appId, apiId, tenantId); + authorizedAPIDAO.patchAuthorizedAPI(appId, apiId, addedScopes, removedScopes, tenantId); + } + + @Override + public void deleteAuthorizedAPI(String appId, String apiId, int tenantId) + throws IdentityApplicationManagementException { + + clearAuthorizedAPIFromCache(appId, apiId, tenantId); + authorizedAPIDAO.deleteAuthorizedAPI(appId, apiId, tenantId); + } + + @Override + public List getAuthorizedScopes(String applicationId, int tenantId) + throws IdentityApplicationManagementException { + + return authorizedAPIDAO.getAuthorizedScopes(applicationId, tenantId); + } + + @Override + public AuthorizedAPI getAuthorizedAPI(String appId, String apiId, int tenantId) + throws IdentityApplicationManagementException { + + AuthorizedAPI authorizedAPI = getAuthorizedAPIFromCache(appId, apiId, tenantId); + if (authorizedAPI == null) { + try { + authorizedAPI = authorizedAPIDAO.getAuthorizedAPI(appId, apiId, tenantId); + if (authorizedAPI != null) { + addToCache(appId, apiId, authorizedAPI, tenantId); + } + } catch (IdentityApplicationManagementException e) { + String error = "Error while retrieving authorized API for application id: " + appId + " and api id: " + + apiId + " in tenant id: " + tenantId; + LOG.error(error, e); + throw new IdentityApplicationManagementException(error, e); + } + } + return authorizedAPI != null ? authorizedAPI : authorizedAPIDAO.getAuthorizedAPI(appId, apiId, tenantId); + } + + private AuthorizedAPI getAuthorizedAPIFromCache(String appId, String apiId, int tenantId) { + + AuthorizedAPI authorizedAPI = null; + if (StringUtils.isNotBlank(appId)) { + AuthorizedAPICacheKey cacheKey = new AuthorizedAPICacheKey(appId, apiId); + AuthorizedAPICacheEntry cacheEntry = authorizedAPICache.getValueFromCache(cacheKey, tenantId); + if (cacheEntry != null) { + authorizedAPI = cacheEntry.getAuthorizedAPI(); + } + } else { + LOG.debug("Application id is empty. Cannot retrieve authorized APIs from cache."); + } + + if (authorizedAPI == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Authorized APIs not found in cache for application id: " + appId + " in tenant id: " + + tenantId); + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Authorized APIs found in cache for application id: " + appId + " in tenant id: " + + tenantId); + } + } + return authorizedAPI; + } + + private void addToCache(String appId, String apiId, AuthorizedAPI authorizedAPI, int tenantId) { + + if (StringUtils.isNotBlank(appId)) { + AuthorizedAPICacheKey cacheKey = new AuthorizedAPICacheKey(appId, apiId); + AuthorizedAPICacheEntry cacheEntry = new AuthorizedAPICacheEntry(authorizedAPI); + authorizedAPICache.addToCache(cacheKey, cacheEntry, tenantId); + } else { + LOG.debug("Application id is empty. Cannot add authorized APIs to cache."); + } + } + + private void clearAuthorizedAPIFromCache(String appId, String apiId, int tenantId) { + + if (StringUtils.isNotBlank(appId)) { + AuthorizedAPICacheKey cacheKey = new AuthorizedAPICacheKey(appId, apiId); + authorizedAPICache.clearCacheEntry(cacheKey, tenantId); + } else { + LOG.debug("Application id is empty. Cannot clear authorized APIs from cache."); + } + } +}