Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -449,6 +449,74 @@ public String getPath(AbstractConnection conn, int id) throws SQLException {
}
}

/**
* Method to get the path of a given path id.
* <p>
* Add a cache entry during a READ operation.
* <p>
* 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<RegistryCacheKey, RegistryCacheEntry> 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.
*
Expand Down Expand Up @@ -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.
* <p>
* Add a cache entry during a READ operation.
* <p>
* 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<RegistryCacheKey,RegistryCacheEntry> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -2202,6 +2202,26 @@ public String getPathFromId(int pathId) throws RegistryException {
}
}

/**
* Add a cache entry during a READ operation.
* <p>
* 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) {
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* <p>
* 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. <code>true</code> for
* authorized else <code>false</code>.
*/
public void addToCacheOnRead(String serverId, int tenantId, String userName,
String resourceId, String action, boolean isAuthorized) {

if (!isCaseSensitiveUsername(userName, tenantId)) {
userName = userName.toLowerCase();
}

Cache<AuthorizationKey, AuthorizeCacheEntry> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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()) {
Expand Down
Loading
Loading