summaryrefslogtreecommitdiffstats
path: root/standalone-container/src/main
diff options
context:
space:
mode:
authorOlli Virtanen <olli.virtanen@oath.com>2018-05-31 10:58:25 +0200
committerOlli Virtanen <olli.virtanen@oath.com>2018-05-31 10:58:25 +0200
commit3eefb81679eb3b3da6b782583b060166b39befd7 (patch)
tree77ec82f306f8d5bf6289e460b2adf621e0ad2f16 /standalone-container/src/main
parent41fafa8edf8c7dda56b30050d5233b17f03babe1 (diff)
Scala code in standalone-container converted to Java
Diffstat (limited to 'standalone-container/src/main')
-rw-r--r--standalone-container/src/main/java/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.java569
-rw-r--r--standalone-container/src/main/java/com/yahoo/application/container/impl/StandaloneContainerRunner.java34
-rw-r--r--standalone-container/src/main/java/com/yahoo/container/standalone/LocalFileDb.java97
-rw-r--r--standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneContainerApplication.java304
-rw-r--r--standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java127
-rw-r--r--standalone-container/src/main/scala/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.scala206
-rw-r--r--standalone-container/src/main/scala/com/yahoo/application/container/impl/StandaloneContainerRunner.scala27
-rw-r--r--standalone-container/src/main/scala/com/yahoo/container/standalone/Converter.scala26
-rw-r--r--standalone-container/src/main/scala/com/yahoo/container/standalone/Environment.scala23
-rw-r--r--standalone-container/src/main/scala/com/yahoo/container/standalone/LocalFileDb.scala75
-rw-r--r--standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneContainerApplication.scala231
-rw-r--r--standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneSubscriberFactory.scala78
12 files changed, 1131 insertions, 666 deletions
diff --git a/standalone-container/src/main/java/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.java b/standalone-container/src/main/java/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.java
new file mode 100644
index 00000000000..8d4126a01e3
--- /dev/null
+++ b/standalone-container/src/main/java/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.java
@@ -0,0 +1,569 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.application.container.impl;
+
+import com.google.common.collect.Lists;
+import com.yahoo.container.standalone.StandaloneContainerApplication;
+import com.yahoo.jdisc.application.OsgiFramework;
+import com.yahoo.jdisc.application.OsgiHeader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+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.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+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;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+
+/**
+ * A (mock) OSGI implementation which loads classes from the system classpath
+ *
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public final class ClassLoaderOsgiFramework implements OsgiFramework {
+ private BundleContextImpl bundleContextImpl = new BundleContextImpl();
+ private SystemBundleImpl systemBundleImpl = new SystemBundleImpl();
+ private BundleWiringImpl bundleWiringImpl = new BundleWiringImpl();
+
+ private List<URL> bundleLocations = new ArrayList<>();
+ private List<Bundle> bundleList = Lists.newArrayList(systemBundleImpl);
+ private ClassLoader classLoader = null;
+
+ private AtomicInteger nextBundleId = new AtomicInteger(1);
+
+ @Override
+ public List<Bundle> installBundle(String bundleLocation) {
+ if (bundleLocation != null && bundleLocation.isEmpty() == false) {
+ try {
+ URL url = new URL(bundleLocation);
+ bundleLocations.add(url);
+ bundleList.add(new JarBundleImpl(url));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ return bundles();
+ }
+
+ private ClassLoader getClassLoader() {
+ if (bundleLocations.isEmpty()) {
+ return getClass().getClassLoader();
+ } else {
+ if (classLoader == null) {
+ classLoader = new URLClassLoader(bundleLocations.toArray(new URL[0]), getClass().getClassLoader());
+ }
+ return classLoader;
+ }
+ }
+
+ @Override
+ public void startBundles(List<Bundle> bundles, boolean privileged) {
+ }
+
+ @Override
+ public void refreshPackages() {
+ }
+
+ @Override
+ public BundleContext bundleContext() {
+ return bundleContextImpl;
+ }
+
+ @Override
+ public List<Bundle> bundles() {
+ return bundleList;
+ }
+
+ @Override
+ public void start() {
+ }
+
+ @Override
+ public void stop() {
+ }
+
+ private abstract class BundleImpl implements Bundle {
+ @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 ClassLoaderOsgiFramework.this.getClass().getName();
+ }
+
+ @Override
+ public String getLocation() {
+ return getSymbolicName();
+ }
+
+ @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) {
+ return getClassLoader().getResource(name);
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return getClassLoader().loadClass(name);
+ }
+
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ return getClassLoader().getResources(name);
+ }
+
+ @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) {
+ throw new UnsupportedOperationException();
+ }
+
+ @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();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T adapt(Class<T> clazz) {
+ if (clazz.equals(BundleRevision.class)) {
+ return (T) new BundleRevisionImpl();
+ } else if (clazz.equals(BundleWiring.class)) {
+ return (T) new BundleWiringImpl();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public File getDataFile(String filename) {
+ return null;
+ }
+
+ @Override
+ public int compareTo(Bundle o) {
+ return Long.compare(getBundleId(), o.getBundleId());
+ }
+ }
+
+ private class BundleRevisionImpl implements BundleRevision {
+ @Override
+ public String getSymbolicName() {
+ return this.getClass().getName();
+ }
+
+ @Override
+ public List<BundleRequirement> getDeclaredRequirements(String p1) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Version getVersion() {
+ return Version.emptyVersion;
+ }
+
+ @Override
+ public BundleWiring getWiring() {
+ return bundleWiringImpl;
+ }
+
+ @Override
+ public List<BundleCapability> getDeclaredCapabilities(String p1) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getTypes() {
+ return 0;
+ }
+
+ @Override
+ public Bundle getBundle() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Capability> getCapabilities(String p1) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Requirement> getRequirements(String p1) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private class BundleWiringImpl implements BundleWiring {
+ @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) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return ClassLoaderOsgiFramework.this.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();
+ }
+ }
+
+ private class SystemBundleImpl extends BundleImpl {
+ @Override
+ public long getBundleId() {
+ return 0L;
+ }
+
+ @Override
+ public Version getVersion() {
+ return Version.emptyVersion;
+ }
+
+ @Override
+ public Dictionary<String, String> getHeaders() {
+ Hashtable<String, String> ret = new Hashtable<>();
+ ret.put(OsgiHeader.APPLICATION, StandaloneContainerApplication.class.getName());
+ return ret;
+ }
+ }
+
+ private class JarBundleImpl extends BundleImpl {
+ private final long bundleId;
+ private final Dictionary<String, String> headers;
+
+ JarBundleImpl(URL location) throws IOException {
+ this.bundleId = (long) nextBundleId.getAndIncrement();
+ this.headers = retrieveHeaders(location);
+ }
+
+ @Override
+ public long getBundleId() {
+ return bundleId;
+ }
+
+ @Override
+ public Dictionary<String, String> getHeaders() {
+ return headers;
+ }
+
+ @Override
+ public String getSymbolicName() {
+ return headers.get("Bundle-SymbolicName");
+ }
+
+ @Override
+ public Version getVersion() {
+ return Version.parseVersion(headers.get("Bundle-Version"));
+ }
+
+ private Dictionary<String, String> retrieveHeaders(URL location) throws IOException {
+ try (JarFile jarFile = new JarFile(location.getFile())) {
+ Attributes attributes = jarFile.getManifest().getMainAttributes();
+ Hashtable<String, String> ret = new Hashtable<>();
+ attributes.forEach((k, v) -> ret.put(k.toString(), v.toString()));
+ return ret;
+ }
+ }
+ }
+
+ private class BundleContextImpl implements BundleContext {
+ @Override
+ public String getProperty(String key) {
+ return null;
+ }
+
+ @Override
+ public Bundle getBundle() {
+ return systemBundleImpl;
+ }
+
+ @Override
+ public Bundle installBundle(String location, InputStream input) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle installBundle(String location) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle getBundle(long id) {
+ return systemBundleImpl;
+ }
+
+ @Override
+ public Bundle[] getBundles() {
+ return new Bundle[] { systemBundleImpl };
+ }
+
+ @Override
+ public Bundle getBundle(String location) {
+ return systemBundleImpl;
+ }
+
+ @Override
+ public void addServiceListener(ServiceListener listener, String filter) {
+ }
+
+ @Override
+ public void addServiceListener(ServiceListener listener) {
+ }
+
+ @Override
+ public void removeServiceListener(ServiceListener listener) {
+ }
+
+ @Override
+ public void addBundleListener(BundleListener listener) {
+ }
+
+ @Override
+ public void removeBundleListener(BundleListener listener) {
+ }
+
+ @Override
+ public void addFrameworkListener(FrameworkListener listener) {
+ }
+
+ @Override
+ public void removeFrameworkListener(FrameworkListener listener) {
+ }
+
+ @Override
+ public ServiceRegistration<?> registerService(String[] classes, Object service, Dictionary<String, ?> properties) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServiceRegistration<?> registerService(String clazz, Object service, Dictionary<String, ?> properties) {
+ return null;
+ }
+
+ @Override
+ public <S> ServiceRegistration<S> registerService(Class<S> clazz, S service, Dictionary<String, ?> properties) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServiceReference<?>[] getServiceReferences(String clazz, String filter) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServiceReference<?>[] getAllServiceReferences(String clazz, String filter) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServiceReference<?> getServiceReference(String clazz) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <S> ServiceReference<S> getServiceReference(Class<S> clazz) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public <S> S getService(ServiceReference<S> reference) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean ungetService(ServiceReference<?> reference) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getDataFile(String filename) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Filter createFilter(String filter) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <S> ServiceRegistration<S> registerService(Class<S> aClass, ServiceFactory<S> serviceFactory,
+ Dictionary<String, ?> dictionary) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <S> ServiceObjects<S> getServiceObjects(ServiceReference<S> serviceReference) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/standalone-container/src/main/java/com/yahoo/application/container/impl/StandaloneContainerRunner.java b/standalone-container/src/main/java/com/yahoo/application/container/impl/StandaloneContainerRunner.java
new file mode 100644
index 00000000000..a0fee3265df
--- /dev/null
+++ b/standalone-container/src/main/java/com/yahoo/application/container/impl/StandaloneContainerRunner.java
@@ -0,0 +1,34 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.application.container.impl;
+
+import com.yahoo.text.Utf8;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class StandaloneContainerRunner {
+ public static Path createApplicationPackage(String servicesXml) {
+ try {
+ return createApplicationDirectory(servicesXml);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static Path createApplicationDirectory(String servicesXml) throws IOException {
+ Path applicationDir = Files.createTempDirectory("application");
+ Path servicesXmlFile = applicationDir.resolve("services.xml");
+ String content = servicesXml;
+
+ if (!servicesXml.startsWith("<?xml")) {
+ content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + servicesXml;
+ }
+ Files.write(servicesXmlFile, Utf8.toBytes(content));
+ return applicationDir;
+ }
+}
diff --git a/standalone-container/src/main/java/com/yahoo/container/standalone/LocalFileDb.java b/standalone-container/src/main/java/com/yahoo/container/standalone/LocalFileDb.java
new file mode 100644
index 00000000000..4bbe9986d90
--- /dev/null
+++ b/standalone-container/src/main/java/com/yahoo/container/standalone/LocalFileDb.java
@@ -0,0 +1,97 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.standalone;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.config.application.api.FileRegistry;
+import com.yahoo.filedistribution.fileacquirer.FileAcquirer;
+import com.yahoo.net.HostName;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * FileAcquirer and FileRegistry working on a local directory.
+ *
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class LocalFileDb implements FileAcquirer, FileRegistry {
+ private static final Constructor<FileReference> fileReferenceConstructor = createFileReferenceConstructor();
+
+ private final Map<FileReference, File> fileReferenceToFile = new HashMap<>();
+ private final Path appPath;
+
+ public LocalFileDb(Path appPath) {
+ this.appPath = appPath;
+ }
+
+ /* FileAcquirer overrides */
+ @Override
+ public File waitFor(FileReference reference, long l, TimeUnit timeUnit) {
+ synchronized (this) {
+ File file = fileReferenceToFile.get(reference);
+ if (file == null) {
+ throw new RuntimeException("Invalid file reference " + reference);
+ }
+ return file;
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ }
+
+ /* FileRegistry overrides */
+ public FileReference addFile(String relativePath) {
+ File file = appPath.resolve(relativePath).toFile();
+ if (!file.exists()) {
+ throw new RuntimeException("The file does not exist: " + file.getPath());
+ }
+
+ FileReference fileReference = null;
+ try {
+ fileReference = fileReferenceConstructor.newInstance("LocalFileDb:" + relativePath);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException("Unable to create new FileReference", e);
+ }
+ fileReferenceToFile.put(fileReference, file);
+ return fileReference;
+ }
+
+ @Override
+ public List<Entry> export() {
+ return fileReferenceToFile.entrySet().stream().map(entry -> new Entry(entry.getValue().getPath(), entry.getKey()))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public FileReference addUri(String uri) {
+ throw new RuntimeException("addUri(String uri) is not implemented here.");
+ }
+
+ public String fileSourceHost() {
+ return HostName.getLocalhost();
+ }
+
+ public Set<String> allRelativePaths() {
+ return fileReferenceToFile.values().stream().map(File::getPath).collect(Collectors.toSet());
+ }
+
+ private static Constructor<FileReference> createFileReferenceConstructor() {
+ try {
+ Constructor<FileReference> method = FileReference.class.getDeclaredConstructor(String.class);
+ method.setAccessible(true);
+ return method;
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+}
diff --git a/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneContainerApplication.java b/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneContainerApplication.java
new file mode 100644
index 00000000000..72937301954
--- /dev/null
+++ b/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneContainerApplication.java
@@ -0,0 +1,304 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.standalone;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.ConfigurationException;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.ProvisionException;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+import com.yahoo.collections.Pair;
+import com.yahoo.config.application.api.ApplicationPackage;
+import com.yahoo.config.application.api.DeployLogger;
+import com.yahoo.config.application.api.FileRegistry;
+import com.yahoo.config.model.ApplicationConfigProducerRoot;
+import com.yahoo.config.model.ConfigModelRepo;
+import com.yahoo.config.model.application.provider.BaseDeployLogger;
+import com.yahoo.config.model.application.provider.FilesApplicationPackage;
+import com.yahoo.config.model.application.provider.StaticConfigDefinitionRepo;
+import com.yahoo.config.model.builder.xml.ConfigModelId;
+import com.yahoo.config.model.builder.xml.XmlHelper;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.container.di.config.SubscriberFactory;
+import com.yahoo.container.jdisc.ConfiguredApplication;
+import com.yahoo.io.IOUtils;
+import com.yahoo.jdisc.application.Application;
+import com.yahoo.text.XML;
+import com.yahoo.vespa.defaults.Defaults;
+import com.yahoo.vespa.model.HostResource;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder;
+import com.yahoo.vespa.model.container.Container;
+import com.yahoo.vespa.model.container.ContainerModel;
+import com.yahoo.vespa.model.container.xml.ConfigServerContainerModelBuilder;
+import com.yahoo.vespa.model.container.xml.ContainerModelBuilder;
+import com.yahoo.vespa.model.container.xml.ContainerModelBuilder.Networking;
+import org.w3c.dom.Element;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.yahoo.collections.CollectionUtil.first;
+
+/**
+ * @author Tony Vaagenes
+ * @author gjoranv
+ * @author ollivir
+ */
+public class StandaloneContainerApplication implements Application {
+ public static final String PACKAGE_NAME = "standalone_jdisc_container";
+ public static final String APPLICATION_LOCATION_INSTALL_VARIABLE = PACKAGE_NAME + ".app_location";
+ public static final String DEPLOYMENT_PROFILE_INSTALL_VARIABLE = PACKAGE_NAME + ".deployment_profile";
+ public static final String DISABLE_NETWORKING_ANNOTATION = "JDisc.disableNetworking";
+ public static final Named APPLICATION_PATH_NAME = Names.named(APPLICATION_LOCATION_INSTALL_VARIABLE);
+ public static final Named CONFIG_MODEL_REPO_NAME = Names.named("ConfigModelRepo");
+
+ private static final String DEFAULT_TMP_BASE_DIR = Defaults.getDefaults().underVespaHome("tmp");
+ private static final String TMP_DIR_NAME = "standalone_container";
+
+ private static final StaticConfigDefinitionRepo configDefinitionRepo = new StaticConfigDefinitionRepo();
+
+ private final Injector injector;
+ private final Path applicationPath;
+ private final LocalFileDb distributedFiles;
+ private final ConfigModelRepo configModelRepo;
+ private final Networking networkingOption;
+ private final VespaModel modelRoot;
+ private final Application configuredApplication;
+ private final Container container;
+
+ @Inject
+ public StandaloneContainerApplication(Injector injector) {
+ this.injector = injector;
+ ConfiguredApplication.ensureVespaLoggingInitialized();
+ this.applicationPath = injectedApplicationPath().orElseGet(this::installApplicationPath);
+ this.distributedFiles = new LocalFileDb(applicationPath);
+ this.configModelRepo = resolveConfigModelRepo();
+ this.networkingOption = resolveNetworkingOption();
+
+ try {
+ Pair<VespaModel, Container> tpl = withTempDir(preprocessedApplicationDir -> createContainerModel(applicationPath,
+ distributedFiles, preprocessedApplicationDir, networkingOption, configModelRepo));
+ this.modelRoot = tpl.getFirst();
+ this.container = tpl.getSecond();
+ } catch (RuntimeException r) {
+ throw r;
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to create ContainerModel", e);
+ }
+ this.configuredApplication = createConfiguredApplication(container);
+ }
+
+ private ConfigModelRepo resolveConfigModelRepo() {
+ try {
+ return injector.getInstance(Key.get(ConfigModelRepo.class, CONFIG_MODEL_REPO_NAME));
+ } catch (Exception e) {
+ return new ConfigModelRepo();
+ }
+ }
+
+ private Networking resolveNetworkingOption() {
+ try {
+ Boolean networkingDisable = injector.getInstance(Key.get(Boolean.class, Names.named(DISABLE_NETWORKING_ANNOTATION)));
+ if (networkingDisable != null) {
+ return networkingDisable ? Networking.disable : Networking.enable;
+ }
+ } catch (Exception ignored) {
+ }
+ return Networking.enable;
+ }
+
+ private Application createConfiguredApplication(Container container) {
+ Injector augmentedInjector = injector.createChildInjector(new AbstractModule() {
+ @Override
+ public void configure() {
+ bind(SubscriberFactory.class).toInstance(new StandaloneSubscriberFactory(modelRoot));
+ }
+ });
+
+ System.setProperty("config.id", container.getConfigId());
+ return augmentedInjector.getInstance(ConfiguredApplication.class);
+ }
+
+ private Optional<Path> injectedApplicationPath() {
+ try {
+ return Optional.ofNullable(injector.getInstance(Key.get(Path.class, APPLICATION_PATH_NAME)));
+ } catch (ConfigurationException | ProvisionException ignored) {
+ }
+ return Optional.empty();
+ }
+
+ private Path installApplicationPath() {
+ Optional<String> variable = optionalInstallVariable(APPLICATION_LOCATION_INSTALL_VARIABLE);
+
+ return variable.map(Paths::get)
+ .orElseThrow(() -> new IllegalStateException("Environment variable not set: " + APPLICATION_LOCATION_INSTALL_VARIABLE));
+ }
+
+ @Override
+ public void start() {
+ try {
+ com.yahoo.container.Container.get().setCustomFileAcquirer(distributedFiles);
+ configuredApplication.start();
+ } catch (Exception e) {
+ com.yahoo.container.Container.resetInstance();
+ throw e;
+ }
+ }
+
+ @Override
+ public void stop() {
+ configuredApplication.stop();
+ }
+
+ @Override
+ public void destroy() {
+ com.yahoo.container.Container.resetInstance();
+ configuredApplication.destroy();
+ }
+
+ public Container container() {
+ return container;
+ }
+
+ private interface ThrowingFunction<T, U> {
+ U apply(T input) throws Exception;
+ }
+
+ private static <T> T withTempDir(ThrowingFunction<File, T> f) throws Exception {
+ File tmpDir = createTempDir();
+ try {
+ return f.apply(tmpDir);
+ } finally {
+ IOUtils.recursiveDeleteDir(tmpDir);
+ }
+ }
+
+ private static File createTempDir() {
+ Path basePath;
+ if (new File(DEFAULT_TMP_BASE_DIR).exists()) {
+ basePath = Paths.get(DEFAULT_TMP_BASE_DIR);
+ } else {
+ basePath = Paths.get(System.getProperty("java.io.tmpdir"));
+ }
+
+ try {
+ Path tmpDir = Files.createTempDirectory(basePath, TMP_DIR_NAME);
+ return tmpDir.toFile();
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot create temp directory", e);
+ }
+ }
+
+ private static void validateApplication(ApplicationPackage applicationPackage) {
+ try {
+ applicationPackage.validateXML();
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private static ContainerModelBuilder newContainerModelBuilder(Networking networkingOption) {
+ Optional<String> profile = optionalInstallVariable(DEPLOYMENT_PROFILE_INSTALL_VARIABLE);
+ if (profile.isPresent()) {
+ String profileName = profile.get();
+ if ("configserver".equals(profileName)) {
+ return new ConfigServerContainerModelBuilder(new CloudConfigInstallVariables());
+ } else {
+ throw new RuntimeException("Invalid deployment profile '" + profileName + "'");
+ }
+ } else {
+ return new ContainerModelBuilder(true, networkingOption);
+ }
+ }
+
+ static Pair<VespaModel, Container> createContainerModel(Path applicationPath, FileRegistry fileRegistry,
+ File preprocessedApplicationDir, Networking networkingOption, ConfigModelRepo configModelRepo) throws Exception {
+ DeployLogger logger = new BaseDeployLogger();
+ FilesApplicationPackage rawApplicationPackage = new FilesApplicationPackage.Builder(applicationPath.toFile())
+ .includeSourceFiles(true).preprocessedDir(preprocessedApplicationDir).build();
+ ApplicationPackage applicationPackage = rawApplicationPackage.preprocess(Zone.defaultZone(), logger);
+ validateApplication(applicationPackage);
+ DeployState deployState = new DeployState.Builder().applicationPackage(applicationPackage).fileRegistry(fileRegistry)
+ .deployLogger(logger).configDefinitionRepo(configDefinitionRepo).build(true);
+
+ VespaModel root = VespaModel.createIncomplete(deployState);
+ ApplicationConfigProducerRoot vespaRoot = new ApplicationConfigProducerRoot(root, "vespa", deployState.getDocumentModel(),
+ deployState.getProperties().vespaVersion(), deployState.getProperties().applicationId());
+
+ Element spec = containerRootElement(applicationPackage);
+ ContainerModel containerModel = newContainerModelBuilder(networkingOption).build(deployState, configModelRepo, vespaRoot, spec);
+ containerModel.getCluster().prepare();
+ initializeContainerModel(containerModel, configModelRepo);
+ Container container = first(containerModel.getCluster().getContainers());
+
+ // TODO: Separate out model finalization from the VespaModel constructor,
+ // such that the above and below code to finalize the container can be
+ // replaced by root.finalize();
+
+ initializeContainer(container, spec);
+
+ root.freezeModelTopology();
+ return new Pair<>(root, container);
+ }
+
+ private static void initializeContainer(Container container, Element spec) {
+ HostResource host = container.getRoot().getHostSystem().getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC);
+
+ container.setBasePort(VespaDomBuilder.getXmlWantedPort(spec));
+ container.setHostResource(host);
+ container.initService();
+ }
+
+ private static Element getJDiscInServices(Element element) {
+ List<Element> jDiscElements = new ArrayList<>();
+ for (ConfigModelId cid : ContainerModelBuilder.configModelIds) {
+ List<Element> children = XML.getChildren(element, cid.getName());
+ jDiscElements.addAll(children);
+ }
+
+ if (jDiscElements.size() == 1) {
+ return jDiscElements.get(0);
+ } else if (jDiscElements.isEmpty()) {
+ throw new RuntimeException("No jdisc element found under services.");
+ } else {
+ List<String> nameAndId = jDiscElements.stream().map(e -> e.getNodeName() + " id='" + e.getAttribute("id") + "'")
+ .collect(Collectors.toList());
+ throw new RuntimeException("Found multiple JDisc elements: " + String.join(", ", nameAndId));
+ }
+ }
+
+ private static Element containerRootElement(ApplicationPackage applicationPackage) {
+ Element element = XmlHelper.getDocument(applicationPackage.getServices()).getDocumentElement();
+ String nodeName = element.getNodeName();
+
+ if (ContainerModelBuilder.configModelIds.stream().anyMatch(id -> id.getName().equals(nodeName))) {
+ return element;
+ } else {
+ return getJDiscInServices(element);
+ }
+ }
+
+ @SuppressWarnings("deprecation") // TODO: what is the not-deprecated way?
+ private static void initializeContainerModel(ContainerModel containerModel, ConfigModelRepo configModelRepo) {
+ containerModel.initialize(configModelRepo);
+ }
+
+ private static Optional<String> optionalInstallVariable(String name) {
+ Optional<String> fromEnv = Optional.ofNullable(System.getenv((name.replace(".", "__"))));
+ if (fromEnv.isPresent()) {
+ return fromEnv;
+ }
+ return Optional.ofNullable(System.getProperty(name)); // for unit testing
+ }
+}
diff --git a/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java b/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java
new file mode 100644
index 00000000000..882bb5709f4
--- /dev/null
+++ b/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java
@@ -0,0 +1,127 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.standalone;
+
+import com.yahoo.config.ConfigBuilder;
+import com.yahoo.config.ConfigInstance;
+import com.yahoo.config.subscription.ConfigInterruptedException;
+import com.yahoo.container.di.config.Subscriber;
+import com.yahoo.container.di.config.SubscriberFactory;
+import com.yahoo.vespa.config.ConfigKey;
+import com.yahoo.vespa.model.VespaModel;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Tony Vaagenes
+ * @author gjoranv
+ * @author ollivir
+ */
+public class StandaloneSubscriberFactory implements SubscriberFactory {
+ private final VespaModel root;
+
+ public StandaloneSubscriberFactory(VespaModel root) {
+ this.root = root;
+ }
+
+ private class StandaloneSubscriber implements Subscriber {
+ private final Set<ConfigKey<ConfigInstance>> configKeys;
+ private long generation = -1L;
+
+ StandaloneSubscriber(Set<ConfigKey<ConfigInstance>> configKeys) {
+ this.configKeys = configKeys;
+ }
+
+ @Override
+ public boolean configChanged() {
+ return generation == 0;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public Map<ConfigKey<ConfigInstance>, ConfigInstance> config() {
+ Map<ConfigKey<ConfigInstance>, ConfigInstance> ret = new HashMap<>();
+ for (ConfigKey<ConfigInstance> key : configKeys) {
+ ConfigInstance.Builder builder = root.getConfig(newBuilderInstance(key), key.getConfigId());
+ if (builder == null) {
+ throw new RuntimeException("Invalid config id " + key.getConfigId());
+ }
+ ret.put(key, newConfigInstance(builder));
+ }
+ return ret;
+ }
+
+ @Override
+ public long waitNextGeneration() {
+ generation++;
+
+ if (generation != 0) {
+ try {
+ while (!Thread.interrupted()) {
+ Thread.sleep(10000);
+ }
+ } catch (InterruptedException e) {
+ throw new ConfigInterruptedException(e);
+ }
+ }
+
+ return generation;
+ }
+
+ // if waitNextGeneration has not yet been called, -1 should be returned
+ @Override
+ public long generation() {
+ return generation;
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Subscriber getSubscriber(Set<? extends ConfigKey<?>> configKeys) {
+ return new StandaloneSubscriber((Set<ConfigKey<ConfigInstance>>) configKeys);
+ }
+
+ public void reloadActiveSubscribers(long generation) {
+ throw new RuntimeException("unsupported");
+ }
+
+ private static ConfigInstance.Builder newBuilderInstance(ConfigKey<ConfigInstance> key) {
+ try {
+ return builderClass(key).getDeclaredConstructor().newInstance();
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+ throw new RuntimeException("ConfigInstance builder cannot be instantiated", e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class<ConfigInstance.Builder> builderClass(ConfigKey<ConfigInstance> key) {
+ Class<?> configClass = key.getConfigClass();
+ if (configClass != null) {
+ Class<?>[] nestedClasses = configClass.getClasses();
+ for (Class<?> clazz : nestedClasses) {
+ if (clazz.getName().equals(key.getConfigClass().getName() + "$Builder")) {
+ return (Class<ConfigInstance.Builder>) clazz;
+ }
+ }
+ }
+ throw new RuntimeException("Builder class for " + (configClass == null ? null : configClass.getName()) + " could not be located");
+ }
+
+ private static ConfigInstance newConfigInstance(ConfigBuilder builder) {
+ try {
+ return configClass(builder).getConstructor(builder.getClass()).newInstance(builder);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+ throw new RuntimeException("ConfigInstance cannot be instantiated", e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class<ConfigInstance> configClass(ConfigBuilder builder) {
+ return (Class<ConfigInstance>) builder.getClass().getEnclosingClass();
+ }
+}
diff --git a/standalone-container/src/main/scala/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.scala b/standalone-container/src/main/scala/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.scala
deleted file mode 100644
index ac8636de2cb..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/application/container/impl/ClassLoaderOsgiFramework.scala
+++ /dev/null
@@ -1,206 +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.application.container.impl
-
-import java.io.InputStream
-import java.net.{URL, URLClassLoader}
-import java.util
-import java.util.concurrent.atomic.AtomicInteger
-import java.util.jar.JarFile
-import java.util.{Collections, Dictionary, Hashtable}
-
-import com.yahoo.container.standalone.StandaloneContainerApplication
-import com.yahoo.jdisc.application.{OsgiFramework, OsgiHeader}
-import org.osgi.framework._
-import org.osgi.framework.wiring._
-import org.osgi.resource.{Capability, Requirement, Wire}
-
-import scala.collection.JavaConverters._
-import scala.collection.mutable.ArrayBuffer
-
-/**
- * A (mock) OSGI implementation which loads classes from the system classpath
- *
- * @author tonytv
- */
-final class ClassLoaderOsgiFramework extends OsgiFramework {
- private val bundleLocations = new ArrayBuffer[URL]
- private val bundleList = ArrayBuffer[Bundle](SystemBundleImpl)
- private var classLoader: ClassLoader = null
-
- private val nextBundleId = new AtomicInteger(1)
-
- override def installBundle(bundleLocation: String) = {
- if (bundleLocation != "") {
- val url = new URL(bundleLocation)
- bundleLocations += url
- bundleList += new JarBundleImpl(url)
- }
-
- bundles()
- }
-
- def getClassLoader = {
- if (bundleLocations.isEmpty) {
- getClass.getClassLoader
- } else {
- if(classLoader == null)
- classLoader = new URLClassLoader(bundleLocations.toArray, getClass.getClassLoader)
-
- classLoader
- }
- }
-
- override def startBundles(bundles: util.List[Bundle], privileged: Boolean) {}
-
- override def refreshPackages() {}
-
- override def bundleContext():BundleContext = BundleContextImpl
-
- override def bundles() = bundleList.asJava
-
- override def start() {}
-
- override def stop() {}
-
- private abstract class BundleImpl extends Bundle {
- override def getState = Bundle.ACTIVE
-
- override def start(options: Int) {}
- override def start() {}
- override def stop(options: Int) {}
- override def stop() {}
- override def update(input: InputStream) {}
- override def update() {}
- override def uninstall() {}
-
- override def getHeaders(locale: String) = getHeaders
-
- override def getSymbolicName = ClassLoaderOsgiFramework.this.getClass.getName
- override def getLocation = getSymbolicName
-
- override def getRegisteredServices = Array[ServiceReference[_]]()
- override def getServicesInUse = getRegisteredServices
-
- override def hasPermission(permission: Any) = true
-
- override def getResource(name: String) = getClassLoader.getResource(name)
- override def loadClass(name: String) = getClassLoader.loadClass(name)
- override def getResources(name: String) = getClassLoader.getResources(name)
-
- override def getEntryPaths(path: String) = throw new UnsupportedOperationException
- override def getEntry(path: String) = throw new UnsupportedOperationException
- override def findEntries(path: String, filePattern: String, recurse: Boolean) = throw new UnsupportedOperationException
-
- override def getLastModified = 1L
-
- override def getBundleContext = throw new UnsupportedOperationException
- override def getSignerCertificates(signersType: Int) = Collections.emptyMap()
-
- override def adapt[A](`type`: Class[A]): A = {
- if (`type` == classOf[BundleRevision]) BundleRevisionImpl.asInstanceOf[A]
- else if (`type` == classOf[BundleWiring]) BundleWiringImpl.asInstanceOf[A]
- else null.asInstanceOf[A]
- }
-
- override def getDataFile(filename: String) = null
- override def compareTo(o: Bundle) = getBundleId compareTo o.getBundleId
- }
-
- private object BundleRevisionImpl extends BundleRevision {
- override def getSymbolicName: String = this.getClass.getName
- override def getDeclaredRequirements(p1: String): util.List[BundleRequirement] = throw new UnsupportedOperationException
- override def getVersion: Version = Version.emptyVersion
- override def getWiring: BundleWiring = BundleWiringImpl
- override def getDeclaredCapabilities(p1: String): util.List[BundleCapability] = throw new UnsupportedOperationException
- override def getTypes: Int = 0
- override def getBundle: Bundle = throw new UnsupportedOperationException
- override def getCapabilities(p1: String): util.List[Capability] = throw new UnsupportedOperationException
- override def getRequirements(p1: String): util.List[Requirement] = throw new UnsupportedOperationException
- }
-
- private object BundleWiringImpl extends BundleWiring {
- override def findEntries(p1: String, p2: String, p3: Int): util.List[URL] = ???
- override def getRequiredResourceWires(p1: String): util.List[Wire] = ???
- override def getResourceCapabilities(p1: String): util.List[Capability] = ???
- override def isCurrent: Boolean = ???
- override def getRequiredWires(p1: String): util.List[BundleWire] = ???
- override def getCapabilities(p1: String): util.List[BundleCapability] = ???
- override def getProvidedResourceWires(p1: String): util.List[Wire] = ???
- override def getProvidedWires(p1: String): util.List[BundleWire] = ???
- override def getRevision: BundleRevision = ???
- override def getResourceRequirements(p1: String): util.List[Requirement] = ???
- override def isInUse: Boolean = ???
- override def listResources(p1: String, p2: String, p3: Int): util.Collection[String] = ???
- override def getClassLoader: ClassLoader = ClassLoaderOsgiFramework.this.getClassLoader
- override def getRequirements(p1: String): util.List[BundleRequirement] = ???
- override def getResource: BundleRevision = ???
- override def getBundle: Bundle = ???
- }
-
- private object SystemBundleImpl extends BundleImpl {
- override val getBundleId = 0L
- override def getVersion = Version.emptyVersion
- override def getHeaders: Dictionary[String, String] = new Hashtable[String, String](Map(OsgiHeader.APPLICATION -> classOf[StandaloneContainerApplication].getName).asJava)
- }
-
-
- private class JarBundleImpl(location: URL) extends BundleImpl {
- override val getBundleId = nextBundleId.getAndIncrement.asInstanceOf[Long]
-
- private val headers = retrieveHeaders(location)
-
- override def getHeaders: Dictionary[String, String] = headers
- override val getSymbolicName = headers.get("Bundle-SymbolicName")
- override val getVersion = Version.parseVersion(headers.get("Bundle-Version"))
-
-
- private def retrieveHeaders(location: URL) = {
- val jarFile = new JarFile(location.getFile)
- try {
- val attributes = jarFile.getManifest.getMainAttributes
- new Hashtable[String, String](attributes.entrySet().asScala.map( entry => entry.getKey.toString -> entry.getValue.toString).toMap.asJava)
- } finally {
- jarFile.close()
- }
- }
- }
-
- private object BundleContextImpl extends BundleContext {
- private val bundleImpl = SystemBundleImpl
-
- override def getProperty(key: String) = null
- override def getBundle = bundleImpl
- override def installBundle(location: String, input: InputStream) = throw new UnsupportedOperationException
- override def installBundle(location: String) = throw new UnsupportedOperationException
-
- override def getBundle(id: Long) = bundleImpl
- override def getBundles = Array(bundleImpl)
- override def getBundle(location: String) = bundleImpl
-
- override def addServiceListener(listener: ServiceListener, filter: String) {}
- override def addServiceListener(listener: ServiceListener) {}
- override def removeServiceListener(listener: ServiceListener) {}
- override def addBundleListener(listener: BundleListener) {}
- override def removeBundleListener(listener: BundleListener) {}
-
- override def addFrameworkListener(listener: FrameworkListener) {}
- override def removeFrameworkListener(listener: FrameworkListener) {}
-
- override def registerService(clazzes: Array[String], service: Any, properties: Dictionary[String, _]) = throw new UnsupportedOperationException
- override def registerService(clazz: String, service: Any, properties: Dictionary[String, _]) = null
- override def registerService[S](clazz: Class[S], service: S, properties: Dictionary[String, _]) = throw new UnsupportedOperationException
- override def getServiceReferences(clazz: String, filter: String) = throw new UnsupportedOperationException
- override def getAllServiceReferences(clazz: String, filter: String) = throw new UnsupportedOperationException
- override def getServiceReference(clazz: String) = throw new UnsupportedOperationException
- override def getServiceReference[S](clazz: Class[S]) = throw new UnsupportedOperationException
- override def getServiceReferences[S](clazz: Class[S], filter: String) = Collections.emptyList()
- override def getService[S](reference: ServiceReference[S]) = throw new UnsupportedOperationException
- override def ungetService(reference: ServiceReference[_]) = throw new UnsupportedOperationException
- override def getDataFile(filename: String) = throw new UnsupportedOperationException
- override def createFilter(filter: String) = throw new UnsupportedOperationException
-
- override def registerService[S](aClass: Class[S], serviceFactory: ServiceFactory[S], dictionary: Dictionary[String, _]): ServiceRegistration[S] = throw new UnsupportedOperationException
- override def getServiceObjects[S](serviceReference: ServiceReference[S]): ServiceObjects[S] = throw new UnsupportedOperationException
- }
-
-}
diff --git a/standalone-container/src/main/scala/com/yahoo/application/container/impl/StandaloneContainerRunner.scala b/standalone-container/src/main/scala/com/yahoo/application/container/impl/StandaloneContainerRunner.scala
deleted file mode 100644
index 91634250fc5..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/application/container/impl/StandaloneContainerRunner.scala
+++ /dev/null
@@ -1,27 +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.application.container.impl
-
-import java.nio.file.Files
-import com.yahoo.text.Utf8
-
-/**
- * @author tonytv
- */
-final class StandaloneContainerRunner {
-
-
-
-}
-
-object StandaloneContainerRunner {
- def createApplicationPackage(servicesXml: String) = {
- val applicationDir = Files.createTempDirectory("application")
-
- val servicesXmlFile = applicationDir.resolve("services.xml");
- var content = servicesXml;
- if ( ! servicesXml.startsWith("<?xml"))
- content = """<?xml version="1.0" encoding="utf-8" ?>""" + '\n' + servicesXml
- Files.write(servicesXmlFile, Utf8.toBytes(content))
- applicationDir
- }
-}
diff --git a/standalone-container/src/main/scala/com/yahoo/container/standalone/Converter.scala b/standalone-container/src/main/scala/com/yahoo/container/standalone/Converter.scala
deleted file mode 100644
index 61128347319..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/container/standalone/Converter.scala
+++ /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.standalone
-
-/**
- * @author tonytv
- */
-trait Converter[T] {
- def convert(s: String): T
-}
-
-object Converter {
- def toConverter[T](f: String => T) = new Converter[T] {
- override def convert(s: String) = f(s)
- }
-
- implicit val intConverter = toConverter(_.toInt)
- implicit val longConverter = toConverter(_.toLong)
- implicit val boolConverter = toConverter(_.toBoolean)
- implicit val stringConverter = toConverter(identity)
-
- implicit val javaIntegerConverter:Converter[Integer] = toConverter(_.toInt)
- implicit val javaLongConverter:Converter[java.lang.Long] = toConverter(_.toLong)
- implicit val javaBooleanConverter:Converter[java.lang.Boolean] = toConverter(_.toBoolean)
-
-
-}
diff --git a/standalone-container/src/main/scala/com/yahoo/container/standalone/Environment.scala b/standalone-container/src/main/scala/com/yahoo/container/standalone/Environment.scala
deleted file mode 100644
index 2aab88d8319..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/container/standalone/Environment.scala
+++ /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.standalone
-
-/**
- * @author tonytv
- * TODO: copied from standalone-container. Move to separate lib module instead.
- */
-object Environment {
- def optionalInstallVariable(name: String) = {
- env(name.replace(".", "__")).
- orElse(systemProperty(name)) //for unit testing
- }
-
- def installVariable(name: String) = {
- optionalInstallVariable(name).
- getOrElse {
- throw new IllegalStateException("Environment variable not set: " + name)
- }
- }
-
- def env(name: String) = Option(System.getenv(name))
- def systemProperty(name: String) = Option(System.getProperty(name))
-}
diff --git a/standalone-container/src/main/scala/com/yahoo/container/standalone/LocalFileDb.scala b/standalone-container/src/main/scala/com/yahoo/container/standalone/LocalFileDb.scala
deleted file mode 100644
index 6507b4c72f0..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/container/standalone/LocalFileDb.scala
+++ /dev/null
@@ -1,75 +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.standalone
-
-import java.io.File
-import java.lang.reflect.Constructor
-import java.nio.file.Path
-import java.util
-import java.util.concurrent.TimeUnit
-
-import com.yahoo.config.FileReference
-import com.yahoo.config.application.api.FileRegistry
-import com.yahoo.config.application.api.FileRegistry.Entry
-import com.yahoo.container.standalone.LocalFileDb._
-import com.yahoo.filedistribution.fileacquirer.FileAcquirer
-import com.yahoo.net.HostName
-
-import scala.collection.JavaConverters._
-import scala.collection.mutable
-
-
-/**
- * FileAcquirer and FileRegistry working on a local directory.
- * @author tonytv
- */
-class LocalFileDb(appPath: Path) extends FileAcquirer with FileRegistry {
- private val fileReferenceToFile = mutable.Map[FileReference, File]()
-
- /** *** FileAcquirer overrides *****/
- def waitFor(reference: FileReference, l: Long, timeUnit: TimeUnit): File = {
- synchronized {
- fileReferenceToFile.get(reference).getOrElse {
- throw new RuntimeException("Invalid file reference " + reference)
- }
- }
- }
-
- override def shutdown() {}
-
- /** *** FileRegistry overrides *****/
- def addFile(relativePath: String): FileReference = {
- val file = appPath.resolve(relativePath).toFile
- if (!file.exists) {
- throw new RuntimeException("The file does not exist: " + file.getPath)
- }
-
- val fileReference: FileReference = fileReferenceConstructor.newInstance("LocalFileDb:" + relativePath)
- fileReferenceToFile.put(fileReference, file)
- fileReference
- }
-
- def fileSourceHost: String =
- HostName.getLocalhost
-
- def allRelativePaths: java.util.Set[String] = {
- new java.util.HashSet(fileReferenceToFile.values.map(_.getPath).asJavaCollection)
- }
-
- override def export(): util.List[Entry] = {
- new java.util.ArrayList(fileReferenceToFile.keys.map{ (ref: FileReference) => new Entry(fileReferenceToFile.get(ref).get.getPath, ref)}.asJavaCollection)
- }
-
- override def addUri(uri: String): FileReference = {
- throw new RuntimeException("addUri(uri: String) is not implemented here.");
- }
-}
-
-object LocalFileDb {
- private def createFileReferenceConstructor: Constructor[FileReference] = {
- val method: Constructor[FileReference] = classOf[FileReference].getDeclaredConstructor(classOf[String])
- method.setAccessible(true)
- method
- }
-
- private val fileReferenceConstructor: Constructor[FileReference] = createFileReferenceConstructor
-}
diff --git a/standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneContainerApplication.scala b/standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneContainerApplication.scala
deleted file mode 100644
index 5271cd400d4..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneContainerApplication.scala
+++ /dev/null
@@ -1,231 +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.standalone
-
-import java.io.{File, IOException}
-import java.lang.{Boolean => JBoolean}
-import java.nio.file.{FileSystems, Files, Path, Paths}
-
-import com.google.inject.name.Names
-import com.google.inject.{AbstractModule, Inject, Injector, Key}
-import com.yahoo.collections.CollectionUtil.first
-import com.yahoo.config.application.api.{ApplicationPackage, FileRegistry}
-import com.yahoo.config.model.application.provider._
-import com.yahoo.config.model.builder.xml.XmlHelper
-import com.yahoo.config.model.deploy.DeployState
-import com.yahoo.config.model.{ApplicationConfigProducerRoot, ConfigModelRepo}
-import com.yahoo.config.provision.Zone
-import com.yahoo.container.di.config.SubscriberFactory
-import com.yahoo.container.jdisc.ConfiguredApplication
-import com.yahoo.container.standalone.Environment._
-import com.yahoo.container.standalone.StandaloneContainerApplication._
-import com.yahoo.io.IOUtils
-import com.yahoo.jdisc.application.Application
-import com.yahoo.text.XML
-import com.yahoo.vespa.defaults.Defaults
-import com.yahoo.vespa.model.VespaModel
-import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder
-import com.yahoo.vespa.model.container.{Container, ContainerModel}
-import com.yahoo.vespa.model.container.xml.ContainerModelBuilder.Networking
-import com.yahoo.vespa.model.container.xml.{ConfigServerContainerModelBuilder, ContainerModelBuilder}
-import org.w3c.dom.Element
-
-import scala.collection.JavaConverters._
-import scala.util.Try
-
-/**
- * @author Tony Vaagenes
- * @author gjoranv
- */
-class StandaloneContainerApplication @Inject()(injector: Injector) extends Application {
-
- ConfiguredApplication.ensureVespaLoggingInitialized()
-
- val applicationPath: Path = injectedApplicationPath.getOrElse(installApplicationPath)
-
- val distributedFiles = new LocalFileDb(applicationPath)
-
- val configModelRepo = Try { injector.getInstance(Key.get(classOf[ConfigModelRepo], configModelRepoName))}.getOrElse(new ConfigModelRepo)
-
- val networkingOption = Try {
- injector.getInstance(Key.get(classOf[JBoolean], Names.named(disableNetworkingAnnotation)))
- }.map {
- case JBoolean.TRUE => Networking.disable
- case JBoolean.FALSE => Networking.enable
- }.getOrElse(Networking.enable)
-
- val (modelRoot, container) = withTempDir(
- preprocessedApplicationDir => createContainerModel(applicationPath, distributedFiles, preprocessedApplicationDir, networkingOption, configModelRepo))
-
- val configuredApplication = createConfiguredApplication(container)
-
- def createConfiguredApplication(container: Container): Application = {
- val augmentedInjector = injector.createChildInjector(new AbstractModule {
- def configure() {
- bind(classOf[SubscriberFactory]).toInstance(new StandaloneSubscriberFactory(modelRoot))
- }
- })
-
- System.setProperty("config.id", container.getConfigId) //TODO: DRY
- augmentedInjector.getInstance(classOf[ConfiguredApplication])
- }
-
- def injectedApplicationPath = Try {
- injector.getInstance(Key.get(classOf[Path], applicationPathName))
- }.toOption
-
- def installApplicationPath = path(installVariable(applicationLocationInstallVariable))
-
- override def start() {
- try {
- com.yahoo.container.Container.get().setCustomFileAcquirer(distributedFiles)
- configuredApplication.start()
- }
- catch {
- case e: Exception => { com.yahoo.container.Container.resetInstance(); throw e; }
- }
- }
-
- override def stop() {
- configuredApplication.stop()
- }
-
- override def destroy() {
- com.yahoo.container.Container.resetInstance()
- configuredApplication.destroy()
- }
-}
-
-object StandaloneContainerApplication {
- val packageName = "standalone_jdisc_container"
- val applicationLocationInstallVariable = s"$packageName.app_location"
- val deploymentProfileInstallVariable = s"$packageName.deployment_profile"
-
- val applicationPathName = Names.named(applicationLocationInstallVariable)
-
- val disableNetworkingAnnotation = "JDisc.disableNetworking"
- val configModelRepoName = Names.named("ConfigModelRepo")
- val configDefinitionRepo = new StaticConfigDefinitionRepo()
-
- val defaultTmpBaseDir = Defaults.getDefaults().underVespaHome("tmp")
- val tmpDirName = "standalone_container"
-
- private def withTempDir[T](f: File => T): T = {
- val tmpDir = createTempDir()
- try {
- f(tmpDir)
- } finally {
- IOUtils.recursiveDeleteDir(tmpDir)
- }
- }
-
- private def createTempDir(): File = {
- def getBaseDir: Path = {
- val tmpBaseDir =
- if (new File(defaultTmpBaseDir).exists())
- defaultTmpBaseDir
- else
- System.getProperty("java.io.tmpdir")
-
- Paths.get(tmpBaseDir)
- }
-
- val basePath: Path = getBaseDir
- val tmpDir = Files.createTempDirectory(basePath, tmpDirName)
- tmpDir.toFile
- }
-
- private def validateApplication(applicationPackage: ApplicationPackage) = {
- try {
- applicationPackage.validateXML()
- } catch {
- case e: IOException => throw new IllegalArgumentException(e)
- }
- }
-
- def newContainerModelBuilder(networkingOption: Networking): ContainerModelBuilder = {
- optionalInstallVariable(deploymentProfileInstallVariable) match {
- case None => new ContainerModelBuilder(true, networkingOption)
- case Some("configserver") => new ConfigServerContainerModelBuilder(new CloudConfigInstallVariables)
- case profileName => throw new RuntimeException(s"Invalid deployment profile '$profileName'")
- }
- }
-
- def createContainerModel(applicationPath: Path,
- fileRegistry: FileRegistry,
- preprocessedApplicationDir: File,
- networkingOption: Networking,
- configModelRepo: ConfigModelRepo = new ConfigModelRepo): (VespaModel, Container) = {
- val logger = new BaseDeployLogger
- val rawApplicationPackage = new FilesApplicationPackage.Builder(applicationPath.toFile).includeSourceFiles(true).preprocessedDir(preprocessedApplicationDir).build()
- val applicationPackage = rawApplicationPackage.preprocess(Zone.defaultZone(), logger)
- validateApplication(applicationPackage)
- val deployState = new DeployState.Builder().
- applicationPackage(applicationPackage).
- fileRegistry(fileRegistry).
- deployLogger(logger).
- configDefinitionRepo(configDefinitionRepo).
- build(true)
-
- val root = VespaModel.createIncomplete(deployState)
- val vespaRoot = new ApplicationConfigProducerRoot(root,
- "vespa",
- deployState.getDocumentModel,
- deployState.getProperties.vespaVersion(),
- deployState.getProperties.applicationId())
-
- val spec = containerRootElement(applicationPackage)
- val containerModel = newContainerModelBuilder(networkingOption).build(deployState, configModelRepo, vespaRoot, spec)
- containerModel.getCluster().prepare()
- DeprecationSuppressor.initializeContainerModel(containerModel, configModelRepo)
- val container = first(containerModel.getCluster().getContainers)
-
- // TODO: Separate out model finalization from the VespaModel constructor,
- // such that the above and below code to finalize the container can be
- // replaced by root.finalize();
-
- initializeContainer(container, spec)
-
- root.freezeModelTopology()
- (root, container)
- }
-
- def initializeContainer(container: Container, spec: Element) {
- val host = container.getRoot.getHostSystem.getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC)
-
- container.setBasePort(VespaDomBuilder.getXmlWantedPort(spec))
- container.setHostResource(host)
- container.initService()
- }
-
- def getJDiscInServices(element: Element): Element = {
- def nameAndId(elements: List[Element]): List[String] = {
- elements map { e => s"${e.getNodeName} id='${e.getAttribute("id")}'" }
- }
-
- val jDiscElements = ContainerModelBuilder.configModelIds.asScala flatMap { name => XML.getChildren(element, name.getName).asScala }
- jDiscElements.toList match {
- case List(e) => e
- case Nil => throw new RuntimeException("No jdisc element found under services.")
- case multipleElements: List[Element] => throw new RuntimeException("Found multiple JDisc elements: " + nameAndId(multipleElements).mkString(", "))
- }
- }
-
- def containerRootElement(applicationPackage: ApplicationPackage) : Element = {
- val element = XmlHelper.getDocument(applicationPackage.getServices).getDocumentElement
- val nodeName = element.getNodeName
-
- if (ContainerModelBuilder.configModelIds.asScala.map(_.getName).contains(nodeName)) element
- else getJDiscInServices(element)
- }
-
- def path(s: String) = FileSystems.getDefault.getPath(s)
-
- // Ugly hack required since Scala cannot suppress warnings. https://issues.scala-lang.org/browse/SI-7934
- private object DeprecationSuppressor extends DeprecationSuppressor
- @deprecated("", "")
- private class DeprecationSuppressor {
- def initializeContainerModel(containerModel: ContainerModel, configModelRepo: ConfigModelRepo): Unit = {
- containerModel.initialize(configModelRepo)
- }
- }
-}
diff --git a/standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneSubscriberFactory.scala b/standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneSubscriberFactory.scala
deleted file mode 100644
index 99cc8259ab3..00000000000
--- a/standalone-container/src/main/scala/com/yahoo/container/standalone/StandaloneSubscriberFactory.scala
+++ /dev/null
@@ -1,78 +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.standalone
-
-import com.yahoo.config.{ConfigBuilder, ConfigInstance}
-import com.yahoo.container.di.ConfigKeyT
-import com.yahoo.container.di.config.{Subscriber, SubscriberFactory}
-import com.yahoo.container.standalone.StandaloneSubscriberFactory._
-import com.yahoo.vespa.config.ConfigKey
-import com.yahoo.vespa.model.VespaModel
-
-import scala.collection.JavaConverters._
-
-/**
- * @author tonytv
- * @author gjoranv
- */
-class StandaloneSubscriberFactory(root: VespaModel) extends SubscriberFactory {
- class StandaloneSubscriber(configKeys: Set[ConfigKeyT]) extends Subscriber {
- override def configChanged =
- generation == 0
-
- override def close() {}
-
- override def config = {
-
- def getConfig(key: ConfigKeyT) = {
- val builderWithModelConfig = root.getConfig(newBuilderInstance(key), key.getConfigId)
-
- require(builderWithModelConfig != null, "Invalid config id " + key.getConfigId )
- (key.asInstanceOf[ConfigKey[ConfigInstance]], newConfigInstance(builderWithModelConfig))
- }
-
- (configKeys map getConfig).toMap.asJava
- }
-
- override def waitNextGeneration() = {
- generation += 1
-
- if (generation != 0) {
- while (!Thread.interrupted())
- Thread.sleep(10000)
- }
-
- generation
- }
-
- //if waitNextGeneration has not yet been called, -1 should be returned
- var generation = -1L
- }
-
- override def getSubscriber(configKeys: java.util.Set[_ <: ConfigKey[_]]) =
- new StandaloneSubscriber(configKeys.asScala.toSet.asInstanceOf[Set[ConfigKeyT]])
-
- def reloadActiveSubscribers(generation: Long) {
- throw new RuntimeException("unsupported")
- }
-}
-
-object StandaloneSubscriberFactory {
-
- private def newBuilderInstance(key: ConfigKeyT) =
- builderClass(key).getDeclaredConstructor().newInstance()
-
- private def builderClass(key: ConfigKeyT) = {
- val nestedClasses = key.getConfigClass.getClasses
- nestedClasses.
- filter {_.getName.equals(key.getConfigClass.getName + "$Builder")}.
- head.
- asInstanceOf[Class[ConfigInstance.Builder]]
- }
-
- private def newConfigInstance(builder: ConfigBuilder) =
- configClass(builder).getConstructor(builder.getClass).newInstance(builder)
-
- private def configClass(builder: ConfigBuilder) =
- builder.getClass.getEnclosingClass.asInstanceOf[Class[ConfigInstance]]
-
-}