<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.felix.dm.impl;

import java.util.Dictionary;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;

import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentDeclaration;
import org.apache.felix.dm.ComponentDependencyDeclaration;
import org.apache.felix.dm.ComponentStateListener;
import org.apache.felix.dm.Dependency;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.Logger;
import org.apache.felix.dm.context.ComponentContext;
import org.apache.felix.dm.context.DependencyContext;
import org.apache.felix.dm.context.Event;
import org.apache.felix.dm.context.EventType;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

/**
 * This class allows to filter a Component interface. All Aspect/Adapters extend this class
 * in order to add functionality to the default Component implementation.
 * 
 * @author <a href="mailto:<EMAIL>">Felix Project Team</a>
 */
public class FilterComponent implements Component, ComponentContext, ComponentDeclaration {
    protected volatile ComponentImpl m_component;
    protected volatile List<ComponentStateListener> m_stateListeners = new CopyOnWriteArrayList<>();
    protected volatile String m_init = "init";
    protected volatile String m_start = "start";
    protected volatile String m_stop = "stop";
    protected volatile String m_destroy = "destroy";
    protected volatile Object m_callbackObject;
    protected volatile Object m_compositionInstance;
    protected volatile String m_compositionMethod;
    protected volatile String[] m_serviceInterfaces;
    protected volatile Object m_serviceImpl;
    protected volatile Object m_factory;
    protected volatile String m_factoryCreateMethod;
    protected volatile Dictionary<String, Object> m_serviceProperties;
    private final Map<DependencyContext, Object> m_dependencyCallbacks = new HashMap<>();

    public FilterComponent(Component service) {
        m_component = (ComponentImpl) service;
    }
    
    @Override
    public Executor getExecutor() {
        return m_component.getExecutor();
    }

    @Override
    public String toString() {
        return m_component.toString();
    }

    public Component add(Dependency ... dependencies) {
        // First, detect if one of the added dependencies is required, and also, remove any callback instance found in
        // dependencies. We'll store such dependency callback instance in our m_dependencyCallbacks map and will
        // re-add them later, in concrete aspect or adapter instances (see the copyDependencies method).
        // We remove dependency callback instance because we don't want to call with internal abstract decorator instances).
        
        boolean allDependenciesOptional = true;
        for (Dependency dependency : dependencies) {
            DependencyContext dc = (DependencyContext) dependency;
            if (dc.isRequired()) {
                allDependenciesOptional = false;
            }
            
            // Temporarily remove dependency callback instance (if set), because we don't want to call it twice (one time from the
            // internal aspect/adapter AbstractDecorator object, and another one time from the actual aspect/adapter component instances).
            // See FELIX-5155.            
            if (dc.getCallbackInstance() != null) {
                m_dependencyCallbacks.put(dc, dc.setCallbackInstance(null));
            }
        }
        
        // Now, add the dependencies in the internal abstract decorator component.
        m_component.add(dependencies);
        
        // If all dependencies are optional, add them to already instantiated aspect or adapter components.
        if (allDependenciesOptional) {
            Object[] instances = m_component.getInstances();
            if (instances.length > 0) {
                AbstractDecorator ad = (AbstractDecorator) instances[0];
                if (ad != null) {
                    ad.addDependency(dependencies);
                }
            }
        }
        return this;
    }

    public Component add(ComponentStateListener listener) {
        m_stateListeners.add(listener);
        // Add the listener to all already instantiated services.
        Object[] instances = m_component.getInstances();
        if (instances.length > 0) {
            AbstractDecorator ad = (AbstractDecorator) instances[0];
            if (ad != null) {
                ad.addStateListener(listener);
            }
        }
        return this;
    }

    public List<DependencyContext> getDependencies() {
        return m_component.getDependencies();
    }

    public String getClassName() {
        return m_component.getClassName();
    }
    
    @SuppressWarnings("unchecked")
	public Dictionary<String, Object> getServiceProperties() {
        return m_serviceProperties;
    }

    public ServiceRegistration getServiceRegistration() {
        return m_component.getServiceRegistration();
    }

    public Component remove(Dependency dependency) {
        m_component.remove(dependency);
        // Remove the dependency (if optional) from all already instantiated services.
        // If the dependency is required, our internal service will be stopped, so in this case
        // we have nothing to do.
        if (!((DependencyContext) dependency).isRequired())
        {
            Object[] instances = m_component.getInstances();
            if (instances.length > 0) {
                AbstractDecorator ad = (AbstractDecorator) instances[0];
                if (ad != null) {
                    ad.removeDependency(dependency);
                }
            }
        }
        return this;
    }

    public Component remove(ComponentStateListener listener) {
        m_stateListeners.remove(listener);
        // Remove the listener from all already instantiated services.
        Object[] instances = m_component.getInstances();
        if (instances.length > 0) {
            AbstractDecorator ad = (AbstractDecorator) instances[0];
            if (ad != null) {
                ad.removeStateListener(listener);
            }
        }
        return this;
    }

    public Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
        m_component.ensureNotActive();
        m_callbackObject = instance;
        m_init = init;
        m_start = start;
        m_stop = stop;
        m_destroy = destroy;
        return this;
    }

    public Component setCallbacks(String init, String start, String stop, String destroy) {
        setCallbacks(null, init, start, stop, destroy);
        return this;
    }

    public Component setComposition(Object instance, String getMethod) {
        m_component.ensureNotActive();
        m_compositionInstance = instance;
        m_compositionMethod = getMethod;
        return this;
    }

    public Component setComposition(String getMethod) {
        m_component.ensureNotActive();
        m_compositionMethod = getMethod;
        return this;
    }

    public Component setFactory(Object factory, String createMethod) {
        m_component.ensureNotActive();
        m_factory = factory;
        m_factoryCreateMethod = createMethod;
        return this;
    }

    public Component setFactory(String createMethod) {
        return setFactory(null, createMethod);
    }

    public Component setImplementation(Object implementation) {
        m_component.ensureNotActive();
        m_serviceImpl = implementation;
        return this;
    }

    public Component setInterface(String serviceName, Dictionary<?, ?> properties) {
        return setInterface(new String[] { serviceName }, properties);
    }

    @SuppressWarnings("unchecked")
    public Component setInterface(String[] serviceInterfaces, Dictionary<?, ?> properties) {
        m_component.ensureNotActive();
        if (serviceInterfaces != null) {
            m_serviceInterfaces = new String[serviceInterfaces.length];
            System.arraycopy(serviceInterfaces, 0, m_serviceInterfaces, 0, serviceInterfaces.length);
            m_serviceProperties = (Dictionary<String, Object>) properties;
        }
        return this;
    }

    @SuppressWarnings("unchecked")
    public Component setServiceProperties(Dictionary<?, ?> serviceProperties) {
        m_serviceProperties = (Dictionary<String, Object>) serviceProperties;
        // Set the properties to all already instantiated services.
        if (serviceProperties != null) {
            Object[] instances = m_component.getInstances();
            if (instances.length > 0) {
                AbstractDecorator ad = (AbstractDecorator) instances[0];
                if (ad != null) {
                    ad.setServiceProperties(serviceProperties);
                }
            }
        }
        return this;
    }

    public void start() {
        m_component.start();
    }

    public void stop() {
        m_component.stop();
    }
    
    public void invokeCallbackMethod(Object[] instances, String methodName, Class<?>[][] signatures, Object[][] parameters) {
        m_component.invokeCallbackMethod(instances, methodName, signatures, parameters);
    }
        
    public DependencyManager getDependencyManager() {
        return m_component.getDependencyManager();
    }

    public Component setAutoConfig(Class<?> clazz, boolean autoConfig) {
        m_component.setAutoConfig(clazz, autoConfig);
        return this;
    }

    public Component setAutoConfig(Class<?> clazz, String instanceName) {
        m_component.setAutoConfig(clazz, instanceName);
        return this;
    }
    
    public boolean getAutoConfig(Class<?> clazz) {
        return m_component.getAutoConfig(clazz);
    }
    
    public String getAutoConfigInstance(Class<?> clazz) {
        return m_component.getAutoConfigInstance(clazz);
    }

    public ComponentDependencyDeclaration[] getComponentDependencies() {
        return m_component.getComponentDependencies();
    }

    public String getName() {
        return m_component.getName();
    }

    public int getState() {
        return m_component.getState();
    }
    
    public long getId() {
        return m_component.getId();
    }

    public String[] getServices() {
        return m_component.getServices();
    }
    
    public BundleContext getBundleContext() {
        return m_component.getBundleContext();
    }
        
    @Override
    public boolean isActive() {
        return m_component.isActive();
    }

    @Override
    public boolean isAvailable() {
        return m_component.isAvailable();
    }

    @Override
    public void handleEvent(DependencyContext dc, EventType type, Event ... e) {
        m_component.handleEvent(dc, type, e);
    }
    
    @Override
    public <T> T getInstance() {
        return m_component.getInstance();
    }

    @Override
    public Object[] getInstances() {
        return m_component.getInstances();
    }
    
    @Override
    public Event getDependencyEvent(DependencyContext dc) {
        return m_component.getDependencyEvent(dc);
    }
    
    @Override
    public Set<Event> getDependencyEvents(DependencyContext dc) {
        return m_component.getDependencyEvents(dc);
    }
    
    public ComponentDeclaration getComponentDeclaration() {
        return this;
    }

	@Override
	public Component setDebug(String label) {
		m_component.setDebug(label);
		return this;
	}
	
    @Override
    public void setThreadPool(Executor threadPool) {
        m_component.setThreadPool(threadPool);
    }

    @Override
    public Map<String, Long> getCallbacksTime() {
        return m_component.getCallbacksTime();
    }

    @Override
    public Bundle getBundle() {
        return m_component.getBundle();
    }

    @Override
    public Logger getLogger() {
        return m_component.getLogger();
    }
    
    protected void copyDependencies(List<DependencyContext> dependencies, Component component) {
        for (DependencyContext dc : dependencies) {
            DependencyContext copy = dc.createCopy();
            Object callbackInstance = m_dependencyCallbacks.get(dc);
            if (callbackInstance != null) {
                copy.setCallbackInstance(callbackInstance);
            }
            component.add(copy);
        }
    }
}<commit_msg>FELIX-5155: cleanup possibly cached dependency callback instance when removing a dependency from an aspect or adapter component.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.felix.dm.impl;

import java.util.Dictionary;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;

import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentDeclaration;
import org.apache.felix.dm.ComponentDependencyDeclaration;
import org.apache.felix.dm.ComponentStateListener;
import org.apache.felix.dm.Dependency;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.Logger;
import org.apache.felix.dm.context.ComponentContext;
import org.apache.felix.dm.context.DependencyContext;
import org.apache.felix.dm.context.Event;
import org.apache.felix.dm.context.EventType;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

/**
 * This class allows to filter a Component interface. All Aspect/Adapters extend this class
 * in order to add functionality to the default Component implementation.
 * 
 * @author <a href="mailto:<EMAIL>">Felix Project Team</a>
 */
public class FilterComponent implements Component, ComponentContext, ComponentDeclaration {
    protected volatile ComponentImpl m_component;
    protected volatile List<ComponentStateListener> m_stateListeners = new CopyOnWriteArrayList<>();
    protected volatile String m_init = "init";
    protected volatile String m_start = "start";
    protected volatile String m_stop = "stop";
    protected volatile String m_destroy = "destroy";
    protected volatile Object m_callbackObject;
    protected volatile Object m_compositionInstance;
    protected volatile String m_compositionMethod;
    protected volatile String[] m_serviceInterfaces;
    protected volatile Object m_serviceImpl;
    protected volatile Object m_factory;
    protected volatile String m_factoryCreateMethod;
    protected volatile Dictionary<String, Object> m_serviceProperties;
    private final Map<DependencyContext, Object> m_dependencyCallbacks = new HashMap<>();

    public FilterComponent(Component service) {
        m_component = (ComponentImpl) service;
    }
    
    @Override
    public Executor getExecutor() {
        return m_component.getExecutor();
    }

    @Override
    public String toString() {
        return m_component.toString();
    }

    public Component add(Dependency ... dependencies) {
        // First, detect if one of the added dependencies is required, and also, remove any callback instance found in
        // dependencies. We'll store such dependency callback instance in our m_dependencyCallbacks map and will
        // re-add them later, in concrete aspect or adapter instances (see the copyDependencies method).
        // We remove dependency callback instance because we don't want to call with internal abstract decorator instances).
        
        boolean allDependenciesOptional = true;
        for (Dependency dependency : dependencies) {
            DependencyContext dc = (DependencyContext) dependency;
            if (dc.isRequired()) {
                allDependenciesOptional = false;
            }
            
            // Temporarily remove dependency callback instance (if set), because we don't want to call it twice (one time from the
            // internal aspect/adapter AbstractDecorator object, and another one time from the actual aspect/adapter component instances).
            // See FELIX-5155.            
            if (dc.getCallbackInstance() != null) {
                m_dependencyCallbacks.put(dc, dc.setCallbackInstance(null));
            }
        }
        
        // Now, add the dependencies in the internal abstract decorator component.
        m_component.add(dependencies);
        
        // If all dependencies are optional, add them to already instantiated aspect or adapter components.
        if (allDependenciesOptional) {
            Object[] instances = m_component.getInstances();
            if (instances.length > 0) {
                AbstractDecorator ad = (AbstractDecorator) instances[0];
                if (ad != null) {
                    ad.addDependency(dependencies);
                }
            }
        }
        return this;
    }

    public Component add(ComponentStateListener listener) {
        m_stateListeners.add(listener);
        // Add the listener to all already instantiated services.
        Object[] instances = m_component.getInstances();
        if (instances.length > 0) {
            AbstractDecorator ad = (AbstractDecorator) instances[0];
            if (ad != null) {
                ad.addStateListener(listener);
            }
        }
        return this;
    }

    public List<DependencyContext> getDependencies() {
        return m_component.getDependencies();
    }

    public String getClassName() {
        return m_component.getClassName();
    }
    
    @SuppressWarnings("unchecked")
	public Dictionary<String, Object> getServiceProperties() {
        return m_serviceProperties;
    }

    public ServiceRegistration getServiceRegistration() {
        return m_component.getServiceRegistration();
    }

    public Component remove(Dependency dependency) {
        m_component.remove(dependency);
        // Remove the dependency (if optional) from all already instantiated services.
        // If the dependency is required, our internal service will be stopped, so in this case
        // we have nothing to do.
        if (!((DependencyContext) dependency).isRequired())
        {
            Object[] instances = m_component.getInstances();
            if (instances.length > 0) {
                AbstractDecorator ad = (AbstractDecorator) instances[0];
                if (ad != null) {
                    ad.removeDependency(dependency);
                }
            }
        }
        // Cleanup possibly cached depenedncy callack instances.
        m_dependencyCallbacks.remove((DependencyContext) dependency);
        return this;
    }

    public Component remove(ComponentStateListener listener) {
        m_stateListeners.remove(listener);
        // Remove the listener from all already instantiated services.
        Object[] instances = m_component.getInstances();
        if (instances.length > 0) {
            AbstractDecorator ad = (AbstractDecorator) instances[0];
            if (ad != null) {
                ad.removeStateListener(listener);
            }
        }
        return this;
    }

    public Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
        m_component.ensureNotActive();
        m_callbackObject = instance;
        m_init = init;
        m_start = start;
        m_stop = stop;
        m_destroy = destroy;
        return this;
    }

    public Component setCallbacks(String init, String start, String stop, String destroy) {
        setCallbacks(null, init, start, stop, destroy);
        return this;
    }

    public Component setComposition(Object instance, String getMethod) {
        m_component.ensureNotActive();
        m_compositionInstance = instance;
        m_compositionMethod = getMethod;
        return this;
    }

    public Component setComposition(String getMethod) {
        m_component.ensureNotActive();
        m_compositionMethod = getMethod;
        return this;
    }

    public Component setFactory(Object factory, String createMethod) {
        m_component.ensureNotActive();
        m_factory = factory;
        m_factoryCreateMethod = createMethod;
        return this;
    }

    public Component setFactory(String createMethod) {
        return setFactory(null, createMethod);
    }

    public Component setImplementation(Object implementation) {
        m_component.ensureNotActive();
        m_serviceImpl = implementation;
        return this;
    }

    public Component setInterface(String serviceName, Dictionary<?, ?> properties) {
        return setInterface(new String[] { serviceName }, properties);
    }

    @SuppressWarnings("unchecked")
    public Component setInterface(String[] serviceInterfaces, Dictionary<?, ?> properties) {
        m_component.ensureNotActive();
        if (serviceInterfaces != null) {
            m_serviceInterfaces = new String[serviceInterfaces.length];
            System.arraycopy(serviceInterfaces, 0, m_serviceInterfaces, 0, serviceInterfaces.length);
            m_serviceProperties = (Dictionary<String, Object>) properties;
        }
        return this;
    }

    @SuppressWarnings("unchecked")
    public Component setServiceProperties(Dictionary<?, ?> serviceProperties) {
        m_serviceProperties = (Dictionary<String, Object>) serviceProperties;
        // Set the properties to all already instantiated services.
        if (serviceProperties != null) {
            Object[] instances = m_component.getInstances();
            if (instances.length > 0) {
                AbstractDecorator ad = (AbstractDecorator) instances[0];
                if (ad != null) {
                    ad.setServiceProperties(serviceProperties);
                }
            }
        }
        return this;
    }

    public void start() {
        m_component.start();
    }

    public void stop() {
        m_component.stop();
    }
    
    public void invokeCallbackMethod(Object[] instances, String methodName, Class<?>[][] signatures, Object[][] parameters) {
        m_component.invokeCallbackMethod(instances, methodName, signatures, parameters);
    }
        
    public DependencyManager getDependencyManager() {
        return m_component.getDependencyManager();
    }

    public Component setAutoConfig(Class<?> clazz, boolean autoConfig) {
        m_component.setAutoConfig(clazz, autoConfig);
        return this;
    }

    public Component setAutoConfig(Class<?> clazz, String instanceName) {
        m_component.setAutoConfig(clazz, instanceName);
        return this;
    }
    
    public boolean getAutoConfig(Class<?> clazz) {
        return m_component.getAutoConfig(clazz);
    }
    
    public String getAutoConfigInstance(Class<?> clazz) {
        return m_component.getAutoConfigInstance(clazz);
    }

    public ComponentDependencyDeclaration[] getComponentDependencies() {
        return m_component.getComponentDependencies();
    }

    public String getName() {
        return m_component.getName();
    }

    public int getState() {
        return m_component.getState();
    }
    
    public long getId() {
        return m_component.getId();
    }

    public String[] getServices() {
        return m_component.getServices();
    }
    
    public BundleContext getBundleContext() {
        return m_component.getBundleContext();
    }
        
    @Override
    public boolean isActive() {
        return m_component.isActive();
    }

    @Override
    public boolean isAvailable() {
        return m_component.isAvailable();
    }

    @Override
    public void handleEvent(DependencyContext dc, EventType type, Event ... e) {
        m_component.handleEvent(dc, type, e);
    }
    
    @Override
    public <T> T getInstance() {
        return m_component.getInstance();
    }

    @Override
    public Object[] getInstances() {
        return m_component.getInstances();
    }
    
    @Override
    public Event getDependencyEvent(DependencyContext dc) {
        return m_component.getDependencyEvent(dc);
    }
    
    @Override
    public Set<Event> getDependencyEvents(DependencyContext dc) {
        return m_component.getDependencyEvents(dc);
    }
    
    public ComponentDeclaration getComponentDeclaration() {
        return this;
    }

	@Override
	public Component setDebug(String label) {
		m_component.setDebug(label);
		return this;
	}
	
    @Override
    public void setThreadPool(Executor threadPool) {
        m_component.setThreadPool(threadPool);
    }

    @Override
    public Map<String, Long> getCallbacksTime() {
        return m_component.getCallbacksTime();
    }

    @Override
    public Bundle getBundle() {
        return m_component.getBundle();
    }

    @Override
    public Logger getLogger() {
        return m_component.getLogger();
    }
    
    protected void copyDependencies(List<DependencyContext> dependencies, Component component) {
        for (DependencyContext dc : dependencies) {
            DependencyContext copy = dc.createCopy();
            Object callbackInstance = m_dependencyCallbacks.get(dc);
            if (callbackInstance != null) {
                copy.setCallbackInstance(callbackInstance);
            }
            component.add(copy);
        }
    }
}
{'fraction_non_alphanumeric': 0.08274372532955984, 'fraction_numerical': 0.0016384896104863335, 'mean_word_length': 2.7143845089903182, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 61, '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': '685514', 'n_tokens_mistral': 6750, 'n_tokens_neox': 6565, 'n_words': 1904}