001package co.codewizards.cloudstore.local.db;
002
003import static co.codewizards.cloudstore.core.util.StringUtil.*;
004import static co.codewizards.cloudstore.local.db.DatabaseAdapterFactory.*;
005import static java.util.Objects.*;
006
007import java.util.ServiceLoader;
008import java.util.SortedMap;
009import java.util.TreeMap;
010
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014import co.codewizards.cloudstore.core.config.ConfigImpl;
015
016public class DatabaseAdapterFactoryRegistry {
017        private static final Logger logger = LoggerFactory.getLogger(DatabaseAdapterFactoryRegistry.class);
018
019        private DatabaseAdapterFactory databaseAdapterFactory;
020
021        protected DatabaseAdapterFactoryRegistry() { }
022
023        private static final class Holder {
024                public static final DatabaseAdapterFactoryRegistry instance = new DatabaseAdapterFactoryRegistry();
025        }
026
027        public static DatabaseAdapterFactoryRegistry getInstance() {
028                return Holder.instance;
029        }
030
031        /**
032         * @deprecated Should normally only be used by tests.
033         */
034        @Deprecated
035        public void clearCache() {
036                logger.info("clearCache: entered.");
037                databaseAdapterFactory = null;
038        }
039
040        public DatabaseAdapter createDatabaseAdapter() {
041                final DatabaseAdapterFactory databaseAdapterFactory= getDatabaseAdapterFactoryOrFail();
042                final DatabaseAdapter databaseAdapter = databaseAdapterFactory.createDatabaseAdapter();
043                if (databaseAdapter == null)
044                        throw new IllegalStateException(String.format("databaseAdapterFactory.createDatabaseAdapter() returned null! Implementation error in %s!",
045                                        databaseAdapterFactory.getClass().getName()));
046
047                return databaseAdapter;
048        }
049
050        protected DatabaseAdapterFactory getDatabaseAdapterFactoryOrFail() {
051                DatabaseAdapterFactory databaseAdapterFactory = this.databaseAdapterFactory;
052                if (databaseAdapterFactory == null) {
053                        final String databaseAdaptorName = ConfigImpl.getInstance().getPropertyAsNonEmptyTrimmedString(
054                                        CONFIG_KEY_DATABASE_ADAPTER_NAME, DEFAULT_DATABASE_ADAPTER_NAME);
055
056                        final SortedMap<String, DatabaseAdapterFactory> name2DatabaseAdapter = getName2DatabaseAdapterFactory();
057                        if (name2DatabaseAdapter.isEmpty())
058                                throw new IllegalStateException("There is no DatabaseAdapterFactory registered!");
059
060                        if (isEmpty(databaseAdaptorName))
061                                databaseAdapterFactory = getDatabaseAdapterFactoryWithHighestPriority(name2DatabaseAdapter);
062                        else {
063                                databaseAdapterFactory = name2DatabaseAdapter.get(databaseAdaptorName);
064                                if (databaseAdapterFactory == null)
065                                        throw new IllegalArgumentException(String.format("There is no DatabaseAdapterFactory with name='%s'!", databaseAdaptorName));
066                        }
067
068                        this.databaseAdapterFactory = databaseAdapterFactory;
069                }
070                else
071                        logger.debug("getDatabaseAdapterFactoryOrFail: returning existing DatabaseAdapterFactory instance.");
072
073                return databaseAdapterFactory;
074        }
075
076        private static SortedMap<String, DatabaseAdapterFactory> getName2DatabaseAdapterFactory() {
077                SortedMap<String, DatabaseAdapterFactory> result = new TreeMap<String, DatabaseAdapterFactory>();
078                for (final DatabaseAdapterFactory a : ServiceLoader.load(DatabaseAdapterFactory.class)) {
079                        final String name = a.getName();
080                        requireNonNull(name, String.format("%s.getName()", a.getClass().getName()));
081                        if (name.indexOf(' ') >= 0)
082                                throw new IllegalStateException(
083                                                String.format("%s.getName() returned a symbolic name containing a space!", a.getClass().getName()));
084
085                        final DatabaseAdapterFactory old = result.put(name, a);
086                        if (old != null)
087                                throw new IllegalStateException(
088                                                        String.format("There are multiple DatabaseAdapterFactory classes with name='%s'! %s + %s",
089                                                                        name, a.getClass().getName(), old.getClass().getName()));
090                }
091                return result;
092        }
093
094        private static DatabaseAdapterFactory getDatabaseAdapterFactoryWithHighestPriority(final SortedMap<String, DatabaseAdapterFactory> name2DatabaseAdapter) {
095                DatabaseAdapterFactory databaseAdapterFactory = null;
096                for (final DatabaseAdapterFactory a : name2DatabaseAdapter.values()) {
097                        if (databaseAdapterFactory == null || databaseAdapterFactory.getPriority() < a.getPriority())
098                                databaseAdapterFactory = a;
099                }
100                return databaseAdapterFactory;
101        }
102}