diff options
Diffstat (limited to 'container-di/src/main/java/com/yahoo')
31 files changed, 0 insertions, 2903 deletions
diff --git a/container-di/src/main/java/com/yahoo/container/bundle/BundleInstantiationSpecification.java b/container-di/src/main/java/com/yahoo/container/bundle/BundleInstantiationSpecification.java deleted file mode 100644 index 0fb8a99a957..00000000000 --- a/container-di/src/main/java/com/yahoo/container/bundle/BundleInstantiationSpecification.java +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.bundle; - -import com.yahoo.component.ComponentId; -import com.yahoo.component.ComponentSpecification; - - -/** - * Specifies how a component should be instantiated from a bundle. - * - * Immutable - * - * @author Tony Vaagenes - */ -public final class BundleInstantiationSpecification { - - public final ComponentId id; - public final ComponentSpecification classId; - public final ComponentSpecification bundle; - - public BundleInstantiationSpecification(ComponentSpecification id, ComponentSpecification classId, ComponentSpecification bundle) { - this.id = id.toId(); - this.classId = (classId != null) ? classId : id.withoutNamespace(); - this.bundle = (bundle != null) ? bundle : this.classId; - } - - // Must only be used when classId != null, otherwise the id must be handled as a ComponentSpecification - // (since converting a spec string to a ComponentId and then to a ComponentSpecification causes loss of information). - public BundleInstantiationSpecification(ComponentId id, ComponentSpecification classId, ComponentSpecification bundle) { - this(id.toSpecification(), classId, bundle); - assert (classId!= null); - } - - private static final String defaultInternalBundle = "container-search-and-docproc"; - - private static BundleInstantiationSpecification getInternalSpecificationFromString(String idSpec, String classSpec) { - return new BundleInstantiationSpecification( - new ComponentSpecification(idSpec), - (classSpec == null || classSpec.isEmpty())? null : new ComponentSpecification(classSpec), - new ComponentSpecification(defaultInternalBundle)); - } - - public static BundleInstantiationSpecification getInternalSearcherSpecification(ComponentSpecification idSpec, - ComponentSpecification classSpec) { - return new BundleInstantiationSpecification(idSpec, classSpec, new ComponentSpecification(defaultInternalBundle)); - } - - // TODO: These are the same for now because they are in the same bundle. - public static BundleInstantiationSpecification getInternalHandlerSpecificationFromStrings(String idSpec, String classSpec) { - return getInternalSpecificationFromString(idSpec, classSpec); - } - - public static BundleInstantiationSpecification getInternalProcessingSpecificationFromStrings(String idSpec, String classSpec) { - return getInternalSpecificationFromString(idSpec, classSpec); - } - - public static BundleInstantiationSpecification getInternalSearcherSpecificationFromStrings(String idSpec, String classSpec) { - return getInternalSpecificationFromString(idSpec, classSpec); - } - - public static BundleInstantiationSpecification getFromStrings(String idSpec, String classSpec, String bundleSpec) { - return new BundleInstantiationSpecification( - new ComponentSpecification(idSpec), - (classSpec == null || classSpec.isEmpty())? null : new ComponentSpecification(classSpec), - (bundleSpec == null || bundleSpec.isEmpty())? null : new ComponentSpecification(bundleSpec)); - } - - /** - * Return a new instance of the specification with bundle name altered - * - * @param bundleName the new name of the bundle - * @return the new instance of the specification - */ - public BundleInstantiationSpecification inBundle(String bundleName) { - return new BundleInstantiationSpecification(this.id, this.classId, new ComponentSpecification(bundleName)); - } - - public String getClassName() { - return classId.getName(); - } - - public BundleInstantiationSpecification nestInNamespace(ComponentId namespace) { - return new BundleInstantiationSpecification(id.nestInNamespace(namespace), classId, bundle); - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/bundle/MockBundle.java b/container-di/src/main/java/com/yahoo/container/bundle/MockBundle.java deleted file mode 100644 index a6524b41886..00000000000 --- a/container-di/src/main/java/com/yahoo/container/bundle/MockBundle.java +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.bundle; - -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.Version; -import org.osgi.framework.wiring.BundleCapability; -import org.osgi.framework.wiring.BundleRequirement; -import org.osgi.framework.wiring.BundleRevision; -import org.osgi.framework.wiring.BundleWire; -import org.osgi.framework.wiring.BundleWiring; -import org.osgi.resource.Capability; -import org.osgi.resource.Requirement; -import org.osgi.resource.Wire; - -import java.io.File; -import java.io.InputStream; -import java.net.URL; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.Collections; -import java.util.Dictionary; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; - -/** - * @author gjoranv - * @author ollivir - */ -public class MockBundle implements Bundle, BundleWiring { - public static final String SymbolicName = "mock-bundle"; - public static final Version BundleVersion = new Version(1, 0, 0); - - private static final Class<BundleWiring> bundleWiringClass = BundleWiring.class; - - @Override - public int getState() { - return Bundle.ACTIVE; - } - - @Override - public void start(int options) { - } - - @Override - public void start() { - } - - @Override - public void stop(int options) { - } - - @Override - public void stop() { - } - - @Override - public void update(InputStream input) { - } - - @Override - public void update() { - } - - @Override - public void uninstall() { - } - - @Override - public Dictionary<String, String> getHeaders(String locale) { - return getHeaders(); - } - - @Override - public String getSymbolicName() { - return SymbolicName; - } - - @Override - public Version getVersion() { - return BundleVersion; - } - - @Override - public String getLocation() { - return getSymbolicName(); - } - - @Override - public long getBundleId() { - return 0L; - } - - @Override - public Dictionary<String, String> getHeaders() { - return new Hashtable<>(); - } - - @Override - public ServiceReference<?>[] getRegisteredServices() { - return new ServiceReference<?>[0]; - } - - @Override - public ServiceReference<?>[] getServicesInUse() { - return getRegisteredServices(); - } - - @Override - public boolean hasPermission(Object permission) { - return true; - } - - @Override - public URL getResource(String name) { - throw new UnsupportedOperationException(); - } - - @Override - public Class<?> loadClass(String name) { - throw new UnsupportedOperationException(); - } - - @Override - public Enumeration<URL> getResources(String name) { - throw new UnsupportedOperationException(); - } - - @Override - public Enumeration<String> getEntryPaths(String path) { - throw new UnsupportedOperationException(); - } - - @Override - public URL getEntry(String path) { - throw new UnsupportedOperationException(); - } - - @Override - public Enumeration<URL> findEntries(String path, String filePattern, boolean recurse) { - return Collections.emptyEnumeration(); - } - - - @Override - public long getLastModified() { - return 1L; - } - - @Override - public BundleContext getBundleContext() { - throw new UnsupportedOperationException(); - } - - @Override - public Map<X509Certificate, List<X509Certificate>> getSignerCertificates(int signersType) { - return Collections.emptyMap(); - } - - @SuppressWarnings("unchecked") - @Override - public <T> T adapt(Class<T> type) { - if (type.equals(bundleWiringClass)) { - return (T) this; - } else { - throw new UnsupportedOperationException(); - } - } - - @Override - public File getDataFile(String filename) { - return null; - } - - @Override - public int compareTo(Bundle o) { - return Long.compare(getBundleId(), o.getBundleId()); - } - - - //TODO: replace with mockito - @Override - public List<URL> findEntries(String p1, String p2, int p3) { - throw new UnsupportedOperationException(); - } - - @Override - public List<Wire> getRequiredResourceWires(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public List<Capability> getResourceCapabilities(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isCurrent() { - throw new UnsupportedOperationException(); - } - - @Override - public List<BundleWire> getRequiredWires(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public List<BundleCapability> getCapabilities(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public List<Wire> getProvidedResourceWires(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public List<BundleWire> getProvidedWires(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public BundleRevision getRevision() { - throw new UnsupportedOperationException(); - } - - @Override - public List<Requirement> getResourceRequirements(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isInUse() { - throw new UnsupportedOperationException(); - } - - @Override - public Collection<String> listResources(String p1, String p2, int p3) { - return Collections.emptyList(); - } - - @Override - public ClassLoader getClassLoader() { - return MockBundle.class.getClassLoader(); - } - - @Override - public List<BundleRequirement> getRequirements(String p1) { - throw new UnsupportedOperationException(); - } - - @Override - public BundleRevision getResource() { - throw new UnsupportedOperationException(); - } - - @Override - public Bundle getBundle() { - throw new UnsupportedOperationException(); - } -} diff --git a/container-di/src/main/java/com/yahoo/container/bundle/package-info.java b/container-di/src/main/java/com/yahoo/container/bundle/package-info.java deleted file mode 100644 index c9707371626..00000000000 --- a/container-di/src/main/java/com/yahoo/container/bundle/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -package com.yahoo.container.bundle; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java b/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java deleted file mode 100644 index 065733a719a..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di; - -import com.yahoo.config.ConfigInstance; -import com.yahoo.config.subscription.ConfigHandle; -import com.yahoo.config.subscription.ConfigSource; -import com.yahoo.config.subscription.ConfigSourceSet; -import com.yahoo.config.subscription.ConfigSubscriber; -import com.yahoo.container.di.config.Subscriber; -import com.yahoo.container.di.config.SubscriberFactory; -import com.yahoo.vespa.config.ConfigKey; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Tony Vaagenes - * @author ollivir - */ -public class CloudSubscriberFactory implements SubscriberFactory { - - private static final Logger log = Logger.getLogger(CloudSubscriberFactory.class.getName()); - - private final ConfigSource configSource; - private final Map<CloudSubscriber, Integer> activeSubscribers = new WeakHashMap<>(); - - private Optional<Long> testGeneration = Optional.empty(); - - public CloudSubscriberFactory(ConfigSource configSource) { - this.configSource = configSource; - } - - @Override - public Subscriber getSubscriber(Set<? extends ConfigKey<?>> configKeys) { - Set<ConfigKey<ConfigInstance>> subscriptionKeys = new HashSet<>(); - for(ConfigKey<?> key: configKeys) { - @SuppressWarnings("unchecked") // ConfigKey is defined as <CONFIGCLASS extends ConfigInstance> - ConfigKey<ConfigInstance> invariant = (ConfigKey<ConfigInstance>) key; - subscriptionKeys.add(invariant); - } - CloudSubscriber subscriber = new CloudSubscriber(subscriptionKeys, configSource); - - testGeneration.ifPresent(subscriber.subscriber::reload); // TODO: test specific code, remove - activeSubscribers.put(subscriber, 0); - - return subscriber; - } - - //TODO: test specific code, remove - @Override - public void reloadActiveSubscribers(long generation) { - testGeneration = Optional.of(generation); - - List<CloudSubscriber> subscribers = new ArrayList<>(activeSubscribers.keySet()); - subscribers.forEach(s -> s.subscriber.reload(generation)); - } - - private static class CloudSubscriber implements Subscriber { - - private final ConfigSubscriber subscriber; - private final Map<ConfigKey<ConfigInstance>, ConfigHandle<ConfigInstance>> handles = new HashMap<>(); - - // if waitNextGeneration has not yet been called, -1 should be returned - private long generation = -1L; - - private CloudSubscriber(Set<ConfigKey<ConfigInstance>> keys, ConfigSource configSource) { - this.subscriber = new ConfigSubscriber(configSource); - keys.forEach(k -> handles.put(k, subscriber.subscribe(k.getConfigClass(), k.getConfigId()))); - } - - @Override - public boolean configChanged() { - return handles.values().stream().anyMatch(ConfigHandle::isChanged); - } - - @Override - public long generation() { - return generation; - } - - //mapValues returns a view,, so we need to force evaluation of it here to prevent deferred evaluation. - @Override - public Map<ConfigKey<ConfigInstance>, ConfigInstance> config() { - Map<ConfigKey<ConfigInstance>, ConfigInstance> ret = new HashMap<>(); - handles.forEach((k, v) -> ret.put(k, v.getConfig())); - return ret; - } - - @Override - public long waitNextGeneration(boolean isInitializing) { - if (handles.isEmpty()) - throw new IllegalStateException("No config keys registered"); - - // Catch and just log config exceptions due to missing config values for parameters that do - // not have a default value. These exceptions occur when the user has removed a component - // from services.xml, and the component takes a config that has parameters without a - // default value in the def-file. There is a new 'components' config underway, where the - // component is removed, so this old config generation will soon be replaced by a new one. - boolean gotNextGen = false; - int numExceptions = 0; - while ( ! gotNextGen) { - try { - if (subscriber.nextGeneration(isInitializing)) - gotNextGen = true; - } - catch (IllegalArgumentException e) { - numExceptions++; - log.log(Level.WARNING, "Got exception from the config system (ignore if you just removed a " + - "component from your application that used the mentioned config) Subscriber info: " + - subscriber.toString(), e); - if (numExceptions >= 5) - throw new IllegalArgumentException("Failed retrieving the next config generation", e); - } - } - - generation = subscriber.getGeneration(); - return generation; - } - - @Override - public void close() { - subscriber.close(); - } - - } - - public static class Provider implements com.google.inject.Provider<SubscriberFactory> { - @Override - public SubscriberFactory get() { - return new CloudSubscriberFactory(ConfigSourceSet.createDefault()); - } - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java b/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java deleted file mode 100644 index 4e3881a6fe6..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di; - -import org.osgi.framework.Bundle; - -import java.util.Collection; -import java.util.List; - -/** - * @author gjoranv - * @author Tony Vaagenes - */ -public interface ComponentDeconstructor { - - /** Deconstructs the given components in order, then the given bundles. */ - void deconstruct(List<Object> components, Collection<Bundle> bundles); - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java b/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java deleted file mode 100644 index a7ff6c46a8b..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di; - -import com.google.common.collect.Sets; -import com.yahoo.config.ConfigInstance; -import com.yahoo.container.di.componentgraph.core.Keys; -import com.yahoo.container.di.config.Subscriber; -import com.yahoo.vespa.config.ConfigKey; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static java.util.logging.Level.FINE; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ollivir - */ -public final class ConfigRetriever { - - private static final Logger log = Logger.getLogger(ConfigRetriever.class.getName()); - - private final Set<ConfigKey<? extends ConfigInstance>> bootstrapKeys; - private Set<ConfigKey<? extends ConfigInstance>> componentSubscriberKeys; - private final Subscriber bootstrapSubscriber; - private Subscriber componentSubscriber; - private final Function<Set<ConfigKey<? extends ConfigInstance>>, Subscriber> subscribe; - - public ConfigRetriever(Set<ConfigKey<? extends ConfigInstance>> bootstrapKeys, - Function<Set<ConfigKey<? extends ConfigInstance>>, Subscriber> subscribe) { - this.bootstrapKeys = bootstrapKeys; - this.componentSubscriberKeys = new HashSet<>(); - this.subscribe = subscribe; - if (bootstrapKeys.isEmpty()) { - throw new IllegalArgumentException("Bootstrap key set is empty"); - } - this.bootstrapSubscriber = subscribe.apply(bootstrapKeys); - this.componentSubscriber = subscribe.apply(componentSubscriberKeys); - } - - public ConfigSnapshot getConfigs(Set<ConfigKey<? extends ConfigInstance>> componentConfigKeys, - long leastGeneration, boolean isInitializing) { - // Loop until we get config. - while (true) { - Optional<ConfigSnapshot> maybeSnapshot = getConfigsOnce(componentConfigKeys, leastGeneration, isInitializing); - if (maybeSnapshot.isPresent()) { - var configSnapshot = maybeSnapshot.get(); - resetComponentSubscriberIfBootstrap(configSnapshot); - return configSnapshot; - } - } - } - - Optional<ConfigSnapshot> getConfigsOnce(Set<ConfigKey<? extends ConfigInstance>> componentConfigKeys, - long leastGeneration, boolean isInitializing) { - if (!Sets.intersection(componentConfigKeys, bootstrapKeys).isEmpty()) { - throw new IllegalArgumentException( - "Component config keys [" + componentConfigKeys + "] overlaps with bootstrap config keys [" + bootstrapKeys + "]"); - } - log.log(FINE, "getConfigsOnce: " + componentConfigKeys); - - Set<ConfigKey<? extends ConfigInstance>> allKeys = new HashSet<>(componentConfigKeys); - allKeys.addAll(bootstrapKeys); - setupComponentSubscriber(allKeys); - - return getConfigsOptional(leastGeneration, isInitializing); - } - - private Optional<ConfigSnapshot> getConfigsOptional(long leastGeneration, boolean isInitializing) { - long newestComponentGeneration = componentSubscriber.waitNextGeneration(isInitializing); - log.log(FINE, "getConfigsOptional: new component generation: " + newestComponentGeneration); - - // leastGeneration is only used to ensure newer generation when the previous generation was invalidated due to an exception - if (newestComponentGeneration < leastGeneration) { - return Optional.empty(); - } else if (bootstrapSubscriber.generation() < newestComponentGeneration) { - long newestBootstrapGeneration = bootstrapSubscriber.waitNextGeneration(isInitializing); - log.log(FINE, "getConfigsOptional: new bootstrap generation: " + bootstrapSubscriber.generation()); - Optional<ConfigSnapshot> bootstrapConfig = bootstrapConfigIfChanged(); - if (bootstrapConfig.isPresent()) { - return bootstrapConfig; - } else { - if (newestBootstrapGeneration == newestComponentGeneration) { - log.log(FINE, "Got new components configs with unchanged bootstrap configs."); - return componentsConfigIfChanged(); - } else { - // This should not be a normal case, and hence a warning to allow investigation. - log.warning("Did not get same generation for bootstrap (" + newestBootstrapGeneration + - ") and components configs (" + newestComponentGeneration + ")."); - return Optional.empty(); - } - } - } else { - // bootstrapGen==componentGen (happens only when a new component subscriber returns first config after bootstrap) - return componentsConfigIfChanged(); - } - } - - private Optional<ConfigSnapshot> bootstrapConfigIfChanged() { - return configIfChanged(bootstrapSubscriber, BootstrapConfigs::new); - } - - private Optional<ConfigSnapshot> componentsConfigIfChanged() { - return configIfChanged(componentSubscriber, ComponentsConfigs::new); - } - - private Optional<ConfigSnapshot> configIfChanged(Subscriber subscriber, - Function<Map<ConfigKey<? extends ConfigInstance>, ConfigInstance>, ConfigSnapshot> constructor) { - if (subscriber.configChanged()) { - return Optional.of(constructor.apply(Keys.covariantCopy(subscriber.config()))); - } else { - return Optional.empty(); - } - } - - private void resetComponentSubscriberIfBootstrap(ConfigSnapshot snapshot) { - if (snapshot instanceof BootstrapConfigs) { - setupComponentSubscriber(Collections.emptySet()); - } - } - - private void setupComponentSubscriber(Set<ConfigKey<? extends ConfigInstance>> keys) { - if (! componentSubscriberKeys.equals(keys)) { - componentSubscriber.close(); - componentSubscriberKeys = keys; - try { - log.log(FINE, "Setting up new component subscriber for keys: " + keys); - componentSubscriber = subscribe.apply(keys); - } catch (Throwable e) { - log.log(Level.WARNING, "Failed setting up subscriptions for component configs: " + e.getMessage()); - log.log(Level.WARNING, "Config keys: " + keys); - throw e; - } - } - } - - public void shutdown() { - bootstrapSubscriber.close(); - componentSubscriber.close(); - } - - //TODO: check if these are really needed - public long getBootstrapGeneration() { - return bootstrapSubscriber.generation(); - } - - public long getComponentsGeneration() { - return componentSubscriber.generation(); - } - - public static class ConfigSnapshot { - private final Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs; - - ConfigSnapshot(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs) { - this.configs = configs; - } - - public Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs() { - return configs; - } - - public int size() { - return configs.size(); - } - } - - public static class BootstrapConfigs extends ConfigSnapshot { - BootstrapConfigs(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs) { - super(configs); - } - } - - public static class ComponentsConfigs extends ConfigSnapshot { - ComponentsConfigs(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs) { - super(configs); - } - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/Container.java b/container-di/src/main/java/com/yahoo/container/di/Container.java deleted file mode 100644 index 82c7f65bc2a..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/Container.java +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di; - -import com.google.inject.Injector; -import com.yahoo.config.ConfigInstance; -import com.yahoo.config.ConfigurationRuntimeException; -import com.yahoo.config.subscription.ConfigInterruptedException; -import com.yahoo.container.ComponentsConfig; -import com.yahoo.container.bundle.BundleInstantiationSpecification; -import com.yahoo.container.di.ConfigRetriever.BootstrapConfigs; -import com.yahoo.container.di.ConfigRetriever.ComponentsConfigs; -import com.yahoo.container.di.ConfigRetriever.ConfigSnapshot; -import com.yahoo.container.di.componentgraph.core.ComponentGraph; -import com.yahoo.container.di.componentgraph.core.ComponentNode; -import com.yahoo.container.di.componentgraph.core.JerseyNode; -import com.yahoo.container.di.componentgraph.core.Node; -import com.yahoo.container.di.config.ApplicationBundlesConfig; -import com.yahoo.container.di.config.PlatformBundlesConfig; -import com.yahoo.container.di.config.RestApiContext; -import com.yahoo.container.di.config.SubscriberFactory; -import com.yahoo.vespa.config.ConfigKey; -import org.osgi.framework.Bundle; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static java.util.logging.Level.FINE; - -/** - * @author gjoranv - * @author Tony Vaagenes - * @author ollivir - */ -public class Container { - - private static final Logger log = Logger.getLogger(Container.class.getName()); - - private final SubscriberFactory subscriberFactory; - private final ConfigKey<ApplicationBundlesConfig> applicationBundlesConfigKey; - private final ConfigKey<PlatformBundlesConfig> platformBundlesConfigKey; - private final ConfigKey<ComponentsConfig> componentsConfigKey; - private final ComponentDeconstructor componentDeconstructor; - private final Osgi osgi; - - private final ConfigRetriever configurer; - private List<String> platformBundles; // Used to verify that platform bundles don't change. - private long previousConfigGeneration = -1L; - private long leastGeneration = -1L; - - public Container(SubscriberFactory subscriberFactory, String configId, ComponentDeconstructor componentDeconstructor, Osgi osgi) { - this.subscriberFactory = subscriberFactory; - this.componentDeconstructor = componentDeconstructor; - this.osgi = osgi; - - applicationBundlesConfigKey = new ConfigKey<>(ApplicationBundlesConfig.class, configId); - platformBundlesConfigKey = new ConfigKey<>(PlatformBundlesConfig.class, configId); - componentsConfigKey = new ConfigKey<>(ComponentsConfig.class, configId); - var bootstrapKeys = Set.of(applicationBundlesConfigKey, platformBundlesConfigKey, componentsConfigKey); - this.configurer = new ConfigRetriever(bootstrapKeys, subscriberFactory::getSubscriber); - } - - public Container(SubscriberFactory subscriberFactory, String configId, ComponentDeconstructor componentDeconstructor) { - this(subscriberFactory, configId, componentDeconstructor, new Osgi() { - }); - } - - public ComponentGraph getNewComponentGraph(ComponentGraph oldGraph, Injector fallbackInjector, boolean isInitializing) { - try { - Collection<Bundle> obsoleteBundles = new HashSet<>(); - ComponentGraph newGraph = getConfigAndCreateGraph(oldGraph, fallbackInjector, isInitializing, obsoleteBundles); - newGraph.reuseNodes(oldGraph); - constructComponents(newGraph); - deconstructObsoleteComponents(oldGraph, newGraph, obsoleteBundles); - return newGraph; - } catch (Throwable t) { - invalidateGeneration(oldGraph.generation(), t); - throw t; - } - } - - private ComponentGraph getConfigAndCreateGraph(ComponentGraph graph, - Injector fallbackInjector, - boolean isInitializing, - Collection<Bundle> obsoleteBundles) // NOTE: Return value - { - ConfigSnapshot snapshot; - while (true) { - snapshot = configurer.getConfigs(graph.configKeys(), leastGeneration, isInitializing); - - log.log(FINE, String.format("createNewGraph:\n" + "graph.configKeys = %s\n" + "graph.generation = %s\n" + "snapshot = %s\n", - graph.configKeys(), graph.generation(), snapshot)); - - if (snapshot instanceof BootstrapConfigs) { - if (getBootstrapGeneration() <= previousConfigGeneration) { - throw new IllegalStateException(String.format( - "Got bootstrap configs out of sequence for old config generation %d.\n" + "Previous config generation is %d", - getBootstrapGeneration(), previousConfigGeneration)); - } - log.log(FINE, "Got new bootstrap generation\n" + configGenerationsString()); - - if (graph.generation() == 0) { - platformBundles = getConfig(platformBundlesConfigKey, snapshot.configs()).bundlePaths(); - osgi.installPlatformBundles(platformBundles); - } else { - throwIfPlatformBundlesChanged(snapshot); - } - Collection<Bundle> bundlesToRemove = installApplicationBundles(snapshot.configs()); - obsoleteBundles.addAll(bundlesToRemove); - - graph = createComponentsGraph(snapshot.configs(), getBootstrapGeneration(), fallbackInjector); - - // Continues loop - - } else if (snapshot instanceof ComponentsConfigs) { - break; - } - } - log.log(FINE, "Got components configs,\n" + configGenerationsString()); - return createAndConfigureComponentsGraph(snapshot.configs(), fallbackInjector); - } - - private long getBootstrapGeneration() { - return configurer.getBootstrapGeneration(); - } - - private long getComponentsGeneration() { - return configurer.getComponentsGeneration(); - } - - private String configGenerationsString() { - return String.format("bootstrap generation = %d\n" + "components generation: %d\n" + "previous generation: %d", - getBootstrapGeneration(), getComponentsGeneration(), previousConfigGeneration); - } - - private void throwIfPlatformBundlesChanged(ConfigSnapshot snapshot) { - var checkPlatformBundles = getConfig(platformBundlesConfigKey, snapshot.configs()).bundlePaths(); - if (! checkPlatformBundles.equals(platformBundles)) - throw new RuntimeException("Platform bundles are not allowed to change!\nOld: " + platformBundles + "\nNew: " + checkPlatformBundles); - } - - private ComponentGraph createAndConfigureComponentsGraph(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> componentsConfigs, - Injector fallbackInjector) { - ComponentGraph componentGraph = createComponentsGraph(componentsConfigs, getComponentsGeneration(), fallbackInjector); - componentGraph.setAvailableConfigs(componentsConfigs); - return componentGraph; - } - - private void constructComponents(ComponentGraph graph) { - graph.nodes().forEach(Node::constructInstance); - } - - private void deconstructObsoleteComponents(ComponentGraph oldGraph, - ComponentGraph newGraph, - Collection<Bundle> obsoleteBundles) { - Map<Object, ?> newComponents = new IdentityHashMap<>(newGraph.size()); - for (Object component : newGraph.allConstructedComponentsAndProviders()) - newComponents.put(component, null); - - List<Object> obsoleteComponents = new ArrayList<>(); - for (Object component : oldGraph.allConstructedComponentsAndProviders()) - if ( ! newComponents.containsKey(component)) - obsoleteComponents.add(component); - - componentDeconstructor.deconstruct(obsoleteComponents, obsoleteBundles); - } - - private Set<Bundle> installApplicationBundles(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configsIncludingBootstrapConfigs) { - ApplicationBundlesConfig applicationBundlesConfig = getConfig(applicationBundlesConfigKey, configsIncludingBootstrapConfigs); - return osgi.useApplicationBundles(applicationBundlesConfig.bundles()); - } - - private ComponentGraph createComponentsGraph(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configsIncludingBootstrapConfigs, - long generation, Injector fallbackInjector) { - previousConfigGeneration = generation; - - ComponentGraph graph = new ComponentGraph(generation); - ComponentsConfig componentsConfig = getConfig(componentsConfigKey, configsIncludingBootstrapConfigs); - if (componentsConfig == null) { - throw new ConfigurationRuntimeException("The set of all configs does not include a valid 'components' config. Config set: " - + configsIncludingBootstrapConfigs.keySet()); - } - addNodes(componentsConfig, graph); - injectNodes(componentsConfig, graph); - - graph.complete(fallbackInjector); - return graph; - } - - private void addNodes(ComponentsConfig componentsConfig, ComponentGraph graph) { - - for (ComponentsConfig.Components config : componentsConfig.components()) { - BundleInstantiationSpecification specification = bundleInstantiationSpecification(config); - Class<?> componentClass = osgi.resolveClass(specification); - Node componentNode; - - if (RestApiContext.class.isAssignableFrom(componentClass)) { - Class<? extends RestApiContext> nodeClass = componentClass.asSubclass(RestApiContext.class); - componentNode = new JerseyNode(specification.id, config.configId(), nodeClass, osgi); - } else { - componentNode = new ComponentNode(specification.id, config.configId(), componentClass, null); - } - graph.add(componentNode); - } - } - - private void injectNodes(ComponentsConfig config, ComponentGraph graph) { - for (ComponentsConfig.Components component : config.components()) { - Node componentNode = ComponentGraph.getNode(graph, component.id()); - - for (ComponentsConfig.Components.Inject inject : component.inject()) { - //TODO: Support inject.name() - componentNode.inject(ComponentGraph.getNode(graph, inject.id())); - } - } - } - - private void invalidateGeneration(long generation, Throwable cause) { - leastGeneration = Math.max(configurer.getComponentsGeneration(), configurer.getBootstrapGeneration()) + 1; - if (!(cause instanceof InterruptedException) && !(cause instanceof ConfigInterruptedException)) { - log.log(Level.WARNING, newGraphErrorMessage(generation, cause), cause); - } - } - - private static String newGraphErrorMessage(long generation, Throwable cause) { - String failedFirstMessage = "Failed to set up first component graph"; - String failedNewMessage = "Failed to set up new component graph"; - String constructMessage = " due to error when constructing one of the components"; - String retainMessage = ". Retaining previous component generation."; - - if (generation == 0) { - if (cause instanceof ComponentNode.ComponentConstructorException) { - return failedFirstMessage + constructMessage; - } else { - return failedFirstMessage; - } - } else { - if (cause instanceof ComponentNode.ComponentConstructorException) { - return failedNewMessage + constructMessage + retainMessage; - } else { - return failedNewMessage + retainMessage; - } - } - } - - public void shutdown(ComponentGraph graph, ComponentDeconstructor deconstructor) { - shutdownConfigurer(); - if (graph != null) { - deconstructAllComponents(graph, deconstructor); - } - } - - void shutdownConfigurer() { - configurer.shutdown(); - } - - // Reload config manually, when subscribing to non-configserver sources - public void reloadConfig(long generation) { - subscriberFactory.reloadActiveSubscribers(generation); - } - - private void deconstructAllComponents(ComponentGraph graph, ComponentDeconstructor deconstructor) { - // This is only used for shutdown, so no need to uninstall any bundles. - deconstructor.deconstruct(graph.allConstructedComponentsAndProviders(), Collections.emptyList()); - } - - public static <T extends ConfigInstance> T getConfig(ConfigKey<T> key, - Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs) { - ConfigInstance inst = configs.get(key); - - if (inst == null || key.getConfigClass() == null) { - throw new RuntimeException("Missing config " + key); - } - - return key.getConfigClass().cast(inst); - } - - private static BundleInstantiationSpecification bundleInstantiationSpecification(ComponentsConfig.Components config) { - return BundleInstantiationSpecification.getFromStrings(config.id(), config.classId(), config.bundle()); - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/Osgi.java b/container-di/src/main/java/com/yahoo/container/di/Osgi.java deleted file mode 100644 index 940986e2f38..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/Osgi.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di; - -import com.yahoo.component.ComponentSpecification; -import com.yahoo.config.FileReference; -import com.yahoo.container.bundle.BundleInstantiationSpecification; -import com.yahoo.container.bundle.MockBundle; -import com.yahoo.container.di.osgi.BundleClasses; -import org.osgi.framework.Bundle; - -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.util.Collections.emptySet; - -/** - * @author gjoranv - * @author Tony Vaagenes - * @author ollivir - */ -public interface Osgi { - default BundleClasses getBundleClasses(ComponentSpecification bundle, Set<String> packagesToScan) { - return new BundleClasses(new MockBundle(), Collections.emptySet()); - } - - default void installPlatformBundles(Collection<String> bundlePaths) { - System.out.println("installPlatformBundles " + bundlePaths); - } - - /** - * Returns the set of bundles that is not used by the current application generation, - * and therefore should be scheduled for uninstalling. - */ - default Set<Bundle> useApplicationBundles(Collection<FileReference> bundles) { - System.out.println("useBundles " + bundles.stream().map(Object::toString).collect(Collectors.joining(", "))); - return emptySet(); - } - - default Class<?> resolveClass(BundleInstantiationSpecification spec) { - System.out.println("resolving class " + spec.classId); - try { - return Class.forName(spec.classId.getName()); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - default Bundle getBundle(ComponentSpecification spec) { - System.out.println("resolving bundle " + spec); - return new MockBundle(); - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java deleted file mode 100644 index 3fd3195e5dd..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph; - -import com.yahoo.component.Deconstructable; - -/** - * <p>Provides a component of the parameter type T. - * If (and only if) dependency injection does not have a component of type T, - * it will request one from the Provider providing type T.</p> - * - * <p>Providers are useful in these situations:</p> - * <ul> - * <li>Some code is needed to create the component instance in question.</li> - * <li>The component creates resources that must be deconstructed.</li> - * <li>A fallback component should be provided in case the application (or system) - * does not provide a component instance.</li> - * </ul> - * - * @author Tony Vaagenes - * @author gjoranv - */ -public interface Provider<T> extends Deconstructable { - - T get(); - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java deleted file mode 100644 index fef2809f236..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; -import com.google.inject.BindingAnnotation; -import com.google.inject.ConfigurationException; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.yahoo.collections.Pair; -import com.yahoo.component.ComponentId; -import com.yahoo.component.provider.ComponentRegistry; -import com.yahoo.config.ConfigInstance; -import com.yahoo.container.di.componentgraph.Provider; -import com.yahoo.container.di.componentgraph.cycle.CycleFinder; -import com.yahoo.container.di.componentgraph.cycle.Graph; - -import java.util.Collections; -import java.util.logging.Level; -import com.yahoo.vespa.config.ConfigKey; - -import java.lang.annotation.Annotation; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.yahoo.container.di.componentgraph.core.Exceptions.removeStackTrace; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ollivir - * - * Not thread safe. - */ -public class ComponentGraph { - - private static final Logger log = Logger.getLogger(ComponentGraph.class.getName()); - - private final long generation; - private final Map<ComponentId, Node> nodesById = new HashMap<>(); - - public ComponentGraph(long generation) { - this.generation = generation; - } - - public ComponentGraph() { - this(0L); - } - - public long generation() { - return generation; - } - - public int size() { - return nodesById.size(); - } - - public Collection<Node> nodes() { - return nodesById.values(); - } - - public void add(Node component) { - if (nodesById.containsKey(component.componentId())) { - throw new IllegalStateException("Multiple components with the same id " + component.componentId()); - } - nodesById.put(component.componentId(), component); - } - - private Optional<Node> lookupGlobalComponent(Key<?> key) { - if (!(key.getTypeLiteral().getType() instanceof Class)) { - throw new RuntimeException("Type not supported " + key.getTypeLiteral()); - } - Class<?> clazz = key.getTypeLiteral().getRawType(); - - Collection<ComponentNode> components = matchingComponentNodes(nodes(), key); - if (components.isEmpty()) { - return Optional.empty(); - } else if (components.size() == 1) { - return Optional.ofNullable(Iterables.get(components, 0)); - } else { - - List<Node> nonProviderComponents = components.stream().filter(c -> !Provider.class.isAssignableFrom(c.instanceType())) - .collect(Collectors.toList()); - if (nonProviderComponents.isEmpty()) { - throw new IllegalStateException("Multiple global component providers for class '" + clazz.getName() + "' found"); - } else if (nonProviderComponents.size() == 1) { - return Optional.of(nonProviderComponents.get(0)); - } else { - throw new IllegalStateException("Multiple global components with class '" + clazz.getName() + "' found"); - } - } - } - - public <T> T getInstance(Class<T> clazz) { - return getInstance(Key.get(clazz)); - } - - @SuppressWarnings("unchecked") - public <T> T getInstance(Key<T> key) { - // TODO: Combine exception handling with lookupGlobalComponent. - Object ob = lookupGlobalComponent(key).map(Node::component) - .orElseThrow(() -> new IllegalStateException(String.format("No global component with key '%s' ", key))); - return (T) ob; - } - - private Collection<ComponentNode> componentNodes() { - return nodesOfType(nodes(), ComponentNode.class); - } - - private Collection<ComponentRegistryNode> componentRegistryNodes() { - return nodesOfType(nodes(), ComponentRegistryNode.class); - } - - private Collection<ComponentNode> osgiComponentsOfClass(Class<?> clazz) { - return componentNodes().stream().filter(node -> clazz.isAssignableFrom(node.componentType())).collect(Collectors.toList()); - } - - public List<Node> complete(Injector fallbackInjector) { - componentNodes().forEach(node -> completeNode(node, fallbackInjector)); - componentRegistryNodes().forEach(this::completeComponentRegistryNode); - return topologicalSort(nodes()); - } - - public List<Node> complete() { - return complete(Guice.createInjector()); - } - - public Set<ConfigKey<? extends ConfigInstance>> configKeys() { - return nodes().stream().flatMap(node -> node.configKeys().stream()).collect(Collectors.toSet()); - } - - public void setAvailableConfigs(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs) { - componentNodes().forEach(node -> node.setAvailableConfigs(Keys.invariantCopy(configs))); - } - - public void reuseNodes(ComponentGraph old) { - // copy instances if node equal - Set<ComponentId> commonComponentIds = Sets.intersection(nodesById.keySet(), old.nodesById.keySet()); - for (ComponentId id : commonComponentIds) { - if (nodesById.get(id).equals(old.nodesById.get(id))) { - nodesById.get(id).instance = old.nodesById.get(id).instance; - } - } - - // reset instances with modified dependencies - for (Node node : topologicalSort(nodes())) { - for (Node usedComponent : node.usedComponents()) { - if (usedComponent.instance.isEmpty()) { - node.instance = Optional.empty(); - } - } - } - } - - /** All constructed components and providers of this, in reverse creation order, i.e., suited for ordered deconstruction. */ - public List<Object> allConstructedComponentsAndProviders() { - List<Node> orderedNodes = topologicalSort(nodes()); - Collections.reverse(orderedNodes); - return orderedNodes.stream().map(node -> node.constructedInstance().get()).collect(Collectors.toList()); - } - - private void completeComponentRegistryNode(ComponentRegistryNode registry) { - registry.injectAll(osgiComponentsOfClass(registry.componentClass())); - } - - private void completeNode(ComponentNode node, Injector fallbackInjector) { - try { - Object[] arguments = node.getAnnotatedConstructorParams().stream().map(param -> handleParameter(node, fallbackInjector, param)) - .toArray(); - - node.setArguments(arguments); - } catch (Exception e) { - throw removeStackTrace(new RuntimeException("When resolving dependencies of " + node.idAndType(), e)); - } - } - - private Object handleParameter(Node node, Injector fallbackInjector, Pair<Type, List<Annotation>> annotatedParameterType) { - Type parameterType = annotatedParameterType.getFirst(); - List<Annotation> annotations = annotatedParameterType.getSecond(); - - if (parameterType instanceof Class && parameterType.equals(ComponentId.class)) { - return node.componentId(); - } else if (parameterType instanceof Class && ConfigInstance.class.isAssignableFrom((Class<?>) parameterType)) { - return handleConfigParameter((ComponentNode) node, (Class<?>) parameterType); - } else if (parameterType instanceof ParameterizedType - && ((ParameterizedType) parameterType).getRawType().equals(ComponentRegistry.class)) { - ParameterizedType registry = (ParameterizedType) parameterType; - return getComponentRegistry(registry.getActualTypeArguments()[0]); - } else if (parameterType instanceof Class) { - return handleComponentParameter(node, fallbackInjector, (Class<?>) parameterType, annotations); - } else if (parameterType instanceof ParameterizedType) { - throw new RuntimeException("Injection of parameterized type " + parameterType + " is not supported."); - } else { - throw new RuntimeException("Injection of type " + parameterType + " is not supported"); - } - } - - private ComponentRegistryNode newComponentRegistryNode(Class<?> componentClass) { - ComponentRegistryNode registry = new ComponentRegistryNode(componentClass); - add(registry); //TODO: don't mutate nodes here. - return registry; - } - - private ComponentRegistryNode getComponentRegistry(Type componentType) { - Class<?> componentClass; - if (componentType instanceof WildcardType) { - WildcardType wildcardType = (WildcardType) componentType; - if (wildcardType.getLowerBounds().length > 0 || wildcardType.getUpperBounds().length > 1) { - throw new RuntimeException("Can't create ComponentRegistry of unknown wildcard type" + wildcardType); - } - componentClass = (Class<?>) wildcardType.getUpperBounds()[0]; - } else if (componentType instanceof Class) { - componentClass = (Class<?>) componentType; - } else if (componentType instanceof TypeVariable) { - throw new RuntimeException("Can't create ComponentRegistry of unknown type variable " + componentType); - } else { - throw new RuntimeException("Can't create ComponentRegistry of unknown type " + componentType); - } - - for (ComponentRegistryNode node : componentRegistryNodes()) { - if (node.componentClass().equals(componentType)) { - return node; - } - } - return newComponentRegistryNode(componentClass); - } - - @SuppressWarnings("unchecked") - private ConfigKey<ConfigInstance> handleConfigParameter(ComponentNode node, Class<?> clazz) { - Class<ConfigInstance> castClass = (Class<ConfigInstance>) clazz; - return new ConfigKey<>(castClass, node.configId()); - } - - private <T> Key<T> getKey(Class<T> clazz, Optional<Annotation> bindingAnnotation) { - return bindingAnnotation.map(annotation -> Key.get(clazz, annotation)).orElseGet(() -> Key.get(clazz)); - } - - private Optional<GuiceNode> matchingGuiceNode(Key<?> key, Object instance) { - return matchingNodes(nodes(), GuiceNode.class, key).stream().filter(node -> node.component() == instance). // TODO: assert that there is only one (after filter) - findFirst(); - } - - private Node lookupOrCreateGlobalComponent(Node node, Injector fallbackInjector, Class<?> clazz, Key<?> key) { - Optional<Node> component = lookupGlobalComponent(key); - if (component.isEmpty()) { - Object instance; - try { - log.log(Level.FINE, "Trying the fallback injector to create" + messageForNoGlobalComponent(clazz, node)); - instance = fallbackInjector.getInstance(key); - } catch (ConfigurationException e) { - throw removeStackTrace(new IllegalStateException( - (messageForMultipleClassLoaders(clazz).isEmpty()) ? "No global" + messageForNoGlobalComponent(clazz, node) - : messageForMultipleClassLoaders(clazz))); - } - component = Optional.of(matchingGuiceNode(key, instance).orElseGet(() -> { - GuiceNode guiceNode = new GuiceNode(instance, key.getAnnotation()); - add(guiceNode); - return guiceNode; - })); - } - return component.get(); - } - - private Node handleComponentParameter(Node node, Injector fallbackInjector, Class<?> clazz, Collection<Annotation> annotations) { - - List<Annotation> bindingAnnotations = annotations.stream().filter(ComponentGraph::isBindingAnnotation).collect(Collectors.toList()); - Key<?> key = getKey(clazz, bindingAnnotations.stream().findFirst()); - - if (bindingAnnotations.size() > 1) { - throw new RuntimeException(String.format("More than one binding annotation used in class '%s'", node.instanceType())); - } - - Collection<ComponentNode> injectedNodesOfCorrectType = matchingComponentNodes(node.componentsToInject, key); - if (injectedNodesOfCorrectType.size() == 0) { - return lookupOrCreateGlobalComponent(node, fallbackInjector, clazz, key); - } else if (injectedNodesOfCorrectType.size() == 1) { - return Iterables.get(injectedNodesOfCorrectType, 0); - } else { - //TODO: !className for last parameter - throw new RuntimeException( - String.format("Multiple components of type '%s' injected into component '%s'", clazz.getName(), node.instanceType())); - } - } - - private static String messageForNoGlobalComponent(Class<?> clazz, Node node) { - return String.format(" component of class %s to inject into component %s.", clazz.getName(), node.idAndType()); - } - - private String messageForMultipleClassLoaders(Class<?> clazz) { - String errMsg = "Class " + clazz.getName() + " is provided by the framework, and cannot be embedded in a user bundle. " - + "To resolve this problem, please refer to osgi-classloading.html#multiple-implementations in the documentation"; - - try { - Class<?> resolvedClass = Class.forName(clazz.getName(), false, this.getClass().getClassLoader()); - if (!resolvedClass.equals(clazz)) { - return errMsg; - } - } catch (ClassNotFoundException ignored) { - - } - return ""; - } - - public static Node getNode(ComponentGraph graph, String componentId) { - return graph.nodesById.get(new ComponentId(componentId)); - } - - private static <T> Collection<T> nodesOfType(Collection<Node> nodes, Class<T> clazz) { - List<T> ret = new ArrayList<>(); - for (Node node : nodes) { - if (clazz.isInstance(node)) { - ret.add(clazz.cast(node)); - } - } - return ret; - } - - private static Collection<ComponentNode> matchingComponentNodes(Collection<Node> nodes, Key<?> key) { - return matchingNodes(nodes, ComponentNode.class, key); - } - - // Finds all nodes with a given nodeType and instance with given key - private static <T extends Node> Collection<T> matchingNodes(Collection<Node> nodes, Class<T> nodeType, Key<?> key) { - Class<?> clazz = key.getTypeLiteral().getRawType(); - Annotation annotation = key.getAnnotation(); - - List<T> filteredByClass = nodesOfType(nodes, nodeType).stream().filter(node -> clazz.isAssignableFrom(node.componentType())) - .collect(Collectors.toList()); - - if (filteredByClass.size() == 1) { - return filteredByClass; - } else { - List<T> filteredByClassAndAnnotation = filteredByClass.stream() - .filter(node -> (annotation == null && node.instanceKey().getAnnotation() == null) - || annotation.equals(node.instanceKey().getAnnotation())) - .collect(Collectors.toList()); - if (filteredByClassAndAnnotation.size() > 0) { - return filteredByClassAndAnnotation; - } else { - return filteredByClass; - } - } - } - - // Returns true if annotation is a BindingAnnotation, e.g. com.google.inject.name.Named - public static boolean isBindingAnnotation(Annotation annotation) { - LinkedList<Class<?>> queue = new LinkedList<>(); - queue.add(annotation.getClass()); - queue.addAll(Arrays.asList(annotation.getClass().getInterfaces())); - - while (!queue.isEmpty()) { - Class<?> clazz = queue.removeFirst(); - if (clazz.getAnnotation(BindingAnnotation.class) != null) { - return true; - } else { - if (clazz.getSuperclass() != null) { - queue.addFirst(clazz.getSuperclass()); - } - } - } - return false; - } - - /** - * The returned list is the nodes from the graph bottom-up. - * - * For each iteration, the algorithm finds the components that are not "wanted by" any other component, - * and prepends those components into the resulting 'sorted' list. Hence, the first element in the returned - * list is the component that is directly or indirectly wanted by "most" other components. - * - * @return A list where a earlier than b in the list implies that there is no path from a to b - */ - private static List<Node> topologicalSort(Collection<Node> nodes) { - Map<ComponentId, Integer> numIncoming = new HashMap<>(); - - nodes.forEach( - node -> node.usedComponents().forEach( - injectedNode -> numIncoming.merge(injectedNode.componentId(), 1, (a, b) -> a + b))); - - LinkedList<Node> sorted = new LinkedList<>(); - List<Node> unsorted = new ArrayList<>(nodes); - - while (!unsorted.isEmpty()) { - List<Node> ready = new ArrayList<>(); - List<Node> notReady = new ArrayList<>(); - unsorted.forEach(node -> { - if (numIncoming.getOrDefault(node.componentId(), 0) == 0) { - ready.add(node); - } else { - notReady.add(node); - } - }); - - if (ready.isEmpty()) { - throw new IllegalStateException("There is a cycle in the component injection graph: " + findCycle(notReady)); - } - - ready.forEach(node -> node.usedComponents() - .forEach(injectedNode -> numIncoming.merge(injectedNode.componentId(), -1, (a, b) -> a + b))); - sorted.addAll(0, ready); - unsorted = notReady; - } - return sorted; - } - - private static List<String> findCycle(List<Node> nodes) { - var cyclicGraph = new Graph<String>(); - for (var node : nodes) { - for (var adjacent : node.usedComponents()) { - cyclicGraph.edge(node.componentId().stringValue(), - adjacent.componentId().stringValue()); - } - } - return new CycleFinder<>(cyclicGraph).findCycle(); - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentNode.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentNode.java deleted file mode 100644 index b6fa4241e26..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentNode.java +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.google.inject.Inject; -import com.google.inject.Key; -import com.yahoo.collections.Pair; -import com.yahoo.component.AbstractComponent; -import com.yahoo.component.ComponentId; -import com.yahoo.config.ConfigInstance; -import com.yahoo.container.di.componentgraph.Provider; -import com.yahoo.vespa.config.ConfigKey; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.yahoo.container.di.componentgraph.core.Exceptions.cutStackTraceAtConstructor; -import static com.yahoo.container.di.componentgraph.core.Exceptions.removeStackTrace; -import static com.yahoo.container.di.componentgraph.core.Keys.createKey; -import static java.util.logging.Level.FINE; -import static java.util.logging.Level.INFO; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ollivir - */ -public class ComponentNode extends Node { - - private static final Logger log = Logger.getLogger(ComponentNode.class.getName()); - - private final Class<?> clazz; - private final Annotation key; - private Object[] arguments = null; - private final String configId; - - private final Constructor<?> constructor; - - private Map<ConfigKey<ConfigInstance>, ConfigInstance> availableConfigs = null; - - - public ComponentNode(ComponentId componentId, - String configId, - Class<?> clazz, Annotation XXX_key) // TODO expose key, not javaAnnotation - { - super(componentId); - if (isAbstract(clazz)) { - throw new IllegalArgumentException("Can't instantiate abstract class " + clazz.getName()); - } - this.configId = configId; - this.clazz = clazz; - this.key = XXX_key; - this.constructor = bestConstructor(clazz); - } - - public ComponentNode(ComponentId componentId, String configId, Class<?> clazz) { - this(componentId, configId, clazz, null); - } - - public String configId() { - return configId; - } - - @Override - public Key<?> instanceKey() { - return createKey(clazz, key); - } - - @Override - public Class<?> instanceType() { - return clazz; - } - - @Override - public List<Node> usedComponents() { - if (arguments == null) { - throw new IllegalStateException("Arguments must be set first."); - } - List<Node> ret = new ArrayList<>(); - for (Object arg : arguments) { - if (arg instanceof Node) { - ret.add((Node) arg); - } - } - return ret; - } - - private static List<Class<?>> allSuperClasses(Class<?> clazz) { - List<Class<?>> ret = new ArrayList<>(); - while (clazz != null) { - ret.add(clazz); - clazz = clazz.getSuperclass(); - } - return ret; - } - - @Override - public Class<?> componentType() { - if (Provider.class.isAssignableFrom(clazz)) { - //TODO: Test what happens if you ask for something that isn't a class, e.g. a parameterized type. - - List<Type> allGenericInterfaces = allSuperClasses(clazz).stream().flatMap(c -> Arrays.stream(c.getGenericInterfaces())).collect(Collectors.toList()); - for (Type t : allGenericInterfaces) { - if (t instanceof ParameterizedType && ((ParameterizedType) t).getRawType().equals(Provider.class)) { - Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments(); - if (typeArgs != null && typeArgs.length > 0) { - return (Class<?>) typeArgs[0]; - } - } - } - throw new IllegalStateException("Component type cannot be resolved"); - } else { - return clazz; - } - } - - public void setArguments(Object[] arguments) { - this.arguments = arguments; - } - - @Override - protected Object newInstance() { - if (arguments == null) { - throw new IllegalStateException("graph.complete must be called before retrieving instances."); - } - - List<Object> actualArguments = new ArrayList<>(); - for (Object ob : arguments) { - if (ob instanceof Node) { - actualArguments.add(((Node) ob).component()); - } else if (ob instanceof ConfigKey) { - actualArguments.add(availableConfigs.get(ob)); - } else { - actualArguments.add(ob); - } - } - - Object instance; - try { - log.log(FINE, () -> "Constructing " + idAndType()); - Instant start = Instant.now(); - instance = constructor.newInstance(actualArguments.toArray()); - Duration duration = Duration.between(start, Instant.now()); - log.log(duration.compareTo(Duration.ofMinutes(1)) > 0 ? INFO : FINE, - () -> "Finished constructing " + idAndType() + " in " + duration); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - StackTraceElement dependencyInjectorMarker = new StackTraceElement("============= Dependency Injection =============", "newInstance", null, -1); - throw removeStackTrace(new ComponentConstructorException("Error constructing " + idAndType() + ": " + e.getMessage(), cutStackTraceAtConstructor(e.getCause(), dependencyInjectorMarker))); - } - - return initId(instance); - } - - private Object initId(Object component) { - if (component instanceof AbstractComponent) { - AbstractComponent abstractComponent = (AbstractComponent) component; - if (abstractComponent.hasInitializedId() && !abstractComponent.getId().equals(componentId())) { - throw new IllegalStateException( - "Component with id '" + componentId() + "' is trying to set its component id explicitly: '" + abstractComponent.getId() + "'. " + - "This is not allowed, so please remove any call to super() in your component's constructor."); - } - abstractComponent.initId(componentId()); - } - return component; - } - - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(arguments); - result = prime * result + ((availableConfigs == null) ? 0 : availableConfigs.hashCode()); - result = prime * result + ((configId == null) ? 0 : configId.hashCode()); - return result; - } - - @Override - public boolean equals(Object other) { - if (other instanceof ComponentNode) { - ComponentNode that = (ComponentNode) other; - return super.equals(that) && equalEdges(Arrays.asList(this.arguments), Arrays.asList(that.arguments)) && this.usedConfigs().equals(that.usedConfigs()); - } else { - return false; - } - } - - private List<ConfigInstance> usedConfigs() { - if (availableConfigs == null) { - throw new IllegalStateException("setAvailableConfigs must be called!"); - } - List<ConfigInstance> ret = new ArrayList<>(); - for (Object arg : arguments) { - if (arg instanceof ConfigKey) { - ret.add(availableConfigs.get(arg)); - } - } - return ret; - } - - protected List<Pair<Type, List<Annotation>>> getAnnotatedConstructorParams() { - Type[] types = constructor.getGenericParameterTypes(); - Annotation[][] annotations = constructor.getParameterAnnotations(); - - List<Pair<Type, List<Annotation>>> ret = new ArrayList<>(); - - for (int i = 0; i < types.length; i++) { - ret.add(new Pair<>(types[i], Arrays.asList(annotations[i]))); - } - return ret; - } - - public void setAvailableConfigs(Map<ConfigKey<ConfigInstance>, ConfigInstance> configs) { - if (arguments == null) { - throw new IllegalStateException("graph.complete must be called before graph.setAvailableConfigs."); - } - this.availableConfigs = configs; - } - - @Override - public Set<ConfigKey<ConfigInstance>> configKeys() { - return configParameterClasses().stream().map(par -> new ConfigKey<>(par, configId)).collect(Collectors.toSet()); - } - - @SuppressWarnings("unchecked") - private List<Class<ConfigInstance>> configParameterClasses() { - List<Class<ConfigInstance>> ret = new ArrayList<>(); - for (Type type : constructor.getGenericParameterTypes()) { - if (type instanceof Class && ConfigInstance.class.isAssignableFrom((Class<?>) type)) { - ret.add((Class<ConfigInstance>) type); - } - } - return ret; - } - - @Override - public String label() { - LinkedList<String> configNames = configKeys().stream().map(k -> k.getName() + ".def").collect(Collectors.toCollection(LinkedList::new)); - - configNames.addFirst(instanceType().getSimpleName()); - configNames.addFirst(Node.packageName(instanceType())); - - return "{" + String.join("|", configNames) + "}"; - } - - private static Constructor<?> bestConstructor(Class<?> clazz) { - Constructor<?>[] publicConstructors = clazz.getConstructors(); - - Constructor<?> annotated = null; - for (Constructor<?> ctor : publicConstructors) { - Annotation annotation = ctor.getAnnotation(Inject.class); - if (annotation != null) { - if (annotated == null) { - annotated = ctor; - } else { - throw componentConstructorException("Multiple constructor annotated with @Inject in class " + clazz.getName()); - } - } - } - if (annotated != null) { - return annotated; - } - - if (publicConstructors.length == 0) { - throw componentConstructorException("No public constructors in class " + clazz.getName()); - } else if (publicConstructors.length == 1) { - return publicConstructors[0]; - } else { - log.warning(String.format("Multiple public constructors found in class %s, there should only be one. " - + "If more than one public constructor is needed, the primary one must be annotated with @Inject.", clazz.getName())); - List<Pair<Constructor<?>, Integer>> withParameterCount = new ArrayList<>(); - for (Constructor<?> ctor : publicConstructors) { - long count = Arrays.stream(ctor.getParameterTypes()).filter(ConfigInstance.class::isAssignableFrom).count(); - withParameterCount.add(new Pair<>(ctor, (int) count)); - } - withParameterCount.sort(Comparator.comparingInt(Pair::getSecond)); - return withParameterCount.get(withParameterCount.size() - 1).getFirst(); - } - } - - private static ComponentConstructorException componentConstructorException(String message) { - return removeStackTrace(new ComponentConstructorException(message)); - } - - public static class ComponentConstructorException extends RuntimeException { - ComponentConstructorException(String message) { - super(message); - } - - ComponentConstructorException(String message, Throwable cause) { - super(message, cause); - } - } - - - private static boolean isAbstract(Class<?> clazz) { - return Modifier.isAbstract(clazz.getModifiers()); - } -}
\ No newline at end of file diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentRegistryNode.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentRegistryNode.java deleted file mode 100644 index 429052c0039..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentRegistryNode.java +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.google.inject.Key; -import com.google.inject.util.Types; -import com.yahoo.component.ComponentId; -import com.yahoo.component.provider.ComponentRegistry; -import com.yahoo.config.ConfigInstance; -import com.yahoo.vespa.config.ConfigKey; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ollivir - */ -public class ComponentRegistryNode extends Node { - - private static ComponentId componentRegistryNamespace = ComponentId.fromString("ComponentRegistry"); - - private final Class<?> componentClass; - - public ComponentRegistryNode(Class<?> componentClass) { - super(componentId(componentClass)); - this.componentClass = componentClass; - } - - @Override - public List<Node> usedComponents() { - return componentsToInject; - } - - @Override - protected Object newInstance() { - ComponentRegistry<Object> registry = new ComponentRegistry<>(); - componentsToInject.forEach(component -> registry.register(component.componentId(), component.component())); - - return registry; - } - - @Override - public Key<?> instanceKey() { - return Key.get(Types.newParameterizedType(ComponentRegistry.class, componentClass)); - } - - @Override - public Class<?> instanceType() { - return instanceKey().getTypeLiteral().getRawType(); - } - - @Override - public Class<?> componentType() { - return instanceType(); - } - - public Class<?> componentClass() { - return componentClass; - } - - @Override - public Set<ConfigKey<ConfigInstance>> configKeys() { - return Collections.emptySet(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((componentClass == null) ? 0 : componentClass.hashCode()); - return result; - } - - @Override - public boolean equals(Object other) { - if (other instanceof ComponentRegistryNode) { - ComponentRegistryNode that = (ComponentRegistryNode) other; - return this.componentId().equals(that.componentId()) && this.instanceType().equals(that.instanceType()) - && equalNodeEdges(this.usedComponents(), that.usedComponents()); - } else { - return false; - } - } - - @Override - public String label() { - return String.format("{ComponentRegistry\\<%s\\>|%s}", componentClass.getSimpleName(), Node.packageName(componentClass)); - } - - private static ComponentId componentId(Class<?> componentClass) { - return syntheticComponentId(componentClass.getName(), componentClass, componentRegistryNamespace); - } - - public static boolean equalNodeEdges(List<Node> edges, List<Node> otherEdges) { - if (edges.size() == otherEdges.size()) { - List<ComponentId> left = edges.stream().map(Node::componentId).sorted().collect(Collectors.toList()); - List<ComponentId> right = otherEdges.stream().map(Node::componentId).sorted().collect(Collectors.toList()); - return left.equals(right); - } else { - return false; - } - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Exceptions.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Exceptions.java deleted file mode 100644 index b0d9d1f3921..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Exceptions.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import java.util.Arrays; - -class Exceptions { - - static <E extends Throwable> E removeStackTrace(E exception) { - if (preserveStackTrace()) { - return exception; - } else { - exception.setStackTrace(new StackTraceElement[0]); - return exception; - } - } - - static boolean preserveStackTrace() { - String preserve = System.getProperty("jdisc.container.preserveStackTrace"); - return (preserve != null && !preserve.isEmpty()); - } - - static Throwable cutStackTraceAtConstructor(Throwable throwable, StackTraceElement marker) { - if (throwable != null && !preserveStackTrace()) { - StackTraceElement[] stackTrace = throwable.getStackTrace(); - int upTo = stackTrace.length - 1; - - // take until ComponentNode is reached - while (upTo >= 0 && !stackTrace[upTo].getClassName().equals(ComponentNode.class.getName())) { - upTo--; - } - - // then drop until <init> is reached - while (upTo >= 0 && !stackTrace[upTo].getMethodName().equals("<init>")) { - upTo--; - } - if (upTo < 0) { - throwable.setStackTrace(new StackTraceElement[0]); - } else { - throwable.setStackTrace(Arrays.copyOfRange(stackTrace, 0, upTo)); - } - - cutStackTraceAtConstructor(throwable.getCause(), marker); - } - return throwable; - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/GuiceNode.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/GuiceNode.java deleted file mode 100644 index 61d0d9bba8d..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/GuiceNode.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.google.inject.Key; -import com.yahoo.component.ComponentId; -import com.yahoo.config.ConfigInstance; -import com.yahoo.vespa.config.ConfigKey; - -import java.lang.annotation.Annotation; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static com.yahoo.container.di.componentgraph.core.Keys.createKey; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ollivir - */ -public final class GuiceNode extends Node { - private static final ComponentId guiceNamespace = ComponentId.fromString("Guice"); - - private final Object myInstance; - private final Annotation annotation; - - public GuiceNode(Object myInstance, - Annotation annotation) { - super(componentId(myInstance)); - this.myInstance = myInstance; - this.annotation = annotation; - } - - @Override - public Set<ConfigKey<ConfigInstance>> configKeys() { - return Collections.emptySet(); - } - - @Override - public Key<?> instanceKey() { - return createKey(myInstance.getClass(), annotation); - } - - @Override - public Class<?> instanceType() { - return myInstance.getClass(); - } - - @Override - public Class<?> componentType() { - return instanceType(); - } - - - @Override - public List<Node> usedComponents() { - return Collections.emptyList(); - } - - @Override - protected Object newInstance() { - return myInstance; - } - - @Override - public void inject(Node component) { - throw new UnsupportedOperationException("Illegal to inject components to a GuiceNode!"); - } - - @Override - public String label() { - return String.format("{{%s|Guice}|%s}", instanceType().getSimpleName(), Node.packageName(instanceType())); - } - - private static ComponentId componentId(Object instance) { - return Node.syntheticComponentId(instance.getClass().getName(), instance, guiceNamespace); - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/JerseyNode.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/JerseyNode.java deleted file mode 100644 index 0f8aa678934..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/JerseyNode.java +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.yahoo.component.ComponentId; -import com.yahoo.component.ComponentSpecification; -import com.yahoo.container.di.Osgi; -import com.yahoo.container.di.config.JerseyBundlesConfig; -import com.yahoo.container.di.config.RestApiContext; -import com.yahoo.container.di.config.RestApiContext.BundleInfo; -import com.yahoo.container.di.osgi.BundleClasses; -import org.osgi.framework.Bundle; -import org.osgi.framework.wiring.BundleWiring; - -import java.net.URL; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; - -/** - * Represents an instance of RestApiContext - * - * @author gjoranv - * @author Tony Vaagenes - * @author ollivir - */ -public class JerseyNode extends ComponentNode { - private static final String WEB_INF_URL = "WebInfUrl"; - - private final Osgi osgi; - - public JerseyNode(ComponentId componentId, String configId, Class<?> clazz, Osgi osgi) { - super(componentId, configId, clazz, null); - this.osgi = osgi; - } - - @Override - protected RestApiContext newInstance() { - Object instance = super.newInstance(); - RestApiContext restApiContext = (RestApiContext) instance; - - List<JerseyBundlesConfig.Bundles> bundles = restApiContext.bundlesConfig.bundles(); - for (JerseyBundlesConfig.Bundles bundleConfig : bundles) { - BundleClasses bundleClasses = osgi.getBundleClasses(ComponentSpecification.fromString(bundleConfig.spec()), - new HashSet<>(bundleConfig.packages())); - - restApiContext.addBundle(createBundleInfo(bundleClasses.bundle(), bundleClasses.classEntries())); - } - - componentsToInject.forEach(component -> restApiContext.addInjectableComponent(component.instanceKey(), component.componentId(), - component.component())); - - return restApiContext; - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object other) { - return super.equals(other) - && (other instanceof JerseyNode && this.componentsToInject.equals(((JerseyNode) other).componentsToInject)); - } - - public static BundleInfo createBundleInfo(Bundle bundle, Collection<String> classEntries) { - BundleInfo bundleInfo = new BundleInfo(bundle.getSymbolicName(), bundle.getVersion(), bundle.getLocation(), webInfUrl(bundle), - bundle.adapt(BundleWiring.class).getClassLoader()); - - bundleInfo.setClassEntries(classEntries); - return bundleInfo; - } - - public static Bundle getBundle(Osgi osgi, String bundleSpec) { - Bundle bundle = osgi.getBundle(ComponentSpecification.fromString(bundleSpec)); - if (bundle == null) { - throw new IllegalArgumentException("Bundle not found: " + bundleSpec); - } - return bundle; - } - - private static URL webInfUrl(Bundle bundle) { - String webInfUrlHeader = bundle.getHeaders().get(WEB_INF_URL); - - if (webInfUrlHeader == null) { - return null; - } else { - return bundle.getEntry(webInfUrlHeader); - } - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java deleted file mode 100644 index be80fc1616d..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.google.inject.Key; -import com.yahoo.config.ConfigInstance; -import com.yahoo.vespa.config.ConfigKey; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; - -/** - * @author ollivir - */ -public class Keys { - - static Key<?> createKey(Type instanceType, Annotation annotation) { - if (annotation == null) { - return Key.get(instanceType); - } else { - return Key.get(instanceType, annotation); - } - } - - @SuppressWarnings("unchecked") - public static Map<ConfigKey<ConfigInstance>, ConfigInstance> invariantCopy(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configs) { - Map<ConfigKey<ConfigInstance>, ConfigInstance> ret = new HashMap<>(); - configs.forEach((k, v) -> ret.put((ConfigKey<ConfigInstance>) k, v)); - return ret; - } - - public static Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> covariantCopy(Map<ConfigKey<ConfigInstance>, ConfigInstance> configs) { - Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> ret = new HashMap<>(); - configs.forEach((k, v) -> ret.put(k, v)); - return ret; - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Node.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Node.java deleted file mode 100644 index 3afc8bb817c..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Node.java +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.core; - -import com.google.inject.Key; -import com.yahoo.component.ComponentId; -import com.yahoo.config.ConfigInstance; -import com.yahoo.container.di.componentgraph.Provider; -import com.yahoo.vespa.config.ConfigKey; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.logging.Logger; - -import static java.util.logging.Level.FINE; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ollivir - */ -public abstract class Node { - - private final static Logger log = Logger.getLogger(Node.class.getName()); - - private final ComponentId componentId; - protected Optional<Object> instance = Optional.empty(); - List<Node> componentsToInject = new ArrayList<>(); - - public Node(ComponentId componentId) { - this.componentId = componentId; - } - - public abstract Key<?> instanceKey(); - - /** - * The components actually used by this node. Consist of a subset of the injected nodes + subset of the global nodes. - */ - public abstract List<Node> usedComponents(); - - protected abstract Object newInstance(); - - /** Constructs the instance represented by this node, if not already done. */ - public void constructInstance() { - if ( ! instance.isPresent()) - instance = Optional.of(newInstance()); - } - - /** - * Returns the component represented by this - which is either the instance, or if the instance is a provider, - * the component returned by it. - */ - public Object component() { - constructInstance(); - if (instance.get() instanceof Provider) { - Provider<?> provider = (Provider<?>) instance.get(); - return provider.get(); - } else { - return instance.get(); - } - } - - public abstract Set<ConfigKey<ConfigInstance>> configKeys(); - - public void inject(Node component) { - componentsToInject.add(component); - } - - public void injectAll(Collection<ComponentNode> componentNodes) { - componentNodes.forEach(this::inject); - } - - public abstract Class<?> instanceType(); - - public abstract Class<?> componentType(); - - public abstract String label(); - - public String idAndType() { - String className = instanceType().getName(); - - if (className.equals(componentId.getName())) { - return "'" + componentId + "'"; - } else { - return "'" + componentId + "' of type '" + className + "'"; - } - } - - private static boolean equalNodes(Object a, Object b) { - if (a instanceof Node && b instanceof Node) { - Node l = (Node) a; - Node r = (Node) b; - return l.componentId.equals(r.componentId); - } else { - return a.equals(b); - } - } - - public static boolean equalEdges(List<?> edges1, List<?> edges2) { - Iterator<?> right = edges2.iterator(); - for (Object l : edges1) { - if (!right.hasNext()) { - return false; - } - Object r = right.next(); - if (!equalNodes(l, r)) { - return false; - } - } - return !right.hasNext(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((componentId == null) ? 0 : componentId.hashCode()); - result = prime * result + ((componentsToInject == null) ? 0 : componentsToInject.hashCode()); - return result; - } - - @Override - public boolean equals(Object other) { - if (other instanceof Node) { - Node that = (Node) other; - return getClass().equals(that.getClass()) && this.componentId.equals(that.componentId) - && this.instanceType().equals(that.instanceType()) && equalEdges(this.usedComponents(), that.usedComponents()); - } else { - return false; - } - } - - public ComponentId componentId() { - return componentId; - } - - /** Returns the already constructed instance in this, if any */ - public Optional<?> constructedInstance() { - return instance; - } - - /** - * @param identityObject he identifying object that makes the Node unique - */ - protected static ComponentId syntheticComponentId(String className, Object identityObject, ComponentId namespace) { - String name = className + "_" + System.identityHashCode(identityObject); - return ComponentId.fromString(name).nestInNamespace(namespace); - } - - public static String packageName(Class<?> componentClass) { - String fullClassName = componentClass.getName(); - int index = fullClassName.lastIndexOf('.'); - if (index < 0) { - return ""; - } else { - return fullClassName.substring(0, index); - } - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/package-info.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/package-info.java deleted file mode 100644 index e9b5b14d5d8..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -package com.yahoo.container.di.componentgraph.core; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/cycle/CycleFinder.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/cycle/CycleFinder.java deleted file mode 100644 index 327949bb8d0..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/cycle/CycleFinder.java +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.componentgraph.cycle; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.yahoo.container.di.componentgraph.cycle.CycleFinder.State.BLACK; -import static com.yahoo.container.di.componentgraph.cycle.CycleFinder.State.GRAY; -import static com.yahoo.container.di.componentgraph.cycle.CycleFinder.State.WHITE; -import static java.util.logging.Level.FINE; -import static java.util.Collections.singletonList; - - -/** - * <p>Applies the - * <a href="https://www.geeksforgeeks.org/detect-cycle-direct-graph-using-colors/"> three-color algorithm</a> - * to detect a cycle in a directed graph. If there are multiple cycles, this implementation only detects one - * of them and does not guarantee that the shortest cycle is found. - * </p> - * - * @author gjoranv - */ -public class CycleFinder<T> { - private static final Logger log = Logger.getLogger(CycleFinder.class.getName()); - - enum State { - WHITE, GRAY, BLACK; - } - - private final Graph<T> graph; - - private Map<T, State> colors; - - private List<T> cycle; - - public CycleFinder(Graph<T> graph) { - this.graph = graph; - } - - private void resetState() { - cycle = null; - colors = new LinkedHashMap<>(); - graph.getVertices().forEach(v -> colors.put(v, WHITE)); - } - - /** - * Returns a list of vertices constituting a cycle in the graph, or an empty - * list if no cycle was found. Only the first encountered cycle is returned. - */ - public List<T> findCycle() { - resetState(); - for (T vertex : graph.getVertices()) { - if (colors.get(vertex) == WHITE) { - if (visitDepthFirst(vertex, new ArrayList<>(singletonList(vertex)))) { - if (cycle == null) throw new IllegalStateException("Null cycle - this should never happen"); - if (cycle.isEmpty()) throw new IllegalStateException("Empty cycle - this should never happen"); - log.log(FINE, "Cycle detected: " + cycle); - return cycle; - } - } - } - return new ArrayList<>(); - } - - private boolean visitDepthFirst(T vertex, List<T> path) { - colors.put(vertex, GRAY); - log.log(FINE, "Vertex start " + vertex + " - colors: " + colors + " - path: " + path); - for (T adjacent : graph.getAdjacent(vertex)) { - path.add(adjacent); - if (colors.get(adjacent) == GRAY) { - cycle = removePathIntoCycle(path); - return true; - } - if (colors.get(adjacent) == WHITE && visitDepthFirst(adjacent, path)) { - return true; - } - path.remove(adjacent); - } - colors.put(vertex, BLACK); - log.log(FINE, "Vertex end " + vertex + " - colors: " + colors + " - path: " + path); - return false; - } - - private List<T> removePathIntoCycle(List<T> pathWithCycle) { - T cycleStart = pathWithCycle.get(pathWithCycle.size() - 1); - return pathWithCycle.stream() - .dropWhile(vertex -> ! vertex.equals(cycleStart)) - .collect(Collectors.toList()); - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/cycle/Graph.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/cycle/Graph.java deleted file mode 100644 index 946330668bd..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/cycle/Graph.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -package com.yahoo.container.di.componentgraph.cycle; - -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -/** - * Class representing a directed graph. - * - * @author gjoranv - */ -public class Graph<T> { - - private final Map<T, LinkedHashSet<T>> adjMap = new LinkedHashMap<>(); - - public void edge(T from, T to) { - if (from == null || to == null) - throw new IllegalArgumentException("Null vertices are not allowed, edge: " + from + "->" + to); - - adjMap.computeIfAbsent(from, k -> new LinkedHashSet<>()).add(to); - adjMap.computeIfAbsent(to, k -> new LinkedHashSet<>()); - } - - Set<T> getVertices() { - return adjMap.keySet(); - } - - /** - * Returns the outgoing edges of the given vertex. - */ - Set<T> getAdjacent(T vertex) { - return adjMap.get(vertex); - } - - private void throwIfMissingVertex(T vertex) { - if (! adjMap.containsKey(vertex)) throw new IllegalArgumentException("No such vertex in the graph: " + vertex); - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/package-info.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/package-info.java deleted file mode 100644 index 0c11cfb5ba4..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -@PublicApi -package com.yahoo.container.di.componentgraph; - -import com.yahoo.api.annotations.PublicApi; -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-di/src/main/java/com/yahoo/container/di/config/ResolveDependencyException.java b/container-di/src/main/java/com/yahoo/container/di/config/ResolveDependencyException.java deleted file mode 100644 index c88f851909c..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/config/ResolveDependencyException.java +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.config; - -/** - * @author gjoranv - */ -public class ResolveDependencyException extends RuntimeException { - - public ResolveDependencyException(String message) { - super(message); - } - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/config/RestApiContext.java b/container-di/src/main/java/com/yahoo/container/di/config/RestApiContext.java deleted file mode 100644 index bfb9a8f9160..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/config/RestApiContext.java +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.config; - -import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; -import com.google.inject.Key; -import com.yahoo.component.ComponentId; -import org.osgi.framework.Version; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * Only for internal JDisc use. - * - * @author gjoranv - */ -public class RestApiContext { - - private final List<BundleInfo> bundles = new ArrayList<>(); - private final List<Injectable> injectableComponents = new ArrayList<>(); - - public final JerseyBundlesConfig bundlesConfig; - public final JerseyInjectionConfig injectionConfig; - - @Inject - public RestApiContext(JerseyBundlesConfig bundlesConfig, JerseyInjectionConfig injectionConfig) { - this.bundlesConfig = bundlesConfig; - this.injectionConfig = injectionConfig; - } - - public List<BundleInfo> getBundles() { - return Collections.unmodifiableList(bundles); - } - - public void addBundle(BundleInfo bundle) { - bundles.add(bundle); - } - - public List<Injectable> getInjectableComponents() { - return Collections.unmodifiableList(injectableComponents); - } - - public void addInjectableComponent(Key<?> key, ComponentId id, Object component) { - injectableComponents.add(new Injectable(key, id, component)); - } - - public static class Injectable { - public final Key<?> key; - public final ComponentId id; - public final Object instance; - - public Injectable(Key<?> key, ComponentId id, Object instance) { - this.key = key; - this.id = id; - this.instance = instance; - } - @Override - public String toString() { - return id.toString(); - } - } - - public static class BundleInfo { - public final String symbolicName; - public final Version version; - public final String fileLocation; - public final URL webInfUrl; - public final ClassLoader classLoader; - - private Set<String> classEntries; - - public BundleInfo(String symbolicName, Version version, String fileLocation, URL webInfUrl, ClassLoader classLoader) { - this.symbolicName = symbolicName; - this.version = version; - this.fileLocation = fileLocation; - this.webInfUrl = webInfUrl; - this.classLoader = classLoader; - } - - @Override - public String toString() { - return symbolicName + ":" + version; - } - - public void setClassEntries(Collection<String> entries) { - this.classEntries = ImmutableSet.copyOf(entries); - } - - public Set<String> getClassEntries() { - return classEntries; - } - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java b/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java deleted file mode 100644 index 60207447bfd..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.config; - -import com.yahoo.config.ConfigInstance; -import com.yahoo.vespa.config.ConfigKey; - -import java.util.Map; - -/** - * @author Tony Vaagenes - * @author gjoranv - */ -public interface Subscriber { - - long waitNextGeneration(boolean isInitializing); - long generation(); - - boolean configChanged(); - Map<ConfigKey<ConfigInstance>, ConfigInstance> config(); - - void close(); - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/config/SubscriberFactory.java b/container-di/src/main/java/com/yahoo/container/di/config/SubscriberFactory.java deleted file mode 100644 index c1c36a1b3de..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/config/SubscriberFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.config; - -import com.google.inject.ProvidedBy; -import com.yahoo.container.di.CloudSubscriberFactory; -import com.yahoo.vespa.config.ConfigKey; - -import java.util.Set; - -/** - * @author Tony Vaagenes - * @author gjoranv - */ -@ProvidedBy(CloudSubscriberFactory.Provider.class) -public interface SubscriberFactory { - - Subscriber getSubscriber(Set<? extends ConfigKey<?>> configKeys); - void reloadActiveSubscribers(long generation); - -} diff --git a/container-di/src/main/java/com/yahoo/container/di/config/package-info.java b/container-di/src/main/java/com/yahoo/container/di/config/package-info.java deleted file mode 100644 index b8f65b1c3c8..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/config/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -package com.yahoo.container.di.config; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-di/src/main/java/com/yahoo/container/di/osgi/BundleClasses.java b/container-di/src/main/java/com/yahoo/container/di/osgi/BundleClasses.java deleted file mode 100644 index bca3ed73d0b..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/osgi/BundleClasses.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.osgi; - -import org.osgi.framework.Bundle; - -import java.util.Collection; - -/** - * @author ollivir - */ -public class BundleClasses { - private final Bundle bundle; - private final Collection<String> classEntries; - - public BundleClasses(Bundle bundle, Collection<String> classEntries) { - this.bundle = bundle; - this.classEntries = classEntries; - } - - public Bundle bundle() { - return bundle; - } - - public Collection<String> classEntries() { - return classEntries; - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/osgi/OsgiUtil.java b/container-di/src/main/java/com/yahoo/container/di/osgi/OsgiUtil.java deleted file mode 100644 index e1854155e5b..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/osgi/OsgiUtil.java +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.di.osgi; - -import com.yahoo.component.ComponentSpecification; -import com.yahoo.osgi.maven.ProjectBundleClassPaths; -import com.yahoo.osgi.maven.ProjectBundleClassPaths.BundleClasspathMapping; -import org.osgi.framework.Bundle; -import org.osgi.framework.wiring.BundleWiring; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.google.common.io.Files.fileTreeTraverser; - -/** - * Tested by com.yahoo.application.container.jersey.JerseyTest - * - * @author Tony Vaagenes - * @author ollivir - */ -public class OsgiUtil { - private static final Logger log = Logger.getLogger(OsgiUtil.class.getName()); - private static final String CLASS_FILE_TYPE_SUFFIX = ".class"; - - public static Collection<String> getClassEntriesInBundleClassPath(Bundle bundle, Set<String> packagesToScan) { - BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); - - if (packagesToScan.isEmpty()) { - return bundleWiring.listResources("/", "*" + CLASS_FILE_TYPE_SUFFIX, - BundleWiring.LISTRESOURCES_LOCAL | BundleWiring.LISTRESOURCES_RECURSE); - } else { - List<String> ret = new ArrayList<>(); - for (String pkg : packagesToScan) { - ret.addAll(bundleWiring.listResources(packageToPath(pkg), "*" + CLASS_FILE_TYPE_SUFFIX, BundleWiring.LISTRESOURCES_LOCAL)); - } - return ret; - } - } - - public static Collection<String> getClassEntriesForBundleUsingProjectClassPathMappings(ClassLoader classLoader, - ComponentSpecification bundleSpec, Set<String> packagesToScan) { - return classEntriesFrom(bundleClassPathMapping(bundleSpec, classLoader).classPathElements, packagesToScan); - } - - private static BundleClasspathMapping bundleClassPathMapping(ComponentSpecification bundleSpec, ClassLoader classLoader) { - ProjectBundleClassPaths projectBundleClassPaths = loadProjectBundleClassPaths(classLoader); - - if (projectBundleClassPaths.mainBundle.bundleSymbolicName.equals(bundleSpec.getName())) { - return projectBundleClassPaths.mainBundle; - } else { - log.log(Level.WARNING, - "Dependencies of the bundle " + bundleSpec + " will not be scanned. Please file a feature request if you need this"); - return matchingBundleClassPathMapping(bundleSpec, projectBundleClassPaths.providedDependencies); - } - } - - public static BundleClasspathMapping matchingBundleClassPathMapping(ComponentSpecification bundleSpec, - Collection<BundleClasspathMapping> providedBundlesClassPathMappings) { - for (BundleClasspathMapping mapping : providedBundlesClassPathMappings) { - if (mapping.bundleSymbolicName.equals(bundleSpec.getName())) { - return mapping; - } - } - throw new RuntimeException("No such bundle: " + bundleSpec); - } - - private static ProjectBundleClassPaths loadProjectBundleClassPaths(ClassLoader classLoader) { - URL classPathMappingsFileLocation = classLoader.getResource(ProjectBundleClassPaths.CLASSPATH_MAPPINGS_FILENAME); - if (classPathMappingsFileLocation == null) { - throw new RuntimeException("Couldn't find " + ProjectBundleClassPaths.CLASSPATH_MAPPINGS_FILENAME + " in the class path."); - } - - try { - return ProjectBundleClassPaths.load(Paths.get(classPathMappingsFileLocation.toURI())); - } catch (IOException | URISyntaxException e) { - throw new RuntimeException(e); - } - } - - private static Collection<String> classEntriesFrom(List<String> classPathEntries, Set<String> packagesToScan) { - Set<String> packagePathsToScan = packagesToScan.stream().map(OsgiUtil::packageToPath).collect(Collectors.toSet()); - List<String> ret = new ArrayList<>(); - - for (String entry : classPathEntries) { - Path path = Paths.get(entry); - if (Files.isDirectory(path)) { - ret.addAll(classEntriesInPath(path, packagePathsToScan)); - } else if (Files.isRegularFile(path) && path.getFileName().toString().endsWith(".jar")) { - ret.addAll(classEntriesInJar(path, packagePathsToScan)); - } else { - throw new RuntimeException("Unsupported path " + path + " in the class path"); - } - } - return ret; - } - - private static String relativePathToClass(Path rootPath, Path pathToClass) { - Path relativePath = rootPath.relativize(pathToClass); - return relativePath.toString(); - } - - private static Collection<String> classEntriesInPath(Path rootPath, Collection<String> packagePathsToScan) { - Iterable<File> fileIterator; - if (packagePathsToScan.isEmpty()) { - fileIterator = fileTreeTraverser().preOrderTraversal(rootPath.toFile()); - } else { - List<File> files = new ArrayList<>(); - for (String packagePath : packagePathsToScan) { - for (File file : fileTreeTraverser().children(rootPath.resolve(packagePath).toFile())) { - files.add(file); - } - } - fileIterator = files; - } - - List<String> ret = new ArrayList<>(); - for (File file : fileIterator) { - if (file.isFile() && file.getName().endsWith(CLASS_FILE_TYPE_SUFFIX)) { - ret.add(relativePathToClass(rootPath, file.toPath())); - } - } - return ret; - } - - private static String packagePath(String name) { - int index = name.lastIndexOf('/'); - if (index < 0) { - return name; - } else { - return name.substring(0, index); - } - } - - private static Collection<String> classEntriesInJar(Path jarPath, Set<String> packagePathsToScan) { - Predicate<String> acceptedPackage; - if (packagePathsToScan.isEmpty()) { - acceptedPackage = ign -> true; - } else { - acceptedPackage = name -> packagePathsToScan.contains(packagePath(name)); - } - - try (JarFile jarFile = new JarFile(jarPath.toFile())) { - return jarFile.stream().map(JarEntry::getName).filter(name -> name.endsWith(CLASS_FILE_TYPE_SUFFIX)).filter(acceptedPackage) - .collect(Collectors.toList()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static String packageToPath(String packageName) { - return packageName.replace('.', '/'); - } -} diff --git a/container-di/src/main/java/com/yahoo/container/di/osgi/package-info.java b/container-di/src/main/java/com/yahoo/container/di/osgi/package-info.java deleted file mode 100644 index 9685cf571bd..00000000000 --- a/container-di/src/main/java/com/yahoo/container/di/osgi/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @author Tony Vaagenes - */ -@ExportPackage -package com.yahoo.container.di.osgi; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-di/src/main/java/com/yahoo/osgi/provider/model/ComponentModel.java b/container-di/src/main/java/com/yahoo/osgi/provider/model/ComponentModel.java deleted file mode 100644 index 8c501963db3..00000000000 --- a/container-di/src/main/java/com/yahoo/osgi/provider/model/ComponentModel.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.osgi.provider.model; - -import com.yahoo.component.ComponentId; -import com.yahoo.component.ComponentSpecification; -import com.yahoo.container.bundle.BundleInstantiationSpecification; - -/** - * Describes how a component should be created. - * - * Immutable - * - * @author gjoranv - */ -public class ComponentModel { - - public final BundleInstantiationSpecification bundleInstantiationSpec; - public final String configId; // only used in the container, null when used in the model - - public ComponentModel(BundleInstantiationSpecification bundleInstantiationSpec, String configId) { - if (bundleInstantiationSpec == null) - throw new IllegalArgumentException("Null bundle instantiation spec!"); - - this.bundleInstantiationSpec = bundleInstantiationSpec; - this.configId = configId; - } - - public ComponentModel(String idSpec, String classSpec, String bundleSpec, String configId) { - this(BundleInstantiationSpecification.getFromStrings(idSpec, classSpec, bundleSpec), configId); - } - - // For vespamodel - public ComponentModel(BundleInstantiationSpecification bundleInstantiationSpec) { - this(bundleInstantiationSpec, null); - } - - // For vespamodel - public ComponentModel(String idSpec, String classSpec, String bundleSpec) { - this(BundleInstantiationSpecification.getFromStrings(idSpec, classSpec, bundleSpec)); - } - - public ComponentId getComponentId() { - return bundleInstantiationSpec.id; - } - - public ComponentSpecification getClassId() { - return bundleInstantiationSpec.classId; - } - -} diff --git a/container-di/src/main/java/com/yahoo/osgi/provider/model/package-info.java b/container-di/src/main/java/com/yahoo/osgi/provider/model/package-info.java deleted file mode 100644 index f930f56ae4a..00000000000 --- a/container-di/src/main/java/com/yahoo/osgi/provider/model/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -@ExportPackage -package com.yahoo.osgi.provider.model; - -import com.yahoo.osgi.annotation.ExportPackage; |