<commit_before>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.component.embed;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

import javax.inject.Provider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.component.annotation.ComponentAnnotationLoader;
import org.xwiki.component.descriptor.ComponentDependency;
import org.xwiki.component.descriptor.ComponentDescriptor;
import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
import org.xwiki.component.internal.RoleHint;
import org.xwiki.component.manager.ComponentEventManager;
import org.xwiki.component.manager.ComponentLifecycleException;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.manager.ComponentManagerInitializer;
import org.xwiki.component.manager.ComponentRepositoryException;
import org.xwiki.component.phase.Disposable;
import org.xwiki.component.util.ReflectionUtils;

/**
 * Simple implementation of {@link ComponentManager} to be used when using some XWiki modules standalone.
 * 
 * @version $Id$
 * @since 2.0M1
 */
public class EmbeddableComponentManager implements ComponentManager
{
    private ComponentEventManager eventManager;

    /**
     * Used as fallback for lookup methods.
     */
    private ComponentManager parent;

    private static class ComponentEntry<R>
    {
        /**
         * Descriptor of the component.
         */
        public ComponentDescriptor<R> descriptor;

        /**
         * Cached instance of the component. Lazily initialized when needed.
         */
        public R instance;

        public ComponentEntry(ComponentDescriptor<R> descriptor, R instance)
        {
            this.descriptor = descriptor;
            this.instance = instance;
        }
    }

    private Map<RoleHint< ? >, ComponentEntry< ? >> componentEntries =
        new ConcurrentHashMap<RoleHint< ? >, ComponentEntry< ? >>();

    /**
     * Maintain a mapping between {@link Provider}s and the type of they provide.
     */
    private Map<RoleHint< ? >, ComponentEntry<Provider>> providerEntries =
        new ConcurrentHashMap<RoleHint< ? >, ComponentEntry<Provider>>();

    private Logger logger = LoggerFactory.getLogger(EmbeddableComponentManager.class);

    /**
     * Finds all lifecycle handlers to use when instantiating a Component.
     */
    private ServiceLoader<LifecycleHandler> lifecycleHandlers = ServiceLoader.load(LifecycleHandler.class);

    /**
     * Load all component annotations and register them as components.
     * 
     * @param classLoader the class loader to use to look for component definitions
     */
    public void initialize(ClassLoader classLoader)
    {
        ComponentAnnotationLoader loader = new ComponentAnnotationLoader();
        loader.initialize(this, classLoader);

        // Extension point to allow component to manipulate ComponentManager initialized state.
        try {
            List<ComponentManagerInitializer> initializers = this.lookupList(ComponentManagerInitializer.class);

            for (ComponentManagerInitializer initializer : initializers) {
                initializer.initialize(this);
            }
        } catch (ComponentLookupException e) {
            // Should never happen
            this.logger.error("Failed to lookup ComponentManagerInitializer components", e);
        }
    }

    @Override
    public <T> boolean hasComponent(Class<T> role, String hint)
    {
        return this.componentEntries.containsKey(new RoleHint<T>(role, hint));
    }

    @Override
    public <T> boolean hasComponent(Class<T> role)
    {
        return this.componentEntries.containsKey(new RoleHint<T>(role));
    }

    @Override
    public <T> T lookup(Class<T> role) throws ComponentLookupException
    {
        return getComponentInstance(new RoleHint<T>(role));
    }

    @Override
    public <T> T lookup(Class<T> role, String hint) throws ComponentLookupException
    {
        return getComponentInstance(new RoleHint<T>(role, hint));
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> List<T> lookupList(Class<T> role) throws ComponentLookupException
    {
        List<T> objects = new ArrayList<T>();
        for (RoleHint< ? > roleHint : this.componentEntries.keySet()) {
            // It's possible Class reference are not the same when it's coming form different ClassLoader so we
            // compare class names
            if (roleHint.getRole().getName().equals(role.getName())) {
                objects.add(getComponentInstance((RoleHint<T>) roleHint));
            }
        }

        // Add parent's list of components
        if (getParent() != null) {
            objects.addAll(getParent().lookupList(role));
        }

        return objects;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> Map<String, T> lookupMap(Class<T> role) throws ComponentLookupException
    {
        Map<String, T> objects = new HashMap<String, T>();
        for (RoleHint< ? > roleHint : this.componentEntries.keySet()) {
            // It's possible Class reference are not the same when it coming for different ClassLoader so we
            // compare class names
            if (roleHint.getRole().getName().equals(role.getName())) {
                objects.put(roleHint.getHint(), getComponentInstance((RoleHint<T>) roleHint));
            }
        }<commit_msg>XCOMMONS-63: Optimize EmbeddableComponentManager More improvements (less useless Map#get)<commit_after>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.component.embed;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

import javax.inject.Provider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.component.annotation.ComponentAnnotationLoader;
import org.xwiki.component.descriptor.ComponentDependency;
import org.xwiki.component.descriptor.ComponentDescriptor;
import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
import org.xwiki.component.internal.RoleHint;
import org.xwiki.component.manager.ComponentEventManager;
import org.xwiki.component.manager.ComponentLifecycleException;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.manager.ComponentManagerInitializer;
import org.xwiki.component.manager.ComponentRepositoryException;
import org.xwiki.component.phase.Disposable;
import org.xwiki.component.util.ReflectionUtils;

/**
 * Simple implementation of {@link ComponentManager} to be used when using some XWiki modules standalone.
 * 
 * @version $Id$
 * @since 2.0M1
 */
public class EmbeddableComponentManager implements ComponentManager
{
    private ComponentEventManager eventManager;

    /**
     * Used as fallback for lookup methods.
     */
    private ComponentManager parent;

    private static class ComponentEntry<R>
    {
        /**
         * Descriptor of the component.
         */
        public ComponentDescriptor<R> descriptor;

        /**
         * Cached instance of the component. Lazily initialized when needed.
         */
        public R instance;

        public ComponentEntry(ComponentDescriptor<R> descriptor, R instance)
        {
            this.descriptor = descriptor;
            this.instance = instance;
        }
    }

    private Map<RoleHint< ? >, ComponentEntry< ? >> componentEntries =
        new ConcurrentHashMap<RoleHint< ? >, ComponentEntry< ? >>();

    /**
     * Maintain a mapping between {@link Provider}s and the type of they provide.
     */
    private Map<RoleHint< ? >, ComponentEntry<Provider>> providerEntries =
        new ConcurrentHashMap<RoleHint< ? >, ComponentEntry<Provider>>();

    private Logger logger = LoggerFactory.getLogger(EmbeddableComponentManager.class);

    /**
     * Finds all lifecycle handlers to use when instantiating a Component.
     */
    private ServiceLoader<LifecycleHandler> lifecycleHandlers = ServiceLoader.load(LifecycleHandler.class);

    /**
     * Load all component annotations and register them as components.
     * 
     * @param classLoader the class loader to use to look for component definitions
     */
    public void initialize(ClassLoader classLoader)
    {
        ComponentAnnotationLoader loader = new ComponentAnnotationLoader();
        loader.initialize(this, classLoader);

        // Extension point to allow component to manipulate ComponentManager initialized state.
        try {
            List<ComponentManagerInitializer> initializers = this.lookupList(ComponentManagerInitializer.class);

            for (ComponentManagerInitializer initializer : initializers) {
                initializer.initialize(this);
            }
        } catch (ComponentLookupException e) {
            // Should never happen
            this.logger.error("Failed to lookup ComponentManagerInitializer components", e);
        }
    }

    @Override
    public <T> boolean hasComponent(Class<T> role, String hint)
    {
        return this.componentEntries.containsKey(new RoleHint<T>(role, hint));
    }

    @Override
    public <T> boolean hasComponent(Class<T> role)
    {
        return this.componentEntries.containsKey(new RoleHint<T>(role));
    }

    @Override
    public <T> T lookup(Class<T> role) throws ComponentLookupException
    {
        return getComponentInstance(new RoleHint<T>(role));
    }

    @Override
    public <T> T lookup(Class<T> role, String hint) throws ComponentLookupException
    {
        return getComponentInstance(new RoleHint<T>(role, hint));
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> List<T> lookupList(Class<T> role) throws ComponentLookupException
    {
        List<T> objects = new ArrayList<T>();

        for (Map.Entry<RoleHint< ? >, ComponentEntry< ? >> entry : this.componentEntries.entrySet()) {
            RoleHint< ? > roleHint = entry.getKey();

            // It's possible Class reference are not the same when it's coming form different ClassLoader so we
            // compare class names
            if (roleHint.getRole().getName().equals(role.getName())) {
                try {
                    objects.add(getComponentInstance((ComponentEntry<T>) entry.getValue()));
                } catch (Exception e) {
                    throw new ComponentLookupException("Failed to lookup component [" + roleHint + "]", e);
                }
            }
        }

        // Add parent's list of components
        if (getParent() != null) {
            objects.addAll(getParent().lookupList(role));
        }

        return objects;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> Map<String, T> lookupMap(Class<T> role) throws ComponentLookupException
    {
        Map<String, T> objects = new HashMap<String, T>();

        for (Map.Entry<RoleHint< ? >, ComponentEntry< ? >> entry : this.componentEntries.entrySet()) {
            RoleHint< ? > roleHint = entry.getKey();

            // It's possible Class reference are not the same when it's coming form different ClassLoader so we
            // compare class names
            if (roleHint.getRole().getName().equals(role.getName())) {
                try {
                    objects.put(roleHint.getHint(), getComponentInstance((ComponentEntry<T>) entry.getValue()));
                } catch (Exception e) {
                    throw new ComponentLookupException("Failed to lookup component [" + roleHint + "]", e);
                }
            }
        }
{'fraction_non_alphanumeric': 0.09187955532651108, 'fraction_numerical': 0.0027976146653905616, 'mean_word_length': 3.0731634182908545, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 95, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5402401', 'n_tokens_mistral': 3475, 'n_tokens_neox': 3382, 'n_words': 1035}