diff --git a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java
index b8a5024689d..2933874c2fa 100644
--- a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java
+++ b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCPathCache.java
@@ -449,6 +449,74 @@ public String getPath(AbstractConnection conn, int id) throws SQLException {
}
}
+ /**
+ * Method to get the path of a given path id.
+ *
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param conn the database connection to use.
+ * @param id the path.
+ *
+ * @return the path corresponding to the given path id.
+ * @throws SQLException if an error occurs while obtaining the path id.
+ */
+ public String getPathOnRead(AbstractConnection conn, int id) throws SQLException {
+
+ String connectionId;
+ if (conn != null && conn.getConnectionId() != null) {
+ connectionId = conn.getConnectionId();
+ } else {
+ throw new SQLException("Connection is null");
+ }
+ RegistryCacheKey key =
+ RegistryUtils.buildRegistryCacheKey(connectionId,
+ CurrentSession.getTenantId(), Integer.toString(id));
+ Cache cache = getCache();
+ RegistryCacheEntry result = cache.get(key);
+ if (result != null) {
+ return result.getPath();
+ } else {
+ PreparedStatement ps = null;
+ ResultSet results = null;
+ try {
+ String sql =
+ "SELECT REG_PATH_VALUE FROM REG_PATH WHERE REG_PATH_ID=? AND REG_TENANT_ID=?";
+
+ ps = conn.prepareStatement(sql);
+ ps.setInt(1, id);
+ ps.setInt(2, CurrentSession.getTenantId());
+
+ results = ps.executeQuery();
+ if (results.next()) {
+ result = new RegistryCacheEntry(results.getString(DatabaseConstants.PATH_VALUE_FIELD));
+ cache.putOnRead(key, result);
+ return result.getPath();
+ }
+
+ } finally {
+ try {
+ try {
+ if (results != null) {
+ results.close();
+ }
+ } finally {
+ if (ps != null) {
+ ps.close();
+ }
+ }
+ } catch (SQLException ex) {
+ String msg = RegistryConstants.RESULT_SET_PREPARED_STATEMENT_CLOSE_ERROR;
+ log.error(msg, ex);
+ }
+ }
+ return null;
+ }
+ }
+
/**
* Method to get the path id of a given path.
*
@@ -539,6 +607,102 @@ public int getPathID(AbstractConnection conn, String path) throws SQLException {
return -1;
}
+ /**
+ * Method to get the path id of a given path.
+ *
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param conn the database connection to use.
+ * @param path the path.
+ *
+ * @return the path id corresponding to the given path.
+ * @throws SQLException if an error occurs while obtaining the path id.
+ */
+ public int getPathIDOnRead(AbstractConnection conn, String path) throws SQLException {
+ String connectionId = null;
+ if (conn != null && conn.getConnectionId() != null) {
+ connectionId = conn.getConnectionId();
+ } else {
+ throw new SQLException("Connection is null");
+ }
+ RegistryCacheKey key =
+ RegistryUtils.buildRegistryCacheKey(connectionId,
+ CurrentSession.getTenantId(), path);
+ Cache cache = getCache();
+ RegistryCacheEntry result = (RegistryCacheEntry) cache.get(key);
+
+ // TODO: FIX: Path Cache should only be updated if the key yields a valid registry path.
+ // Recently, this has lead to:
+ // org.wso2.carbon.registry.core.exceptions.RegistryException: Failed to add resource to
+ // path /_system. Cannot add or update a child row: a foreign key constraint fails
+ // (`stratos_db`.`REG_RESOURCE`, CONSTRAINT `REG_RESOURCE_FK_BY_PATH_ID` FOREIGN KEY
+ // (`REG_PATH_ID`, `REG_TENANT_ID`) REFERENCES `REG_PATH` (`REG_PATH_ID`, `REG_TENANT_ID`))
+ //
+ // when registry separation is enabled. Thus, we need a better solution to address this, and
+ // a better key which also contains the name of the DB in use. Un-comment the below once
+ // this has been done.
+ //
+ // IMPORTANT: Never remove this comment until we are certain that the current fix is
+ // actually working - Senaka.
+
+ if (result != null) {
+ return result.getPathId();
+ } else {
+ ResultSet results = null;
+ PreparedStatement ps = null;
+ try {
+ String sql =
+ "SELECT REG_PATH_ID FROM REG_PATH WHERE REG_PATH_VALUE=? " +
+ "AND REG_TENANT_ID=?";
+ ps = conn.prepareStatement(sql);
+ ps.setString(1, path);
+ ps.setInt(2, CurrentSession.getTenantId());
+ results = ps.executeQuery();
+
+ int pathId;
+ if (results.next()) {
+ pathId = results.getInt(DatabaseConstants.PATH_ID_FIELD);
+
+ if (pathId > 0) {
+ RegistryCacheEntry e = new RegistryCacheEntry(pathId);
+ cache.putOnRead(key, e);
+ return pathId;
+ }
+ } else {
+ //not found . set -1 in the cache as well for the path
+ RegistryCacheEntry e = new RegistryCacheEntry(-1);
+ cache.putOnRead(key, e);
+ }
+
+ } catch (SQLException e) {
+ String msg = "Failed to retrieving resource from " + path + ". " + e.getMessage();
+ log.error(msg, e);
+ throw e;
+ } finally {
+ try {
+ try {
+ if (results != null) {
+ results.close();
+ }
+ } finally {
+ if (ps != null) {
+ ps.close();
+ }
+ }
+ } catch (SQLException e) {
+ String msg = RegistryConstants.RESULT_SET_PREPARED_STATEMENT_CLOSE_ERROR +
+ e.getMessage();
+ log.error(msg, e);
+ }
+ }
+ }
+ return -1;
+ }
+
/**
* Retrieves the existing path ID after rolling back an aborted transaction
* caused by a constraint violation during concurrent path creation.
diff --git a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCResourceDAO.java b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCResourceDAO.java
index cbd7ce6e60a..9aaa1846ff5 100644
--- a/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCResourceDAO.java
+++ b/core/org.wso2.carbon.registry.core/src/main/java/org/wso2/carbon/registry/core/jdbc/dao/JDBCResourceDAO.java
@@ -72,7 +72,7 @@ public ResourceIDImpl getResourceID(String path) throws RegistryException {
try {
// step1: need to check whether it is a resource or collection while retrieving path id
JDBCPathCache pathCache = JDBCPathCache.getPathCache();
- int pathID = pathCache.getPathID(conn, path);
+ int pathID = pathCache.getPathIDOnRead(conn, path);
boolean isCollection = true;
if (pathID == -1) {
isCollection = false;
@@ -86,7 +86,7 @@ public ResourceIDImpl getResourceID(String path) throws RegistryException {
String parentPath = RegistryUtils.getParentPath(path);
resourceName = RegistryUtils.getResourceName(path);
- pathID = pathCache.getPathID(conn, parentPath);
+ pathID = pathCache.getPathIDOnRead(conn, parentPath);
}
if (pathID != -1) {
@@ -118,7 +118,7 @@ public ResourceIDImpl getResourceID(String path, boolean isCollection)
int pathID;
String resourceName = null;
if (isCollection) {
- pathID = JDBCPathCache.getPathCache().getPathID(conn, path);
+ pathID = JDBCPathCache.getPathCache().getPathIDOnRead(conn, path);
} else {
// we have to re-get the path id for the parent path..
String parentPath;
@@ -129,7 +129,7 @@ public ResourceIDImpl getResourceID(String path, boolean isCollection)
}
resourceName = RegistryUtils.getResourceName(path);
- pathID = JDBCPathCache.getPathCache().getPathID(conn, parentPath);
+ pathID = JDBCPathCache.getPathCache().getPathIDOnRead(conn, parentPath);
}
if (pathID != -1) {
@@ -2202,6 +2202,26 @@ public String getPathFromId(int pathId) throws RegistryException {
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ */
+ public String getPathFromIdOnRead(int pathId) throws RegistryException {
+
+ try {
+ return JDBCPathCache.getPathCache()
+ .getPathOnRead(JDBCDatabaseTransaction.getConnection(), pathId);
+ } catch (SQLException e) {
+ String msg = "Failed to get the path for the path id " + pathId + ". " + e.getMessage();
+ log.error(msg, e);
+ throw new RegistryException(msg, e);
+ }
+ }
+
public String getPath(long version) throws RegistryException {
ResourceDO resourceDO = getResourceDO(version);
if (resourceDO == null) {
@@ -2212,7 +2232,7 @@ public String getPath(long version) throws RegistryException {
public String getPath(int pathId, String resourceName, boolean checkExistence)
throws RegistryException {
- String pathCollection = getPathFromId(pathId);
+ String pathCollection = getPathFromIdOnRead(pathId);
if (pathCollection == null) {
return null;
}
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/AuthorizationCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/AuthorizationCache.java
index 3861a6710e9..acb8f44e631 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/AuthorizationCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/AuthorizationCache.java
@@ -123,6 +123,39 @@ public void addToCache(String serverId, int tenantId, String userName,
cache.put(key, cacheEntry);
}
+ /**
+ * Add a cache entry during a READ operation.
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * Adds an entry to the cache. Says whether given user or role is authorized
+ * or not.
+ *
+ * @param serverId unique identifier for carbon server instance
+ * @param userName Name of the user which was authorized. If this is null
+ * roleName must not be null.
+ * @param resourceId The resource on which user/role was authorized.
+ * @param action The action which user/role authorized for.
+ * @param isAuthorized Whether role/user was authorized or not. true for
+ * authorized else false.
+ */
+ public void addToCacheOnRead(String serverId, int tenantId, String userName,
+ String resourceId, String action, boolean isAuthorized) {
+
+ if (!isCaseSensitiveUsername(userName, tenantId)) {
+ userName = userName.toLowerCase();
+ }
+
+ Cache cache = this.getAuthorizationCache();
+ if (isCacheNull(cache)) {
+ return;
+ }
+ AuthorizationKey key = new AuthorizationKey(serverId, tenantId, userName, resourceId, action);
+ AuthorizeCacheEntry cacheEntry = new AuthorizeCacheEntry(isAuthorized);
+ cache.putOnRead(key, cacheEntry);
+ }
+
/**
* Looks up from cache whether given user is already authorized. If an entry
* is not found throws an exception.
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/JDBCAuthorizationManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/JDBCAuthorizationManager.java
index b10bc60a7cd..d71f5c2750b 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/JDBCAuthorizationManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/authorization/JDBCAuthorizationManager.java
@@ -287,7 +287,7 @@ public boolean isUserAuthorized(String userName, String resourceId, String actio
null, null,
PermissionTreeUtil.toComponenets(resourceId));
if (sr.getLastNodeAllowedAccess()) {
- authorizationCache.addToCache(cacheIdentifier, tenantId, userName, resourceId, action, true);
+ authorizationCache.addToCacheOnRead(cacheIdentifier, tenantId, userName, resourceId, action, true);
return true;
}
@@ -370,7 +370,7 @@ public boolean isUserAuthorized(String userName, String resourceId, String actio
}
//need to add the authorization decision taken by role based permission
- authorizationCache.addToCache(cacheIdentifier, this.tenantId, userName, resourceId, action,
+ authorizationCache.addToCacheOnRead(cacheIdentifier, this.tenantId, userName, resourceId, action,
userAllowed);
if (log.isDebugEnabled()) {
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/AbstractUserStoreManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/AbstractUserStoreManager.java
index 05b0b02c213..8778a932d52 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/AbstractUserStoreManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/AbstractUserStoreManager.java
@@ -8504,7 +8504,7 @@ private UserStore getUserStoreInternalWithId(String userId) throws UserStoreExce
// in our local database. If so we can use that.
String domainName = null;
if (userUniqueIDDomainResolver != null) {
- domainName = userUniqueIDDomainResolver.getDomainForUserId(userId, tenantId);
+ domainName = userUniqueIDDomainResolver.getDomainForUserIdOnRead(userId, tenantId);
}
// If we don't have the domain name in our side, then we have to iterate through each user store and find
@@ -9499,6 +9499,23 @@ protected void addToUserRolesCache(int tenantID, String userName, String[] roleL
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ */
+ protected void addToUserRolesCacheOnRead(int tenantID, String userName, String[] roleList) {
+
+ if (userRolesCache != null) {
+ String usernameWithDomain = UserCoreUtil.addDomainToName(userName, getMyDomainName());
+ String[] rolesWithDomain = UserCoreUtil.addDomainToNames(roleList, getMyDomainName());
+ userRolesCache.addToCacheOnRead(cacheIdentifier, tenantID, usernameWithDomain, rolesWithDomain);
+ }
+ }
+
protected void clearUserRolesCache(String userIdentifier) {
String usernameWithDomain = UserCoreUtil.addDomainToName(userIdentifier, getMyDomainName());
@@ -9825,7 +9842,7 @@ private List getUserRolesWithID(String userID, String filter) throws Use
// Add to user role cache uisng username.
String username = getUserNameFromUserID(userID);
if (username != null) {
- addToUserRolesCache(this.tenantId, username, roleList);
+ addToUserRolesCacheOnRead(this.tenantId, username, roleList);
}
return Arrays.asList(roleList);
}
@@ -9889,7 +9906,7 @@ private String[] getUserRoles(String username, String filter) throws UserStoreEx
}
}
}
- addToUserRolesCache(this.tenantId, username, roleList);
+ addToUserRolesCacheOnRead(this.tenantId, username, roleList);
return roleList;
}
@@ -11246,8 +11263,8 @@ public String[] getUserList(Condition condition, String domain, String profileNa
if (((AbstractUserStoreManager) secManager).isUniqueUserIdEnabled()) {
UniqueIDPaginatedSearchResult users = ((AbstractUserStoreManager) secManager).doGetUserListWithID(condition,
profileName, limit, offset, sortBy, sortOrder);
- addUsersToUserIdCache(users.getUsers());
- addUsersToUserNameCache(users.getUsers());
+ addUsersToUserIdCacheOnRead(users.getUsers());
+ addUsersToUserNameCacheOnRead(users.getUsers());
filteredUsers = users.getUsers().stream().map(User::getUsername).toArray(String[]::new);
} else {
PaginatedSearchResult users = ((AbstractUserStoreManager) secManager).doGetUserList(condition,
@@ -12360,7 +12377,7 @@ private AuthenticationResult authenticateInternalWithID(String preferredUserName
if (status) {
String userID = userUniqueIDManger.getUniqueId(users.get(0), this);
User user = userUniqueIDManger.
- getUser(userID, this, abstractUserStoreManager.getMyDomainName());
+ getUserOnRead(userID, this, abstractUserStoreManager.getMyDomainName());
user.setTenantDomain(getTenantDomain(tenantId));
authenticationResult.setAuthenticatedUser(user);
} else {
@@ -12614,7 +12631,7 @@ private AuthenticationResult authenticateInternalWithID(String userID, Object cr
.doAuthenticateWithID(userID, credential);
} else {
User user = userUniqueIDManger
- .getUser(userID, (AbstractUserStoreManager) abstractUserStoreManager);
+ .getUserOnRead(userID, (AbstractUserStoreManager) abstractUserStoreManager);
boolean status = ((AbstractUserStoreManager) abstractUserStoreManager)
.doAuthenticate(user.getUsername(), credential);
if (status) {
@@ -12806,7 +12823,7 @@ public User getUserWithID(String userID, String[] requestedClaims, String profil
if (isUniqueIdEnabled) {
isUserExists = doCheckExistingUserWithID(userID);
} else {
- user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
isUserExists = user != null;
}
@@ -12827,7 +12844,7 @@ public User getUserWithID(String userID, String[] requestedClaims, String profil
// If unique id feature is not enabled, we have to call the legacy methods.
if (!isUniqueUserIdEnabledInUserStore(userStore)) {
if (user == null) {
- user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
}
} else {
user = getUserFromID(userID, requestedClaims, userStore.getDomainName(), profileName);
@@ -12891,7 +12908,7 @@ public boolean isExistingUserWithID(String userID) throws UserStoreException {
// If unique id feature is not enabled, we have to call the legacy methods.
if (!isUniqueUserIdEnabledInUserStore(userStore)) {
- User user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ User user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
if (user == null) {
return false;
}
@@ -13186,7 +13203,7 @@ public final String getUserClaimValueWithID(String userID, String claim, String
if (isUniqueIdEnabled) {
isUserExists = doCheckExistingUserWithID(userID);
} else{
- user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
isUserExists = user != null;
}
@@ -13284,9 +13301,9 @@ public final Map getUserClaimValuesWithID(String userID, String[
isUserExists = doCheckExistingUserWithID(userID);
} else {
if (userStore != null && StringUtils.isNotBlank(userStore.getDomainName())) {
- user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
} else {
- user = userUniqueIDManger.getUser(userID, this);
+ user = userUniqueIDManger.getUserOnRead(userID, this);
}
isUserExists = user != null;
}
@@ -13381,7 +13398,7 @@ public final List getUserClaimValuesWithID(String userID, String profileN
// If unique id feature is not enabled, we have to call the legacy methods.
if (!isUniqueIdEnabled) {
- User user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ User user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
return Arrays.asList(getUserClaimValues(user.getDomainQualifiedUsername(), profileName));
}
@@ -13808,7 +13825,7 @@ public User getUser(String userID, String userName) throws UserStoreException {
user.setUserStoreDomain(domain);
if (StringUtils.isNotEmpty(userID) &&
- StringUtils.isEmpty(userUniqueIDDomainResolver.getDomainForUserId(userID, tenantId))) {
+ StringUtils.isEmpty(userUniqueIDDomainResolver.getDomainForUserIdOnRead(userID, tenantId))) {
userUniqueIDDomainResolver.setDomainForUserIdIfNotExists(userID, domain, tenantId);
}
return user;
@@ -13893,8 +13910,8 @@ public String getUserIDFromUserName(String userName) throws UserStoreException {
log.debug("User is not available in cache or database.");
return null;
}
- addToUserIDCache(userID, userName, userStore);
- addToUserNameCache(userID, userName, userStore);
+ addToUserIDCacheOnRead(userID, userName, userStore);
+ addToUserNameCacheOnRead(userID, userName, userStore);
return userID;
}
@@ -13903,8 +13920,8 @@ public String getUserIDFromUserName(String userName) throws UserStoreException {
userStore.getDomainName(), null);
if (claims != null && claims.size() == 1) {
userID = claims.get(USER_ID_CLAIM_URI);
- addToUserIDCache(userID, userName, userStore);
- addToUserNameCache(userID, userName, userStore);
+ addToUserIDCacheOnRead(userID, userName, userStore);
+ addToUserNameCacheOnRead(userID, userName, userStore);
return userID;
}
}
@@ -13944,7 +13961,7 @@ protected String doGetUserNameFromUserID(String userID) throws UserStoreExceptio
}
return doGetUserNameFromUserIDWithID(userID);
}
- User user = userUniqueIDManger.getUser(userID, this);
+ User user = userUniqueIDManger.getUserOnRead(userID, this);
return user.getUsername();
}
@@ -13966,7 +13983,7 @@ public String getUserNameFromUserID(String userID) throws UserStoreException {
if (isUniqueUserIdEnabledInUserStore(userStore)) {
return getUserNameFromCurrentUserStore(userID, userStore);
} else {
- User user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ User user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
if (user == null) {
if (log.isDebugEnabled()) {
log.debug(String.format("User with user id %s is not available in cache or database.", userID));
@@ -13997,8 +14014,8 @@ private String getUserNameFromCurrentUserStore(String userID, UserStore userStor
}
return null;
}
- addToUserNameCache(userID, userName, userStore);
- addToUserIDCache(userID, userName, userStore);
+ addToUserNameCacheOnRead(userID, userName, userStore);
+ addToUserIDCacheOnRead(userID, userName, userStore);
}
return UserCoreUtil.addDomainToName(userName, userStore.getDomainName());
}
@@ -14043,6 +14060,13 @@ private void addToUserIDCache(String userID, String userName, UserStore userStor
RESOLVE_USER_ID_FROM_USER_NAME_CACHE_NAME, tenantId);
}
+ private void addToUserIDCacheOnRead(String userID, String userName, UserStore userStore) {
+
+ UserIdResolverCache.getInstance()
+ .addToCacheOnRead(UserCoreUtil.addDomainToName(userName, userStore.getDomainName()), userID,
+ RESOLVE_USER_ID_FROM_USER_NAME_CACHE_NAME, tenantId);
+ }
+
private void addToUserNameCache(String userID, String userName, UserStore userStore) {
UserIdResolverCache.getInstance()
@@ -14050,6 +14074,13 @@ private void addToUserNameCache(String userID, String userName, UserStore userSt
RESOLVE_USER_NAME_FROM_USER_ID_CACHE_NAME, tenantId);
}
+ private void addToUserNameCacheOnRead(String userID, String userName, UserStore userStore) {
+
+ UserIdResolverCache.getInstance()
+ .addToCacheOnRead(userID, UserCoreUtil.addDomainToName(userName, userStore.getDomainName()),
+ RESOLVE_USER_NAME_FROM_USER_ID_CACHE_NAME, tenantId);
+ }
+
private void clearUserIDResolverCache(String userID, String userName, UserStore userStore) {
UserIdResolverCache.getInstance()
@@ -14073,6 +14104,16 @@ private void addUsersToUserIdCache(List userList) {
}
}
+ private void addUsersToUserIdCacheOnRead(List userList) {
+
+ UserIdResolverCache userIdResolverCacheInstance = UserIdResolverCache.getInstance();
+ for (User user : userList) {
+ userIdResolverCacheInstance.addToCacheOnRead(
+ UserCoreUtil.addDomainToName(user.getUsername(), user.getUserStoreDomain()), user.getUserID(),
+ RESOLVE_USER_ID_FROM_USER_NAME_CACHE_NAME, tenantId);
+ }
+ }
+
private void addUsersToUserNameCache(List userList) {
UserIdResolverCache userIdResolverCacheInstance = UserIdResolverCache.getInstance();
@@ -14083,6 +14124,16 @@ private void addUsersToUserNameCache(List userList) {
}
}
+ private void addUsersToUserNameCacheOnRead(List userList) {
+
+ UserIdResolverCache userIdResolverCacheInstance = UserIdResolverCache.getInstance();
+ for (User user : userList) {
+ userIdResolverCacheInstance.addToCacheOnRead(
+ user.getUserID(), UserCoreUtil.addDomainToName(user.getUsername(), user.getUserStoreDomain()),
+ RESOLVE_USER_NAME_FROM_USER_ID_CACHE_NAME, tenantId);
+ }
+ }
+
/**
* provides the userName of the given user.
*
@@ -16478,7 +16529,7 @@ public boolean isUserInRoleWithID(String userID, String roleName) throws UserSto
// #################### Domain Name Free Zone Starts Here ################################
// If unique id feature is not enabled, we have to call the legacy methods.
if (!isUniqueUserIdEnabledInUserStore(userStore)) {
- User user = userUniqueIDManger.getUser(userID, this, userStore.getDomainName());
+ User user = userUniqueIDManger.getUserOnRead(userID, this, userStore.getDomainName());
// If we don't have a record for this user, let's try to call directly using the user id.
if (user == null) {
return false;
@@ -16883,8 +16934,8 @@ public List getUserListWithID(Condition condition, String domain, String p
User user = getUser(getUserIDFromUserName(username), username);
user.setUserStoreDomain(UserCoreUtil.extractDomainFromName(username));
identityClaimFilteredUsers.add(user);
- addToUserIDCache(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
- addToUserNameCache(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
+ addToUserIDCacheOnRead(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
+ addToUserNameCacheOnRead(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
}
return identityClaimFilteredUsers;
}
@@ -17193,8 +17244,8 @@ private List getFilteredUsers(Condition condition, String profileName, int
if (isUniqueUserIdEnabled(secManager)) {
UniqueIDPaginatedSearchResult users = ((AbstractUserStoreManager) secManager)
.doGetUserListWithID(condition, profileName, limit, offset, sortBy, sortOrder);
- addUsersToUserIdCache(users.getUsers());
- addUsersToUserNameCache(users.getUsers());
+ addUsersToUserIdCacheOnRead(users.getUsers());
+ addUsersToUserNameCacheOnRead(users.getUsers());
filteredUsers = users.getUsers();
} else {
PaginatedSearchResult users = ((AbstractUserStoreManager) secManager)
@@ -18451,8 +18502,8 @@ public List getUserListOfGroup(String groupID, int limit, int offset, Stri
UniqueIDPaginatedSearchResult users = this.doGetUserListWithID(condition,
UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, resolveUserListLimit(limit), offset,
sortBy, sortOrder);
- addUsersToUserIdCache(users.getUsers());
- addUsersToUserNameCache(users.getUsers());
+ addUsersToUserIdCacheOnRead(users.getUsers());
+ addUsersToUserNameCacheOnRead(users.getUsers());
filteredUsers = users.getUsers();
} else {
PaginatedSearchResult users = this.doGetUserList(condition, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME,
@@ -20073,6 +20124,26 @@ public UserUniqueIDDomainResolver getUserUniqueIDDomainResolver() {
return userUniqueIDDomainResolver;
}
+ /**
+ * Add userID and username to UserID cache
+ *
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param userID User id.
+ * @param userName Username.
+ * @param userStoreDomain User store Domain.
+ */
+ protected void addToUserIDCacheOnRead(String userID, String userName, String userStoreDomain) {
+
+ UserIdResolverCache.getInstance()
+ .addToCacheOnRead(UserCoreUtil.addDomainToName(userName, userStoreDomain), userID,
+ RESOLVE_USER_ID_FROM_USER_NAME_CACHE_NAME, tenantId);
+ }
+
/**
* Retrieves the user count that belongs to a given group.
*
@@ -20134,6 +20205,26 @@ protected boolean isCircuitBreakerEnabledAndOpen() throws UserStoreException {
return false;
}
+ /**
+ * Add userID and username to Username cache
+ *
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param userID User id.
+ * @param userName Username.
+ * @param userStoreDomain User store Domain.
+ */
+ protected void addToUserNameCacheOnRead(String userID, String userName, String userStoreDomain) {
+
+ UserIdResolverCache.getInstance()
+ .addToCacheOnRead(userID, UserCoreUtil.addDomainToName(userName, userStoreDomain),
+ RESOLVE_USER_NAME_FROM_USER_ID_CACHE_NAME, tenantId);
+ }
+
/**
* Merge all identity claim filtered usernames and non identity claim filtered usernames in an efficient manner.
*
@@ -20210,8 +20301,8 @@ private List getUserListByUsernames(List usernames) throws UserSto
User user = getUser(getUserIDFromUserName(username), username);
user.setUserStoreDomain(UserCoreUtil.extractDomainFromName(username));
userList.add(user);
- addToUserIDCache(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
- addToUserNameCache(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
+ addToUserIDCacheOnRead(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
+ addToUserNameCacheOnRead(user.getUserID(), user.getUsername(), user.getUserStoreDomain());
}
return userList;
}
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/DefaultRealmService.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/DefaultRealmService.java
index ef8f1d19593..9818e5735d9 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/DefaultRealmService.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/DefaultRealmService.java
@@ -188,7 +188,7 @@ private org.wso2.carbon.user.api.UserRealm getTenantUserRealmInternal(int tenant
userRealm = getCachedUserRealm(tenantId);
if (userRealm == null) {
userRealm = initializeRealm(tenantRealmConfig, tenantId);
- realmCache.addToCache(tenantId, PRIMARY_TENANT_REALM, userRealm);
+ realmCache.addToCacheOnRead(tenantId, PRIMARY_TENANT_REALM, userRealm);
}
}
}
@@ -256,7 +256,7 @@ private UserRealm getUserRealmInternal(RealmConfiguration tenantRealmConfig) thr
userRealm = (UserRealm) realmCache.getUserRealm(tenantId, PRIMARY_TENANT_REALM);
if (userRealm == null) {
userRealm = initializeRealm(tenantRealmConfig, tenantId);
- realmCache.addToCache(tenantId, PRIMARY_TENANT_REALM, userRealm);
+ realmCache.addToCacheOnRead(tenantId, PRIMARY_TENANT_REALM, userRealm);
}
}
}
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/GroupIdResolverCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/GroupIdResolverCache.java
index 8e06f0f8066..cfa4baa4fdf 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/GroupIdResolverCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/GroupIdResolverCache.java
@@ -86,6 +86,26 @@ public void addToCache(String key, String entry, String cacheName, int tenantId)
}
}
+ public void addToCacheOnRead(String key, String entry, String cacheName, int tenantId) {
+
+ if (validateAddToCacheRequest(key, entry, cacheName)) {
+ return;
+ }
+ try {
+ startTenantFlow(tenantId);
+ Cache cache = getGroupIdResolverCache(cacheName);
+ if (cache != null && !cache.containsKey(key)) {
+ cache.putOnRead(key, entry);
+ if (log.isDebugEnabled()) {
+ log.debug(String.format("Cache: %s which is under %s, added the entry: %s for the key: " +
+ "%s successfully", cacheName, GROUP_ID_RESOLVER_CACHE_MANAGER, entry, key));
+ }
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/RealmCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/RealmCache.java
index 5f6db448d63..4dcb77e6abd 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/RealmCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/RealmCache.java
@@ -102,6 +102,20 @@ public void addToCache(int tenantId, String realmName, UserRealm userRealm) {
new RealmCacheEntry(userRealm));
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ */
+ public void addToCacheOnRead(int tenantId, String realmName, UserRealm userRealm) {
+
+ instance.addToCacheOnRead(new RealmCacheKey(tenantId, realmName),
+ new RealmCacheEntry(userRealm));
+ }
+
/**
* Clear the cache entry
*
@@ -139,6 +153,32 @@ public void addToCache(RealmCacheKey key, RealmCacheEntry entry) {
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param key Key which cache entry is indexed.
+ * @param entry Actual object where cache entry is placed.
+ */
+ public void addToCacheOnRead(RealmCacheKey key, RealmCacheEntry entry) {
+
+ try {
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ carbonContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID);
+ carbonContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
+ Cache cache = getRealmCache();
+ if (!cache.containsKey(key)) {
+ cache.putOnRead(key, entry);
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserIdResolverCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserIdResolverCache.java
index 87150575aca..3370649fe66 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserIdResolverCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserIdResolverCache.java
@@ -82,6 +82,36 @@ public void addToCache(String key, String entry, String cacheName, int tenantId)
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param key Key which cache entry is indexed.
+ * @param entry Actual object where cache entry is placed.
+ * @param cacheName Name of the cache.
+ * @param tenantId Tenant ID.
+ */
+ public void addToCacheOnRead(String key, String entry, String cacheName, int tenantId) {
+
+ if (validateAddToCacheRequest(key, entry, cacheName)) return;
+ try {
+ startTenantFlow(tenantId);
+ Cache cache = UserIdResolverCache(cacheName);
+ if (cache != null && !cache.containsKey(key)) {
+ cache.putOnRead(key, entry);
+ if (log.isDebugEnabled()) {
+ log.debug("Cache: " + cacheName + " which is under " + USER_ID_RESOLVER_CACHE_MANAGER + "," +
+ "added the entry: " + entry + " for the key: " + key + " successfully");
+ }
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserRolesCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserRolesCache.java
index 574273b7ddd..68ed70b9182 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserRolesCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserRolesCache.java
@@ -18,7 +18,13 @@
*/
package org.wso2.carbon.user.core.common;
-import org.apache.commons.lang.StringUtils;
+import java.util.concurrent.TimeUnit;
+
+import javax.cache.Cache;
+import javax.cache.CacheConfiguration;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.caching.impl.CachingConstants;
@@ -29,12 +35,6 @@
import org.wso2.carbon.user.core.internal.UserStoreMgtDSComponent;
import org.wso2.carbon.user.core.util.UserCoreUtil;
-import javax.cache.Cache;
-import javax.cache.CacheConfiguration;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import java.util.concurrent.TimeUnit;
-
public class UserRolesCache {
private static final String USER_ROLES_CACHE_MANAGER = "USER_ROLES_CACHE_MANAGER";
@@ -126,6 +126,40 @@ public void addToCache(String serverId, int tenantId, String userName, String[]
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ */
+ public void addToCacheOnRead(String serverId, int tenantId, String userName, String[] userRoleList) {
+
+ try {
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ carbonContext.setTenantId(tenantId, true);
+
+ Cache cache = this.getUserRolesCache();
+ //check for null
+ if (isCacheNull(cache)) {
+ return;
+ }
+ if (!isCaseSensitiveUsername(userName, tenantId)) {
+ userName = userName.toLowerCase();
+ }
+ //create cache key
+ UserRolesCacheKey userRolesCacheKey = new UserRolesCacheKey(serverId, tenantId, userName);
+ //create cache entry
+ UserRolesCacheEntry userRolesCacheEntry = new UserRolesCacheEntry(userRoleList);
+ //add to cache
+ cache.putOnRead(userRolesCacheKey, userRolesCacheEntry);
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
//get roles list of user
public String[] getRolesListOfUser(String serverId, int tenantId, String userName) {
try {
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDDomainResolver.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDDomainResolver.java
index 0da4b9aeb8d..8bdfcfebbe6 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDDomainResolver.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDDomainResolver.java
@@ -151,6 +151,77 @@ public String getDomainForUserId(String userId, int tenantId) throws UserStoreEx
}
}
+ /**
+ * Get the domain for the given user id.
+ *
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param userId Unique user id of the user.
+ * @return Domain related to this user. Null if no domain name recorded.
+ * @throws UserStoreException If error occurred.
+ */
+ public String getDomainForUserIdOnRead(String userId, int tenantId) throws UserStoreException {
+
+ try {
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ carbonContext.setTenantId(tenantId, true);
+ CacheManager cacheManager = Caching.getCacheManagerFactory()
+ .getCacheManager(UNIQUE_ID_DOMAIN_RESOLVER_CACHE_MANGER_NAME);
+ Cache uniqueIdDomainCache = cacheManager.getCache(UNIQUE_ID_DOMAIN_RESOLVER_CACHE_NAME);
+
+ if (StringUtils.isEmpty(userId)) {
+ throw new UserStoreException("User Id cannot be empty or null.");
+ }
+
+ // Read the cache first.
+ String domainName = uniqueIdDomainCache.get(userId);
+
+ if (StringUtils.isBlank(domainName)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Cache miss for user id: " + userId + " searching from the database.");
+ }
+
+ // Read the domain name from the Database;
+ domainName = getDomainFromDB(userId, tenantId);
+
+ // Update the cache.
+ if (StringUtils.isNotBlank(domainName)) {
+ uniqueIdDomainCache.putOnRead(userId, domainName);
+ if (log.isDebugEnabled()) {
+ log.debug("Domain with name: " + domainName + " retrieved from the database.");
+ }
+ }
+ }
+ if (StringUtils.isNotBlank(domainName) &&
+ !UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME.equals(domainName)) {
+ RealmService realmService = UserCoreUtil.getRealmService();
+ UserStoreManager userStoreManager = null;
+ if (realmService != null) {
+ userStoreManager = ((AbstractUserStoreManager) realmService.getTenantUserRealm(tenantId)
+ .getUserStoreManager()).getSecondaryUserStoreManager(domainName);
+ }
+ if (userStoreManager == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Entry is outdated. Clearing cache and the database entries.");
+ }
+ deleteDomainFromDB(domainName, userId, tenantId);
+ clearUserIDResolverCache(userId, tenantId);
+ domainName = null;
+ }
+ }
+ return domainName;
+ } catch (org.wso2.carbon.user.api.UserStoreException e) {
+ throw new UserStoreException("Tenant user realm cannot be resolved for tenantId: " + tenantId, e);
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Set the domain for the user id. This will update the domain name if there is already a record available.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDManger.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDManger.java
index 9b13564d8a7..eff823afe96 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDManger.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/common/UserUniqueIDManger.java
@@ -106,8 +106,65 @@ public User getUser(String uniqueId, AbstractUserStoreManager userStoreManager,
return null;
}
userName = usernames[0];
- addToUserNameCache(uniqueId, userName);
- addToUserIDCache(uniqueId, userName);
+ addToUserNameCacheOnRead(uniqueId, userName);
+ addToUserIDCacheOnRead(uniqueId, userName);
+ }
+
+ User user = new User();
+ user.setUserID(uniqueId);
+ user.setUsername(UserCoreUtil.removeDomainFromName(userName));
+ user.setUserStoreDomain(UserCoreUtil.extractDomainFromName(userName));
+ return user;
+ }
+
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * Get user from unique id.
+ * @param uniqueId User's unique id.
+ * @return User object if user presents for the unique id. Null otherwise.
+ */
+ public User getUserOnRead(String uniqueId, AbstractUserStoreManager userStoreManager)
+ throws UserStoreException {
+
+ return getUserOnRead(uniqueId, userStoreManager, null);
+ }
+
+ /**
+ * Get user from unique id with user store domain present.
+ * @param uniqueId User's unique id.
+ * @param userStoreManager User store manager instance.
+ * @param userStoreDomain User store domain of the user.
+ * @return User object if user presents for the unique id. Null otherwise.
+ */
+ public User getUserOnRead(String uniqueId, AbstractUserStoreManager userStoreManager, String userStoreDomain)
+ throws UserStoreException {
+
+ String userName = getFromUserNameCache(uniqueId);
+ if (StringUtils.isEmpty(userName)) {
+ String[] usernames;
+ if (StringUtils.isNotEmpty(userStoreDomain)) {
+ usernames = userStoreManager.getUserList(UserCoreClaimConstants.USER_ID_CLAIM_URI,
+ UserCoreUtil.addDomainToName(uniqueId, userStoreDomain), null);
+ } else {
+ usernames = userStoreManager.getUserList(UserCoreClaimConstants.USER_ID_CLAIM_URI,
+ uniqueId, null);
+ }
+
+ if (usernames.length > 1) {
+ throw new UserStoreException("More than one user presents with the same user unique id.");
+ }
+
+ if (usernames.length == 0) {
+ return null;
+ }
+ userName = usernames[0];
+ addToUserNameCacheOnRead(uniqueId, userName);
+ addToUserIDCacheOnRead(uniqueId, userName);
}
User user = new User();
@@ -124,6 +181,23 @@ private void addToUserIDCache(String userID, String userName) {
RESOLVE_USER_UNIQUE_ID_FROM_USER_NAME_CACHE_NAME, SUPER_TENANT_ID);
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param userID
+ * @param userName
+ */
+ private void addToUserIDCacheOnRead(String userID, String userName) {
+
+ UserIdResolverCache.getInstance()
+ .addToCacheOnRead(userName, userID,
+ RESOLVE_USER_UNIQUE_ID_FROM_USER_NAME_CACHE_NAME, SUPER_TENANT_ID);
+ }
+
private void addToUserNameCache(String userID, String userName) {
UserIdResolverCache.getInstance()
@@ -131,6 +205,23 @@ private void addToUserNameCache(String userID, String userName) {
RESOLVE_USER_NAME_FROM_UNIQUE_USER_ID_CACHE_NAME, SUPER_TENANT_ID);
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param userID
+ * @param userName
+ */
+ private void addToUserNameCacheOnRead(String userID, String userName) {
+
+ UserIdResolverCache.getInstance()
+ .addToCacheOnRead(userID, userName,
+ RESOLVE_USER_NAME_FROM_UNIQUE_USER_ID_CACHE_NAME, SUPER_TENANT_ID);
+ }
+
private String getFromUserNameCache(String userID) {
return UserIdResolverCache.getInstance().getValueFromCache(userID,
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/jdbc/UniqueIDJDBCUserStoreManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/jdbc/UniqueIDJDBCUserStoreManager.java
index 44c28d312ad..d0cde532b05 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/jdbc/UniqueIDJDBCUserStoreManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/jdbc/UniqueIDJDBCUserStoreManager.java
@@ -4029,8 +4029,8 @@ private void processUserResultSet(ResultSet rs, List userList) throws SQLE
String userID = rs.getString(1);
String userName = rs.getString(2);
if (StringUtils.isNotBlank(userID) && StringUtils.isNotBlank(userName)) {
- addToUserIDCache(userID, userName, getMyDomainName());
- addToUserNameCache(userID, userName, getMyDomainName());
+ addToUserIDCacheOnRead(userID, userName, getMyDomainName());
+ addToUserNameCacheOnRead(userID, userName, getMyDomainName());
}
User user = getUser(userID, userName);
@@ -4043,8 +4043,8 @@ private void processUsernameResultSet(ResultSet rs, List usernameList) t
String userID = rs.getString(1);
String userName = rs.getString(2);
if (StringUtils.isNotBlank(userID) && StringUtils.isNotBlank(userName)) {
- addToUserIDCache(userID, userName, getMyDomainName());
- addToUserNameCache(userID, userName, getMyDomainName());
+ addToUserIDCacheOnRead(userID, userName, getMyDomainName());
+ addToUserNameCacheOnRead(userID, userName, getMyDomainName());
}
userName = UserCoreUtil.addDomainToName(userName, getMyDomainName());
usernameList.add(userName);
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/ReadOnlyLDAPUserStoreManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/ReadOnlyLDAPUserStoreManager.java
index dbe4b2dc6e7..25272b8945c 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/ReadOnlyLDAPUserStoreManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/ReadOnlyLDAPUserStoreManager.java
@@ -908,7 +908,7 @@ public boolean doCheckExistingUser(String userName) throws UserStoreException {
if (userDN != null && userDN.length() > 0) {
bFound = true;
LdapName ldapName = new LdapName(userDN);
- putToUserCache(userName, ldapName);
+ putToUserCacheOnRead(userName, ldapName);
break;
}
}
@@ -2525,7 +2525,7 @@ protected String getNameInSpaceForUserName(String userName, String searchBase, S
}
if (userDN != null) {
LdapName ldn = new LdapName(userDN);
- putToUserCache(userName, ldn);
+ putToUserCacheOnRead(userName, ldn);
}
if (debug) {
log.debug("Name in space for " + userName + " is " + userDN);
@@ -4662,6 +4662,36 @@ protected void putToUserCache(String name, LdapName value) {
}
}
+ /**
+ * Puts the DN into the cache.
+ *
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * @param name the username.
+ * @param value the LDAP name (DN)
+ */
+ protected void putToUserCacheOnRead(String name, LdapName value) {
+
+ try {
+ startTenantFlow();
+ Cache userDnCache = createOrGetUserDnCache();
+ if (userDnCache == null) {
+ // User cache may be null while initializing.
+ return;
+ }
+ userDnCache.putOnRead(name, value);
+ } catch (IllegalStateException e) {
+ // There is no harm ignoring the put, as the cache(local) is already is of no use. Mis-penalty is low.
+ log.error("Error occurred while putting User DN to the cache having search base : " + userSearchBase, e);
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Returns the LDAP Name (DN) for the given user name, if it exists in the cache.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/UniqueIDReadOnlyLDAPUserStoreManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/UniqueIDReadOnlyLDAPUserStoreManager.java
index 50d9ae42dfa..dcde45e9873 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/UniqueIDReadOnlyLDAPUserStoreManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/UniqueIDReadOnlyLDAPUserStoreManager.java
@@ -1529,8 +1529,8 @@ public List doGetUserListFromPropertiesWithID(String property, String va
if (StringUtils.equals(property,
realmConfig.getUserStoreProperty(LDAPConstants.USER_NAME_ATTRIBUTE))) {
putToUserCache(value, new LdapName(sr.getNameInNamespace()));
- addToUserNameCache(propertyValue, value, getMyDomainName());
- addToUserIDCache(propertyValue, value, getMyDomainName());
+ addToUserNameCacheOnRead(propertyValue, value, getMyDomainName());
+ addToUserIDCacheOnRead(propertyValue, value, getMyDomainName());
}
}
}
@@ -1634,8 +1634,8 @@ protected UniqueIDPaginatedUsernameSearchResult doGetUsernameListWithID(Conditio
doGetUserListWithID(condition, profileName, limit, offset, sortBy, sortOrder);
List usernames = new ArrayList<>();
uniqueIDPaginatedSearchResult.getUsers().forEach(user -> {
- addToUserIDCache(user.getUserID(), user.getUsername(), getMyDomainName());
- addToUserNameCache(user.getUserID(), user.getUsername(), getMyDomainName());
+ addToUserIDCacheOnRead(user.getUserID(), user.getUsername(), getMyDomainName());
+ addToUserNameCacheOnRead(user.getUserID(), user.getUsername(), getMyDomainName());
usernames.add(user.getDomainQualifiedUsername());
});
result.setUsers(usernames);
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/FileSystemTenantManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/FileSystemTenantManager.java
index fbaab129630..5b9ab3fedc2 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/FileSystemTenantManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/FileSystemTenantManager.java
@@ -142,7 +142,7 @@ public Tenant getTenant(int tenantId) throws UserStoreException {
tenant.setRealmConfig(realmConfig);
tenant.setAdminName(realmConfig.getAdminUserName());
- tenantCacheManager.addToCache(new TenantIdKey(tenantId), new TenantCacheEntry(tenant));
+ tenantCacheManager.addToCacheOnRead(new TenantIdKey(tenantId), new TenantCacheEntry(tenant));
} catch (CarbonException e) {
String errorMessage = "Error occurred while getting tenant from tenant id : " + tenant;
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/JDBCTenantManager.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/JDBCTenantManager.java
index 7b8ae855e70..96c4d72ec3c 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/JDBCTenantManager.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/JDBCTenantManager.java
@@ -498,9 +498,9 @@ public Tenant getTenant(int tenantId) throws UserStoreException {
+ ", hence adding tenant to cache where tenantDomain: {" + domain + "}");
}
tenantDomainNameValidation(domain);
- tenantCacheManager.addToCache(new TenantIdKey(id), new TenantCacheEntry(tenant));
- tenantDomainCache.addToCache(new TenantIdKey(id), new TenantDomainEntry(domain));
- tenantIdCache.addToCache(new TenantDomainKey(domain), new TenantIdEntry(id));
+ tenantCacheManager.addToCacheOnRead(new TenantIdKey(id), new TenantCacheEntry(tenant));
+ tenantDomainCache.addToCacheOnRead(new TenantIdKey(id), new TenantDomainEntry(domain));
+ tenantIdCache.addToCacheOnRead(new TenantDomainKey(domain), new TenantIdEntry(id));
}
dbConnection.commit();
} catch (SQLException e) {
@@ -648,8 +648,8 @@ public String getDomain(int tenantId) throws UserStoreException {
+ "tenant ID:" + tenantId + ", hence adding tenant domain and tenant ID to cache.");
}
tenantDomainNameValidation(tenantDomain);
- tenantDomainCache.addToCache(tenantIdKey, new TenantDomainEntry(tenantDomain));
- tenantIdCache.addToCache(new TenantDomainKey(tenantDomain), new TenantIdEntry(tenantId));
+ tenantDomainCache.addToCacheOnRead(tenantIdKey, new TenantDomainEntry(tenantDomain));
+ tenantIdCache.addToCacheOnRead(new TenantDomainKey(tenantDomain), new TenantIdEntry(tenantId));
}
if (tenantDomain != null) {
@@ -750,8 +750,8 @@ public int getTenantId(String tenantDomain) throws UserStoreException {
+ tenantDomain + "}, hence adding tenant domain and tenant ID to cache.");
}
tenantDomainNameValidation(tenantDomain);
- tenantIdCache.addToCache(tenantDomainKey, new TenantIdEntry(tenantId));
- tenantDomainCache.addToCache(new TenantIdKey(tenantId), new TenantDomainEntry(tenantDomain));
+ tenantIdCache.addToCacheOnRead(tenantDomainKey, new TenantIdEntry(tenantId));
+ tenantDomainCache.addToCacheOnRead(new TenantIdKey(tenantId), new TenantDomainEntry(tenantDomain));
}
} catch (SQLException e) {
DatabaseUtil.rollBack(dbConnection);
@@ -830,10 +830,11 @@ public Tenant getTenant(String tenantUniqueID) throws UserStoreException {
+ ", hence adding tenant to cache where tenantDomain: {" + domain + "}");
}
tenantDomainNameValidation(domain);
- tenantUniqueIdCache.addToCache(new TenantUniqueIDKey(uniqueId), new TenantCacheEntry(tenant));
- tenantCacheManager.addToCache(new TenantIdKey(id), new TenantCacheEntry(tenant));
- tenantDomainCache.addToCache(new TenantIdKey(id), new TenantDomainEntry(domain));
- tenantIdCache.addToCache(new TenantDomainKey(domain), new TenantIdEntry(id));
+ tenantUniqueIdCache
+ .addToCacheOnRead(new TenantUniqueIDKey(uniqueId), new TenantCacheEntry(tenant));
+ tenantCacheManager.addToCacheOnRead(new TenantIdKey(id), new TenantCacheEntry(tenant));
+ tenantDomainCache.addToCacheOnRead(new TenantIdKey(id), new TenantDomainEntry(domain));
+ tenantIdCache.addToCacheOnRead(new TenantDomainKey(domain), new TenantIdEntry(id));
}
dbConnection.commit();
} catch (SQLException e) {
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantCache.java
index 3cf8c381705..9b01782fe1c 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantCache.java
@@ -94,6 +94,46 @@ public void addToCache(TenantIdKey key, T entry) {
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * Add a cache entry.
+ * Tenant
+ *
+ * @param key Key which cache entry is indexed.
+ * @param entry Actual object where cache entry is placed.
+ */
+ public void addToCacheOnRead(TenantIdKey key, T entry) {
+
+ PrivilegedCarbonContext.startTenantFlow();
+
+ try {
+ PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
+ carbonContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID);
+ carbonContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
+
+ Cache cache = getTenantCache();
+ if (cache != null) {
+ cache.putOnRead(key, entry);
+ if (log.isDebugEnabled()) {
+ log.debug(TENANT_CACHE + " which is under " + TENANT_CACHE_MANAGER + ", added the entry : " + entry
+ + " for the key : " + key + " successfully");
+ }
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Error while getting the cache : " + TENANT_CACHE + " which is under " +
+ TENANT_CACHE_MANAGER);
+ }
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantDomainCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantDomainCache.java
index 8335fb6f50f..1b436b35875 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantDomainCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantDomainCache.java
@@ -22,15 +22,15 @@
* Date: Oct 1, 2010 Time: 2:36:37 PM
*/
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-
/**
* This is the tenant cache.
*/
@@ -84,6 +84,38 @@ public void addToCache(TenantIdKey key, TenantDomainEntry entry) {
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * Add a cache entry.
+ *
+ * @param key Key which cache entry is indexed.
+ * @param entry Actual object where cache entry is placed.
+ */
+ public void addToCacheOnRead(TenantIdKey key, TenantDomainEntry entry) {
+
+ try {
+ startSuperTenantFlow();
+ Cache cache = getTenantDomainCache();
+ if (cache != null) {
+ cache.putOnRead(key, entry);
+ log.debug(TENANT_DOMAIN_CACHE + " which is under " + TENANT_DOMAIN_CACHE_MANAGER +
+ ", added the entry : " + entry + " for the key : " + key + " successfully");
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Error while getting the cache : " + TENANT_DOMAIN_CACHE +
+ " which is under " + TENANT_DOMAIN_CACHE_MANAGER);
+ }
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantIdCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantIdCache.java
index ad28972bf89..474d45f4e3c 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantIdCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantIdCache.java
@@ -88,6 +88,38 @@ public void addToCache(TenantDomainKey key, TenantIdEntry entry) {
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * Add a cache entry.
+ *
+ * @param key Key which cache entry is indexed.
+ * @param entry Actual object where cache entry is placed.
+ */
+ public void addToCacheOnRead(TenantDomainKey key, TenantIdEntry entry) {
+
+ try {
+ startSuperTenantFlow();
+ Cache cache = getTenantIdCache();
+ if (cache != null) {
+ cache.putOnRead(key, entry);
+ log.debug(TENANT_ID_CACHE + " which is under " + TENANT_ID_CACHE_MANAGER + ", added the entry : " +
+ entry + " for the key : " + key + " successfully");
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Error while getting the cache : " + TENANT_ID_CACHE + " which is under " +
+ TENANT_ID_CACHE_MANAGER);
+ }
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*
diff --git a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantUniqueIdCache.java b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantUniqueIdCache.java
index 5a661df81fd..be7e15b1296 100644
--- a/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantUniqueIdCache.java
+++ b/core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/tenant/TenantUniqueIdCache.java
@@ -93,6 +93,43 @@ public void addToCache(TenantUniqueIDKey key, T entry) {
}
}
+ /**
+ * Add a cache entry during a READ operation.
+ *
+ * This populates the cache only if the key does not already have a value.
+ * If a value already exists, the cache is left unchanged, which avoids
+ * unnecessary cache invalidation broadcasts in clustered environments.
+ *
+ * Add a cache entry.
+ * Tenant
+ *
+ * @param key Key which cache entry is indexed.
+ * @param entry Actual object where cache entry is placed.
+ */
+ public void addToCacheOnRead(TenantUniqueIDKey key, T entry) {
+
+ PrivilegedCarbonContext.startTenantFlow();
+
+ try {
+ startSuperTenantFlow();
+ Cache cache = getTenantUUIDCache();
+ if (cache != null) {
+ cache.putOnRead(key, entry);
+ if (log.isDebugEnabled()) {
+ log.debug(TENANT_UNIQUE_ID_CACHE + " which is under " + TENANT_UNIQUE_ID_CACHE_MANAGER + ", " +
+ "added the entry : " + entry + " for the key : " + key + " successfully");
+ }
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Error while getting the cache : " + TENANT_UNIQUE_ID_CACHE + " which is under " +
+ TENANT_UNIQUE_ID_CACHE_MANAGER);
+ }
+ }
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+
/**
* Retrieves a cache entry.
*