<commit_before>/**
 * Copyright (c) 2011, 2014 Eurotech and/or its affiliates
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Eurotech
 */
package org.eclipse.kura.deployment.agent.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.eclipse.kura.deployment.agent.DeploymentAgentService;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.ComponentException;
import org.osgi.service.deploymentadmin.BundleInfo;
import org.osgi.service.deploymentadmin.DeploymentAdmin;
import org.osgi.service.deploymentadmin.DeploymentException;
import org.osgi.service.deploymentadmin.DeploymentPackage;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author cdealti
 *
 * The bundles installed from deployment packages are managed by the deployment admin itself.
 * Once installed they are persisted in the persistent storage area provided by the framework.
 * The persistent storage area is wiped up if the framework is stated with the '-clean' option.
 * The way deployment packages and their bundles are stored in the persistence storage area
 * is implementation dependent and we should not rely on that.
 *
 * In order to be able to reinstall deployment packages across reboots of the framework with
 * the '-clean' option set, we need to store the deployment package files (.dp) in a different
 * persistent location.
 *
 * Limitations:
 * We should also keep the entire installation history. This is needed because deployment
 * packages can be partially upgraded through 'fix packages' and these must be reinstalled in the
 * right order.
 * We DO NOT support this yet. We assume that for every installed deployment package
 * there is a single deployment package file (.dp) that needs to be reinstalled.
 */
public class DeploymentAgent implements DeploymentAgentService, CommandProvider {
	private static Logger s_logger = LoggerFactory.getLogger(DeploymentAgent.class);

	private static final String DPA_CONF_PATH_PROPNAME = "dpa.configuration";
	private static final String KURA_CONF_URL_PROPNAME  = "kura.configuration";
	private static final String PACKAGES_PATH_PROPNAME = "kura.packages";

	private static final String CONN_TIMEOUT_PROPNAME = "dpa.connection.timeout";
	private static final String READ_TIMEOUT_PROPNAME = "dpa.read.timeout";
	
	private final static long THREAD_TERMINATION_TOUT = 1; // in seconds
	
	private static ScheduledFuture<?>  s_installerTask;
	private static ScheduledFuture<?>  s_uninstallerTask;

	private DeploymentAdmin m_deploymentAdmin;
	private EventAdmin m_eventAdmin;

	private Queue<String> m_instPackageUrls;
	private Queue<String> m_uninstPackageNames;
	
	private ScheduledThreadPoolExecutor m_installerExecutor;
	private ScheduledThreadPoolExecutor m_uninstallerExecutor;
	
	private String m_dpaConfPath;
	private String m_packagesPath;

	private Properties m_deployedPackages;

	private int m_connTimeout;
	private int m_readTimeout;

	protected void activate(ComponentContext componentContext) {

		m_deployedPackages = new Properties();

		m_dpaConfPath = System.getProperty(DPA_CONF_PATH_PROPNAME);
		if (m_dpaConfPath == null || m_dpaConfPath.isEmpty()) {
			throw new ComponentException("The value of '" + DPA_CONF_PATH_PROPNAME + "' is not defined");
		}

		String sKuraConfUrl = System.getProperty(KURA_CONF_URL_PROPNAME);
		if (sKuraConfUrl == null || sKuraConfUrl.isEmpty()) {
			throw new ComponentException("The value of '" + KURA_CONF_URL_PROPNAME + "' is not defined");
		}

		URL kuraUrl = null;
		try {
			kuraUrl = new URL(sKuraConfUrl);
		} catch (MalformedURLException e) {
			throw new ComponentException("Invalid Kura configuration URL");
		}

		Properties kuraProperties = new Properties();
		try {
			kuraProperties.load(kuraUrl.openStream());
		} catch (FileNotFoundException e) {
			throw new ComponentException("Kura configuration file not found", e);
		} catch (IOException e) {
			throw new ComponentException("Exception loading Kura configuration file", e);
		}

		m_packagesPath = kuraProperties.getProperty(PACKAGES_PATH_PROPNAME);
		if (m_packagesPath == null || m_packagesPath.isEmpty()) {
			throw new ComponentException("The value of '" + PACKAGES_PATH_PROPNAME + "' is not defined");
		}
		if(kuraProperties.getProperty(PACKAGES_PATH_PROPNAME) != null && kuraProperties.getProperty(PACKAGES_PATH_PROPNAME).trim().equals("kura/packages")) {
			kuraProperties.setProperty(PACKAGES_PATH_PROPNAME, "/opt/eurotech/kura/kura/packages");
			m_packagesPath = kuraProperties.getProperty(PACKAGES_PATH_PROPNAME);
			s_logger.warn("Overridding invalid kura.packages location");
		}

		String sConnTimeout = kuraProperties.getProperty(CONN_TIMEOUT_PROPNAME);
		if (sConnTimeout != null) {
			m_connTimeout = Integer.valueOf(sConnTimeout);
		}

		String sReadTimeout = kuraProperties.getProperty(READ_TIMEOUT_PROPNAME);
		if (sReadTimeout != null) {
			m_readTimeout = Integer.valueOf(sReadTimeout);
		}

		File dpaConfFile = new File(m_dpaConfPath);
		if (dpaConfFile.getParentFile() != null && !dpaConfFile.getParentFile().exists()) {
			dpaConfFile.getParentFile().mkdirs();
		}
		if (!dpaConfFile.exists()) {<commit_msg>Fixed deployment agent path based on new directory structure<commit_after>/**
 * Copyright (c) 2011, 2014 Eurotech and/or its affiliates
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Eurotech
 */
package org.eclipse.kura.deployment.agent.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.eclipse.kura.deployment.agent.DeploymentAgentService;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.ComponentException;
import org.osgi.service.deploymentadmin.BundleInfo;
import org.osgi.service.deploymentadmin.DeploymentAdmin;
import org.osgi.service.deploymentadmin.DeploymentException;
import org.osgi.service.deploymentadmin.DeploymentPackage;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author cdealti
 *
 * The bundles installed from deployment packages are managed by the deployment admin itself.
 * Once installed they are persisted in the persistent storage area provided by the framework.
 * The persistent storage area is wiped up if the framework is stated with the '-clean' option.
 * The way deployment packages and their bundles are stored in the persistence storage area
 * is implementation dependent and we should not rely on that.
 *
 * In order to be able to reinstall deployment packages across reboots of the framework with
 * the '-clean' option set, we need to store the deployment package files (.dp) in a different
 * persistent location.
 *
 * Limitations:
 * We should also keep the entire installation history. This is needed because deployment
 * packages can be partially upgraded through 'fix packages' and these must be reinstalled in the
 * right order.
 * We DO NOT support this yet. We assume that for every installed deployment package
 * there is a single deployment package file (.dp) that needs to be reinstalled.
 */
public class DeploymentAgent implements DeploymentAgentService, CommandProvider {
	private static Logger s_logger = LoggerFactory.getLogger(DeploymentAgent.class);

	private static final String DPA_CONF_PATH_PROPNAME = "dpa.configuration";
	private static final String KURA_CONF_URL_PROPNAME  = "kura.configuration";
	private static final String PACKAGES_PATH_PROPNAME = "kura.packages";

	private static final String CONN_TIMEOUT_PROPNAME = "dpa.connection.timeout";
	private static final String READ_TIMEOUT_PROPNAME = "dpa.read.timeout";
	
	private final static long THREAD_TERMINATION_TOUT = 1; // in seconds
	
	private static ScheduledFuture<?>  s_installerTask;
	private static ScheduledFuture<?>  s_uninstallerTask;

	private DeploymentAdmin m_deploymentAdmin;
	private EventAdmin m_eventAdmin;

	private Queue<String> m_instPackageUrls;
	private Queue<String> m_uninstPackageNames;
	
	private ScheduledThreadPoolExecutor m_installerExecutor;
	private ScheduledThreadPoolExecutor m_uninstallerExecutor;
	
	private String m_dpaConfPath;
	private String m_packagesPath;

	private Properties m_deployedPackages;

	private int m_connTimeout;
	private int m_readTimeout;

	protected void activate(ComponentContext componentContext) {

		m_deployedPackages = new Properties();

		m_dpaConfPath = System.getProperty(DPA_CONF_PATH_PROPNAME);
		if (m_dpaConfPath == null || m_dpaConfPath.isEmpty()) {
			throw new ComponentException("The value of '" + DPA_CONF_PATH_PROPNAME + "' is not defined");
		}

		String sKuraConfUrl = System.getProperty(KURA_CONF_URL_PROPNAME);
		if (sKuraConfUrl == null || sKuraConfUrl.isEmpty()) {
			throw new ComponentException("The value of '" + KURA_CONF_URL_PROPNAME + "' is not defined");
		}

		URL kuraUrl = null;
		try {
			kuraUrl = new URL(sKuraConfUrl);
		} catch (MalformedURLException e) {
			throw new ComponentException("Invalid Kura configuration URL");
		}

		Properties kuraProperties = new Properties();
		try {
			kuraProperties.load(kuraUrl.openStream());
		} catch (FileNotFoundException e) {
			throw new ComponentException("Kura configuration file not found", e);
		} catch (IOException e) {
			throw new ComponentException("Exception loading Kura configuration file", e);
		}

		m_packagesPath = kuraProperties.getProperty(PACKAGES_PATH_PROPNAME);
		if (m_packagesPath == null || m_packagesPath.isEmpty()) {
			throw new ComponentException("The value of '" + PACKAGES_PATH_PROPNAME + "' is not defined");
		}
		if(kuraProperties.getProperty(PACKAGES_PATH_PROPNAME) != null && kuraProperties.getProperty(PACKAGES_PATH_PROPNAME).trim().equals("kura/packages")) {
			kuraProperties.setProperty(PACKAGES_PATH_PROPNAME, "/opt/eclipse/kura/kura/packages");
			m_packagesPath = kuraProperties.getProperty(PACKAGES_PATH_PROPNAME);
			s_logger.warn("Overridding invalid kura.packages location");
		}

		String sConnTimeout = kuraProperties.getProperty(CONN_TIMEOUT_PROPNAME);
		if (sConnTimeout != null) {
			m_connTimeout = Integer.valueOf(sConnTimeout);
		}

		String sReadTimeout = kuraProperties.getProperty(READ_TIMEOUT_PROPNAME);
		if (sReadTimeout != null) {
			m_readTimeout = Integer.valueOf(sReadTimeout);
		}

		File dpaConfFile = new File(m_dpaConfPath);
		if (dpaConfFile.getParentFile() != null && !dpaConfFile.getParentFile().exists()) {
			dpaConfFile.getParentFile().mkdirs();
		}
		if (!dpaConfFile.exists()) {
{'fraction_non_alphanumeric': 0.0862992125984252, 'fraction_numerical': 0.002362204724409449, 'mean_word_length': 5.470198675496689, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4633353', 'n_tokens_mistral': 3823, 'n_tokens_neox': 3624, 'n_words': 1012}