io.smartspaces.system.bootstrap.osgi.GeneralSmartSpacesSupportActivator.java Source code

Java tutorial

Introduction

Here is the source code for io.smartspaces.system.bootstrap.osgi.GeneralSmartSpacesSupportActivator.java

Source

/*
 * Copyright (C) 2016 Keith M. Hughes
 * Copyright (C) 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package io.smartspaces.system.bootstrap.osgi;

import io.smartspaces.configuration.Configuration;
import io.smartspaces.configuration.FileSystemConfigurationStorageManager;
import io.smartspaces.configuration.SystemConfigurationStorageManager;
import io.smartspaces.evaluation.ExpressionEvaluatorFactory;
import io.smartspaces.event.observable.StandardEventObservableRegistry;
import io.smartspaces.expression.language.ssel.SselExpressionEvaluatorFactory;
import io.smartspaces.logging.ExtendedLog;
import io.smartspaces.logging.StandardExtendedLog;
import io.smartspaces.resource.managed.ManagedResource;
import io.smartspaces.resource.managed.ManagedResources;
import io.smartspaces.resource.managed.StandardManagedResources;
import io.smartspaces.scope.ManagedScope;
import io.smartspaces.scope.StandardManagedScope;
import io.smartspaces.service.Service;
import io.smartspaces.service.ServiceRegistry;
import io.smartspaces.system.BasicSmartSpacesFilesystem;
import io.smartspaces.system.SmartSpacesEnvironment;
import io.smartspaces.system.core.configuration.ConfigurationProvider;
import io.smartspaces.system.core.configuration.CoreConfiguration;
import io.smartspaces.system.core.container.ContainerCustomizerProvider;
import io.smartspaces.system.core.container.SmartSpacesSystemControl;
import io.smartspaces.system.core.logging.LoggingProvider;
import io.smartspaces.system.internal.osgi.OsgiContainerResourceManager;
import io.smartspaces.system.internal.osgi.OsgiSmartSpacesEnvironment;
import io.smartspaces.system.resources.ContainerResourceManager;
import io.smartspaces.tasks.ManagedTasks;
import io.smartspaces.tasks.StandardManagedTasks;
import io.smartspaces.time.provider.LocalTimeProvider;
import io.smartspaces.time.provider.NtpTimeProvider;
import io.smartspaces.time.provider.TimeProvider;
import io.smartspaces.util.concurrency.DefaultScheduledExecutorService;
import io.smartspaces.util.net.InetAddressFactory;

import org.apache.commons.logging.Log;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.wiring.FrameworkWiring;
import org.ros.log.RosLogFactory;
import org.ros.master.uri.MasterUriProvider;
import org.ros.master.uri.StaticMasterUriProvider;
import org.ros.master.uri.SwitchableMasterUriProvider;
import org.ros.osgi.common.RosEnvironment;
import org.ros.osgi.common.SimpleRosEnvironment;

import java.io.File;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Activate general services needed by a Smart Spaces container.
 *
 * @author Keith M. Hughes
 */
public class GeneralSmartSpacesSupportActivator implements BundleActivator {

    /**
     * The bundle context for this activator.
     */
    private BundleContext bundleContext;

    /**
     * Thread pool for everyone to use.
     */
    private ScheduledExecutorService executorService;

    /**
     * Smart Spaces environment for the container.
     */
    private OsgiSmartSpacesEnvironment spaceEnvironment;

    /**
     * The Smart Spaces-wide file system.
     */
    private BasicSmartSpacesFilesystem filesystem;

    /**
     * ROS environment for the container.
     */
    private SimpleRosEnvironment rosEnvironment;

    /**
     * The storage manager for system configurations.
     */
    private FileSystemConfigurationStorageManager systemConfigurationStorageManager;

    /**
     * Factory for expression evaluators.
     */
    private ExpressionEvaluatorFactory expressionEvaluatorFactory;

    /**
     * The system control for Smart Spaces.
     */
    private SmartSpacesSystemControl systemControl;

    /**
     * The ROS Master URI provider in use.
     */
    private SwitchableMasterUriProvider masterUriProvider;

    /**
     * The platform logging provider.
     */
    private LoggingProvider loggingProvider;

    /**
     * The container log.
     */
    private ExtendedLog containerLog;

    /**
     * The platform configuration provider.
     */
    private ConfigurationProvider configurationProvider;

    /**
     * The platform container customizer provider.
     *
     * <p>
     * Can be {@code null} if none is provided.
     */
    private ContainerCustomizerProvider containerCustomizerProvider;

    /**
     * The platform time provider.
     */
    private TimeProvider timeProvider;

    /**
     * The container resource manager.
     */
    private OsgiContainerResourceManager containerResourceManager;

    /**
     * All service registrations put into place.
     */
    private final List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<>();

    /**
     * Host address to use if address lookup fails.
     */
    private static final String UNKNOWN_HOST_ADDRESS = "unknown";

    /**
     * Update period for NTP.
     */
    private static final long NTP_UPDATE_PERIOD_SECONDS = 10L;

    /**
     * The managed scope for the entire container.
     */
    private ManagedScope containerManagedScope;

    @Override
    public void start(BundleContext context) throws Exception {
        bundleContext = context;

        String baseInstallDirProperty = bundleContext
                .getProperty(CoreConfiguration.CONFIGURATION_NAME_SMARTSPACES_BASE_INSTALL_DIR);
        File baseInstallDir = new File(baseInstallDirProperty);

        try {

            executorService = new DefaultScheduledExecutorService();

            getCoreServices();

            containerLog = new StandardExtendedLog("container", loggingProvider.getLog());

            ManagedResources managedResources = new StandardManagedResources(containerLog);

            ManagedTasks managedTasks = new StandardManagedTasks(executorService, containerLog);

            containerManagedScope = new StandardManagedScope(managedResources, managedTasks, executorService);
            containerManagedScope.startup();

            setupSpaceEnvironment(baseInstallDir);

            createAdditionalResources();

            registerOsgiServices();

            spaceEnvironment.getLog().formatInfo("Base system startup. Smart Spaces Version %s",
                    spaceEnvironment.getSystemConfiguration()
                            .getPropertyString(SmartSpacesEnvironment.CONFIGURATION_NAME_SMARTSPACES_VERSION));
        } catch (Exception e) {
            spaceEnvironment.getLog().error("Could not start up smartspaces system", e);
        }
    }

    /**
     * Create any additional resources needed by the container.
     */
    private void createAdditionalResources() {
        containerResourceManager = new OsgiContainerResourceManager(bundleContext,
                bundleContext.getBundle(0).adapt(FrameworkWiring.class), filesystem,
                configurationProvider.getConfigFolder(), spaceEnvironment.getLog());
        containerResourceManager.startup();
        containerManagedScope.managedResources().addResource(containerResourceManager);

        long containerStartupTime = spaceEnvironment.getTimeProvider().getCurrentTime();
        spaceEnvironment.getSystemConfiguration().setProperty(
                SmartSpacesEnvironment.CONFIGURATION_NAME_CONTAINER_STARTUP_TIME,
                Long.toString(containerStartupTime));
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        containerManagedScope.shutdown();

        // Remove all OSGi service registrations.
        for (ServiceRegistration<?> registration : serviceRegistrations) {
            registration.unregister();
        }
    }

    /**
     * Get all core services needed.
     *
     * <p>
     * These services should have been provided by the OSGi container bootstrap
     * and so will be immediately available. They will never go away since they
     * are only destroyed when bundle 0 goes, which means the entire container is
     * being shut down.
     *
     * @throws Exception
     *           something bad happened
     */
    private void getCoreServices() throws Exception {
        ServiceReference<LoggingProvider> loggingProviderServiceReference = bundleContext
                .getServiceReference(LoggingProvider.class);
        loggingProvider = bundleContext.getService(loggingProviderServiceReference);

        ServiceReference<ConfigurationProvider> configurationProviderServiceReference = bundleContext
                .getServiceReference(ConfigurationProvider.class);
        configurationProvider = bundleContext.getService(configurationProviderServiceReference);

        ServiceReference<ContainerCustomizerProvider> containerCustomizerProviderServiceReference = bundleContext
                .getServiceReference(ContainerCustomizerProvider.class);
        containerCustomizerProvider = bundleContext.getService(containerCustomizerProviderServiceReference);

        ServiceReference<SmartSpacesSystemControl> systemControlReference = bundleContext
                .getServiceReference(SmartSpacesSystemControl.class);
        systemControl = bundleContext.getService(systemControlReference);
    }

    /**
     * Register all services which need to be made available to others.
     */
    private void registerOsgiServices() {
        registerOsgiService(ContainerResourceManager.class.getName(), containerResourceManager);
        registerOsgiService(ExpressionEvaluatorFactory.class.getName(), expressionEvaluatorFactory);
        registerOsgiService(SystemConfigurationStorageManager.class.getName(), systemConfigurationStorageManager);
        registerOsgiService(SmartSpacesEnvironment.class.getName(), spaceEnvironment);
        registerOsgiService(RosEnvironment.class.getName(), rosEnvironment);
        registerOsgiService(SwitchableMasterUriProvider.class.getName(), masterUriProvider);
    }

    /**
     * Register an OSGi service.
     *
     * @param name
     *          name of the service
     * @param service
     *          the service object
     */
    private void registerOsgiService(String name, Object service) {
        serviceRegistrations.add(bundleContext.registerService(name, service, null));
    }

    /**
     * Set up the {@link SmartSpacesEnvironment} everyone should use.
     *
     * @param baseInstallDir
     *          the base directory where Smart Spaces is installed
     */
    private void setupSpaceEnvironment(File baseInstallDir) {
        Map<String, String> containerProperties = configurationProvider.getInitialConfiguration();

        filesystem = new BasicSmartSpacesFilesystem(baseInstallDir);
        filesystem.startup();
        containerManagedScope.addResource(filesystem);

        spaceEnvironment = new OsgiSmartSpacesEnvironment();
        spaceEnvironment.setExecutorService(executorService);
        spaceEnvironment.setLoggingProvider(loggingProvider, containerLog);
        spaceEnvironment.setFilesystem(filesystem);
        spaceEnvironment
                .setNetworkType(containerProperties.get(SmartSpacesEnvironment.CONFIGURATION_NAME_NETWORK_TYPE));
        spaceEnvironment.setContainerManagedScope(containerManagedScope);
        spaceEnvironment.setEventObservableRegistry(new StandardEventObservableRegistry(containerLog));

        setupSystemConfiguration(containerProperties, containerLog);

        timeProvider = getTimeProvider(containerProperties, loggingProvider.getLog());
        spaceEnvironment.setTimeProvider(timeProvider);
        timeProvider.startup();
        containerManagedScope.managedResources().addResource(timeProvider);

        setupRosEnvironment(systemConfigurationStorageManager.getSystemConfiguration().getCollapsedMap(),
                loggingProvider.getLog());

        // TODO(keith): Get the value property in a central place.
        spaceEnvironment.setValue("environment.ros", rosEnvironment);

        // Potentially request the container to permit file control.
        spaceEnvironment.getSystemConfiguration().setProperty(
                SmartSpacesEnvironment.CONFIGURATION_NAME_CONTAINER_FILE_CONTROLLABLE,
                Boolean.toString(containerCustomizerProvider.isFileControllable()));

        customizeContainer();
    }

    /**
     * Get the time provider to use.
     *
     * @param containerProperties
     *          properties to use for configuration
     * @param log
     *          logger for messages
     *
     * @return the time provider to use
     */
    public TimeProvider getTimeProvider(Map<String, String> containerProperties, Log log) {
        String provider = containerProperties.get(SmartSpacesEnvironment.CONFIGURATION_NAME_PROVIDER_TIME);
        if (provider == null) {
            provider = SmartSpacesEnvironment.CONFIGURATION_VALUE_PROVIDER_TIME_DEFAULT;
        }

        if (SmartSpacesEnvironment.CONFIGURATION_VALUE_PROVIDER_TIME_NTP.equals(provider)) {
            String host = containerProperties.get(SmartSpacesEnvironment.CONFIGURATION_NAME_PROVIDER_TIME_NTP_URL);
            if (host != null) {
                InetAddress ntpAddress = InetAddressFactory.newFromHostString(host);
                // TODO(keith): Make sure got valid address. Also, move copy of
                // factory class into SS.
                return new NtpTimeProvider(ntpAddress, NTP_UPDATE_PERIOD_SECONDS, TimeUnit.SECONDS, executorService,
                        log);
            } else {
                log.warn(String.format("Could not find host for NTP time provider. No value for configuration %s",
                        SmartSpacesEnvironment.CONFIGURATION_NAME_PROVIDER_TIME_NTP_URL));

                return new LocalTimeProvider();
            }
        } else {
            return new LocalTimeProvider();
        }
    }

    /**
     * Add any customization to the service from services and other objects
     * provided by the container.
     */
    public void customizeContainer() {
        if (containerCustomizerProvider != null) {
            ServiceRegistry serviceRegistry = spaceEnvironment.getServiceRegistry();
            for (Entry<String, Object> entry : containerCustomizerProvider.getServices().entrySet()) {
                serviceRegistry.registerService((Service) entry.getValue());
            }
        }
    }

    /**
     * Set up the full ROS environment.
     *
     * @param containerProperties
     *          properties for configuration
     * @param log
     *          logger to use
     */
    private void setupRosEnvironment(Map<String, String> containerProperties, Log log) {
        RosLogFactory.setLog(log);
        rosEnvironment = new SimpleRosEnvironment();
        rosEnvironment.setExecutorService(executorService);
        rosEnvironment.setLog(spaceEnvironment.getLog());
        rosEnvironment.setMaster(SmartSpacesEnvironment.CONFIGURATION_VALUE_CONTAINER_TYPE_MASTER
                .equals(containerProperties.get(SmartSpacesEnvironment.CONFIGURATION_NAME_CONTAINER_TYPE)));
        rosEnvironment
                .setNetworkType(containerProperties.get(SmartSpacesEnvironment.CONFIGURATION_NAME_NETWORK_TYPE));

        for (Entry<String, String> entry : containerProperties.entrySet()) {
            rosEnvironment.setProperty(entry.getKey(), entry.getValue());
        }

        configureRosFromSmartspaces(containerProperties);

        // Want to start Smart Spaces with no master URI unless there was
        // one in the config properties.
        rosEnvironment.setMasterUri(null);
        rosEnvironment.startup();
        containerManagedScope.addResource(new ManagedResource() {

            @Override
            public void startup() {
                // Won't be calling startup
            }

            @Override
            public void shutdown() {
                rosEnvironment.shutdown();
            }
        });

        MasterUriProvider baseProvider = null;
        URI masterUri = rosEnvironment.getMasterUri();
        if (masterUri != null) {
            log.info(String.format("Have initial ROS Master URI %s", masterUri));
            baseProvider = new StaticMasterUriProvider(masterUri);
        }

        masterUriProvider = new SwitchableMasterUriProvider(baseProvider);
        rosEnvironment.setMasterUriProvider(masterUriProvider);
    }

    /**
     * Configure the ROS environment from the smart spaces properties.
     *
     * @param containerProperties
     *          the properties from the container configuration
     */
    private void configureRosFromSmartspaces(Map<String, String> containerProperties) {
        rosEnvironment.setProperty(RosEnvironment.CONFIGURATION_NAME_ROS_NODE_NAME,
                RosEnvironment.ROS_NAME_SEPARATOR
                        + containerProperties.get(SmartSpacesEnvironment.CONFIGURATION_NAME_HOSTID));
        rosEnvironment.setProperty(RosEnvironment.CONFIGURATION_NAME_ROS_NETWORK_TYPE,
                spaceEnvironment.getNetworkType());
        rosEnvironment.setProperty(RosEnvironment.CONFIGURATION_NAME_ROS_CONTAINER_TYPE,
                spaceEnvironment.getSystemConfiguration()
                        .getRequiredPropertyString(SmartSpacesEnvironment.CONFIGURATION_NAME_CONTAINER_TYPE));
        rosEnvironment.setProperty(RosEnvironment.CONFIGURATION_NAME_ROS_HOST, spaceEnvironment
                .getSystemConfiguration().getPropertyString(SmartSpacesEnvironment.CONFIGURATION_NAME_HOST_NAME));

        // This call is so that the ROS URI gets evaluated.
        rosEnvironment.setProperty(RosEnvironment.CONFIGURATION_NAME_ROS_MASTER_URI, spaceEnvironment
                .getSystemConfiguration().getPropertyString(RosEnvironment.CONFIGURATION_NAME_ROS_MASTER_URI));
    }

    /**
     * Set up the system configuration.
     *
     * @param containerProperties
     *          properties for the container
     * @param log
     *          the logger to use
     */
    private void setupSystemConfiguration(Map<String, String> containerProperties, Log log) {
        expressionEvaluatorFactory = new SselExpressionEvaluatorFactory();

        FileSystemConfigurationStorageManager fileSystemConfigurationStorageManager = new FileSystemConfigurationStorageManager();
        fileSystemConfigurationStorageManager.setLog(spaceEnvironment.getLog());
        fileSystemConfigurationStorageManager.setExpressionEvaluatorFactory(expressionEvaluatorFactory);
        fileSystemConfigurationStorageManager.setSmartspacesFilesystem(filesystem);
        fileSystemConfigurationStorageManager.setConfigFolder(configurationProvider.getConfigFolder());

        systemConfigurationStorageManager = fileSystemConfigurationStorageManager;
        systemConfigurationStorageManager.startup();
        containerManagedScope.addResource(systemConfigurationStorageManager);

        Configuration systemConfiguration = systemConfigurationStorageManager.getSystemConfiguration();

        systemConfiguration.setProperties(containerProperties);

        systemConfiguration.setProperty(SmartSpacesEnvironment.CONFIGURATION_NAME_SMARTSPACES_VERSION,
                bundleContext.getProperty(CoreConfiguration.CONFIGURATION_NAME_SMARTSPACES_VERSION));

        String hostAddress = getHostAddress(systemConfiguration);
        if (hostAddress != null) {
            log.info(String.format("Using container host address %s", hostAddress));
            systemConfiguration.setProperty(SmartSpacesEnvironment.CONFIGURATION_NAME_HOST_ADDRESS, hostAddress);
        } else {
            log.warn("Could not determine container host address.");
        }

        systemConfiguration.setProperty(SmartSpacesEnvironment.CONFIGURATION_NAME_SYSTEM_FILESYSTEM_DIR_INSTALL,
                filesystem.getInstallDirectory().getAbsolutePath());
        systemConfiguration.setProperty(SmartSpacesEnvironment.CONFIGURATION_NAME_SYSTEM_FILESYSTEM_DIR_DATA,
                filesystem.getDataDirectory().getAbsolutePath());
        systemConfiguration.setProperty(SmartSpacesEnvironment.CONFIGURATION_NAME_SYSTEM_FILESYSTEM_DIR_TMP,
                filesystem.getTempDirectory().getAbsolutePath());

        spaceEnvironment.setSystemConfiguration(systemConfiguration);
    }

    /**
     * Get the IP address for the system.
     *
     * @param systemConfiguration
     *          The system configuration
     *
     * @return host IP address
     */
    private String getHostAddress(Configuration systemConfiguration) {
        try {
            String hostname = systemConfiguration
                    .getPropertyString(SmartSpacesEnvironment.CONFIGURATION_NAME_HOST_NAME);
            if (hostname != null) {
                InetAddress address = InetAddress.getByName(hostname);
                return address.getHostAddress();
            }

            String hostInterface = systemConfiguration
                    .getPropertyString(SmartSpacesEnvironment.CONFIGURATION_NAME_HOST_INTERFACE);
            if (hostInterface != null) {
                spaceEnvironment.getLog().formatInfo("Using network interface with name %s", hostInterface);
                NetworkInterface networkInterface = NetworkInterface.getByName(hostInterface);
                if (networkInterface != null) {
                    for (InetAddress inetAddress : Collections.list(networkInterface.getInetAddresses())) {
                        if (inetAddress instanceof Inet4Address) {
                            return inetAddress.getHostAddress();
                        }
                    }
                } else {
                    spaceEnvironment.getLog().formatWarn("No network interface with name %s from configuration %s",
                            hostInterface, SmartSpacesEnvironment.CONFIGURATION_NAME_HOST_INTERFACE);

                }
            }

            // See if a single network interface. If so, we will use it.
            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            if (interfaces.size() == 1) {
                for (InetAddress inetAddress : Collections.list(interfaces.get(0).getInetAddresses())) {
                    if (inetAddress instanceof Inet4Address) {
                        return inetAddress.getHostAddress();
                    }
                }
            }

            return null;
        } catch (Exception e) {
            spaceEnvironment.getLog().error("Could not obtain IP address", e);
            return UNKNOWN_HOST_ADDRESS;
        }
    }
}