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