import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.InputStream;
-import java.math.BigInteger;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
-import java.util.regex.Pattern;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
* @author
*/
public class ServiceMain {
- final static Logger logger = LoggerFactory.getLogger(ServiceMain.class);
-
- public static final String VER_DISPLAY_NAME = "CollectionSpace Services v6.0";
- public static final String VER_MAJOR = "6";
- public static final String VER_MINOR = "0";
- public static final String VER_PATCH = "0";
- public static final String VER_BUILD = "1";
+ final static Logger logger = LoggerFactory.getLogger(ServiceMain.class);
private static final int PRIMARY_REPOSITORY_DOMAIN = 0;
/**
}
}
- private String applyRepositoryUpgradeScripts(Connection conn, String dataSourceName, String repositoryName, String fromVersion, String stage) throws Exception {
- Map<String, List<File>> upgradeScriptFiles = getRepositoryUpgradeScripts(dataSourceName, repositoryName, fromVersion, stage);
- Set<String> versions = upgradeScriptFiles.keySet();
-
- String upgradedToVersion = null;
-
- if (versions.size() > 0) {
- for (String version : versions) {
- logger.info(String.format("upgrading %s repository to version %s", repositoryName, version));
-
- List<File> scriptFiles = upgradeScriptFiles.get(version);
-
- for (File file : scriptFiles) {
- if (file.getName().endsWith(".sql")) {
- logger.info(String.format("Running %s", file.getName()));
-
- JDBCTools.runScript(conn, file);
- }
- }
-
- upgradedToVersion = version;
- }
- }
-
- return upgradedToVersion;
- }
-
- private void upgradeRepository(String dataSourceName, String repositoryName, String cspaceInstanceId) throws Exception {
- // Install the pgcrypto extension so that the gen_random_uuid function will be available
- // to upgrade scripts.
-
- JDBCTools.executeUpdate(JDBCTools.CSADMIN_NUXEO_DATASOURCE_NAME, repositoryName, cspaceInstanceId, "CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"");
-
- String stage = "post-init";
- Connection conn = null;
-
- try {
- conn = JDBCTools.getConnection(dataSourceName, repositoryName, cspaceInstanceId);
-
- conn.setAutoCommit(false);
-
- String version = JDBCTools.getRepositoryDatabaseVersion(conn);
-
- logger.info(String.format("%s repository current version is %s", repositoryName, version));
-
- String upgradedToVersion = applyRepositoryUpgradeScripts(conn, dataSourceName, repositoryName, version, stage);
-
- if (upgradedToVersion != null) {
- logger.info(String.format("%s repository upgraded to version %s", repositoryName, upgradedToVersion));
-
- JDBCTools.setRepositoryDatabaseVersion(conn, upgradedToVersion);
- }
-
- conn.commit();
- }
- catch (Exception e) {
- if (conn != null) {
- conn.rollback();
- }
- }
- finally {
- if (conn != null) {
- conn.close();
- }
- }
- }
-
- void upgradeDatabase() throws Exception {
- Hashtable<String, TenantBindingType> tenantBindingTypeMap = tenantBindingConfigReader.getTenantBindings();
-
- // Loop through all tenants in tenant-bindings.xml
-
- String cspaceInstanceId = getCspaceInstanceId();
-
- for (TenantBindingType tbt : tenantBindingTypeMap.values()) {
- List<String> repositoryNameList = ConfigUtils.getRepositoryNameList(tbt);
-
- if (repositoryNameList != null && repositoryNameList.isEmpty() == false) {
- // Loop through each repo/DB defined in a tenant bindings file
-
- for (String repositoryName : repositoryNameList) {
- upgradeRepository(JDBCTools.NUXEO_DATASOURCE_NAME, repositoryName, cspaceInstanceId);
- }
- } else {
- String errMsg = "repositoryNameList was empty or null.";
-
- logger.error(errMsg);
-
- throw new Exception(errMsg);
- }
- }
- }
-
- public static Map<String, List<File>> getRepositoryUpgradeScripts(String dataSourceName, String repositoryName, String fromVersion, String stage) throws Exception {
- Map<String, List<File>> upgradeScriptFiles = new LinkedHashMap<>();
-
- Path upgradesPath = Paths.get(
- ServiceMain.getInstance().getServerRootDir(),
- JEEServerDeployment.DATABASE_SCRIPTS_DIR_PATH,
- JDBCTools.getDatabaseProductType(dataSourceName, repositoryName).toString(),
- "upgrade"
- );
-
- File upgradesDirectory = upgradesPath.toFile();
-
- if (!upgradesDirectory.isDirectory() || !upgradesDirectory.canRead()) {
- return upgradeScriptFiles;
- }
-
- File[] upgradesDirectoryFiles = upgradesDirectory.listFiles();
- List<File> versionDirectories = new ArrayList<>();
- VersionComparator versionComparator = new VersionComparator();
-
- for (File file : upgradesDirectoryFiles) {
- if (
- file.isDirectory()
- && file.canRead()
- && file.getName().matches("^\\d+\\.\\d+(\\.\\d+)?$")
- && versionComparator.compare(fromVersion, file.getName()) < 0
- ) {
- versionDirectories.add(file);
- }
- }
-
- versionDirectories.sort(new VersionFileNameComparator());
-
- for (File versionDir : versionDirectories) {
- Path versionStagePath = versionDir.toPath().resolve(stage);
- File versionStageDirectory = versionStagePath.toFile();
-
- if (versionStageDirectory.isDirectory()) {
- File[] versionStageFiles = versionStageDirectory.listFiles();
-
- Arrays.sort(versionStageFiles);
-
- List<File> scriptFiles = new ArrayList<>();
-
- for (File file : versionStageFiles) {
- if (
- file.isFile()
- && file.canRead()
- ) {
- scriptFiles.add(file);
- }
- }
-
- if (scriptFiles.size() > 0) {
- upgradeScriptFiles.put(versionDir.getName(), scriptFiles);
- }
- }
- }
-
- return upgradeScriptFiles;
- }
-
- /**
- * From https://dzone.com/articles/semantically-ordering-versioned-file-names-in-java
- */
- public static class VersionComparator implements Comparator<String> {
- private static final Pattern NUMBERS = Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
-
- @Override
- public final int compare(String o1, String o2) {
- // Optional "NULLS LAST" semantics:
- if (o1 == null || o2 == null) {
- return o1 == null ? o2 == null ? 0 : -1 : 1;
- }
-
- // Splitting both input strings by the above patterns
- String[] split1 = NUMBERS.split(o1);
- String[] split2 = NUMBERS.split(o2);
- int length = Math.min(split1.length, split2.length);
-
- // Looping over the individual segments
- for (int i = 0; i < length; i++) {
- char c1 = split1[i].charAt(0);
- char c2 = split2[i].charAt(0);
- int cmp = 0;
-
- // If both segments start with a digit, sort them
- // numerically using BigInteger to stay safe
- if (c1 >= '0' && c1 <= '9' && c2 >= 0 && c2 <= '9')
- cmp = new BigInteger(split1[i]).compareTo(
- new BigInteger(split2[i]));
-
- // If we haven't sorted numerically before, or if
- // numeric sorting yielded equality (e.g 007 and 7)
- // then sort lexicographically
- if (cmp == 0)
- cmp = split1[i].compareTo(split2[i]);
-
- // Abort once some prefix has unequal ordering
- if (cmp != 0)
- return cmp;
- }
-
- // If we reach this, then both strings have equally
- // ordered prefixes, but maybe one string is longer than
- // the other (i.e. has more segments)
- return split1.length - split2.length;
- }
- }
-
- public static class VersionFileNameComparator implements Comparator<File> {
- private final VersionComparator versionComparator = new VersionComparator();
-
- @Override
- public final int compare(File o1, File o2) {
- return versionComparator.compare(o1.getName(), o2.getName());
- }
- }
-
/**
* Create required indexes (aka indices) in database tables not associated
* with any specific tenant.
}
return result;
- }
+ }
+ /*
+ * Look through the tenant bindings and create the required Nuxeo databases -each tenant can declare
+ * their own Nuxeo repository/database.
+ * Get the NuxeoDS info and create the necessary databases.
+ * Consider the tenant bindings to find and get the data sources for each tenant.
+ * There may be only one, one per tenant, or something in between.
+ *
+ */
+ private HashSet<String> createNuxeoDatabases() throws Exception {
+ String nuxeoUser = getBasicDataSourceUsername(JDBCTools.NUXEO_DATASOURCE_NAME);
+ String nuxeoPW = getBasicDataSourcePassword(JDBCTools.NUXEO_DATASOURCE_NAME);
- /*
- * Look through the tenant bindings and create the required Nuxeo databases -each tenant can declare
- * their own Nuxeo repository/database.
- * Get the NuxeoDS info and create the necessary databases.
- * Consider the tenant bindings to find and get the data sources for each tenant.
- * There may be only one, one per tenant, or something in between.
- *
- */
- private HashSet<String> createNuxeoDatabases() throws Exception {
- String nuxeoUser = getBasicDataSourceUsername(JDBCTools.NUXEO_DATASOURCE_NAME);
- String nuxeoPW = getBasicDataSourcePassword(JDBCTools.NUXEO_DATASOURCE_NAME);
-
- String readerUser = getBasicDataSourceUsername(JDBCTools.NUXEO_READER_DATASOURCE_NAME);
- String readerPW = getBasicDataSourcePassword(JDBCTools.NUXEO_READER_DATASOURCE_NAME);
-
- DatabaseProductType dbType = JDBCTools.getDatabaseProductType(JDBCTools.CSADMIN_DATASOURCE_NAME,
- getServiceConfig().getDbCsadminName());
-
- Hashtable<String, TenantBindingType> tenantBindings =
- tenantBindingConfigReader.getTenantBindings();
- HashSet<String> nuxeoDBsChecked = new HashSet<String>();
-
- // First check and create the roles as needed. (nuxeo and reader)
- for (TenantBindingType tenantBinding : tenantBindings.values()) {
- String tId = tenantBinding.getId();
- String tName = tenantBinding.getName();
-
- List<RepositoryDomainType> repoDomainList = tenantBinding.getRepositoryDomain();
- for (RepositoryDomainType repoDomain : repoDomainList) {
- String repoDomainName = repoDomain.getName();
- String repositoryName = repoDomain.getRepositoryName();
- String cspaceInstanceId = getCspaceInstanceId();
- String dbName = JDBCTools.getDatabaseName(repositoryName, cspaceInstanceId);
- if (nuxeoDBsChecked.contains(dbName)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Another user of db: " + dbName + ": Repo: " + repoDomainName
- + " and tenant: " + tName + " (id:" + tId + ")");
- }
- } else {
- if (logger.isDebugEnabled()) {
- logger.debug("Need to prepare db: " + dbName + " for Repo: " + repoDomainName
- + " and tenant: " + tName + " (id:" + tId + ")");
- }
- boolean dbExists = JDBCTools.hasDatabase(dbType, dbName);
- if (dbExists) {
- if (logger.isDebugEnabled()) {
- logger.debug("Database: " + dbName + " already exists.");
- }
- } else {
- // Create the user as needed
- JDBCTools.createNewDatabaseUser(JDBCTools.CSADMIN_DATASOURCE_NAME, repositoryName, cspaceInstanceId, dbType, nuxeoUser, nuxeoPW);
- if (readerUser != null) {
- JDBCTools.createNewDatabaseUser(JDBCTools.CSADMIN_DATASOURCE_NAME, repositoryName, cspaceInstanceId, dbType, readerUser, readerPW);
- }
- // Create the database
- createDatabaseWithRights(dbType, dbName, nuxeoUser, nuxeoPW, readerUser, readerPW);
- initRepositoryDatabaseVersion(JDBCTools.NUXEO_DATASOURCE_NAME, repositoryName, cspaceInstanceId);
- }
- nuxeoDBsChecked.add(dbName);
- }
- } // Loop on repos for tenant
- } // Loop on tenants
+ String readerUser = getBasicDataSourceUsername(JDBCTools.NUXEO_READER_DATASOURCE_NAME);
+ String readerPW = getBasicDataSourcePassword(JDBCTools.NUXEO_READER_DATASOURCE_NAME);
- return nuxeoDBsChecked;
+ DatabaseProductType dbType = JDBCTools.getDatabaseProductType(JDBCTools.CSADMIN_DATASOURCE_NAME,
+ getServiceConfig().getDbCsadminName());
- }
+ Hashtable<String, TenantBindingType> tenantBindings =
+ tenantBindingConfigReader.getTenantBindings();
+ HashSet<String> nuxeoDBsChecked = new HashSet<String>();
- /**
- * Creates a Nuxeo-managed database, sets up an owner for that
- * database, and adds (at least) connection privileges to a reader
- * of that database.
- *
- * @param conn
- * @param dbType
- * @param dbName
- * @param ownerName
- * @param ownerPW
- * @param readerName
- * @param readerPW
- * @throws Exception
- */
+ // First check and create the roles as needed. (nuxeo and reader)
+ for (TenantBindingType tenantBinding : tenantBindings.values()) {
+ String tId = tenantBinding.getId();
+ String tName = tenantBinding.getName();
+
+ List<RepositoryDomainType> repoDomainList = tenantBinding.getRepositoryDomain();
+ for (RepositoryDomainType repoDomain : repoDomainList) {
+ String repoDomainName = repoDomain.getName();
+ String repositoryName = repoDomain.getRepositoryName();
+ String cspaceInstanceId = getCspaceInstanceId();
+ String dbName = JDBCTools.getDatabaseName(repositoryName, cspaceInstanceId);
+ if (nuxeoDBsChecked.contains(dbName)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Another user of db: " + dbName + ": Repo: " + repoDomainName
+ + " and tenant: " + tName + " (id:" + tId + ")");
+ }
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Need to prepare db: " + dbName + " for Repo: " + repoDomainName
+ + " and tenant: " + tName + " (id:" + tId + ")");
+ }
+ boolean dbExists = JDBCTools.hasDatabase(dbType, dbName);
+ if (dbExists) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Database: " + dbName + " already exists.");
+ }
+ } else {
+ // Create the user as needed
+ JDBCTools.createNewDatabaseUser(JDBCTools.CSADMIN_DATASOURCE_NAME, repositoryName, cspaceInstanceId, dbType, nuxeoUser, nuxeoPW);
+ if (readerUser != null) {
+ JDBCTools.createNewDatabaseUser(JDBCTools.CSADMIN_DATASOURCE_NAME, repositoryName, cspaceInstanceId, dbType, readerUser, readerPW);
+ }
+ // Create the database
+ createDatabaseWithRights(dbType, dbName, nuxeoUser, nuxeoPW, readerUser, readerPW);
+ }
+ nuxeoDBsChecked.add(dbName);
+ }
+ } // Loop on repos for tenant
+ } // Loop on tenants
+
+ return nuxeoDBsChecked;
+
+ }
+
+ /**
+ * Creates a Nuxeo-managed database, sets up an owner for that
+ * database, and adds (at least) connection privileges to a reader
+ * of that database.
+ *
+ * @param conn
+ * @param dbType
+ * @param dbName
+ * @param ownerName
+ * @param ownerPW
+ * @param readerName
+ * @param readerPW
+ * @throws Exception
+ */
private void createDatabaseWithRights(DatabaseProductType dbType, String dbName, String ownerName,
String ownerPW, String readerName, String readerPW) throws Exception {
- Connection conn = null;
+ Connection conn = null;
Statement stmt = null;
try {
DataSource csadminDataSource = JDBCTools.getDataSource(JDBCTools.CSADMIN_DATASOURCE_NAME);
if (stmt != null) {
stmt.close();
}
- if (conn != null) {
- conn.close();
- }
+ if (conn != null) {
+ conn.close();
+ }
} catch (SQLException se) {
se.printStackTrace();
}
}
- }
-
- private void initRepositoryDatabaseVersion(String dataSourceName, String repositoryName, String cspaceInstanceId) throws Exception {
- String version = ServiceMain.VER_MAJOR + "." + ServiceMain.VER_MINOR + "." + ServiceMain.VER_PATCH;
- Connection conn = null;
-
- try {
- conn = JDBCTools.getConnection(dataSourceName, repositoryName, cspaceInstanceId);
- JDBCTools.setRepositoryDatabaseVersion(conn, version);
- }
- finally {
- if (conn != null) {
- conn.close();
- }
- }
}
private BasicDataSource getBasicDataSource(String dataSourceName) {
*/
package org.collectionspace.services.common.storage;
-import org.collectionspace.services.common.ServiceMain;
-import org.collectionspace.services.common.api.JEEServerDeployment;
import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.config.ConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java_cup.version;
-
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.DatabaseMetaData;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
import javax.sql.rowset.CachedRowSet;
import javax.sql.rowset.RowSetFactory;
import javax.sql.rowset.RowSetProvider;
-import org.apache.ibatis.jdbc.ScriptRunner;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
/**
public static String DEFAULT_NUXEO_REPOSITORY_NAME = ConfigUtils.DEFAULT_NUXEO_REPOSITORY_NAME;
public static String DEFAULT_NUXEO_DATABASE_NAME = ConfigUtils.DEFAULT_NUXEO_DATABASE_NAME;
public static String CSADMIN_DATASOURCE_NAME = "CsadminDS";
- public static String CSADMIN_NUXEO_DATASOURCE_NAME = "Csadmin_NuxeoDS";
public static String NUXEO_READER_DATASOURCE_NAME = "NuxeoReaderDS";
public static String NUXEO_USER_NAME = "nuxeo";
public static String SQL_WILDCARD = "%";
public static String DATABASE_SELECT_PRIVILEGE_NAME = "SELECT";
public static String POSTGRES_UNIQUE_VIOLATION = "23505";
- private final static String DATABASE_RESOURCE_DIRECTORY_NAME = "db";
//
// Private constants
//
private static String DBProductName = null;
- private static String serverResourcesPath;
//todo: make sure this will get instantiated in the right order
final static Logger logger = LoggerFactory.getLogger(JDBCTools.class);
}
}
- public static boolean cspaceMetaTableExists(Connection conn) throws SQLException {
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery("SELECT true FROM pg_tables WHERE schemaname = 'cspace' AND tablename = 'meta'");
-
- boolean exists = false;
-
- if (rs.next()) {
- exists = rs.getBoolean(1);
- };
-
- rs.close();
- stmt.close();
-
- return exists;
- }
-
- public static void createCspaceMetaTable(Connection conn) throws SQLException {
- Statement stmt = conn.createStatement();
-
- stmt.executeUpdate("CREATE SCHEMA cspace");
- stmt.executeUpdate("CREATE TABLE cspace.meta (version varchar(32))");
- stmt.executeUpdate("INSERT INTO cspace.meta (version) values (null)");
-
- stmt.close();
- }
-
- public static String getRepositoryDatabaseVersion(Connection conn) throws SQLException {
- String version = "0";
-
- if (cspaceMetaTableExists(conn)) {
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery("SELECT version FROM cspace.meta");
-
- if (rs.next()) {
- version = rs.getString(1);
- }
-
- rs.close();
- stmt.close();
- }
-
- return version;
- }
-
- public static void setRepositoryDatabaseVersion(Connection conn, String version) throws SQLException {
- if (!cspaceMetaTableExists(conn)) {
- createCspaceMetaTable(conn);
- }
-
- PreparedStatement stmt = conn.prepareStatement("UPDATE cspace.meta SET version = ?");
-
- stmt.setString(1, version);
- stmt.executeUpdate();
-
- stmt.close();
- }
-
- public static void runScript(Connection conn, File scriptFile) throws FileNotFoundException {
- ScriptRunner scriptRunner = new ScriptRunner(conn);
- Reader reader = new BufferedReader(new FileReader(scriptFile));
-
- scriptRunner.runScript(reader);
- }
}