All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bridje.ioc.impl.ServiceMap Maven / Gradle / Ivy

There is a newer version: 0.6.4
Show newest version
/*
 * Copyright 2015 Bridje Framework.
 *
 * 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.bridje.ioc.impl;

import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.bridje.ioc.IocContext;

/**
 * An object to keep track of the services of the components.
 */
class ServiceMap
{
    /**
     * A cache for the ServiceMap of all scopes.
     */
    private static final Map, ServiceMap> SERVICES_MAP = new ConcurrentHashMap<>();

    /**
     * The service map, who links a services to a list of components.
     */
    private final Map>> map;

    /**
     * A map who links the components to a list of all it´s services.
     */
    private final Map, List> compMap;

    /**
     * Constructor for this class.
     *
     * @param baseMap A service map to base this service map from.
     * @param clsSet  The components to create this services map for.
     */
    public ServiceMap(ClassSet clsSet)
    {
        Map>> servMap = new HashMap<>();
        Map, List> compsMap = new HashMap<>();
        if (clsSet != null)
        {
            for (Class component : clsSet)
            {
                List services = findServices(component);
                compsMap.put(component, services);
                services.stream()
                        .forEach((service) -> addComponentToService(servMap, service, component));
            }
        }
        servMap.values().stream()
                .forEach((value) -> ClassUtils.sort(value));
        this.map = servMap;
        this.compMap = compsMap;
    }

    /**
     * Finds the first component class by the given service type.
     *
     * @param service The type of the service.
     *
     * @return The component class or null if none can be found.
     */
    public Class findOne(Type service)
    {
        return findOne(service, null);
    }

    /**
     * Finds the first component class by the given service type.
     *
     * @param service  The type of the service.
     * @param priority The priority
     *
     * @return The component class or null if none can be found.
     */
    public Class findOne(Type service, Integer priority)
    {
        if (ClassUtils.rawClass(service).equals(IocContext.class))
        {
            return map.get(ClassUtils.rawClass(service)).get(0);
        }
        List> lst = map.get(service);
        if (lst == null || lst.isEmpty())
        {
            return null;
        }
        if (priority == null)
        {
            return (Class) lst.get(0);
        }
        else
        {
            for (Class cls : lst)
            {
                int v1 = ClassUtils.findPriority(cls);
                if (v1 > priority || v1 == Integer.MAX_VALUE)
                {
                    return (Class) cls;
                }
            }
        }
        return null;
    }

    /**
     * Determines whenever a service is provided by a least one component.
     *
     * @param service The serivce to look for.
     *
     * @return true at least one component provides the given service.
     */
    public boolean exists(Type service)
    {
        return map.containsKey(service);
    }

    /**
     * Finds all components classes by the given service type.
     *
     * @param service The service to lookup
     *
     * @return The list of components that provides the given service if any.
     */
    public List> findAll(Type service)
    {
        Type realService = service;
        if (service instanceof WildcardType)
        {
            realService = ClassUtils.typeOf((WildcardType) service);
        }
        if (realService != null)
        {
            List> result = map.get(realService);
            if (result == null)
            {
                return null;
            }
            return Collections.unmodifiableList(result);
        }
        return Collections.EMPTY_LIST;
    }

    /**
     * Gets the service map by the given scope.
     *
     * @param scope The scope to look for.
     *
     * @return A service map with all the service in the given scope or null if
     *         the given scope has no components.
     */
    public static ServiceMap findByScope(Class scope)
    {
        if (!SERVICES_MAP.containsKey(scope))
        {
            ClassSet classSet = ClassSet.findByScope(scope);
            if (classSet != null)
            {
                ServiceMap result = new ServiceMap(classSet);
                SERVICES_MAP.put(scope, result);
                return result;
            }
            return null;
        }
        return SERVICES_MAP.get(scope);
    }

    /**
     * Gets all the services provided by a component.
     *
     * @param component The component to look for.
     *
     * @return The list of service the especified component provides.
     */
    public List getServices(Class component)
    {
        return compMap.get(component);
    }

    /**
     * Creates a list of all services the especified component provides.
     *
     * @param component The component to search.
     *
     * @return The list of all services the especified component provides.
     */
    private static List findServices(Class component)
    {
        List result = new ArrayList<>();
        result.add(Object.class);
        result.add(component);
        fillServicesSuperClasses(component, result);
        fillServicesIntefaces(component, result);
        return result;
    }

    /**
     * Fills all the services provided by all supper classes of the component.
     *
     * @param component    The component to look for it´s services for.
     * @param servicesList The list to put all finded services.
     */
    private static void fillServicesSuperClasses(Class component, List servicesList)
    {
        Type supClass = component.getGenericSuperclass();
        while (supClass != null && supClass != Object.class)
        {
            if (!ClassUtils.hasGenericDeclaration(supClass)
                    && !servicesList.contains(supClass))
            {
                servicesList.add(supClass);
            }
            Class cls = ClassUtils.rawClass(supClass);
            servicesList.add(cls);
            fillServicesIntefaces(cls, servicesList);
            if (cls != null)
            {
                supClass = cls.getGenericSuperclass();
            }
            else
            {
                supClass = null;
            }
        }
    }

    /**
     * Fills all the services provided by all supper interfaces of the
     * component.
     *
     * @param component    The component to look for it´s services for.
     * @param servicesList The list to put all finded services.
     */
    private static void fillServicesIntefaces(Class cls, List servicesList)
    {
        Type[] interfaces = cls.getGenericInterfaces();
        for (Type ifc : interfaces)
        {
            if (!ClassUtils.hasGenericDeclaration(ifc)
                    && !servicesList.contains(ifc))
            {
                servicesList.add(ifc);
            }
            Class icfCls = ClassUtils.rawClass(ifc);
            servicesList.add(icfCls);
            if (icfCls != null)
            {
                fillServicesIntefaces(icfCls, servicesList);
            }
        }
    }

    /**
     * Adds a component to a list of components that provides the given service.
     *
     * @param service   The service provided
     * @param component The component who provides the given services.
     */
    private static void addComponentToService(Map>> servMap, Type service, Class component)
    {
        List> components = servMap.get(service);
        if (components == null)
        {
            components = new ArrayList<>();
            servMap.put(service, components);
        }
        if (!components.contains(component))
        {
            components.add(component);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy