http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/DatabaseCreator.java ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/DatabaseCreator.java b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/DatabaseCreator.java new file mode 100644 index 0000000..5aa423c --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/DatabaseCreator.java @@ -0,0 +1,353 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.sharing.registry.db.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.*; +import java.util.StringTokenizer; + +/** + * This class creates the database tables required for airavata with default configuration this + * class creates derby database in server mode. User can specify required database in appropriate + * properties files. + */ +public class DatabaseCreator { + private final static Logger logger = LoggerFactory.getLogger(DatabaseCreator.class); + + public enum DatabaseType { + derby("(?i).*derby.*"), mysql("(?i).*mysql.*"), other(""); + + private String pattern; + + private DatabaseType(String matchingPattern) { + this.pattern = matchingPattern; + } + + public String getMatchingPattern() { + return this.pattern; + } + } + + private static DatabaseType[] supportedDatabase = new DatabaseType[] { DatabaseType.derby, DatabaseType.mysql }; + + private static Logger log = LoggerFactory.getLogger(DatabaseCreator.class); + private static final String delimiter = ";"; + + /** + * Creates database + * + * @throws Exception + */ + public static void createRegistryDatabase(String prefix, Connection conn) throws Exception { + createDatabase(prefix, conn); + } + + + + /** + * Checks whether database tables are created by using select * on given table name + * + * @param tableName + * Table which should be existed + * @return <code>true</core> if checkSQL is success, else <code>false</code> . + */ + public static boolean isDatabaseStructureCreated(String tableName, Connection conn) { + try { + + log.debug("Running a query to test the database tables existence."); + + // check whether the tables are already created with a query + Statement statement = null; + try { + statement = conn.createStatement(); + ResultSet rs = statement.executeQuery("select * from " + tableName); + if (rs != null) { + rs.close(); + } + } finally { + try { + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + return false; + } + } + } catch (SQLException e) { + return false; + } + + return true; + } + + /** + * executes given sql + * + * @param sql + * @throws Exception + */ + private static void executeSQL(String sql, Connection conn) throws Exception { + // Check and ignore empty statements + if ("".equals(sql.trim())) { + return; + } + + Statement statement = null; + try { + log.debug("SQL : " + sql); + + boolean ret; + int updateCount = 0, updateCountTotal = 0; + statement = conn.createStatement(); + ret = statement.execute(sql); + updateCount = statement.getUpdateCount(); + do { + if (!ret) { + if (updateCount != -1) { + updateCountTotal += updateCount; + } + } + ret = statement.getMoreResults(); + if (ret) { + updateCount = statement.getUpdateCount(); + } + } while (ret); + + log.debug(sql + " : " + updateCountTotal + " rows affected"); + + SQLWarning warning = conn.getWarnings(); + while (warning != null) { + log.info(warning + " sql warning"); + warning = warning.getNextWarning(); + } + conn.clearWarnings(); + } catch (SQLException e) { + if (e.getSQLState().equals("X0Y32")) { + // eliminating the table already exception for the derby + // database + log.info("Table Already Exists", e); + } else { + throw new Exception("Error occurred while executing : " + sql, e); + } + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + log.error("Error occurred while closing result set.", e); + } + } + } + } + + /** + * computes relatational database type using database name + * + * @return DatabaseType + * @throws Exception + * + */ + public static DatabaseType getDatabaseType(Connection conn) throws Exception { + try { + if (conn != null && (!conn.isClosed())) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return checkType(databaseProductName); + } + } catch (SQLException e) { + String msg = "Failed to create Airavata database." + e.getMessage(); + log.error(msg, e); + throw new Exception(msg, e); + } + return DatabaseType.other; + } + + /** + * Overloaded method with String input + * + * @return DatabaseType + * @throws Exception + * + */ + public static DatabaseType getDatabaseType(String dbUrl) throws Exception { + return checkType(dbUrl); + } + + private static DatabaseType checkType(String text) throws Exception { + try { + if (text != null) { + for (DatabaseType type : supportedDatabase) { + if (text.matches(type.getMatchingPattern())) + return type; + } + } + String msg = "Unsupported database: " + text + + ". Database will not be created automatically by the Airavata. " + + "Please create the database using appropriate database scripts for " + "the database."; + throw new Exception(msg); + + } catch (SQLException e) { + String msg = "Failed to create Airavatadatabase." + e.getMessage(); + log.error(msg, e); + throw new Exception(msg, e); + } + } + + /** + * Get scripts location which is prefix + "-" + databaseType + ".sql" + * + * @param prefix + * @param databaseType + * @return script location + */ + private static String getScriptLocation(String prefix, DatabaseType databaseType) { + String scriptName = prefix + "-" + databaseType + ".sql"; + log.debug("Loading database script from :" + scriptName); + return scriptName; + } + + private static void createDatabase(String prefix, Connection conn) throws Exception { + Statement statement = null; + try { + conn.setAutoCommit(false); + statement = conn.createStatement(); + executeSQLScript(getScriptLocation(prefix, DatabaseCreator.getDatabaseType(conn)), conn); + conn.commit(); + log.debug("Tables are created successfully."); + } catch (SQLException e) { + String msg = "Failed to create database tables for Airavata resource store. " + e.getMessage(); + log.error(msg, e); + conn.rollback(); + throw new Exception(msg, e); + } finally { + conn.setAutoCommit(true); + try { + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + log.error("Failed to close statement.", e); + } + } + } + + private static void executeSQLScript(String dbscriptName, Connection conn) throws Exception { + StringBuffer sql = new StringBuffer(); + BufferedReader reader = null; + + try { + InputStream is = DatabaseCreator.class.getClassLoader().getResourceAsStream(dbscriptName); + if(is == null) { + logger.info("Script file not found at " + dbscriptName + ". Uses default database script file"); + DatabaseType databaseType = DatabaseCreator.getDatabaseType(conn); + if(databaseType.equals(DatabaseType.derby)){ + is = DatabaseCreator.class.getClassLoader().getResourceAsStream("experiment-derby.sql"); + }else if(databaseType.equals(DatabaseType.mysql)){ + is = DatabaseCreator.class.getClassLoader().getResourceAsStream("experiment-mysql.sql"); + } + } + reader = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.startsWith("//")) { + continue; + } + if (line.startsWith("--")) { + continue; + } + StringTokenizer st = new StringTokenizer(line); + if (st.hasMoreTokens()) { + String token = st.nextToken(); + if ("REM".equalsIgnoreCase(token)) { + continue; + } + } + sql.append(" ").append(line); + + // SQL defines "--" as a comment to EOL + // and in Oracle it may contain a hint + // so we cannot just remove it, instead we must end it + if (line.indexOf("--") >= 0) { + sql.append("\n"); + } + if ((checkStringBufferEndsWith(sql, delimiter))) { + executeSQL(sql.substring(0, sql.length() - delimiter.length()), conn); + sql.replace(0, sql.length(), ""); + } + } + // Catch any statements not followed by ; + if (sql.length() > 0) { + executeSQL(sql.toString(), conn); + } + } catch (IOException e) { + log.error("Error occurred while executing SQL script for creating Airavata database", e); + throw new Exception("Error occurred while executing SQL script for creating Airavata database", e); + + } finally { + if (reader != null) { + reader.close(); + } + } + } + + /** + * Checks that a string buffer ends up with a given string. It may sound trivial with the existing JDK API but the + * various implementation among JDKs can make those methods extremely resource intensive and perform poorly due to + * massive memory allocation and copying. See + * + * @param buffer + * the buffer to perform the check on + * @param suffix + * the suffix + * @return <code>true</code> if the character sequence represented by the argument is a suffix of the character + * sequence represented by the StringBuffer object; <code>false</code> otherwise. Note that the result will + * be <code>true</code> if the argument is the empty string. + */ + public static boolean checkStringBufferEndsWith(StringBuffer buffer, String suffix) { + if (suffix.length() > buffer.length()) { + return false; + } + // this loop is done on purpose to avoid memory allocation performance + // problems on various JDKs + // StringBuffer.lastIndexOf() was introduced in jdk 1.4 and + // implementation is ok though does allocation/copying + // StringBuffer.toString().endsWith() does massive memory + // allocation/copying on JDK 1.5 + // See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169 + int endIndex = suffix.length() - 1; + int bufferIndex = buffer.length() - 1; + while (endIndex >= 0) { + if (buffer.charAt(bufferIndex) != suffix.charAt(endIndex)) { + return false; + } + bufferIndex--; + endIndex--; + } + return true; + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JPAUtils.java ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JPAUtils.java b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JPAUtils.java new file mode 100644 index 0000000..f879c15 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JPAUtils.java @@ -0,0 +1,230 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.sharing.registry.db.utils; + +import org.apache.airavata.common.exception.ApplicationSettingsException; +import org.apache.airavata.common.utils.ServerSettings; +import org.apache.airavata.sharing.registry.models.SharingRegistryException; +import org.apache.derby.drda.NetworkServerControl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.*; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class JPAUtils { + private final static Logger logger = LoggerFactory.getLogger(JPAUtils.class); + + public static final String PERSISTENCE_UNIT_NAME = "airavata-sharing-registry"; + public static final String SHARING_REG_JDBC_DRIVER = "sharingcatalog.jdbc.driver"; + public static final String SHARING_REG_JDBC_URL = "sharingcatalog.jdbc.url"; + public static final String SHARING_REG_JDBC_USER = "sharingcatalog.jdbc.user"; + public static final String SHARING_REG_JDBC_PWD = "sharingcatalog.jdbc.password"; + public static final String SHARING_REG_VALIDATION_QUERY = "sharingcatalog.validationQuery"; + public static final String JPA_CACHE_SIZE = "jpa.cache.size"; + public static final String JPA_CACHE_ENABLED = "cache.enable"; + + public static final String CONFIGURATION = "CONFIGURATION"; + public static final String START_DERBY_ENABLE = "start.derby.server.mode"; + public static final String DERBY_SERVER_MODE_SYS_PROPERTY = "derby.drda.startNetworkServer"; + private static NetworkServerControl server; + private static JdbcStorage db; + private static String jdbcURl; + private static String jdbcDriver; + private static String jdbcUser; + private static String jdbcPassword; + + + @PersistenceUnit(unitName = PERSISTENCE_UNIT_NAME) + protected static EntityManagerFactory factory; + @PersistenceContext(unitName = PERSISTENCE_UNIT_NAME) + private static EntityManager entityManager; + + public static EntityManager getEntityManager() throws SharingRegistryException { + if (factory == null) { + String connectionProperties = "DriverClassName=" + readServerProperties(SHARING_REG_JDBC_DRIVER) + "," + + "Url=" + readServerProperties(SHARING_REG_JDBC_URL) + "?autoReconnect=true," + + "Username=" + readServerProperties(SHARING_REG_JDBC_USER) + "," + + "Password=" + readServerProperties(SHARING_REG_JDBC_PWD) + + ",validationQuery=" + readServerProperties(SHARING_REG_VALIDATION_QUERY); +// + +// String connectionProperties = "DriverClassName=com.mysql.jdbc.Driver," + +// "Url=jdbc:mysql://localhost:3306/airavata_sharing_catalog?autoReconnect=true," + +// "Username=root," + +// "Password=," + +// ",validationQuery=SELECT 1 FROM CONFIGURATION"; + + Map<String, String> properties = new HashMap<String, String>(); + properties.put("openjpa.ConnectionDriverName", "org.apache.commons.dbcp.BasicDataSource"); + properties.put("openjpa.ConnectionProperties", connectionProperties); + properties.put("openjpa.DynamicEnhancementAgent", "true"); + properties.put("openjpa.RuntimeUnenhancedClasses", "unsupported"); + // For app catalog, we don't need caching +// properties.put("openjpa.DataCache","" + readServerProperties(JPA_CACHE_ENABLED) + "(CacheSize=" + Integer.valueOf(readServerProperties(JPA_CACHE_SIZE)) + ", SoftReferenceSize=0)"); +// properties.put("openjpa.QueryCache","" + readServerProperties(JPA_CACHE_ENABLED) + "(CacheSize=" + Integer.valueOf(readServerProperties(JPA_CACHE_SIZE)) + ", SoftReferenceSize=0)"); + properties.put("openjpa.RemoteCommitProvider", "sjvm"); + properties.put("openjpa.Log", "DefaultLevel=INFO, Runtime=INFO, Tool=INFO, SQL=INFO"); + properties.put("openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)"); + properties.put("openjpa.jdbc.QuerySQLCache", "false"); + properties.put("openjpa.ConnectionFactoryProperties", "PrettyPrint=true, PrettyPrintLineLength=72," + + " PrintParameters=true, MaxActive=10, MaxIdle=5, MinIdle=2, MaxWait=31536000, autoReconnect=true"); + properties.put("openjpa.RuntimeUnenhancedClasses", "warn"); + factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, properties); + } + entityManager = factory.createEntityManager(); + return entityManager; + } + + public static <R> R execute(Committer<EntityManager, R> committer) throws SharingRegistryException { + EntityManager entityManager = JPAUtils.getEntityManager(); + try { + entityManager.getTransaction().begin(); + R r = committer.commit(entityManager); + entityManager.getTransaction().commit(); + return r; + }finally { + if (entityManager != null && entityManager.isOpen()) { + if (entityManager.getTransaction().isActive()) { + entityManager.getTransaction().rollback(); + } + entityManager.close(); + } + } + } + + public static void initializeDB() throws SharingRegistryException { + jdbcDriver = readServerProperties(SHARING_REG_JDBC_DRIVER); + jdbcURl = readServerProperties(SHARING_REG_JDBC_URL); + jdbcUser = readServerProperties(SHARING_REG_JDBC_USER); + jdbcPassword = readServerProperties(SHARING_REG_JDBC_PWD); + jdbcURl = jdbcURl + "?" + "user=" + jdbcUser + "&" + "password=" + jdbcPassword; + + if (getDBType(jdbcURl).equals("derby") && isDerbyStartEnabled()) { + startDerbyInServerMode(); + } + db = new JdbcStorage(10, 50, jdbcURl, jdbcDriver, true); + + Connection conn = null; + try { + conn = db.connect(); + if (!DatabaseCreator.isDatabaseStructureCreated(CONFIGURATION, conn)) { + DatabaseCreator.createRegistryDatabase("database_scripts/sharing-registry", conn); + logger.info("New Database created for Sharing Catalog !!! "); + } else { + logger.info("Database already created for Sharing Catalog !!!"); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException("Database failure", e); + } finally { + db.closeConnection(conn); + try { + if(conn != null){ + if (!conn.getAutoCommit()) { + conn.commit(); + } + conn.close(); + } + } catch (SQLException e) { + logger.error("Error while closing database connection...", e.getMessage(), e); + } + } + } + + public static String getDBType(String jdbcUrl){ + try{ + String cleanURI = jdbcUrl.substring(5); + URI uri = URI.create(cleanURI); + return uri.getScheme(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return null; + } + } + + public static boolean isDerbyStartEnabled(){ + try { + String s = ServerSettings.getSetting(START_DERBY_ENABLE); + if("true".equals(s)){ + return true; + } + } catch (ApplicationSettingsException e) { + logger.error("Unable to read airavata server properties", e.getMessage(), e); + return false; + } + return false; + } + + public static void startDerbyInServerMode() { + try { + System.setProperty(DERBY_SERVER_MODE_SYS_PROPERTY, "true"); + server = new NetworkServerControl(InetAddress.getByName("0.0.0.0"), + getPort(jdbcURl), + jdbcUser, jdbcPassword); + java.io.PrintWriter consoleWriter = new java.io.PrintWriter(System.out, true); + server.start(consoleWriter); + } catch (IOException e) { + logger.error("Unable to start Apache derby in the server mode! Check whether " + + "specified port is available"); + } catch (Exception e) { + logger.error("Unable to start Apache derby in the server mode! Check whether " + + "specified port is available"); + } + } + + public static void stopDerbyInServerMode() { + System.setProperty(DERBY_SERVER_MODE_SYS_PROPERTY, "false"); + if (server!=null){ + try { + server.shutdown(); + } catch (Exception e) { + logger.error("Error when stopping the derby server : "+e.getLocalizedMessage()); + } + } + } + + public static int getPort(String jdbcURL){ + try{ + String cleanURI = jdbcURL.substring(5); + URI uri = URI.create(cleanURI); + return uri.getPort(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return -1; + } + } + + public static String readServerProperties(String propertyName) throws SharingRegistryException { + try { + return ServerSettings.getSetting(propertyName); + } catch (ApplicationSettingsException e) { + logger.error("Unable to read airavata-server.properties...", e); + throw new SharingRegistryException("Unable to read airavata-server.properties..."); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JdbcStorage.java ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JdbcStorage.java b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JdbcStorage.java new file mode 100644 index 0000000..377c50b --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/JdbcStorage.java @@ -0,0 +1,175 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.sharing.registry.db.utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; + +public class JdbcStorage { + private static Logger log = LoggerFactory.getLogger(JdbcStorage.class); + + private ConnectionPool connectionPool; + + public JdbcStorage(String jdbcUrl, String jdbcDriver) { + // default init connection and max connection + this(3, 50, jdbcUrl, jdbcDriver, true); + } + + public JdbcStorage(int initCon, int maxCon, String url, String driver, boolean enableTransactions) { + try { + if (enableTransactions) { + connectionPool = new ConnectionPool(driver, url, initCon, maxCon, true, false, + Connection.TRANSACTION_SERIALIZABLE); + } else { + connectionPool = new ConnectionPool(driver, url, initCon, maxCon, true); + } + } catch (Exception e) { + throw new RuntimeException("Failed to create database connection pool.", e); + } + } + + /** + * Check if this connection pool is auto commit or not + * + * @return + */ + public boolean isAutoCommit() { + return connectionPool.isAutoCommit(); + } + + public void commit(Connection conn) { + try { + if (conn != null && !conn.getAutoCommit()) { + conn.commit(); + } + } catch (SQLException sqle) { + log.error("Cannot commit data", sqle); + } + } + + public void commitAndFree(Connection conn) { + commit(conn); + closeConnection(conn); + } + + public void rollback(Connection conn) { + try { + if (conn != null && !conn.getAutoCommit()) { + conn.rollback(); + } + } catch (SQLException sqle) { + log.error("Cannot Rollback data", sqle); + } + } + + public void rollbackAndFree(Connection conn) { + rollback(conn); + closeConnection(conn); + } + + public Connection connect() { + + Connection conn = null; + try { + conn = connectionPool.getConnection(); + } catch (SQLException e) { + log.error(e.getMessage(), e); + } + return conn; + } + + /** + * This method is provided so that you can have better control over the statement. For example: You can use + * stmt.setString to convert quotation mark automatically in an UPDATE statement + * + * NOTE: Statement is closed after execution + */ + public int executeUpdateAndClose(PreparedStatement stmt) throws SQLException { + int rows = 0; + try { + rows = stmt.executeUpdate(); + if (rows == 0) { + log.info("Problem: 0 rows affected by insert/update/delete statement."); + } + } finally { + stmt.close(); + } + return rows; + } + + public int countRow(String tableName, String columnName) throws SQLException { + String query = new String("SELECT COUNT(" + columnName + ") FROM " + tableName); + int count = -1; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = connectionPool.getConnection(); + stmt = conn.prepareStatement(query); + ResultSet rs = stmt.executeQuery(); + rs.next(); + count = rs.getInt(1); + commit(conn); + } catch (SQLException sql) { + rollback(conn); + throw sql; + } finally { + try { + if (stmt != null && !stmt.isClosed()) { + stmt.close(); + } + } finally { + closeConnection(conn); + } + } + return count; + } + + public void quietlyClose(Connection conn, Statement... stmts) { + if (stmts != null) { + for (Statement stmt : stmts) { + try { + if (stmt != null && !stmt.isClosed()) { + stmt.close(); + } + } catch (SQLException sql) { + log.error(sql.getMessage(), sql); + } + } + } + closeConnection(conn); + } + + public void closeConnection(Connection conn) { + if (conn != null) { + connectionPool.free(conn); + } + } + + public void closeAllConnections() { + if (connectionPool != null) + connectionPool.dispose(); + } + + public void shutdown() throws SQLException { + connectionPool.shutdown(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/ObjectMapperSingleton.java ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/ObjectMapperSingleton.java b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/ObjectMapperSingleton.java new file mode 100644 index 0000000..de6bea9 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/db/utils/ObjectMapperSingleton.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.sharing.registry.db.utils; + +import org.dozer.DozerBeanMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ObjectMapperSingleton extends DozerBeanMapper{ + private final static Logger logger = LoggerFactory.getLogger(ObjectMapperSingleton.class); + + private static ObjectMapperSingleton instance; + + private ObjectMapperSingleton(){} + + public static ObjectMapperSingleton getInstance(){ + if(instance == null) + instance = new ObjectMapperSingleton(); + return instance; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServer.java ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServer.java b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServer.java new file mode 100644 index 0000000..96fdb90 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServer.java @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.sharing.registry.server; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SharingRegistryServer { + private final static Logger logger = LoggerFactory.getLogger(SharingRegistryServer.class); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServerHandler.java ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServerHandler.java b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServerHandler.java new file mode 100644 index 0000000..b260018 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/java/org/apache/airavata/sharing/registry/server/SharingRegistryServerHandler.java @@ -0,0 +1,676 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.airavata.sharing.registry.server; + +import org.apache.airavata.common.exception.ApplicationSettingsException; +import org.apache.airavata.common.utils.ServerSettings; +import org.apache.airavata.sharing.registry.db.entities.GroupMembershipEntityPK; +import org.apache.airavata.sharing.registry.db.entities.SharingEntityPK; +import org.apache.airavata.sharing.registry.db.repositories.*; +import org.apache.airavata.sharing.registry.db.utils.DBConstants; +import org.apache.airavata.sharing.registry.db.utils.JPAUtils; +import org.apache.airavata.sharing.registry.models.*; +import org.apache.airavata.sharing.registry.service.cpi.GovRegistryService; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.*; + +public class SharingRegistryServerHandler implements GovRegistryService.Iface{ + private final static Logger logger = LoggerFactory.getLogger(SharingRegistryServerHandler.class); + + public static String GLOBAL_PERMISSION_NAME = "OWNER"; + + private DomainRepository domainRepository; + private UserRepository userRepository; + private UserGroupRepository userGroupRepository; + private GroupMembershipRepository groupMembershipRepository; + private EntityTypeRepository entityTypeRepository; + private PermissionTypeRepository permissionTypeRepository; + private EntityRepository entityRepository; + private SharingRepository sharingRepository; + + public SharingRegistryServerHandler() throws ApplicationSettingsException, TException { + JPAUtils.initializeDB(); + + this.domainRepository = new DomainRepository(); + this.userRepository = new UserRepository(); + this.userGroupRepository = new UserGroupRepository(); + this.groupMembershipRepository = new GroupMembershipRepository(); + this.entityTypeRepository = new EntityTypeRepository(); + this.permissionTypeRepository = new PermissionTypeRepository(); + this.entityRepository = new EntityRepository(); + this.sharingRepository = new SharingRepository(); + + if(!domainRepository.isExists(ServerSettings.getDefaultUserGateway())){ + Domain domain = new Domain(); + domain.setDomainId(ServerSettings.getDefaultUserGateway()); + domain.setName(ServerSettings.getDefaultUserGateway()); + domain.setDescription("Domain entry for " + domain.name); + createDomain(domain); + + User user = new User(); + user.setDomainId(domain.domainId); + user.setUserId(ServerSettings.getDefaultUser()+"@"+ServerSettings.getDefaultUserGateway()); + user.setUserName(ServerSettings.getDefaultUser()); + createUser(user); + + //Creating Entity Types for each domain + EntityType entityType = new EntityType(); + entityType.setEntityTypeId(domain.domainId+":PROJECT"); + entityType.setDomainId(domain.domainId); + entityType.setName("PROJECT"); + entityType.setDescription("Project entity type"); + createEntityType(entityType); + + entityType = new EntityType(); + entityType.setEntityTypeId(domain.domainId+":EXPERIMENT"); + entityType.setDomainId(domain.domainId); + entityType.setName("EXPERIMENT"); + entityType.setDescription("Experiment entity type"); + createEntityType(entityType); + + entityType = new EntityType(); + entityType.setEntityTypeId(domain.domainId+":FILE"); + entityType.setDomainId(domain.domainId); + entityType.setName("FILE"); + entityType.setDescription("File entity type"); + createEntityType(entityType); + + //Creating Permission Types for each domain + PermissionType permissionType = new PermissionType(); + permissionType.setPermissionTypeId(domain.domainId+":READ"); + permissionType.setDomainId(domain.domainId); + permissionType.setName("READ"); + permissionType.setDescription("Read permission type"); + createPermissionType(permissionType); + + permissionType = new PermissionType(); + permissionType.setPermissionTypeId(domain.domainId+":WRITE"); + permissionType.setDomainId(domain.domainId); + permissionType.setName("WRITE"); + permissionType.setDescription("Write permission type"); + createPermissionType(permissionType); + + } + } + + /** + * * Domain Operations + * * + */ + @Override + public String createDomain(Domain domain) throws SharingRegistryException, TException { + if(domainRepository.get(domain.domainId) != null) + throw new SharingRegistryException("There exist domain with given domain id"); + + domain.setCreatedTime(System.currentTimeMillis()); + domain.setUpdatedTime(System.currentTimeMillis()); + domainRepository.create(domain); + + //create the global permission for the domain + PermissionType permissionType = new PermissionType(); + permissionType.setPermissionTypeId(domain.domainId+":"+GLOBAL_PERMISSION_NAME); + permissionType.setDomainId(domain.domainId); + permissionType.setName(GLOBAL_PERMISSION_NAME); + permissionType.setDescription("GLOBAL permission to " + domain.domainId); + permissionType.setCreatedTime(System.currentTimeMillis()); + permissionType.setUpdatedTime(System.currentTimeMillis()); + permissionTypeRepository.create(permissionType); + + return domain.domainId; + } + + @Override + public boolean updateDomain(Domain domain) throws SharingRegistryException, TException { + Domain oldDomain = domainRepository.get(domain.domainId); + domain.setCreatedTime(oldDomain.createdTime); + domain.setUpdatedTime(System.currentTimeMillis()); + domain = getUpdatedObject(oldDomain, domain); + domainRepository.update(domain); + return true; + } + + @Override + public boolean deleteDomain(String domainId) throws SharingRegistryException, TException { + domainRepository.delete(domainId); + return true; + } + + @Override + public Domain getDomain(String domainId) throws SharingRegistryException, TException { + return domainRepository.get(domainId); + } + + @Override + public List<Domain> getDomains(int offset, int limit) throws TException { + return domainRepository.select(new HashMap<>(), offset, limit); + } + + /** + * * User Operations + * * + */ + @Override + public String createUser(User user) throws SharingRegistryException, TException { + if(userRepository.get(user.userId) != null) + throw new SharingRegistryException("There exist user with given user id"); + + user.setCreatedTime(System.currentTimeMillis()); + user.setUpdatedTime(System.currentTimeMillis()); + userRepository.create(user); + + UserGroup userGroup = new UserGroup(); + userGroup.setGroupId(user.userId); + userGroup.setDomainId(user.domainId); + userGroup.setName(user.userName); + userGroup.setDescription("user " + user.userName + " group"); + userGroup.setOwnerId(user.userId); + userGroup.setGroupType(GroupType.SINGLE_USER); + createGroup(userGroup); + + return user.userId; + } + + @Override + public boolean updatedUser(User user) throws SharingRegistryException, TException { + User oldUser = userRepository.get(user.userId); + user.setCreatedTime(oldUser.createdTime); + user.setUpdatedTime(System.currentTimeMillis()); + user = getUpdatedObject(oldUser, user); + userRepository.update(user); + + UserGroup userGroup = userGroupRepository.get(user.userId); + userGroup.setName(user.userName); + userGroup.setDescription("user " + user.userName + " group"); + updateGroup(userGroup); + return true; + } + + @Override + public boolean deleteUser(String userId) throws SharingRegistryException, TException { + userRepository.delete(userId); + userGroupRepository.delete(userId); + return true; + } + + @Override + public User getUser(String userId) throws SharingRegistryException, TException { + return userRepository.get(userId); + } + + @Override + public List<User> getUsers(String domain, int offset, int limit) throws SharingRegistryException, TException { + HashMap<String, String> filters = new HashMap<>(); + filters.put(DBConstants.UserTable.DOMAIN_ID, domain); + return userRepository.select(filters, offset, limit); + } + + /** + * * Group Operations + * * + */ + @Override + public String createGroup(UserGroup group) throws SharingRegistryException, TException { + if(userGroupRepository.get(group.groupId) != null) + throw new SharingRegistryException("There exist group with given group id"); + + group.setCreatedTime(System.currentTimeMillis()); + group.setUpdatedTime(System.currentTimeMillis()); + userGroupRepository.create(group); + return group.groupId; + } + + @Override + public boolean updateGroup(UserGroup group) throws SharingRegistryException, TException { + group.setUpdatedTime(System.currentTimeMillis()); + UserGroup oldGroup = userGroupRepository.get(group.groupId); + group.setCreatedTime(oldGroup.createdTime); + group = getUpdatedObject(oldGroup, group); + userGroupRepository.update(group); + return true; + } + + @Override + public boolean deleteGroup(String groupId) throws SharingRegistryException, TException { + userGroupRepository.delete(groupId); + return true; + } + + @Override + public UserGroup getGroup(String groupId) throws SharingRegistryException, TException { + return userGroupRepository.get(groupId); + } + + @Override + public List<UserGroup> getGroups(String domain, int offset, int limit) throws TException { + HashMap<String, String> filters = new HashMap<>(); + filters.put(DBConstants.UserTable.DOMAIN_ID, domain); + return userGroupRepository.select(filters, offset, limit); + } + + @Override + public boolean addUsersToGroup(List<String> userIds, String groupId) throws SharingRegistryException, TException { + for(int i=0; i < userIds.size(); i++){ + GroupMembership groupMembership = new GroupMembership(); + groupMembership.setParentId(groupId); + groupMembership.setChildId(userIds.get(i)); + groupMembership.setChildType(GroupChildType.USER); + groupMembership.setCreatedTime(System.currentTimeMillis()); + groupMembership.setUpdatedTime(System.currentTimeMillis()); + groupMembershipRepository.create(groupMembership); + } + return true; + } + + @Override + public boolean removeUsersFromGroup(List<String> userIds, String groupId) throws SharingRegistryException, TException { + for(int i=0; i < userIds.size(); i++){ + GroupMembershipEntityPK groupMembershipEntityPK = new GroupMembershipEntityPK(); + groupMembershipEntityPK.setParentId(groupId); + groupMembershipEntityPK.setChildId(userIds.get(i)); + groupMembershipRepository.delete(groupMembershipEntityPK); + } + return true; + } + + @Override + public Map<String, GroupChildType> getGroupMembers(String groupId, int offset, int limit) throws SharingRegistryException, TException { + HashMap<String, GroupChildType> groupMembers = new HashMap<>(); + HashMap<String, String> filters = new HashMap<>(); + filters.put(DBConstants.GroupMembershipTable.PARENT_ID, groupId); + List<GroupMembership> groupMembershipList = groupMembershipRepository.select(filters, 0, -1); + groupMembershipList.stream().forEach(gm->{groupMembers.put(gm.getChildId(), gm.getChildType());}); + return groupMembers; + } + + @Override + public boolean addChildGroupToParentGroup(String childId, String groupId) throws SharingRegistryException, TException { + //Todo check for cyclic dependencies + GroupMembership groupMembership = new GroupMembership(); + groupMembership.setParentId(groupId); + groupMembership.setChildId(childId); + groupMembership.setChildType(GroupChildType.GROUP); + groupMembership.setCreatedTime(System.currentTimeMillis()); + groupMembership.setUpdatedTime(System.currentTimeMillis()); + groupMembershipRepository.create(groupMembership); + return true; + } + + @Override + public boolean removeChildGroupFromParentGroup(String childId, String groupId) throws SharingRegistryException, TException { + GroupMembershipEntityPK groupMembershipEntityPK = new GroupMembershipEntityPK(); + groupMembershipEntityPK.setParentId(groupId); + groupMembershipEntityPK.setChildId(childId); + groupMembershipRepository.delete(groupMembershipEntityPK); + return true; + } + + /** + * * EntityType Operations + * * + */ + @Override + public String createEntityType(EntityType entityType) throws SharingRegistryException, TException { + if(entityTypeRepository.get(entityType.entityTypeId) != null) + throw new SharingRegistryException("There exist EntityType with given EntityType id"); + + entityType.setCreatedTime(System.currentTimeMillis()); + entityType.setUpdatedTime(System.currentTimeMillis()); + entityTypeRepository.create(entityType); + return entityType.entityTypeId; + } + + @Override + public boolean updateEntityType(EntityType entityType) throws SharingRegistryException, TException { + entityType.setUpdatedTime(System.currentTimeMillis()); + EntityType oldEntityType = entityTypeRepository.get(entityType.entityTypeId); + entityType.setCreatedTime(oldEntityType.createdTime); + entityType = getUpdatedObject(oldEntityType, entityType); + entityTypeRepository.update(entityType); + return true; + } + + @Override + public boolean deleteEntityType(String entityTypeId) throws SharingRegistryException, TException { + entityTypeRepository.delete(entityTypeId); + return true; + } + + @Override + public EntityType getEntityType(String entityTypeId) throws SharingRegistryException, TException { + return entityTypeRepository.get(entityTypeId); + } + + @Override + public List<EntityType> getEntityTypes(String domain, int offset, int limit) throws TException { + HashMap<String, String> filters = new HashMap<>(); + filters.put(DBConstants.EntityTypeTable.DOMAIN_ID, domain); + return entityTypeRepository.select(domain, offset, limit); + } + + /** + * * Permission Operations + * * + */ + @Override + public String createPermissionType(PermissionType permissionType) throws SharingRegistryException, TException { + if(permissionTypeRepository.get(permissionType.permissionTypeId) != null) + throw new SharingRegistryException("There exist PermissionType with given PermissionType id"); + permissionType.setCreatedTime(System.currentTimeMillis()); + permissionType.setUpdatedTime(System.currentTimeMillis()); + permissionTypeRepository.create(permissionType); + return permissionType.permissionTypeId; + } + + @Override + public boolean updatePermissionType(PermissionType permissionType) throws SharingRegistryException, TException { + permissionType.setUpdatedTime(System.currentTimeMillis()); + PermissionType oldPermissionType = permissionTypeRepository.get(permissionType.permissionTypeId); + permissionType = getUpdatedObject(oldPermissionType, permissionType); + permissionTypeRepository.update(permissionType); + return true; + } + + @Override + public boolean deletePermissionType(String entityTypeId) throws SharingRegistryException, TException { + permissionTypeRepository.delete(entityTypeId); + return true; + } + + @Override + public PermissionType getPermissionType(String permissionTypeId) throws SharingRegistryException, TException { + return permissionTypeRepository.get(permissionTypeId); + } + + @Override + public List<PermissionType> getPermissionTypes(String domain, int offset, int limit) throws SharingRegistryException, TException { + HashMap<String, String> filters = new HashMap<>(); + filters.put(DBConstants.PermissionTypeTable.DOMAIN_ID, domain); + return permissionTypeRepository.select(filters, offset, limit); + } + + /** + * * Entity Operations + * * + */ + @Override + public String createEntity(Entity entity) throws SharingRegistryException, TException { + if(entityRepository.get(entity.entityId) != null) + throw new SharingRegistryException("There exist Entity with given Entity id"); + + if(!userRepository.isExists(entity.getOwnerId())){ + User user = new User(); + user.setUserId(entity.getOwnerId()); + user.setDomainId(entity.domainId); + user.setUserName(user.userId.split("@")[0]); + + createUser(user); + + UserGroup userGroup = new UserGroup(); + userGroup.setGroupId(user.userId); + userGroup.setDomainId(user.domainId); + userGroup.setOwnerId(user.userId); + userGroup.setName(user.userName); + userGroup.setDescription("Single user group for " + user.userName); + userGroup.setGroupType(GroupType.SINGLE_USER); + + createGroup(userGroup); + } + + entity.setCreatedTime(System.currentTimeMillis()); + entity.setUpdatedTime(System.currentTimeMillis()); + entityRepository.create(entity); + + //Assigning global permission for the owner + Sharing newSharing = new Sharing(); + newSharing.setPermissionTypeId(permissionTypeRepository.getGlobalPermissionTypeIdForDomain(entity.domainId)); + newSharing.setEntityId(entity.entityId); + newSharing.setGroupId(entity.ownerId); + newSharing.setSharingType(SharingType.DIRECT_CASCADING); + newSharing.setInheritedParentId(entity.entityId); + newSharing.setCreatedTime(System.currentTimeMillis()); + newSharing.setUpdatedTime(System.currentTimeMillis()); + + sharingRepository.create(newSharing); + + //creating records for inherited permissions + if(entity.getParentEntityId() != null && entity.getParentEntityId() != ""){ + List<Sharing> sharings = sharingRepository.getCascadingPermissionsForEntity(entity.parentEntityId); + for(Sharing sharing : sharings){ + newSharing = new Sharing(); + newSharing.setPermissionTypeId(sharing.permissionTypeId); + newSharing.setEntityId(entity.entityId); + newSharing.setGroupId(sharing.groupId); + newSharing.setInheritedParentId(sharing.inheritedParentId); + newSharing.setSharingType(SharingType.INDIRECT_CASCADING); + newSharing.setCreatedTime(System.currentTimeMillis()); + newSharing.setUpdatedTime(System.currentTimeMillis()); + + sharingRepository.create(newSharing); + } + } + + return entity.entityId; + } + + @Override + public boolean updateEntity(Entity entity) throws SharingRegistryException, TException { + //TODO Check for permission changes + entity.setUpdatedTime(System.currentTimeMillis()); + Entity oldEntity = entityRepository.get(entity.getEntityId()); + entity.setCreatedTime(oldEntity.createdTime); + entity = getUpdatedObject(oldEntity, entity); + entityRepository.update(entity); + return true; + } + + @Override + public boolean deleteEntity(String entityId) throws SharingRegistryException, TException { + //TODO Check for permission changes + entityRepository.delete(entityId); + return true; + } + + @Override + public Entity getEntity(String entityId) throws SharingRegistryException, TException { + return entityRepository.get(entityId); + } + + @Override + public List<Entity> searchEntities(String userId, String entityTypeId, Map<EntitySearchFields, String> filters, + int offset, int limit) throws SharingRegistryException, TException { + List<String> groupIds = new ArrayList<>(); + groupIds.add(userId); + groupMembershipRepository.getAllParentMembershipsForChild(userId).stream().forEach(gm->groupIds.add(gm.parentId)); + return entityRepository.searchEntities(groupIds, entityTypeId, filters, offset, limit); + } + + @Override + public List<User> getListOfSharedUsers(String entityId, String permissionTypeId) throws SharingRegistryException, TException { + return null; + } + + @Override + public List<UserGroup> getListOfSharedGroups(String entityId, String permissionTypeId) throws SharingRegistryException, TException { + return null; + } + + /** + * * Sharing Entity with Users and Groups + * * + * + * @param entityId + * @param userList + * @param permissionType + */ + @Override + public boolean shareEntityWithUsers(String entityId, List<String> userList, String permissionTypeId, boolean cascadePermission) throws SharingRegistryException, TException { + return shareEntity(entityId, userList, permissionTypeId, GroupType.SINGLE_USER, cascadePermission); + } + + @Override + public boolean shareEntityWithGroups(String entityId, List<String> groupList, String permissionTypeId, boolean cascadePermission) throws SharingRegistryException, TException { + return shareEntity(entityId, groupList, permissionTypeId, GroupType.MULTI_USER, cascadePermission); + } + + private boolean shareEntity(String entityId, List<String> groupOrUserList, String permissionTypeId, GroupType groupType, boolean cascadePermission) throws SharingRegistryException, TException { + //Adding permission for the specified users/groups for the specified entity + LinkedList<Entity> temp = new LinkedList<>(); + for(String userId : groupOrUserList){ + Sharing sharing = new Sharing(); + sharing.setPermissionTypeId(permissionTypeId); + sharing.setEntityId(entityId); + sharing.setGroupId(userId); + sharing.setInheritedParentId(entityId); + if(cascadePermission) { + sharing.setSharingType(SharingType.DIRECT_CASCADING); + }else { + sharing.setSharingType(SharingType.DIRECT_NON_CASCADING); + } + sharing.setCreatedTime(System.currentTimeMillis()); + sharing.setUpdatedTime(System.currentTimeMillis()); + + sharingRepository.create(sharing); + } + + if(cascadePermission){ + //Adding permission for the specified users/groups for all child entities + entityRepository.getChildEntities(entityId).stream().forEach(e-> temp.addLast(e)); + while(temp.size() > 0){ + Entity entity = temp.pop(); + String childEntityId = entity.entityId; + for(String userId : groupOrUserList){ + Sharing sharing = new Sharing(); + sharing.setPermissionTypeId(permissionTypeId); + sharing.setEntityId(childEntityId); + sharing.setGroupId(userId); + sharing.setInheritedParentId(entityId); + sharing.setSharingType(SharingType.INDIRECT_CASCADING); + sharing.setInheritedParentId(entityId); + sharing.setCreatedTime(System.currentTimeMillis()); + sharing.setUpdatedTime(System.currentTimeMillis()); + sharingRepository.create(sharing); + entityRepository.getChildEntities(childEntityId).stream().forEach(e-> temp.addLast(e)); + } + } + } + return true; + } + + @Override + public boolean revokeEntitySharingFromUsers(String entityId, List<String> userList, String permissionTypeId) throws SharingRegistryException, TException { + return revokeEntitySharing(entityId, userList, permissionTypeId); + } + + + @Override + public boolean revokeEntitySharingFromGroups(String entityId, List<String> groupList, String permissionTypeId) throws SharingRegistryException, TException { + return revokeEntitySharing(entityId, groupList, permissionTypeId); + } + + @Override + public boolean userHasAccess(String domainId, String userId, String entityId, String permissionTypeId) throws SharingRegistryException, TException { + //check whether the user has permission directly or indirectly + List<GroupMembership> parentMemberships = groupMembershipRepository.getAllParentMembershipsForChild(userId); + List<String> groupIds = new ArrayList<>(); + parentMemberships.stream().forEach(pm->groupIds.add(pm.parentId)); + groupIds.add(userId); + return sharingRepository.hasAccess(entityId, groupIds, Arrays.asList(permissionTypeId, + permissionTypeRepository.getGlobalPermissionTypeIdForDomain(domainId))); + } + + public boolean revokeEntitySharing(String entityId, List<String> groupOrUserList, String permissionTypeId) throws SharingRegistryException { + //revoking permission for the entity + for(String groupId : groupOrUserList){ + SharingEntityPK sharingEntityPK = new SharingEntityPK(); + sharingEntityPK.setEntityId(entityId); + sharingEntityPK.setGroupId(groupId); + sharingEntityPK.setPermissionTypeId(permissionTypeId); + sharingEntityPK.setInheritedParentId(entityId); + + sharingRepository.delete(sharingEntityPK); + } + + //revoking permission from inheritance + List<Sharing> temp = new ArrayList<>(); + sharingRepository.getIndirectSharedChildren(entityId, permissionTypeId).stream().forEach(s->temp.add(s)); + for(Sharing sharing : temp){ + String childEntityId = sharing.entityId; + for(String groupId : groupOrUserList){ + SharingEntityPK sharingEntityPK = new SharingEntityPK(); + sharingEntityPK.setEntityId(childEntityId); + sharingEntityPK.setGroupId(groupId); + sharingEntityPK.setPermissionTypeId(permissionTypeId); + sharingEntityPK.setInheritedParentId(entityId); + + sharingRepository.delete(sharingEntityPK); + } + } + return true; + } + + + + private <T> T getUpdatedObject(T oldEntity, T newEntity) throws SharingRegistryException { + Field[] newEntityFields = newEntity.getClass().getDeclaredFields(); + Hashtable newHT = fieldsToHT(newEntityFields, newEntity); + + Class oldEntityClass = oldEntity.getClass(); + Field[] oldEntityFields = oldEntityClass.getDeclaredFields(); + + for (Field field : oldEntityFields){ + field.setAccessible(true); + Object o = newHT.get(field.getName()); + if (o != null){ + Field f = null; + try { + f = oldEntityClass.getDeclaredField(field.getName()); + f.setAccessible(true); + logger.debug("setting " + f.getName()); + f.set(oldEntity, o); + } catch (Exception e) { + throw new SharingRegistryException(e.getMessage()); + } + } + } + return oldEntity; + } + + private static Hashtable<String, Object> fieldsToHT(Field[] fields, Object obj){ + Hashtable<String,Object> hashtable = new Hashtable<>(); + for (Field field: fields){ + field.setAccessible(true); + try { + Object retrievedObject = field.get(obj); + if (retrievedObject != null){ + logger.debug("scanning " + field.getName()); + hashtable.put(field.getName(), field.get(obj)); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + return hashtable; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/resources/META-INF/persistence.xml ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/resources/META-INF/persistence.xml b/modules/sharing-registry/sharing-registry-core/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..7b08528 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> + + <persistence-unit name="airavata-sharing-registry"> + <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> + <class>org.apache.airavata.sharing.registry.db.entities.DomainEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.EntityEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.EntityTypeEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.GroupMembershipEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.PermissionTypeEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.SharingEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.SharingUserEntity</class> + <class>org.apache.airavata.sharing.registry.db.entities.UserGroupEntity</class> + </persistence-unit> +</persistence> http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-derby.sql ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-derby.sql b/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-derby.sql new file mode 100644 index 0000000..4e0fab3 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-derby.sql @@ -0,0 +1,138 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + * +*/ + +CREATE TABLE DOMAIN ( + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (DOMAIN_ID) +); + +CREATE TABLE SHARING_USER ( + USER_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + USER_NAME VARCHAR(255) NOT NULL, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (USER_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +CREATE TABLE USER_GROUP ( + GROUP_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + OWNER_ID VARCHAR(255) NOT NULL, + GROUP_TYPE VARCHAR(255) NOT NULL, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (GROUP_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (OWNER_ID) REFERENCES SHARING_USER(USER_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + + +CREATE TABLE GROUP_MEMBERSHIP ( + PARENT_ID VARCHAR(255) NOT NULL, + CHILD_ID VARCHAR(255) NOT NULL, + CHILD_TYPE VARCHAR(255) NOT NULL, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (PARENT_ID, CHILD_ID), + FOREIGN KEY (PARENT_ID) REFERENCES USER_GROUP(GROUP_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (CHILD_ID) REFERENCES USER_GROUP(GROUP_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +CREATE TABLE ENTITY_TYPE ( + ENTITY_TYPE_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (ENTITY_TYPE_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +CREATE TABLE PERMISSION_TYPE ( + PERMISSION_TYPE_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (PERMISSION_TYPE_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +CREATE TABLE ENTITY ( + ENTITY_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + ENTITY_TYPE_ID VARCHAR(255) NOT NULL, + OWNER_ID VARCHAR(255) NOT NULL, + PARENT_ENTITY_ID VARCHAR(255), + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + FULL_TEXT CLOB, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (ENTITY_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (ENTITY_TYPE_ID) REFERENCES ENTITY_TYPE(ENTITY_TYPE_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (OWNER_ID) REFERENCES SHARING_USER(USER_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (PARENT_ENTITY_ID) REFERENCES ENTITY(ENTITY_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +-- ALTER TABLE ENTITY ADD FULLTEXT FULL_TEXT_INDEX(FULL_TEXT); + +CREATE TABLE ENTITY_METADATA ( + ENTITY_ID VARCHAR (255) NOT NULL, + META_KEY VARCHAR (255) NOT NULL, + META_VALUE VARCHAR (255) NOT NULL, + PRIMARY KEY (ENTITY_ID, META_KEY), + FOREIGN KEY (ENTITY_ID) REFERENCES ENTITY(ENTITY_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +CREATE TABLE SHARING ( + PERMISSION_TYPE_ID VARCHAR(255) NOT NULL, + ENTITY_ID VARCHAR(255) NOT NULL, + GROUP_ID VARCHAR(255) NOT NULL, + SHARING_TYPE VARCHAR(255) NOT NULL, + INHERITED_PARENT_ID VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (PERMISSION_TYPE_ID, ENTITY_ID, GROUP_ID, INHERITED_PARENT_ID), + FOREIGN KEY (PERMISSION_TYPE_ID) REFERENCES PERMISSION_TYPE(PERMISSION_TYPE_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (INHERITED_PARENT_ID) REFERENCES ENTITY(ENTITY_ID) ON DELETE CASCADE ON UPDATE NO ACTION, + FOREIGN KEY (GROUP_ID) REFERENCES USER_GROUP(GROUP_ID) ON DELETE CASCADE ON UPDATE NO ACTION +); + +CREATE TABLE CONFIGURATION +( + CONFIG_KEY VARCHAR(255) NOT NULL, + CONFIG_VALUE VARCHAR(255) NOT NULL, + PRIMARY KEY(CONFIG_KEY, CONFIG_VALUE) +); + +INSERT INTO CONFIGURATION (CONFIG_KEY, CONFIG_VALUE) VALUES('sharing_reg_version', '0.17'); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata/blob/82e57526/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-mysql.sql ---------------------------------------------------------------------- diff --git a/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-mysql.sql b/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-mysql.sql new file mode 100644 index 0000000..ebb3ec0 --- /dev/null +++ b/modules/sharing-registry/sharing-registry-core/src/main/resources/sharing-registry-mysql.sql @@ -0,0 +1,138 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + * +*/ + +CREATE TABLE DOMAIN ( + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (DOMAIN_ID) +); + +CREATE TABLE SHARING_USER ( + USER_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + USER_NAME VARCHAR(255) NOT NULL, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (USER_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE USER_GROUP ( + GROUP_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + OWNER_ID VARCHAR(255) NOT NULL, + GROUP_TYPE VARCHAR(255) NOT NULL, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (GROUP_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (OWNER_ID) REFERENCES SHARING_USER(USER_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + + +CREATE TABLE GROUP_MEMBERSHIP ( + PARENT_ID VARCHAR(255) NOT NULL, + CHILD_ID VARCHAR(255) NOT NULL, + CHILD_TYPE VARCHAR(255) NOT NULL, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (PARENT_ID, CHILD_ID), + FOREIGN KEY (PARENT_ID) REFERENCES USER_GROUP(GROUP_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (CHILD_ID) REFERENCES USER_GROUP(GROUP_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE ENTITY_TYPE ( + ENTITY_TYPE_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (ENTITY_TYPE_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE PERMISSION_TYPE ( + PERMISSION_TYPE_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (PERMISSION_TYPE_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE ENTITY ( + ENTITY_ID VARCHAR(255) NOT NULL, + DOMAIN_ID VARCHAR(255) NOT NULL, + ENTITY_TYPE_ID VARCHAR(255) NOT NULL, + OWNER_ID VARCHAR(255) NOT NULL, + PARENT_ENTITY_ID VARCHAR(255), + NAME VARCHAR(255) NOT NULL, + DESCRIPTION VARCHAR(255), + FULL_TEXT TEXT, + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (ENTITY_ID), + FOREIGN KEY (DOMAIN_ID) REFERENCES DOMAIN(DOMAIN_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ENTITY_TYPE_ID) REFERENCES ENTITY_TYPE(ENTITY_TYPE_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (OWNER_ID) REFERENCES SHARING_USER(USER_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (PARENT_ENTITY_ID) REFERENCES ENTITY(ENTITY_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +ALTER TABLE ENTITY ADD FULLTEXT FULL_TEXT_INDEX(FULL_TEXT); + +CREATE TABLE ENTITY_METADATA ( + ENTITY_ID VARCHAR (255) NOT NULL, + META_KEY VARCHAR (255) NOT NULL, + META_VALUE VARCHAR (255) NOT NULL, + PRIMARY KEY (ENTITY_ID, META_KEY), + FOREIGN KEY (ENTITY_ID) REFERENCES ENTITY(ENTITY_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE SHARING ( + PERMISSION_TYPE_ID VARCHAR(255) NOT NULL, + ENTITY_ID VARCHAR(255) NOT NULL, + GROUP_ID VARCHAR(255) NOT NULL, + SHARING_TYPE VARCHAR(255) NOT NULL, + INHERITED_PARENT_ID VARCHAR(255), + CREATED_TIME BIGINT NOT NULL, + UPDATED_TIME BIGINT NOT NULL, + PRIMARY KEY (PERMISSION_TYPE_ID, ENTITY_ID, GROUP_ID, INHERITED_PARENT_ID), + FOREIGN KEY (PERMISSION_TYPE_ID) REFERENCES PERMISSION_TYPE(PERMISSION_TYPE_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (INHERITED_PARENT_ID) REFERENCES ENTITY(ENTITY_ID) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (GROUP_ID) REFERENCES USER_GROUP(GROUP_ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE CONFIGURATION +( + CONFIG_KEY VARCHAR(255) NOT NULL, + CONFIG_VALUE VARCHAR(255) NOT NULL, + PRIMARY KEY(CONFIG_KEY, CONFIG_VALUE) +); + +INSERT INTO CONFIGURATION (CONFIG_KEY, CONFIG_VALUE) VALUES('sharing_reg_version', '0.17'); \ No newline at end of file
