<commit_before>/**
 * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.eventsourcing;

import lombok.SneakyThrows;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;

import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Provides an event and command sets from OSGi bundles
 */
@Component(immediate = true)
public class OSGiEntitiesProvider implements CommandSetProvider, EventSetProvider {

    private List<Class<? extends Command>> commands = new ArrayList<>();
    private List<Class<? extends Event>> events = new ArrayList<>();
    private BundleTracker<Object> tracker;

    @Activate
    protected void activate(ComponentContext context) {
        tracker = new BundleTracker<>(context.getBundleContext(), Bundle.ACTIVE,
                                    new ScannerBundleTracker());
        tracker.open();
    }

    @Deactivate
    protected void deactivate() {
        tracker.close();
    }


    <T> List<Class<? extends T>> findSubTypesOf(Bundle bundle, Collection<Class<T>> superclasses) {
        BundleWiring wiring = bundle.adapt(BundleWiring.class);
        Collection<String> names = wiring
                .listResources("/", "*", BundleWiring.LISTRESOURCES_RECURSE);
        return names.stream().map(new Function<String, Class<?>>() {
            @Override @SneakyThrows
            public Class<?> apply(String name) {
                String n = name.replaceAll("\\.class$", "").replace('/', '.');
                try {
                    return bundle.loadClass(n);
                } catch (ClassNotFoundException | NoClassDefFoundError e) {
                    return null;
                }
            }
        }).filter(c -> c != null).filter(c -> superclasses.stream().anyMatch(sc -> sc.isAssignableFrom(c)))
                    .filter(c -> !c.isInterface() && !Modifier.isAbstract(c.getModifiers()))
                    .map((Function<Class<?>, Class<? extends T>>) aClass -> (Class<? extends T>) aClass)
                    .collect(Collectors.toList());
    }

    @Override
    public Set<Class<? extends Event>> getEvents() {
        return new HashSet<>(events);
    }

    @Override public Set<Class<? extends Command>> getCommands() {
        return new HashSet<>(commands);
    }

    private class ScannerBundleTracker implements BundleTrackerCustomizer<Object> {
        @Override public Object addingBundle(Bundle bundle,
                                             BundleEvent event) {
            events.addAll(findSubTypesOf(bundle, Arrays.asList(Event.class)));
            commands.addAll(findSubTypesOf(bundle, Arrays.asList(Command.class)));
            return null;
        }

        @Override
        public void modifiedBundle(Bundle bundle, BundleEvent event,
                                   Object object) {
        }

        @Override
        public void removedBundle(Bundle bundle, BundleEvent event,
                                  Object object) {
            events.removeAll(findSubTypesOf(bundle, Arrays.asList(Event.class)));
            commands.removeAll(findSubTypesOf(bundle, Arrays.asList(Command.class)));
        }
    }
}<commit_msg>Problem: OSGiEntitiesProvider's results are not updated over time<commit_after>/**
 * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.eventsourcing;

import com.google.common.base.Joiner;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;

import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Provides an event and command sets from OSGi bundles
 */
@Component(immediate = true)
public class OSGiEntitiesProvider {

    private BundleTracker<Collection<ServiceRegistration>> tracker;

    @Activate
    protected void activate(ComponentContext context) {
        tracker = new BundleTracker<>(context.getBundleContext(), Bundle.ACTIVE,
                                    new ScannerBundleTracker(context.getBundleContext()));
        tracker.open();
    }

    @Deactivate
    protected void deactivate() {
        tracker.close();
    }


    private static class BundleCommandEventSetProvider implements CommandSetProvider, EventSetProvider {

        private final List<Class<? extends Command>> commands;
        private final List<Class<? extends Event>> events;

        public BundleCommandEventSetProvider(Bundle bundle) {
            commands = findSubTypesOf(bundle, Collections.singleton(Command.class));
            events = findSubTypesOf(bundle, Collections.singleton(Event.class));
        }

        private <T> List<Class<? extends T>> findSubTypesOf(Bundle bundle, Collection<Class<T>> superclasses) {
            BundleWiring wiring = bundle.adapt(BundleWiring.class);
            Collection<String> names = wiring
                    .listResources("/", "*", BundleWiring.LISTRESOURCES_RECURSE);
            return names.stream().map(new Function<String, Class<?>>() {
                @Override @SneakyThrows
                public Class<?> apply(String name) {
                    String n = name.replaceAll("\\.class$", "").replace('/', '.');
                    try {
                        return bundle.loadClass(n);
                    } catch (ClassNotFoundException | NoClassDefFoundError e) {
                        return null;
                    }
                }
            }).filter(c -> c != null).filter(c -> superclasses.stream().anyMatch(sc -> sc.isAssignableFrom(c)))
                        .filter(c -> !c.isInterface() && !Modifier.isAbstract(c.getModifiers()))
                        .map((Function<Class<?>, Class<? extends T>>) aClass -> (Class<? extends T>) aClass)
                        .collect(Collectors.toList());
        }

        @Override public Set<Class<? extends Event>> getEvents() {
            return new HashSet<>(events);
        }

        @Override public Set<Class<? extends Command>> getCommands() {
            return new HashSet<>(commands);
        }
    }

    @Slf4j
    private static class ScannerBundleTracker implements BundleTrackerCustomizer<Collection<ServiceRegistration>> {

        private final BundleContext bundleContext;

        public ScannerBundleTracker(BundleContext bundleContext) {
            this.bundleContext = bundleContext;
        }

        @Override public Collection<ServiceRegistration> addingBundle(Bundle bundle, BundleEvent event) {
            BundleCommandEventSetProvider bundleCommandEventSetProvider = new BundleCommandEventSetProvider(bundle);

            ArrayList<ServiceRegistration> registrations = new ArrayList<>();
            Hashtable<String, Object> properties = new Hashtable<>();
            properties.put("bundle", bundle.getSymbolicName());
            if (!bundleCommandEventSetProvider.getCommands().isEmpty()) {
                properties.put("commands", Joiner.on(", ").join(
                        bundleCommandEventSetProvider.getCommands().stream().map(Class::getName).collect(Collectors.toList())));
                log.info("Registering a service for providing commands in {}", bundle.getSymbolicName());
                registrations.add(bundleContext.registerService(CommandSetProvider.class, bundleCommandEventSetProvider,
                                                           properties));
            }
            if (!bundleCommandEventSetProvider.getEvents().isEmpty()) {
                properties.put("events", Joiner.on(", ").join(
                        bundleCommandEventSetProvider.getEvents().stream().map(Class::getName).collect(Collectors.toList())));
                log.info("Registering a service for providing events in {}", bundle.getSymbolicName());
                registrations.add(bundleContext.registerService(EventSetProvider.class, bundleCommandEventSetProvider,
                                                                properties));
            }
            return registrations;
        }

        @Override
        public void modifiedBundle(Bundle bundle, BundleEvent event,
                                   Collection<ServiceRegistration> registrations) {
        }

        @Override
        public void removedBundle(Bundle bundle, BundleEvent event,
                                  Collection<ServiceRegistration> registrations) {
            if (!registrations.isEmpty()) {
                log.info("Deregistering services for providing commands and events in {}", bundle.getSymbolicName());
                registrations.forEach(ServiceRegistration::unregister);
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.10720702735076862, 'fraction_numerical': 0.0018965861449391096, 'mean_word_length': 2.575660242683797, 'pattern_counts': {'":': 0, '<': 66, '<?xml version=': 0, '>': 76, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7061995', 'n_tokens_mistral': 2556, 'n_tokens_neox': 2454, 'n_words': 571}