001package co.codewizards.cloudstore.ls.core.invoke.filter;
002
003import static co.codewizards.cloudstore.core.util.AssertUtil.*;
004
005import java.util.ArrayList;
006import java.util.Collections;
007import java.util.Comparator;
008import java.util.Iterator;
009import java.util.List;
010import java.util.ServiceLoader;
011
012public class InvocationFilterRegistry {
013
014        private List<Class<? extends InvocationFilter>> invocationFilterClasses;
015
016        private static final class Holder {
017                public static final InvocationFilterRegistry instance = new InvocationFilterRegistry();
018        }
019
020        private InvocationFilterRegistry() {
021        }
022
023        public static InvocationFilterRegistry getInstance() {
024                return Holder.instance;
025        }
026
027        private List<InvocationFilter> loadInvocationFilters() {
028                final List<InvocationFilter> result = new ArrayList<>();
029
030                final Iterator<InvocationFilter> iterator = ServiceLoader.load(InvocationFilter.class).iterator();
031                while (iterator.hasNext())
032                        result.add(iterator.next());
033
034                Collections.sort(result, new Comparator<InvocationFilter>() {
035                        @Override
036                        public int compare(InvocationFilter o1, InvocationFilter o2) {
037                                int result = -1 * Integer.compare(o1.getPriority(), o2.getPriority());
038                                if (result != 0)
039                                        return result;
040
041                                result = o1.getClass().getName().compareTo(o2.getClass().getName());
042                                return result;
043                        }
044                });
045                return result;
046        }
047
048        protected List<Class<? extends InvocationFilter>> getInvocationFilterClasses() {
049                if (invocationFilterClasses == null) {
050                        final List<InvocationFilter> invocationFilters = loadInvocationFilters();
051                        final List<Class<? extends InvocationFilter>> l = new ArrayList<>(invocationFilters.size());
052                        for (final InvocationFilter invocationFilter : invocationFilters)
053                                l.add(invocationFilter.getClass());
054
055                        invocationFilterClasses = Collections.unmodifiableList(l);
056                }
057                return invocationFilterClasses;
058        }
059
060        protected List<InvocationFilter> getInvocationFilters() {
061                final List<Class<? extends InvocationFilter>> invocationFilterClasses = getInvocationFilterClasses();
062
063                final List<InvocationFilter> result = new ArrayList<InvocationFilter>(invocationFilterClasses.size());
064                for (Class<? extends InvocationFilter> invocationFilterClass : invocationFilterClasses)
065                        result.add(newInstance(invocationFilterClass));
066
067                return Collections.unmodifiableList(result);
068        }
069
070        private <T> T newInstance(Class<T> clazz) {
071                try {
072                        return clazz.newInstance();
073                } catch (InstantiationException | IllegalAccessException e) {
074                        throw new RuntimeException(e);
075                }
076        }
077
078        public boolean canInvoke(final ExtMethodInvocationRequest extMethodInvocationRequest) {
079                assertNotNull(extMethodInvocationRequest, "extMethodInvocationRequest");
080                for (final InvocationFilter invocationFilter : getInvocationFilters()) {
081                        final Boolean result = invocationFilter.canInvoke(extMethodInvocationRequest);
082                        if (result != null)
083                                return result;
084                }
085                return false;
086        }
087
088        public void assertCanInvoke(final ExtMethodInvocationRequest extMethodInvocationRequest) {
089                if (! canInvoke(extMethodInvocationRequest))
090                        throw new SecurityException("Invocation denied: " + extMethodInvocationRequest.getMethodInvocationRequest());
091        }
092}