Package org.auraframework.util

Source Code of org.auraframework.util.ServiceLoaderImpl

/*
* Copyright (C) 2013 salesforce.com, inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.auraframework.util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Set;

import org.auraframework.util.ServiceLocator.ServiceLocatorException;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.scanners.TypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Sets;

/**
* @since 0.0.233
*/
public class ServiceLoaderImpl implements ServiceLoader {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface AuraConfiguration {
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Impl {
        String name() default "";
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface PrimaryImpl {
    }

    private static final ServiceLoader instance = new ServiceLoaderImpl();

    @SuppressWarnings("unchecked")
    private static final Predicate<? super Method> predicate = Predicates.and(
            ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withAnnotation(Impl.class),
            ReflectionUtils.withModifier(Modifier.STATIC), ReflectionUtils.withParametersCount(0));

    private final Reflections reflections;

    private ServiceLoaderImpl() {
        Predicate<String> filter = new FilterBuilder().include(FilterBuilder.prefix("configuration"));

        reflections = new Reflections(new ConfigurationBuilder().filterInputsBy(filter)
                .setUrls(ClasspathHelper.forPackage("configuration"))
                .setScanners(new TypeAnnotationsScanner(), new MethodAnnotationsScanner(), new TypesScanner()));

    }

    public static final ServiceLoader get() {
        return instance;
    }

    @Override
    public <T> T get(Class<T> type) {
        try {

            Set<Class<?>> classes = reflections.getTypesAnnotatedWith(AuraConfiguration.class);

            // First try those marked with primary
            T ret = get(type, classes, true, predicate);
            if (ret != null) {
                return ret;
            }

            return get(type, classes, false, predicate);

        } catch (Throwable t) {
            throw new ServiceLocatorException(t);
        }
    }

    @SuppressWarnings("unchecked")
    private <T> T get(Class<T> type, Set<Class<?>> classes, boolean primary, Predicate<? super Method> predicate) {
        Set<Method> beanMethods = Sets.newHashSet();
        Predicate<Method> pred;

        pred = Predicates.and(predicate, ReflectionUtils.withReturnTypeAssignableTo(type));
        if (primary) {
            pred = Predicates.and(pred, ReflectionUtils.withAnnotation(PrimaryImpl.class));
        }

        /*
         * This is a better way to do it, but hits a runtime dep on Guava 12, so
         * until we upgrade to Guava 12, working around this.
         */

        for (Class<?> clazz : classes) {
            for (Method meth : clazz.getDeclaredMethods()) {
                if (pred.apply(meth)) {
                    beanMethods.add(meth);
                }
            }
        }

        T ret = null;
        try {
            for (Method meth : beanMethods) {
                T tmp = (T) meth.invoke(null);
                if (tmp != null) {
                    if (ret != null) {
                        throw new ServiceLocatorException("More than one implementation found (primary=" + primary
                                + ").");
                    }
                    ret = tmp;
                }
            }
        } catch (Exception e) {
            throw new ServiceLocatorException(e);
        }
        return ret;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> Set<T> getAll(Class<T> type) {
        Set<Method> beanMethods = Sets.newHashSet();

        Set<T> ret = Sets.newHashSet();

        Predicate<Method> pred = Predicates.and(predicate, ReflectionUtils.withReturnTypeAssignableTo(type));

        Set<Class<?>> classes = reflections.getTypesAnnotatedWith(AuraConfiguration.class);

        /*
         * This is a better way to do it, but hits a runtime dep on Guava 12, so
         * until we upgrade to Guava 12, working around this.
         */

        for (Class<?> clazz : classes) {
            for (Method meth : clazz.getDeclaredMethods()) {
                if (pred.apply(meth)) {
                    beanMethods.add(meth);
                }
            }
        }

        try {
            for (Method meth : beanMethods) {
                T val = (T) meth.invoke(null);
                if (val != null) {
                    ret.add(val);
                }
            }
        } catch (Exception e) {
            throw new ServiceLocatorException(e);
        }

        return ret;
    }

    @Override
    public <T> T get(Class<T> type, final String name) {
        try {

            Predicate<? super Method> predicate = Predicates.and(ServiceLoaderImpl.predicate, new Predicate<Method>() {

                @Override
                public boolean apply(Method input) {
                    return input.getAnnotation(Impl.class).name().equals(name);
                }

            });
            Set<Class<?>> classes = reflections.getTypesAnnotatedWith(AuraConfiguration.class);

            // First try those marked with primary
            T ret = get(type, classes, true, predicate);
            if (ret != null) {
                return ret;
            }

            return get(type, classes, false, predicate);

        } catch (Throwable t) {
            throw new ServiceLocatorException(t);
        }
    }
}
TOP

Related Classes of org.auraframework.util.ServiceLoaderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.