diff --git a/src/main/java/de/adito/picoservice/DefaultPicoRegistry.java b/src/main/java/de/adito/picoservice/DefaultPicoRegistry.java new file mode 100644 index 0000000..03a5953 --- /dev/null +++ b/src/main/java/de/adito/picoservice/DefaultPicoRegistry.java @@ -0,0 +1,86 @@ +package de.adito.picoservice; + +import javax.annotation.Nonnull; +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * @author j.boesl, 21.04.17 + */ +public class DefaultPicoRegistry implements IPicoRegistry +{ + + private final Collection loadedServices; + private final Map, Collection>> searchedTypeToAnnotatedClassesMap; + + + protected DefaultPicoRegistry() + { + loadedServices = _loadServices(); + searchedTypeToAnnotatedClassesMap = new HashMap<>(); + } + + @Nonnull + @Override + public Map, A> find(@Nonnull Class pSearchedType, + @Nonnull Class pAnnotationClass) + { + Map, A> map = new HashMap<>(); + for (Class cls : _getSearchedTypes(pSearchedType)) { + A annotation = cls.getAnnotation(pAnnotationClass); + if (annotation != null) + map.put(cls, annotation); + } + return map; + } + + @Nonnull + @Override + public Stream find(@Nonnull Class pSearchedType, + @Nonnull Function, T> pResolverFunction) + { + Collection> searchedTypes = _getSearchedTypes(pSearchedType); + return searchedTypes.stream() + .map(pResolverFunction) + .filter(Objects::nonNull); + } + + @SuppressWarnings("unchecked") + private Collection> _getSearchedTypes(Class pSearchedType) + { + return (Collection) searchedTypeToAnnotatedClassesMap.computeIfAbsent(pSearchedType, searchedType -> { + ArrayList> st = new ArrayList<>(); + for (IPicoRegistration registration : loadedServices) { + Class annotatedClass = registration.getAnnotatedClass(); + if (searchedType.isAssignableFrom(annotatedClass)) + st.add((Class) annotatedClass); + } + if (st.isEmpty()) + return Collections.emptySet(); + st.trimToSize(); + return Collections.unmodifiableCollection(st); + }); + } + + /** + * We have to load all of our PicoServices into a separate collection, because + * the Java-ServiceLoader throws a ConcurrentModificationException if >1 iterators + * are iterated at the same time. + * Reloading of cached Registrations is currently not supported yet. + * + * @see https://anydoby.com/jblog/en/java/2128 + * @see https://issues.apache.org/jira/browse/SIS-193 + */ + @Nonnull + private Collection _loadServices() + { + ServiceLoader serviceLoader = ServiceLoader.load(IPicoRegistration.class); + Set foundServices = new HashSet<>(); + for (IPicoRegistration registration : serviceLoader) + foundServices.add(registration); + return Collections.unmodifiableSet(foundServices); + } + +} diff --git a/src/main/java/de/adito/picoservice/InstanceLoader.java b/src/main/java/de/adito/picoservice/InstanceLoader.java index bd19d8a..8ddcb9d 100644 --- a/src/main/java/de/adito/picoservice/InstanceLoader.java +++ b/src/main/java/de/adito/picoservice/InstanceLoader.java @@ -1,10 +1,6 @@ package de.adito.picoservice; -import javax.annotation.Nonnull; -import java.lang.annotation.Annotation; import java.util.*; -import java.util.function.Function; -import java.util.stream.Stream; /** * Default implementation for {@link de.adito.picoservice.IPicoRegistry} available at @@ -25,71 +21,6 @@ IPicoRegistry load() return iterator.next(); // create default - return new IPicoRegistry() - { - private final ServiceLoader serviceLoader = ServiceLoader.load(IPicoRegistration.class); - private final Collection loadedServices = _loadServices(); - - @Nonnull - @Override - public Map, A> find(@Nonnull Class pSearchedType, - @Nonnull Class pAnnotationClass) - { - Map, A> map = new HashMap<>(); - for (IPicoRegistration registration : loadedServices) - { - Class annotatedClass = registration.getAnnotatedClass(); - if (pSearchedType.isAssignableFrom(annotatedClass)) - { - Annotation annotation = annotatedClass.getAnnotation(pAnnotationClass); - if (annotation != null) - //noinspection unchecked - map.put((Class) annotatedClass, (A) annotation); - } - } - return map; - } - - @Nonnull - @Override - public Stream find(@Nonnull Class pSearchedType, - @Nonnull Function, T> pResolverFunction) - { - Stream.Builder streamBuilder = Stream.builder(); - for (IPicoRegistration registration : loadedServices) - { - Class annotatedClass = registration.getAnnotatedClass(); - if (pSearchedType.isAssignableFrom(annotatedClass)) - { - @SuppressWarnings("unchecked") - T result = pResolverFunction.apply((Class) annotatedClass); - if (result != null) - streamBuilder.add(result); - } - } - return streamBuilder.build(); - } - - /** - * We have to load all of our PicoServices into a separate collection, because - * the Java-ServiceLoader throws a ConcurrentModificationException if >1 iterators - * are iterated at the same time. - * Reloading of cached Registrations is currently not supported yet. - * - * @see https://anydoby.com/jblog/en/java/2128 - * @see https://issues.apache.org/jira/browse/SIS-193 - */ - @Nonnull - private Collection _loadServices() - { - synchronized (serviceLoader) - { - HashSet foundServices = new HashSet<>(); - for (IPicoRegistration registration : serviceLoader) - foundServices.add(registration); - return Collections.unmodifiableSet(foundServices); - } - } - }; + return new DefaultPicoRegistry(); } }