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}