diff --git a/pom.xml b/pom.xml index 7d76f6c..5de3b1f 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,12 @@ 3.3 compile + + org.apache.commons + commons-dbcp2 + 2.1.1 + compile + diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/CKanUtilsImpl.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/CKanUtilsImpl.java index 80b2ad8..800c2be 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/CKanUtilsImpl.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/CKanUtilsImpl.java @@ -1,9 +1,9 @@ package org.gcube.datacatalogue.ckanutillibrary; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -15,6 +15,7 @@ import net.htmlparser.jericho.Renderer; import net.htmlparser.jericho.Segment; import net.htmlparser.jericho.Source; +import org.apache.commons.dbcp2.BasicDataSource; import org.gcube.datacatalogue.ckanutillibrary.models.CKanUserWrapper; import org.gcube.datacatalogue.ckanutillibrary.models.ResourceBean; import org.gcube.datacatalogue.ckanutillibrary.models.RolesIntoOrganization; @@ -55,12 +56,19 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ private Integer CKAN_DB_PORT; private String CKAN_TOKEN_SYS; - // Connection to the db - private Connection connection; + // use connections pool (multiple threads can use this CKanUtilsImpl instance) + private BasicDataSource ds; + /** + * The ckan catalogue url and database will be discovered in this scope + * @param scope + * @throws Exception if unable to find datacatalogue info + */ public CKanUtilsImpl(String scope) throws Exception{ CKanRunningCluster runningInstance = new CKanRunningCluster(scope); + + // save information CKAN_DB_URL = runningInstance.getDatabaseHosts().get(0); CKAN_DB_NAME = runningInstance.getDataBaseName(); CKAN_DB_USER = runningInstance.getDataBaseUser(); @@ -68,26 +76,42 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ logger.debug("Plain password first 3 chars are " + CKAN_DB_PASSWORD.substring(0, 3)); CKAN_TOKEN_SYS = runningInstance.getSysAdminToken(); logger.debug("Plain sys admin token first 3 chars are " + CKAN_TOKEN_SYS.substring(0, 3)); - CKAN_DB_PORT = runningInstance.getDatabasePorts().get(0); CKAN_CATALOGUE_URL = runningInstance.getDataCatalogueUrl().get(0); + + // create connection pool + String url = "jdbc:postgresql://" + CKAN_DB_URL + ":" + CKAN_DB_PORT + "/" + CKAN_DB_NAME; + ds = new BasicDataSource(); + ds.setDriverClassName("org.postgresql.Driver"); + ds.setUsername(CKAN_DB_USER); + ds.setPassword(CKAN_DB_PASSWORD); + ds.setUrl(url); - Class.forName("org.postgresql.Driver"); - connection = DriverManager.getConnection( - "jdbc:postgresql://" + CKAN_DB_URL + ":" + CKAN_DB_PORT + "/" + CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD); + } + + /** + * Retrieve connection from the pool + * @return + * @throws SQLException + */ + private Connection getConnection() throws SQLException{ + + return ds.getConnection(); + } @Override public String getApiKeyFromUsername(String username) { + logger.debug("Request api key for user = " + username); + // in order to avoid errors, the username is always converted String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username); - logger.debug("Request api key for user = " + username); String apiToReturn = null; try{ String query = "SELECT \"apikey\" FROM \"user\" WHERE \"name\"=? and \"state\"=?;"; - PreparedStatement preparedStatement = connection.prepareStatement(query); + PreparedStatement preparedStatement = getConnection().prepareStatement(query); preparedStatement.setString(1, ckanUsername); preparedStatement.setString(2, State.ACTIVE.toString().toLowerCase()); @@ -111,17 +135,13 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ CKanUserWrapper user = new CKanUserWrapper(); try{ String query = "SELECT * FROM \"user\" WHERE \"apikey\"=? and \"state\"=?;"; - PreparedStatement preparedStatement = connection.prepareStatement(query); + PreparedStatement preparedStatement = getConnection().prepareStatement(query); preparedStatement.setString(1, apiKey); preparedStatement.setString(2, State.ACTIVE.toString().toLowerCase()); ResultSet rs = preparedStatement.executeQuery(); while (rs.next()) { - // check if it is active - if(State.DELETED.equals(rs.getString("state"))) - break; - user.setId(rs.getString("id")); user.setName(rs.getString("name")); user.setApiKey(apiKey); @@ -149,7 +169,6 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ // in order to avoid errors, the username is always converted String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username); - List organizationIds = getOrganizationsIds(); String userId = getUserIdByUsername(ckanUsername); // list to return @@ -159,10 +178,12 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ CkanClient client = new CkanClient(CKAN_CATALOGUE_URL); try{ + List organizationIds = getOrganizationsIds(); + // for each org id, check if the user is included for (String orgId : organizationIds) { String query = "SELECT * FROM \"member\" WHERE \"table_id\"=? and \"group_id\"=? and \"table_name\"=? and \"state\"=?;"; - PreparedStatement preparedStatement = connection.prepareStatement(query); + PreparedStatement preparedStatement = getConnection().prepareStatement(query); preparedStatement.setString(1, userId); preparedStatement.setString(2, orgId); preparedStatement.setString(3, "user"); @@ -173,7 +194,6 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ logger.debug("User " + ckanUsername + " belongs to organization with id " + orgId); toReturn.add(client.getOrganization(orgId)); } - } }catch(Exception e){ logger.error("Unable to get user's organizations", e); @@ -193,13 +213,12 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ // in order to avoid errors, the username is always converted String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username); - // get its key - String apiKey = getApiKeyFromUsername(ckanUsername); - - // retrieve the user and if it is a sys_admin, for every organizations will be created in the map, add also + // retrieve the user and if it is a sys_admin, for every organizations that will be created in the map add also // the sys_admin role boolean isSysAdmin = false; if(rolesToMatch.contains(RolesIntoOrganization.SYSADMIN)){ + // get its key + String apiKey = getApiKeyFromUsername(ckanUsername); isSysAdmin = isSysAdmin(ckanUsername, apiKey); } @@ -208,17 +227,14 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ // get id from the user String userId = getUserIdByUsername(ckanUsername); - // use the above method to require the list of user's organizations - List usersOrganizations = getOrganizationsByUser(ckanUsername); + // get the id of all the organizations + List organizationIds = getOrganizationsIds(); - for (CkanOrganization ckanOrganization : usersOrganizations) { - - // get the org id - String orgId = ckanOrganization.getId(); + for (String orgId : organizationIds) { // go to the member table, that says which role has this user into the org String query = "SELECT * FROM \"member\" WHERE \"table_id\"=? and \"group_id\"=? and \"table_name\"=? and \"state\"=?;"; - PreparedStatement preparedStatement = connection.prepareStatement(query); + PreparedStatement preparedStatement = getConnection().prepareStatement(query); preparedStatement.setString(1, userId); preparedStatement.setString(2, orgId); preparedStatement.setString(3, "user"); @@ -236,9 +252,8 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ // check String role = rs.getString("capacity"); if(rolesToMatch.contains(RolesIntoOrganization.valueOf(role))){ - rolesIntoOrg.add(RolesIntoOrganization.valueOf(role)); - logger.debug("User " + ckanUsername + " has role " + role + " into organization " + ckanOrganization.getName()); + logger.debug("User " + ckanUsername + " has role " + role + " into organization with id " + orgId); } } @@ -262,18 +277,11 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ // in order to avoid errors, the username is always converted String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username); - - String userId = null; + + String userId = null; try{ - String query = "SELECT \"id\" FROM \"user\" WHERE \"name\"=? and \"state\"=?;"; - PreparedStatement preparedStatement = connection.prepareStatement(query); - preparedStatement.setString(1, ckanUsername); - preparedStatement.setString(2, State.ACTIVE.toString().toLowerCase()); - ResultSet rs = preparedStatement.executeQuery(); - while (rs.next()) { - userId = rs.getString("id"); - break; - } + CkanClient client = new CkanClient(CKAN_CATALOGUE_URL); + client.getUser(ckanUsername).getId(); logger.debug("User id retrieved for " + ckanUsername + " "+ userId); }catch(Exception e){ logger.error("Unable to retrieve user with name " + ckanUsername, e); @@ -314,7 +322,7 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username); List orgs = getOrganizationsByUser(ckanUsername); - + List orgsName = new ArrayList(); for (CkanOrganization ckanOrganization : orgs) { orgsName.add(ckanOrganization.getName()); @@ -651,7 +659,7 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ logger.debug("Request for checking if " + username + " into " + organizationName + " has role " + correspondentRoleToCheck); if(correspondentRoleToCheck.equals(RolesIntoOrganization.SYSADMIN)){ - + logger.debug("SYSADMIN role cannot be created programmatically... The user role will be turned into admin"); correspondentRoleToCheck = RolesIntoOrganization.ADMIN; } @@ -679,7 +687,7 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ CloseableHttpClient httpClient = HttpClientBuilder.create().build(); try { - + HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + path); request.addHeader("Authorization", CKAN_TOKEN_SYS); // sys token StringEntity params = new StringEntity(parameter); @@ -715,7 +723,7 @@ public class CKanUtilsImpl implements CKanUtilsInterface{ @Override protected void finalize() throws Throwable { - logger.debug("Closing connection on finalize()"); - connection.close(); + logger.debug("Closing connection poolon finalize()"); + ds.close(); } }