content: package alien4cloud.it;
  
  import java.beans.IntrospectionException;
  import java.io.IOException;
  import java.net.InetSocketAddress;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.util.*;
  
  import org.alien4cloud.tosca.model.definitions.AbstractPropertyValue;
  import org.alien4cloud.tosca.model.definitions.IValue;
  import org.alien4cloud.tosca.model.definitions.PropertyConstraint;
  import org.alien4cloud.tosca.model.types.AbstractInheritableToscaType;
  import org.apache.commons.lang3.StringUtils;
  import org.elasticsearch.client.Client;
  import org.elasticsearch.client.transport.TransportClient;
  import org.elasticsearch.common.settings.Settings;
  import org.elasticsearch.common.transport.TransportAddress;
  import org.elasticsearch.transport.client.PreBuiltTransportClient;
  import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
  import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
  import org.springframework.core.io.ClassPathResource;
  import org.springframework.core.io.InputStreamResource;
  import org.springframework.core.io.Resource;
  import org.springframework.expression.EvaluationContext;
  import org.springframework.expression.spel.support.StandardEvaluationContext;
  import org.springframework.util.PropertyPlaceholderHelper;
  
  import com.fasterxml.jackson.core.Version;
  import com.fasterxml.jackson.databind.ObjectMapper;
  import com.fasterxml.jackson.databind.module.SimpleModule;
  import com.google.common.base.Joiner;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Maps;
  
  import alien4cloud.it.exception.ITException;
  import alien4cloud.it.provider.util.AwsClient;
  import alien4cloud.it.provider.util.OpenStackClient;
  import alien4cloud.it.utils.TestUtils;
  import alien4cloud.json.deserializer.*;
  import alien4cloud.model.application.Application;
  import alien4cloud.model.common.MetaPropConfiguration;
  import alien4cloud.rest.utils.RestClient;
  import alien4cloud.rest.utils.RestMapper;
  import alien4cloud.topology.task.AbstractTask;
  import alien4cloud.utils.MapUtil;
  import alien4cloud.utils.VersionUtil;
  import cucumber.runtime.io.ClasspathResourceLoader;
  import lombok.SneakyThrows;
  import lombok.extern.slf4j.Slf4j;
  
  /**
   * In order to communicate between different step definitions
   *
   * @author mkv
   *
   */
  @Slf4j
  public class Context {
      public static final Path REQUESTS_PATH = Paths.get("src/test/resources/data/requests");
  
      public static final String FASTCONNECT_NEXUS = "http://fastconnect.org/maven/service/local/artifact/maven/redirect?";
  
      public static final String GIT_URL_SUFFIX = ".git";
  
      public static final Path GIT_ARTIFACT_TARGET_PATH = Paths.get("target/git");
  
      public static final Path CSAR_TARGET_PATH = Paths.get("target/csars");
  
      public static final Path LOCAL_TEST_DATA_PATH = Paths.get("src/test/resources");
  
      public static final int SCP_PORT = 22;
  
      public static final String HOST = "localhost";
  
      public static final int PORT = 8088;
  
      public static final String CONTEXT_PATH = "";
  
      public static final String WEB_SOCKET_END_POINT = "/rest/v1/alienEndPoint";
  
      /** Alien's current version. */
      public static final String VERSION;
  
      private static final Context INSTANCE = new Context();
  
      private static Client ES_CLIENT_INSTANCE;
  
      private static RestClient REST_CLIENT_INSTANCE;
  
      private static ObjectMapper JSON_MAPPER;
  
      private static String ES_HOST = "localhost";
  
      private static String ES_CLUSTER = "escluster";
  
      static {
          YamlPropertiesFactoryBean propertiesFactoryBean = new YamlPropertiesFactoryBean();
          propertiesFactoryBean.setResources(new Resource[] { new ClassPathResource("version.yml") });
          Properties properties = propertiesFactoryBean.getObject();
          VERSION = properties.getProperty("version");
  
          ClassPathResource esClasspathResource = new ClassPathResource("es.yml");
          if (esClasspathResource.exists()) {
              propertiesFactoryBean = new YamlPropertiesFactoryBean();
              propertiesFactoryBean.setResources(new Resource[] { esClasspathResource });
              properties = propertiesFactoryBean.getObject();
              if (properties.containsKey("host")) {
                  ES_HOST = properties.getProperty("host");
              }
              if (properties.containsKey("cluster")) {
                  ES_CLUSTER = properties.getProperty("cluster");
              }
          }
      }
  
      public static Client getEsClientInstance() {
          if (ES_CLIENT_INSTANCE == null) {
  /***
              Settings settings = Settings.settingsBuilder().put("discovery.zen.ping.multicast.enabled", false)
                      .put("discovery.zen.ping.unicast.hosts", ES_HOST).put("discovery.zen.ping.unicast.enabled", true).build();
              ES_CLIENT_INSTANCE = NodeBuilder.nodeBuilder().client(true).clusterName(ES_CLUSTER).local(false).settings(settings).node().client();
  ***/
              Settings settings = Settings.builder()
                  .put("transport.type", "netty4")
                  .put("cluster.name", ES_CLUSTER)
                  .build();
              TransportClient transportClient = new PreBuiltTransportClient(settings);
              transportClient.addTransportAddress(new TransportAddress(new InetSocketAddress(ES_HOST, 9300)));
  
              ES_CLIENT_INSTANCE = transportClient;
          }
          return ES_CLIENT_INSTANCE;
      }
  
      public static RestClient getRestClientInstance() {
          if (REST_CLIENT_INSTANCE == null) {
              String alienUrl = System.getenv("ALIEN_URL");
              if (alienUrl == null || alienUrl.isEmpty()) {
                  alienUrl = "http://" + HOST + ":" + PORT + CONTEXT_PATH;
              }
              log.info("Connecting rest client to " + alienUrl);
              REST_CLIENT_INSTANCE = new RestClient(alienUrl);
          }
          return REST_CLIENT_INSTANCE;
      }
  
      public static Context getInstance() {
          return INSTANCE;
      }
  
      public static ObjectMapper getJsonMapper() {
          if (JSON_MAPPER == null) {
              JSON_MAPPER = new RestMapper();
              SimpleModule module = new SimpleModule("PropDeser", new Version(1, 0, 0, null, null, null));
              module.addDeserializer(AbstractPropertyValue.class, new PropertyValueDeserializer());
              module.addDeserializer(IValue.class, new AttributeDeserializer());
              try {
                  module.addDeserializer(PropertyConstraint.class, new PropertyConstraintDeserializer());
              } catch (ClassNotFoundException | IOException | IntrospectionException e) {
                  log.error("Unable to initialize test context.");
              }
              JSON_MAPPER.registerModule(module);
  
              // task deserializers
              module = new SimpleModule("taskDeser", new Version(1, 0, 0, null, null, null));
              module.addDeserializer(AbstractTask.class, new TaskDeserializer());
              module.addDeserializer(AbstractInheritableToscaType.class, new TaskIndexedInheritableToscaElementDeserializer());
              JSON_MAPPER.registerModule(module);
  
          }
          return JSON_MAPPER;
      }
  
      private final TestPropertyPlaceholderConfigurer appProps;
  
      private String restResponseLocal;
  
      private String csarLocal;
  
      private Set<String> componentsIdsLocal;
  
      private String topologyIdLocal;
  
      private String csarIdLocal;
      /* templateName -> templateVersion -> topologyId */
      private Map<String, Map<String, String>> topologyTemplateId = Maps.newHashMap();
  
      private EvaluationContext spelEvaluationContext;
  
      private Application applicationLocal;
  
      private Map<String, String> applicationInfos;
  
      private Map<String, String> orchestratorIds;
  
      private Map<String, String> serviceIds;
  
      private Map<String, Map<String, String>> orchestratorLocationIds;
  
      /* orchestratorId -> { locationID -> { resourceName -> resourceId } } */
      private Map<String, Map<String, Map<String, String>>> orchestratorLocationResourceIds;
  
      private String topologyCloudInfos;
  
      private Map<String, String> preRegisteredOrchestratorProperties;
  
      private Map<String, Object> orchestratorConfiguration;
  
      private Map<String, MetaPropConfiguration> configurationTags;
  
      private String topologyDeploymentId;
  
      private Map<String, String> groupIdToGroupNameMapping = Maps.newHashMap();
  
      private Map<String, String> cloudImageNameToCloudImageIdMapping = Maps.newHashMap();
  
      private Map<String, String> applicationVersionNameToApplicationVersionIdMapping = Maps.newHashMap();
  
      private Map<String, Map<String, String>> environmentInfos;
  
      private OpenStackClient openStackClient;
  
      private AwsClient awsClient;
  
      private String currentWorkflowName;
  
      private String csarGitRepositoryId;
  
      private String currentExternalId;
  
      private Map<String, String> stringContent = new HashMap<String, String>();
  
      private Context() {
          ClasspathResourceLoader classpathResourceLoader = new ClasspathResourceLoader(Thread.currentThread().getContextClassLoader());
          Iterable<cucumber.runtime.io.Resource> properties = classpathResourceLoader.resources("", "alien4cloud-config.yml");
          List<Resource> resources = Lists.newArrayList();
          for (cucumber.runtime.io.Resource property : properties) {
              try {
                  resources.add(new InputStreamResource(property.getInputStream()));
              } catch (IOException e) {
                  throw new ITException("Could not load properties file at [" + property.getPath() + "]", e);
              }
          }
          YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
          if (resources.isEmpty()) {
              resources = Lists.<Resource> newArrayList(new ClassPathResource("alien4cloud-config.yml"));
          }
          factory.setResources(resources.toArray(new Resource[resources.size()]));
          this.appProps = new TestPropertyPlaceholderConfigurer();
          this.appProps.setProperties(factory.getObject());
      }
  
      private static class TestPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
  
          private PropertyPlaceholderHelper.PlaceholderResolver resolver;
  
          private Properties properties;
  
          private final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, valueSeparator,
                  ignoreUnresolvablePlaceholders);
  
          @SneakyThrows
          public String getProperty(String key) {
              if (resolver == null) {
                  properties = mergeProperties();
                  convertProperties(properties);
                  resolver = new PropertyPlaceholderConfigurerResolver(properties);
              }
              String value = this.helper.replacePlaceholders(resolvePlaceholder(key, properties, SYSTEM_PROPERTIES_MODE_OVERRIDE), this.resolver);
              return (value.equals(nullValue) ? null : value);
          }
  
          private class PropertyPlaceholderConfigurerResolver implements PropertyPlaceholderHelper.PlaceholderResolver {
  
              private final Properties props;
  
              private PropertyPlaceholderConfigurerResolver(Properties props) {
                  this.props = props;
              }
  
              @Override
              public String resolvePlaceholder(String placeholderName) {
                  return TestPropertyPlaceholderConfigurer.this.resolvePlaceholder(placeholderName, props, SYSTEM_PROPERTIES_MODE_OVERRIDE);
              }
          }
      }
  
      public void registerGroupId(String groupName, String groupId) {
          groupIdToGroupNameMapping.put(groupName, groupId);
      }
  
      public String getGroupId(String groupName) {
          return groupIdToGroupNameMapping.get(groupName);
      }
  
      public void registerCloudImageId(String cloudImageName, String cloudImageId) {
          cloudImageNameToCloudImageIdMapping.put(cloudImageName, cloudImageId);
      }
  
      public String getCloudImageId(String cloudImageName) {
          return cloudImageNameToCloudImageIdMapping.get(cloudImageName);
      }
  
      public void registerApplicationVersionId(String applicationVersionName, String applicationVersionId) {
          applicationVersionNameToApplicationVersionIdMapping.put(applicationVersionName, applicationVersionId);
      }
  
      public String getApplicationVersionId(String applicationVersionName) {
          return applicationVersionNameToApplicationVersionIdMapping.get(applicationVersionName);
      }
  
      public void registerRestResponse(String restResponse) {
          log.debug("Registering [" + restResponse + "] in the context");
          restResponseLocal = restResponse;
      }
  
      public String getRestResponse() {
          return restResponseLocal;
      }
  
      public String takeRestResponse() {
          String response = restResponseLocal;
          restResponseLocal = null;
          return response;
      }
  
      public void registerCSAR(String csarPath) {
          log.debug("Registering csar [" + csarPath + "] in the context");
          csarLocal = csarPath;
      }
  
      public String getCSAR() {
          String csar = csarLocal;
          csarLocal = null;
          return csar;
      }
  
      public String getAppProperty(String key) {
          return appProps.getProperty(key);
      }
  
      public Path getAlienPath() {
          return Paths.get(getAppProperty("directories.alien"));
      }
  
      public Path getRepositoryDirPath() {
          return Paths.get(getAlienPath() + "/" + getAppProperty("directories.csar_repository"));
      }
  
      public Path getUploadTempDirPath() {
          return Paths.get(getAlienPath() + "/" + getAppProperty("directories.upload_temp"));
      }
  
      public Path getPluginDirPath() {
          return Paths.get(getAlienPath() + "/plugins");
      }
  
      public Path getWorkPath() {
          return Paths.get(getAlienPath() + "/work");
      }
  
      public Path getArtifactDirPath() {
          return Paths.get(getAlienPath() + "/" + getAppProperty("directories.artifact_repository"));
      }
  
      public Path getTmpDirectory() {
          return Paths.get("target/tmp/");
      }
  
      public String getElasticSearchClusterName() {
          return getAppProperty("elasticSearch.clusterName");
      }
  
      public void clearComponentsIds() {
          componentsIdsLocal = null;
      }
  
      public Set<String> getComponentsIds() {
          return componentsIdsLocal;
      }
  
      public Set<String> takeComponentsIds() {
          Set<String> componentsIds = componentsIdsLocal;
          clearComponentsIds();
          return componentsIds;
      }
  
      public void registerComponentId(String componentid) {
          if (componentsIdsLocal == null) {
              componentsIdsLocal = new HashSet<String>();
          }
          log.debug("Registering componentID [" + componentid + "] in the context");
          componentsIdsLocal.add(componentid);
      }
  
      public String getComponentId(String componentid) {
          if (componentsIdsLocal != null && componentsIdsLocal.contains(componentid)) {
              return componentid;
          }
          return null;
      }
  
      public String takeComponentId(String componentid) {
          if (componentsIdsLocal != null && componentsIdsLocal.contains(componentid)) {
              componentsIdsLocal.remove(componentid);
              return componentid;
          }
          return null;
      }
  
      public String getComponentId(int position) {
          if (componentsIdsLocal != null && componentsIdsLocal.size() >= (position - 1)) {
              int index = 0;
              for (String componentID : componentsIdsLocal) {
                  if (index == position) {
                      return componentID;
                  }
                  index++;
              }
          }
          return null;
      }
  
      public String takeComponentId(int position) {
          if (componentsIdsLocal != null && componentsIdsLocal.size() >= (position - 1)) {
              int index = 0;
              for (String componentID : componentsIdsLocal) {
                  if (index == position) {
                      componentsIdsLocal.remove(componentID);
                      return componentID;
                  }
                  index++;
              }
          }
          return null;
      }
  
      public void registerTopologyId(String topologyId) {
          log.debug("Registering topology Id [" + topologyId + "] in the context");
          topologyIdLocal = topologyId;
      }
  
      public String getTopologyId() {
          return topologyIdLocal;
      }
  
      public String takeTopologyId() {
          String topoId = topologyIdLocal;
          topologyIdLocal = null;
          return topoId;
      }
  
      public void registerCsarId(String csarId) {
          log.debug("Registering csarId Id [" + csarId + "] in the context");
          csarIdLocal = csarId;
      }
  
      public String getCsarId() {
          return csarIdLocal;
      }
  
      public String takeCsarId() {
          String csarId = csarIdLocal;
          csarIdLocal = null;
          return csarId;
      }
  
      public void registerApplication(Application application) {
          log.debug("Registering application [" + application.getId() + "] in the context");
          applicationLocal = application;
      }
  
      public Application getApplication() {
          return applicationLocal;
      }
  
      public Application takeApplication() {
          Application app = applicationLocal;
          applicationLocal = null;
          return app;
      }
  
      public EvaluationContext getSpelEvaluationContext() {
          return spelEvaluationContext;
      }
  
      public void buildEvaluationContext(Object object) {
          log.debug("Building evaluation context with object of class [" + object.getClass() + "] and keep it in the context");
          spelEvaluationContext = new StandardEvaluationContext(object);
      }
  
      public void registerService(String serviceId, String serviceName) {
          if (serviceIds == null) {
              serviceIds = Maps.newHashMap();
          }
          serviceIds.put(serviceName, serviceId);
      }
  
      public String getServiceId(String serviceName) {
          return serviceIds.get(serviceName);
      }
  
      public void registerOrchestrator(String orchestratorId, String orchestratorName) {
          if (orchestratorIds != null) {
              orchestratorIds.put(orchestratorName, orchestratorId);
              return;
          }
          orchestratorIds = MapUtil.newHashMap(new String[] { orchestratorName }, new String[] { orchestratorId });
      }
  
      public void unregisterOrchestrator(String orchestratorName) {
          orchestratorIds.remove(orchestratorName);
      }
  
      public String getOrchestratorId(String orchestratorName) {
          return orchestratorIds.get(orchestratorName);
      }
  
      public Collection<String> getOrchestratorIds() {
          if (orchestratorIds != null) {
              return orchestratorIds.values();
          } else {
              return Lists.newArrayList();
          }
      }
  
      public void registerOrchestratorProperties(Map<String, String> deployApplicationProperties) {
          this.preRegisteredOrchestratorProperties = deployApplicationProperties;
      }
  
      public Map<String, String> getPreRegisteredOrchestratorProperties() {
          return preRegisteredOrchestratorProperties;
      }
  
      public Map<String, String> takePreRegisteredOrchestratorProperties() {
          Map<String, String> tmp = preRegisteredOrchestratorProperties;
          preRegisteredOrchestratorProperties = null;
          return tmp;
      }
  
      public Map<String, Object> getOrchestratorConfiguration() {
          return orchestratorConfiguration;
      }
  
      public void setOrchestratorConfiguration(Map<String, Object> orchestratorConfiguration) {
          this.orchestratorConfiguration = orchestratorConfiguration;
      }
  
      public void registerConfigurationTag(String configurationTagName, MetaPropConfiguration tagConfiguration) {
          if (configurationTags != null) {
              configurationTags.put(configurationTagName, tagConfiguration);
              return;
          }
          configurationTags = MapUtil.newHashMap(new String[] { configurationTagName }, new MetaPropConfiguration[] { tagConfiguration });
      }
  
      public MetaPropConfiguration getConfigurationTag(String configurationTagName) {
          return configurationTags.get(configurationTagName);
      }
  
      public MetaPropConfiguration takeConfigurationTag(String configurationTagName) {
          return configurationTags.get(configurationTagName);
      }
  
      public Map<String, MetaPropConfiguration> getConfigurationTags() {
          return configurationTags;
      }
  
      public void registerTopologyDeploymentId(String topoDeploymentId) {
          topologyDeploymentId = topoDeploymentId;
      }
  
      public String getTopologyDeploymentId() {
          return topologyDeploymentId;
      }
  
      public void registerApplicationEnvironmentId(String applicationName, String applicationEnvironmentName, String applicationEnvironmentId) {
          Map<String, Map<String, String>> envsInfoMap = this.environmentInfos;
          if (envsInfoMap != null) {
              Map<String, String> envs = envsInfoMap.get(applicationName);
              if (envs == null) {
                  envs = Maps.newHashMap();
              }
              envs.put(applicationEnvironmentName, applicationEnvironmentId);
              envsInfoMap.put(applicationName, envs);
              this.environmentInfos = envsInfoMap;
              return;
  
          }
          envsInfoMap = Maps.newHashMap();
          envsInfoMap.put(applicationName, MapUtil.newHashMap(new String[] { applicationEnvironmentName }, new String[] { applicationEnvironmentId }));
          this.environmentInfos = envsInfoMap;
      }
  
      public String getApplicationEnvironmentId(String applicationName, String applicationEnvironmentName) {
          return this.environmentInfos.get(applicationName).get(applicationEnvironmentName);
      }
  
      public Map<String, String> getAllEnvironmentForApplication(String applicationName) {
          return this.environmentInfos.get(applicationName);
      }
  
      public void clearEnvironmentInfos() {
          this.environmentInfos = Maps.newHashMap();
      }
  
      public String getDefaultApplicationEnvironmentId(String applicationName) {
          return getApplicationEnvironmentId(applicationName, "Environment");
      }
  
      public void registerApplicationId(String applicationName, String applicationId) {
          if (this.applicationInfos != null) {
              this.applicationInfos.put(applicationName, applicationId);
              return;
          }
          this.applicationInfos = MapUtil.newHashMap(new String[] { applicationName }, new String[] { applicationId });
      }
  
      public String getApplicationId(String applicationName) {
          return this.applicationInfos.get(applicationName);
      }
  
      public void registerTopologyTemplateId(String topologyId) {
          String name = TestUtils.getNameFromId(topologyId);
          if (topologyTemplateId.get(name) == null) {
              topologyTemplateId.put(name, Maps.newHashMap());
          }
          topologyTemplateId.get(name).put(TestUtils.getVersionFromId(topologyId), topologyId);
      }
  
      public String getTopologyTemplateId(String name, String version) {
          if (StringUtils.isBlank(version)) {
              version = VersionUtil.DEFAULT_VERSION_NAME;
          }
          return (String) MapUtil.get(topologyTemplateId, Joiner.on(".").join(name, version).toString());
      }
  
      public OpenStackClient getOpenStackClient() {
          if (this.openStackClient == null) {
              this.openStackClient = new OpenStackClient(this.appProps.getProperty("openstack.user"), this.appProps.getProperty("openstack.password"),
                      this.appProps.getProperty("openstack.tenant"), this.appProps.getProperty("openstack.url"), this.appProps.getProperty("openstack.region"));
          }
          return this.openStackClient;
      }
  
      public AwsClient getAwsClient() {
          if (this.awsClient == null) {
              this.awsClient = new AwsClient();
          }
          return this.awsClient;
      }
  
      public void registerOrchestratorLocation(String orchestratorId, String locationId, String locationName) {
          if (orchestratorLocationIds == null) {
              orchestratorLocationIds = Maps.newHashMap();
          }
          Map<String, String> locations = orchestratorLocationIds.get(orchestratorId);
          if (locations == null) {
              locations = Maps.newHashMap();
              orchestratorLocationIds.put(orchestratorId, locations);
          }
          locations.put(locationName, locationId);
      }
  
      public String getLocationId(String orchestratorId, String locationName) {
          return orchestratorLocationIds.get(orchestratorId).get(locationName);
      }
  
      public void registerOrchestratorLocationResource(String orchestratorId, String locationId, String resourceId, String resourceName) {
          if (orchestratorLocationResourceIds == null) {
              orchestratorLocationResourceIds = Maps.newHashMap();
          }
          Map<String, Map<String, String>> locations = orchestratorLocationResourceIds.get(orchestratorId);
          if (locations == null) {
              locations = Maps.newHashMap();
              orchestratorLocationResourceIds.put(orchestratorId, locations);
          }
          Map<String, String> resources = locations.get(locationId);
          if (resources == null) {
              resources = Maps.newHashMap();
              locations.put(locationId, resources);
          }
          resources.put(resourceName, resourceId);
      }
  
      public String getLocationResourceId(String orchestratorId, String locationId, String resourceName) {
          return orchestratorLocationResourceIds.get(orchestratorId).get(locationId).get(resourceName);
      }
  
      public void setCurrentWorkflowName(String workflowName) {
          currentWorkflowName = workflowName;
      }
  
      public String getCurrentWorkflowName() {
          return currentWorkflowName;
      }
  
      public void setCsarGitRepositoryId(String id) {
          this.csarGitRepositoryId = id;
      }
  
      public String getCsarGitRepositoryId() {
          return this.csarGitRepositoryId;
      }
  
      public void registerStringContent(String key, String value) {
          this.stringContent.put(key, value);
      }
  
      public String getRegisteredStringContent(String key) {
          return this.stringContent.get(key);
      }
  
      public String getCurrentExternalId() {
          return currentExternalId;
      }
  
      public void setCurrentExternalId(String currentExternalId) {
          this.currentExternalId = currentExternalId;
      }
  }
  