001package co.codewizards.cloudstore.core.repo.transport;
002
003import static java.util.Objects.*;
004
005import java.net.URL;
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.Comparator;
009import java.util.Iterator;
010import java.util.List;
011import java.util.ServiceLoader;
012
013public class RepoTransportFactoryRegistry {
014
015        private static class RepoTransportFactoryRegistryHolder {
016                public static final RepoTransportFactoryRegistry instance = new RepoTransportFactoryRegistry();
017        }
018
019        public static RepoTransportFactoryRegistry getInstance() {
020                return RepoTransportFactoryRegistryHolder.instance;
021        }
022
023        protected RepoTransportFactoryRegistry() { }
024
025        private List<RepoTransportFactory> repoTransportFactories;
026
027        public RepoTransportFactory getRepoTransportFactoryOrFail(URL remoteRoot) {
028                RepoTransportFactory repoTransportFactory = getRepoTransportFactory(remoteRoot);
029                if (repoTransportFactory == null)
030                        throw new IllegalStateException("There is no RepoTransportFactory supporting this URL: " + remoteRoot);
031
032                return repoTransportFactory;
033        }
034
035        public RepoTransportFactory getRepoTransportFactory(URL remoteRoot) {
036                for (RepoTransportFactory factory : getRepoTransportFactories()) {
037                        if (factory.isSupported(remoteRoot))
038                                return factory;
039                }
040                return null;
041        }
042
043        public List<RepoTransportFactory> getRepoTransportFactories(URL remoteRoot) {
044                List<RepoTransportFactory> result = new ArrayList<RepoTransportFactory>();
045                for (RepoTransportFactory factory : getRepoTransportFactories()) {
046                        if (factory.isSupported(remoteRoot))
047                                result.add(factory);
048                }
049                return Collections.unmodifiableList(result);
050        }
051
052        public synchronized List<RepoTransportFactory> getRepoTransportFactories() {
053                List<RepoTransportFactory> repoTransportFactories = this.repoTransportFactories;
054                if (repoTransportFactories == null) {
055                        repoTransportFactories = loadRepoTransportFactoriesViaServiceLoader();
056                        sortRepoTransportFactories(repoTransportFactories);
057                        this.repoTransportFactories = repoTransportFactories = Collections.unmodifiableList(repoTransportFactories);
058                }
059                return repoTransportFactories;
060        }
061
062        private static List<RepoTransportFactory> loadRepoTransportFactoriesViaServiceLoader() {
063                ArrayList<RepoTransportFactory> repoTransportFactories = new ArrayList<RepoTransportFactory>();
064                ServiceLoader<RepoTransportFactory> sl = ServiceLoader.load(RepoTransportFactory.class);
065                for (Iterator<RepoTransportFactory> it = sl.iterator(); it.hasNext(); ) {
066                        repoTransportFactories.add(it.next());
067                }
068                repoTransportFactories.trimToSize();
069                return repoTransportFactories;
070        }
071
072        protected static int _compare(int x, int y) {
073        return (x < y) ? -1 : ((x == y) ? 0 : 1);
074    }
075
076        private static void sortRepoTransportFactories(List<RepoTransportFactory> repoTransportFactories) {
077                Collections.sort(repoTransportFactories, new Comparator<RepoTransportFactory>() {
078                        @Override
079                        public int compare(RepoTransportFactory o1, RepoTransportFactory o2) {
080                                int result = -1 * _compare(o1.getPriority(), o2.getPriority());
081                                if (result != 0)
082                                        return result;
083
084                                String name1 = o1.getName() == null ? "" : o1.getName();
085                                String name2 = o2.getName() == null ? "" : o2.getName();
086                                result = name1.compareTo(name2);
087                                if (result != 0)
088                                        return result;
089
090                                return o1.getClass().getName().compareTo(o2.getClass().getName());
091                        }
092                });
093        }
094
095        public <F extends RepoTransportFactory> F getRepoTransportFactoryOrFail(Class<F> factoryClass) {
096                F repoTransportFactory = getRepoTransportFactory(factoryClass);
097                if (repoTransportFactory == null)
098                        throw new IllegalArgumentException("There is no factory registered implementing this interface or extending this class: " + factoryClass.getName());
099
100                return repoTransportFactory;
101        }
102
103        public <F extends RepoTransportFactory> F getRepoTransportFactory(Class<F> factoryClass) {
104                requireNonNull(factoryClass, "factoryClass");
105                List<RepoTransportFactory> repoTransportFactories = getRepoTransportFactories();
106                for (RepoTransportFactory repoTransportFactory : repoTransportFactories) {
107                        if (factoryClass.isInstance(repoTransportFactory)) {
108                                return factoryClass.cast(repoTransportFactory);
109                        }
110                }
111                return null;
112        }
113}