001package co.codewizards.cloudstore.local;
002
003import static co.codewizards.cloudstore.core.io.StreamUtil.*;
004import static co.codewizards.cloudstore.core.oio.OioFileFactory.*;
005import static co.codewizards.cloudstore.core.repo.local.LocalRepoManager.*;
006import static co.codewizards.cloudstore.core.util.StringUtil.*;
007import static java.util.Objects.*;
008
009import java.io.InputStream;
010import java.sql.Connection;
011import java.sql.DriverManager;
012import java.sql.SQLException;
013import java.util.Map;
014import java.util.Properties;
015import java.util.UUID;
016
017import javax.jdo.PersistenceManagerFactory;
018
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021
022import co.codewizards.cloudstore.core.oio.File;
023
024/**
025 * Factory creating JDBC connections to the repository's derby database.
026 * <p>
027 * <b>Important: This is for maintenance only!</b> Ordinary operations work with a {@link PersistenceManagerFactory}
028 * which is managed by {@link LocalRepoManagerImpl}.
029 * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
030 */
031public class JdbcConnectionFactory {
032        private static final Logger logger = LoggerFactory.getLogger(JdbcConnectionFactory.class);
033
034        private final File localRoot;
035
036        private String connectionURL;
037
038        private String connectionDriverName;
039
040        private String connectionUserName;
041
042        private String connectionPassword;
043
044        public JdbcConnectionFactory(final File localRoot) {
045                this.localRoot = requireNonNull(localRoot, "localRoot");
046                if (!localRoot.isDirectory())
047                        throw new IllegalArgumentException("The given localRoot is not an existing directory: " + localRoot.getAbsolutePath());
048
049                initProperties();
050                initDriverClass();
051        }
052
053        private UUID readRepositoryIdFromRepositoryPropertiesFile() {
054                final File repositoryPropertiesFile = createFile(getMetaDir(), REPOSITORY_PROPERTIES_FILE_NAME);
055                try {
056                        final Properties repositoryProperties = new Properties();
057                        try (InputStream in = castStream(repositoryPropertiesFile.createInputStream())) {
058                                repositoryProperties.load(in);
059                        }
060                        final String repositoryIdStr = repositoryProperties.getProperty(PROP_REPOSITORY_ID);
061                        if (isEmpty(repositoryIdStr))
062                                throw new IllegalStateException("repositoryProperties.getProperty(PROP_REPOSITORY_ID) is empty!");
063
064                        final UUID repositoryId = UUID.fromString(repositoryIdStr);
065                        return repositoryId;
066                } catch (Exception x) {
067                        throw new RuntimeException("Reading readRepositoryId from '" + repositoryPropertiesFile.getAbsolutePath() + "' failed: " + x, x);
068                }
069        }
070
071        private void initProperties() {
072                UUID repositoryId = readRepositoryIdFromRepositoryPropertiesFile();
073                Map<String, String> persistenceProperties = new PersistencePropertiesProvider(repositoryId, localRoot).getPersistenceProperties();
074                connectionDriverName = persistenceProperties.get(PersistencePropertiesEnum.CONNECTION_DRIVER_NAME.key);
075                connectionURL = persistenceProperties.get(PersistencePropertiesEnum.CONNECTION_URL.key);
076                connectionUserName = persistenceProperties.get(PersistencePropertiesEnum.CONNECTION_USER_NAME.key);
077                connectionPassword = persistenceProperties.get(PersistencePropertiesEnum.CONNECTION_PASSWORD.key);
078        };
079
080        protected File getMetaDir() {
081                return createFile(localRoot, META_DIR_NAME);
082        }
083
084        private void initDriverClass() {
085                if (isEmpty(connectionDriverName))
086                        return;
087
088                try {
089                        Class.forName(connectionDriverName);
090                } catch (Throwable e) { // Might theoretically be a link error (i.e. a sub-class of Error instead of Exception) => catch Throwable
091                        logger.warn("initDriverClass" + e, e);
092                }
093        }
094
095        public Connection createConnection() throws SQLException {
096                if (isEmpty(connectionUserName) && isEmpty(connectionPassword))
097                        return DriverManager.getConnection(connectionURL);
098                else
099                        return DriverManager.getConnection(connectionURL, connectionUserName, connectionPassword);
100        }
101}