ddf.test.itests.AbstractIntegrationTest.java Source code

Java tutorial

Introduction

Here is the source code for ddf.test.itests.AbstractIntegrationTest.java

Source

/**
 * Copyright (c) Codice Foundation
 * <p>
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 * <p>
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package ddf.test.itests;

import static org.ops4j.pax.exam.CoreOptions.cleanCaches;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.maven;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
import static org.ops4j.pax.exam.CoreOptions.systemTimeout;
import static org.ops4j.pax.exam.CoreOptions.vmOption;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFileExtend;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.replaceConfigurationFile;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.useOwnExamBundlesStartLevel;
import static ddf.test.itests.AbstractIntegrationTest.DynamicUrl.INSECURE_ROOT;
import static ddf.test.itests.AbstractIntegrationTest.DynamicUrl.SECURE_ROOT;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import org.apache.commons.io.FileUtils;
import org.apache.karaf.features.BootFinished;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.shell.api.console.SessionFactory;
import org.junit.Rule;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.karaf.options.LogLevelOption;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.metatype.MetaTypeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.istack.NotNull;

import ddf.catalog.CatalogFramework;
import ddf.catalog.source.CatalogProvider;
import ddf.catalog.source.FederatedSource;
import ddf.common.test.AdminConfig;
import ddf.common.test.PaxExamRule;
import ddf.common.test.PostTestConstruct;
import ddf.common.test.ServiceManager;
import ddf.test.itests.common.SecurityPolicyConfigurator;
import ddf.test.itests.common.UrlResourceReaderConfigurator;

/**
 * Abstract integration test with helper methods and configuration at the container level
 */
public abstract class AbstractIntegrationTest {

    protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractIntegrationTest.class);

    protected static final String LOG_CONFIG_PID = AdminConfig.LOG_CONFIG_PID;

    protected static final String LOGGER_PREFIX = AdminConfig.LOGGER_PREFIX;

    protected static final String KARAF_VERSION = "4.0.4";

    protected static final String OPENSEARCH_SOURCE_ID = "openSearchSource";

    protected static final String CSW_SOURCE_ID = "cswSource";

    protected static ServerSocket placeHolderSocket;

    protected static Integer basePort;

    protected static final String DDF_HOME_PROPERTY = "ddf.home";

    protected static String ddfHome;

    protected static final String[] DEFAULT_REQUIRED_APPS = { "catalog-app", "solr-app", "spatial-app", "sdk-app" };

    protected static String[] getDefaultRequiredApps() {
        return Arrays.copyOf(DEFAULT_REQUIRED_APPS, DEFAULT_REQUIRED_APPS.length);
    }

    /**
     * An enum that returns a port number based on the class variable {@link #basePort}. Used to allow parallel itests
     * and dynamic allocation of ports to prevent conflicts on hard coded port numbers.
     * {@link #basePort} needs to be set in the {@link @BeforeExam} method of every test class that uses DynamicPort or
     * {@link DynamicUrl}. E.g. 'basePort = {@link #getBasePort()}`
     */
    public static class DynamicPort {

        private final String systemProperty;

        private final Integer ordinal;

        public DynamicPort(Integer ordinal) {
            this.systemProperty = null;
            this.ordinal = ordinal;
        }

        public DynamicPort(String systemProperty, Integer ordinal) {
            this.systemProperty = systemProperty;
            this.ordinal = ordinal;
        }

        String getSystemProperty() {
            return this.systemProperty;
        }

        public String getPort(Integer basePort) {
            return String.valueOf(basePort + this.ordinal());
        }

        public String getPort() {
            return String.valueOf(basePort + this.ordinal());
        }

        Integer ordinal() {
            return this.ordinal;
        }
    }

    /**
     * A class used to give a dynamic {@link String} that evaluates when called rather than at compile time.
     * Used to allow parallel itests and dynamic URLs to prevent conflicts on hard coded port numbers and endpoint, source, etc URLs.
     * Constructed with a {@link AbstractIntegrationTest.DynamicPort}
     */
    public static class DynamicUrl {
        public static final String SECURE_ROOT = "https://localhost:";

        public static final String INSECURE_ROOT = "http://localhost:";

        private final String root;

        private final String tail;

        private final DynamicPort port;

        private final DynamicUrl url;

        public DynamicUrl(String root, @NotNull DynamicPort port) {
            this(root, port, "");
        }

        public DynamicUrl(String root, @NotNull DynamicPort port, String tail) {
            if (null == port) {
                throw new IllegalArgumentException("Port cannot be null");
            }
            this.root = root;
            this.port = port;
            this.url = null;
            this.tail = tail;
        }

        public DynamicUrl(@NotNull DynamicUrl url, String tail) {
            if (null == url) {
                throw new IllegalArgumentException("Url cannot be null");
            }
            this.root = null;
            this.port = null;
            this.url = url;
            this.tail = tail;
        }

        public String getUrl() {
            if (null != port) {
                return root + port.getPort() + tail;
            } else {
                return url.getUrl() + tail;
            }
        }

        /**
         * @return the same String as {@link #getUrl()}
         */
        @Override
        public String toString() {
            return this.getUrl();
        }

    }

    public static final DynamicPort BASE_PORT = new DynamicPort("org.codice.ddf.system.basePort", 0);

    public static final DynamicPort HTTP_PORT = new DynamicPort("org.codice.ddf.system.httpPort", 1);

    public static final DynamicPort HTTPS_PORT = new DynamicPort("org.codice.ddf.system.httpsPort", 2);

    public static final DynamicPort DEFAULT_PORT = new DynamicPort("org.codice.ddf.system.port", 2);

    public static final DynamicPort SSH_PORT = new DynamicPort(3);

    public static final DynamicPort RMI_SERVER_PORT = new DynamicPort(4);

    public static final DynamicPort RMI_REG_PORT = new DynamicPort(5);

    public static final DynamicUrl SERVICE_ROOT = new DynamicUrl(SECURE_ROOT, HTTPS_PORT, "/services");

    public static final DynamicUrl INSECURE_SERVICE_ROOT = new DynamicUrl(INSECURE_ROOT, HTTP_PORT, "/services");

    public static final DynamicUrl REST_PATH = new DynamicUrl(SERVICE_ROOT, "/catalog/");

    public static final DynamicUrl OPENSEARCH_PATH = new DynamicUrl(REST_PATH, "query");

    public static final DynamicUrl CSW_PATH = new DynamicUrl(SERVICE_ROOT, "/csw");

    public static final DynamicUrl CSW_SUBSCRIPTION_PATH = new DynamicUrl(SERVICE_ROOT, "/csw/subscription");

    public static final DynamicUrl CSW_EVENT_PATH = new DynamicUrl(SERVICE_ROOT, "/csw/subscription/event");

    public static final DynamicUrl ADMIN_ALL_SOURCES_PATH = new DynamicUrl(SECURE_ROOT, HTTPS_PORT,
            "/jolokia/exec/org.codice.ddf.catalog.admin.poller.AdminPollerServiceBean:service=admin-source-poller-service/allSourceInfo");

    public static final DynamicUrl ADMIN_STATUS_PATH = new DynamicUrl(SECURE_ROOT, HTTPS_PORT,
            "/jolokia/exec/org.codice.ddf.catalog.admin.poller.AdminPollerServiceBean:service=admin-source-poller-service/sourceStatus/");

    static {
        // Make Pax URL use the maven.repo.local setting if present
        if (System.getProperty("maven.repo.local") != null) {
            System.setProperty("org.ops4j.pax.url.mvn.localRepository", System.getProperty("maven.repo.local"));
        }
    }

    @Rule
    public PaxExamRule paxExamRule = new PaxExamRule(this);

    protected String logLevel = "";

    @Inject
    protected ConfigurationAdmin configAdmin;

    @Inject
    protected FeaturesService features;

    @Inject
    protected SessionFactory sessionFactory;

    @Inject
    protected MetaTypeService metatype;

    /**
     * To make sure the tests run only when the boot features are fully installed
     */
    @Inject
    BootFinished bootFinished;

    private AdminConfig adminConfig;

    private ServiceManager serviceManager;

    private SecurityPolicyConfigurator securityPolicy;

    private CatalogBundle catalogBundle;

    private UrlResourceReaderConfigurator urlResourceReaderConfigurator;

    @PostTestConstruct
    public void initFacades() {
        ddfHome = System.getProperty(DDF_HOME_PROPERTY);
        adminConfig = new AdminConfig(configAdmin);
        serviceManager = new ServiceManager(metatype, adminConfig);
        catalogBundle = new CatalogBundle(serviceManager, adminConfig);
        securityPolicy = new SecurityPolicyConfigurator(serviceManager, configAdmin);
        urlResourceReaderConfigurator = new UrlResourceReaderConfigurator(configAdmin);
    }

    /**
     * Configures the pax exam test container
     *
     * @return list of pax exam options
     */
    @org.ops4j.pax.exam.Configuration
    public Option[] config() throws URISyntaxException, IOException {
        basePort = findPortNumber(20000);
        return combineOptions(configureCustom(), configureDistribution(), configureAdditionalBundles(),
                configureConfigurationPorts(), configureMavenRepos(), configureSystemSettings(),
                configureVmOptions(), configureStartScript(), configurePaxExam());
    }

    private static Integer findPortNumber(Integer portToTry) {
        try {
            placeHolderSocket = new ServerSocket(portToTry);
            placeHolderSocket.setReuseAddress(true);
            return portToTry;
        } catch (Exception e) {
            portToTry += 10;
            LOGGER.debug("Bad port, trying {}", portToTry);
            return findPortNumber(portToTry);
        }
    }

    protected AdminConfig getAdminConfig() {
        return adminConfig;
    }

    protected ServiceManager getServiceManager() {
        return serviceManager;
    }

    protected CatalogBundle getCatalogBundle() {
        return catalogBundle;
    }

    protected SecurityPolicyConfigurator getSecurityPolicy() {
        return securityPolicy;
    }

    protected UrlResourceReaderConfigurator getUrlResourceReaderConfigurator() {
        return urlResourceReaderConfigurator;
    }

    /**
     * Combines all the {@link Option} objects contained in multiple {@link Option} arrays.
     *
     * @param options arrays of {@link Option} objects to combine. Arrays can be {@code null} or
     *                empty.
     * @return array that combines all the {@code Option} objects from the arrays provided.
     * {@code null} and empty arrays will be ignored, but {@code null} {@link Option} objects will
     * be added to the result.
     */
    protected Option[] combineOptions(Option[]... options) {
        List<Option> optionList = new ArrayList<>();
        for (Option[] array : options) {
            if (array != null && array.length > 0) {
                optionList.addAll(Arrays.asList(array));
            }
        }
        Option[] finalArray = new Option[optionList.size()];
        optionList.toArray(finalArray);
        return finalArray;
    }

    protected Option[] configureDistribution() {
        return options(karafDistributionConfiguration(
                maven().groupId("org.codice.ddf").artifactId("ddf").type("zip").versionAsInProject().getURL(),
                "ddf", KARAF_VERSION).unpackDirectory(new File("target/exam")).useDeployFolder(false));
    }

    protected Option[] configurePaxExam() {
        return options(logLevel(LogLevelOption.LogLevel.WARN), useOwnExamBundlesStartLevel(100),
                // increase timeout for CI environment
                systemTimeout(TimeUnit.MINUTES.toMillis(10)),
                when(Boolean.getBoolean("keepRuntimeFolder")).useOptions(keepRuntimeFolder()), cleanCaches(true));
    }

    protected Option[] configureAdditionalBundles() {
        return options(junitBundles(),
                wrappedBundle(mavenBundle("org.apache.httpcomponents", "httpclient").versionAsInProject()),
                wrappedBundle(mavenBundle("org.apache.httpcomponents", "httpcore").versionAsInProject()),
                wrappedBundle(mavenBundle("commons-codec", "commons-codec").versionAsInProject()),
                wrappedBundle(mavenBundle("commons-logging", "commons-logging").versionAsInProject()),
                // HACK: incorrect version exported to override hamcrest-core from exam
                // feature which causes a split package issue for rest-assured
                wrappedBundle(mavenBundle("org.hamcrest", "hamcrest-all").versionAsInProject())
                        .exports("*;version=1.3.0.10"),
                wrappedBundle(
                        mavenBundle("org.apache.karaf.itests", "itests").classifier("tests").versionAsInProject()),
                wrappedBundle(mavenBundle("ddf.test.itests", "test-itests-common").classifier("tests")
                        .versionAsInProject()).bundleSymbolicName("test-itests-common"),
                wrappedBundle(mavenBundle("ddf.security", "ddf-security-common").versionAsInProject())
                        .bundleSymbolicName("test-security-common"),
                mavenBundle("ddf.test.thirdparty", "rest-assured").versionAsInProject(),
                wrappedBundle(mavenBundle("com.google.guava", "guava").versionAsInProject())
                        .exports("*;version=18.0"));
    }

    protected Option[] configureConfigurationPorts() throws URISyntaxException, IOException {
        return options(editConfigurationFilePut("etc/system.properties", "urlScheme", "https"),
                editConfigurationFilePut("etc/system.properties", "host", "localhost"),
                editConfigurationFilePut("etc/system.properties", "jetty.port", HTTPS_PORT.getPort()),
                editConfigurationFilePut("etc/system.properties", "hostContext", "/solr"),
                editConfigurationFilePut("etc/system.properties", "ddf.home", "${karaf.home}"),

                editConfigurationFilePut("etc/system.properties", HTTP_PORT.getSystemProperty(),
                        HTTP_PORT.getPort()),
                editConfigurationFilePut("etc/system.properties", HTTPS_PORT.getSystemProperty(),
                        HTTPS_PORT.getPort()),
                editConfigurationFilePut("etc/system.properties", DEFAULT_PORT.getSystemProperty(),
                        DEFAULT_PORT.getPort()),
                editConfigurationFilePut("etc/system.properties", BASE_PORT.getSystemProperty(),
                        BASE_PORT.getPort()),

                // DDF-1572: Disables the periodic backups of .bundlefile. In itests, having those
                // backups serves no purpose and it appears that intermittent failures have occurred
                // when the background thread attempts to create the backup before the exam bundle
                // is completely exploded.
                editConfigurationFilePut("etc/system.properties", "eclipse.enableStateSaver",
                        Boolean.FALSE.toString()),

                editConfigurationFilePut("etc/org.apache.karaf.shell.cfg", "sshPort", SSH_PORT.getPort()),
                editConfigurationFilePut("etc/ddf.platform.config.cfg", "port", HTTPS_PORT.getPort()),
                editConfigurationFilePut("etc/ddf.platform.config.cfg", "host", "localhost"),
                editConfigurationFilePut("etc/org.ops4j.pax.web.cfg", "org.osgi.service.http.port",
                        HTTP_PORT.getPort()),
                editConfigurationFilePut("etc/org.ops4j.pax.web.cfg", "org.osgi.service.http.port.secure",
                        HTTPS_PORT.getPort()),
                editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiRegistryPort",
                        RMI_REG_PORT.getPort()),
                editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiServerPort",
                        RMI_SERVER_PORT.getPort()),
                installStartupFile(getClass().getResourceAsStream("/hazelcast.xml"), "/etc/hazelcast.xml"),
                installStartupFile(getClass().getResourceAsStream("/ddf.security.sts.client.configuration.config"),
                        "/etc/ddf.security.sts.client.configuration.config"),
                editConfigurationFilePut("etc/ddf.security.sts.client.configuration.config", "address",
                        "\"" + SECURE_ROOT + HTTPS_PORT.getPort() + "/services/SecurityTokenService?wsdl" + "\""),
                installStartupFile(
                        getClass().getResourceAsStream("/ddf.catalog.solr.external.SolrHttpCatalogProvider.config"),
                        "/etc/ddf.catalog.solr.external.SolrHttpCatalogProvider.config"));
    }

    protected Option[] configureMavenRepos() {
        return options(editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg",
                "org.ops4j.pax.url.mvn.repositories",
                "http://repo1.maven.org/maven2@id=central,"
                        + "http://oss.sonatype.org/content/repositories/snapshots@snapshots@noreleases@id=sonatype-snapshot,"
                        + "http://oss.sonatype.org/content/repositories/ops4j-snapshots@snapshots@noreleases@id=ops4j-snapshot,"
                        + "http://repository.apache.org/content/groups/snapshots-group@snapshots@noreleases@id=apache,"
                        + "http://svn.apache.org/repos/asf/servicemix/m2-repo@id=servicemix,"
                        + "http://repository.springsource.com/maven/bundles/release@id=springsource,"
                        + "http://repository.springsource.com/maven/bundles/external@id=springsourceext,"
                        + "http://oss.sonatype.org/content/repositories/releases/@id=sonatype"),
                when(System.getProperty("maven.repo.local") != null)
                        .useOptions(editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg",
                                "org.ops4j.pax.url.mvn.localRepository", System.getProperty("maven.repo.local"))));
    }

    protected Option[] configureSystemSettings() {
        return options(
                when(System.getProperty(AdminConfig.TEST_LOGLEVEL_PROPERTY) != null)
                        .useOptions(systemProperty(AdminConfig.TEST_LOGLEVEL_PROPERTY)
                                .value(System.getProperty(AdminConfig.TEST_LOGLEVEL_PROPERTY, ""))),
                when(Boolean.getBoolean("isDebugEnabled"))
                        .useOptions(vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")),
                when(System.getProperty("maven.repo.local") != null)
                        .useOptions(systemProperty("org.ops4j.pax.url.mvn.localRepository")
                                .value(System.getProperty("maven.repo.local", ""))));
    }

    protected Option[] configureVmOptions() {
        return options(vmOption("-Xmx2048M"),
                // avoid integration tests stealing focus on OS X
                vmOption("-Djava.awt.headless=true"));
    }

    protected Option[] configureStartScript() {
        String featuresUrl = maven("ddf.distribution", "sdk-app").classifier("features").type("xml")
                .versionAsInProject().getURL();
        return options(
                // Need to add catalog-core since there are imports in the itests from catalog-core.
                editConfigurationFileExtend("etc/org.apache.karaf.features.cfg", "featuresBoot", "catalog-core"),
                editConfigurationFileExtend("etc/org.apache.karaf.features.cfg", "featuresRepositories",
                        featuresUrl));
    }

    protected Integer getBasePort() {
        return Integer.parseInt(System.getProperty(BASE_PORT.getSystemProperty()));
    }

    protected void configureEnforcedMetacardValidators(List<String> enforcedValidators) throws IOException {

        // Update metacardMarkerPlugin config with no enforcedMetacardValidators
        Configuration config = configAdmin
                .getConfiguration("ddf.catalog.metacard.validation.MetacardValidityMarkerPlugin", null);

        Dictionary<String, Object> properties = new Hashtable<>();
        properties.put("enforcedMetacardValidators", enforcedValidators);
        config.update(properties);
    }

    protected void configureMetacardValidityFilterPlugin(List<String> securityAttributeMappings)
            throws IOException {
        Configuration config = configAdmin
                .getConfiguration("ddf.catalog.metacard.validation.MetacardValidityFilterPlugin", null);
        Dictionary properties = new Hashtable<>();
        properties.put("attributeMap", securityAttributeMappings);
        config.update(properties);
    }

    protected void configureShowInvalidMetacards(String showInvalidMetacards) throws IOException {
        Configuration config = configAdmin.getConfiguration("ddf.catalog.federation.impl.CachingFederationStrategy",
                null);

        Dictionary properties = new Hashtable<>();
        properties.put("showInvalidMetacards", showInvalidMetacards);
        config.update(properties);
    }

    /**
     * Allows extending classes to add any custom options to the configuration.
     */
    protected Option[] configureCustom() {
        return null;
    }

    /**
     * Copies the content of a JAR resource to the destination specified before the container
     * starts up. Useful to add test configuration files before tests are run.
     *
     * @param resourceInputStream input stream to te he JAR resource to copy
     * @param destination         destination relative to DDF_HOME
     * @return option object to include in a {@link #configureCustom()} method
     * @throws IOException thrown if a problem occurs while copying the resource
     */
    protected Option installStartupFile(InputStream resourceInputStream, String destination) throws IOException {
        File tempFile = Files.createTempFile("StartupFile", ".temp").toFile();
        tempFile.deleteOnExit();
        FileUtils.copyInputStreamToFile(resourceInputStream, tempFile);
        return replaceConfigurationFile(destination, tempFile);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#waitForHttpEndpoint(String)
     * getServiceManager().waitForHttpEndpoint()} instead.
     */
    @Deprecated
    protected void waitForHttpEndpoint(String path) throws InterruptedException {
        serviceManager.waitForHttpEndpoint(path);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#stopFeature(boolean, String...)
     * getServiceManager().stopFeature()} instead.
     */
    @Deprecated
    protected void stopFeature(boolean wait, String... featureNames) throws Exception {
        serviceManager.stopFeature(wait, featureNames);
    }

    /**
     * @deprecated since 2.8.0. Use {@link AdminConfig#setLogLevels()
     * getAdminConfig().setLogLevels()} instead.
     */
    @Deprecated
    protected void setLogLevels() throws IOException {
        adminConfig.setLogLevels();
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#startFeature(boolean, String...)
     * getServiceManager().startFeature()} instead.
     */
    @Deprecated
    protected void startFeature(boolean wait, String... featureNames) throws Exception {
        serviceManager.startFeature(wait, featureNames);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#createManagedService(String, Map)
     * getServiceManager.createManagedService()} instead.
     */
    @Deprecated
    protected void createManagedService(String factoryPid, Map<String, Object> properties) throws IOException {
        serviceManager.createManagedService(factoryPid, properties);
    }

    /**
     * @deprecated since 2.8.0. Use {@link CatalogBundle#setFanout(boolean)
     * getCatalogBundle().setFanout()} instead.
     */
    @Deprecated
    protected void setFanout(boolean fanoutEnabled) throws IOException {
        catalogBundle.setFanout(fanoutEnabled);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#waitForRequiredBundles(String)
     * getServiceManager.waitForRequiredBundles()} instead.
     */
    @Deprecated
    protected void waitForRequiredBundles(String symbolicNamePrefix) throws InterruptedException {
        serviceManager.waitForRequiredBundles(symbolicNamePrefix);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#waitForSourcesToBeAvailable(String, String...)
     * getServiceManager.waitForSourcesToBeAvailable()} instead.
     */
    @Deprecated
    protected void waitForSourcesToBeAvailable(String... sources) throws InterruptedException {
        serviceManager.waitForSourcesToBeAvailable(REST_PATH.getUrl(), sources);
    }

    /**
     * @deprecated since 2.8.0. Use {@link CatalogBundle#waitForFederatedSource(String)
     * getCatalogBundle.waitForFederatedSource()} instead.
     */
    @Deprecated
    protected FederatedSource waitForFederatedSource(String id)
            throws InterruptedException, InvalidSyntaxException {
        return catalogBundle.waitForFederatedSource(id);
    }

    /**
     * @deprecated since 2.8.0. Use {@link CatalogBundle#waitForCatalogProvider()
     * getCatalogBundle.waitForCatalogProvider()} instead.
     */
    @Deprecated
    protected CatalogProvider waitForCatalogProvider() throws InterruptedException {
        return catalogBundle.waitForCatalogProvider();
    }

    /**
     * @deprecated since 2.8.0. Use {@link CatalogBundle#getCatalogFramework()
     * getCatalogBundle.getCatalogFramework()} instead.
     */
    @Deprecated
    protected CatalogFramework getCatalogFramework() throws InterruptedException {
        return catalogBundle.getCatalogFramework();
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#getMetatypeDefaults(String, String)
     * getServiceManager.getMetatypeDefaults()} instead.
     */
    @Deprecated
    protected Map<String, Object> getMetatypeDefaults(String symbolicName, String factoryPid) {
        return serviceManager.getMetatypeDefaults(symbolicName, factoryPid);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#startManagedService(String, Map)
     * getServiceManager.startManagedService()} instead.
     */
    @Deprecated
    protected void startManagedService(String servicePid, Map<String, Object> properties) throws IOException {
        serviceManager.startManagedService(servicePid, properties);
    }

    /**
     * @deprecated since 2.8.0. Use {@link ServiceManager#waitForAllBundles()
     * getServiceManager.waitForAllBundles()} instead.
     */
    @Deprecated
    protected void waitForAllBundles() throws InterruptedException {
        serviceManager.waitForAllBundles();
    }

    public class OpenSearchSourceProperties extends HashMap<String, Object> {

        public static final String SYMBOLIC_NAME = "catalog-opensearch-source";

        public static final String FACTORY_PID = "OpenSearchSource";

        public OpenSearchSourceProperties(String sourceId) {
            this.putAll(getMetatypeDefaults(SYMBOLIC_NAME, FACTORY_PID));

            this.put("shortname", sourceId);
            this.put("endpointUrl", OPENSEARCH_PATH.getUrl());
        }

    }

    public class CswSourceProperties extends HashMap<String, Object> {

        public static final String SYMBOLIC_NAME = "spatial-csw-source";

        public static final String FACTORY_PID = "Csw_Federated_Source";

        public static final String GMD_FACTORY_PID = "Gmd_Csw_Federated_Source";

        public CswSourceProperties(String sourceId) {
            this(sourceId, FACTORY_PID);
        }

        public CswSourceProperties(String sourceId, String factoryPid) {
            this.putAll(getMetatypeDefaults(SYMBOLIC_NAME, factoryPid));

            this.put("id", sourceId);
            this.put("cswUrl", CSW_PATH.getUrl());
            this.put("pollInterval", 1);
        }

    }

    public class CswConnectedSourceProperties extends HashMap<String, Object> {

        public static final String SYMBOLIC_NAME = "spatial-csw-source";

        public static final String FACTORY_PID = "Csw_Connected_Source";

        public CswConnectedSourceProperties(String sourceId) {
            this.putAll(getMetatypeDefaults(SYMBOLIC_NAME, FACTORY_PID));

            this.put("id", sourceId);
            this.put("cswUrl", CSW_PATH.getUrl());
            this.put("pollInterval", 1);
        }

    }

    public class CswRegistryStoreProperties extends HashMap<String, Object> {

        public static final String SYMBOLIC_NAME = "catalog-registry-api-impl";

        public static final String FACTORY_PID = "Csw_Registry_Store";

        public CswRegistryStoreProperties(String sourceId) {
            this.putAll(getMetatypeDefaults(SYMBOLIC_NAME, FACTORY_PID));

            this.put("id", sourceId);
            this.put("cswUrl", CSW_PATH.getUrl());
            this.put("pollInterval", 1);
        }
    }
}