From f12f541b11a46934d7db537eb5a3166749f5c4f3 Mon Sep 17 00:00:00 2001
From: Luca Frosini
Date: Thu, 16 Jun 2022 13:54:13 +0200
Subject: [PATCH] Added inital code
---
FUNDING.md | 26 +
.../handler/resourceregistry/Constants.java | 28 +
.../resourceregistry/ContextUtility.java | 87 +++
.../resourceregistry/EServiceHandler.java | 275 ++++++++
.../resourceregistry/HostingNodeHandler.java | 263 +++++++
.../resourcemanager/EServiceManager.java | 410 +++++++++++
.../resourcemanager/HostingNodeManager.java | 659 ++++++++++++++++++
.../LinuxDistributionInfo.java | 93 +++
8 files changed, 1841 insertions(+)
create mode 100644 FUNDING.md
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/Constants.java
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/ContextUtility.java
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/EServiceHandler.java
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/HostingNodeHandler.java
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/EServiceManager.java
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/HostingNodeManager.java
create mode 100644 src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/LinuxDistributionInfo.java
diff --git a/FUNDING.md b/FUNDING.md
new file mode 100644
index 0000000..9e48b94
--- /dev/null
+++ b/FUNDING.md
@@ -0,0 +1,26 @@
+# Acknowledgments
+
+The projects leading to this software have received funding from a series of European Union programmes including:
+
+- the Sixth Framework Programme for Research and Technological Development
+ - [DILIGENT](https://cordis.europa.eu/project/id/004260) (grant no. 004260).
+- the Seventh Framework Programme for research, technological development and demonstration
+ - [D4Science](https://cordis.europa.eu/project/id/212488) (grant no. 212488);
+ - [D4Science-II](https://cordis.europa.eu/project/id/239019) (grant no.239019);
+ - [ENVRI](https://cordis.europa.eu/project/id/283465) (grant no. 283465);
+ - [iMarine](https://cordis.europa.eu/project/id/283644) (grant no. 283644);
+ - [EUBrazilOpenBio](https://cordis.europa.eu/project/id/288754) (grant no. 288754).
+- the H2020 research and innovation programme
+ - [SoBigData](https://cordis.europa.eu/project/id/654024) (grant no. 654024);
+ - [PARTHENOS](https://cordis.europa.eu/project/id/654119) (grant no. 654119);
+ - [EGI-Engage](https://cordis.europa.eu/project/id/654142) (grant no. 654142);
+ - [ENVRI PLUS](https://cordis.europa.eu/project/id/654182) (grant no. 654182);
+ - [BlueBRIDGE](https://cordis.europa.eu/project/id/675680) (grant no. 675680);
+ - [PerformFISH](https://cordis.europa.eu/project/id/727610) (grant no. 727610);
+ - [AGINFRA PLUS](https://cordis.europa.eu/project/id/731001) (grant no. 731001);
+ - [DESIRA](https://cordis.europa.eu/project/id/818194) (grant no. 818194);
+ - [ARIADNEplus](https://cordis.europa.eu/project/id/823914) (grant no. 823914);
+ - [RISIS 2](https://cordis.europa.eu/project/id/824091) (grant no. 824091);
+ - [EOSC-Pillar](https://cordis.europa.eu/project/id/857650) (grant no. 857650);
+ - [Blue Cloud](https://cordis.europa.eu/project/id/862409) (grant no. 862409);
+ - [SoBigData-PlusPlus](https://cordis.europa.eu/project/id/871042) (grant no. 871042);
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/Constants.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/Constants.java
new file mode 100644
index 0000000..57a4920
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/Constants.java
@@ -0,0 +1,28 @@
+package org.gcube.smartgears.handler.resourceregistry;
+
+import org.gcube.smartgears.handler.resourceregistry.resourcemanager.HostingNodeManager;
+
+/**
+ * Library-wide constants.
+ * @author Luca Frosini
+ * @author Lucio Lelii
+ */
+public class Constants {
+
+ public static final String HOSTING_NODE_MANAGER_PROPERTY = HostingNodeManager.class.getSimpleName();
+
+// /**
+// * The name of the context property that contains the EService Resource.
+// */
+// public static final String ESERVICE_MANAGER_PROPERTY = EServiceManager.class.getSimpleName();
+
+ /**
+ * The configuration name of {@link EServiceHandler} and {@link HostingNodeHandler}.
+ */
+ public static final String RESOURCE_MANAGEMENT = "resource-management";
+
+ public static final long default_container_publication_frequency_in_seconds = 60;
+
+ public static final int application_republish_frequency_in_minutes = 20;
+
+}
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/ContextUtility.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/ContextUtility.java
new file mode 100644
index 0000000..500ea0d
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/ContextUtility.java
@@ -0,0 +1,87 @@
+package org.gcube.smartgears.handler.resourceregistry;
+
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.gcube.common.authorization.client.proxy.AuthorizationProxy;
+import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
+import org.gcube.common.scope.api.ScopeProvider;
+import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
+import org.gcube.smartgears.provider.ProviderFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Luca Frosini (ISTI-CNR)
+ */
+public class ContextUtility {
+
+ private static Logger logger = LoggerFactory.getLogger(ContextUtility.class);
+
+ private static AuthorizationProxy authorizationProxy;
+
+ static {
+ authorizationProxy = ProviderFactory.provider().authorizationProxy();
+ }
+
+ public static void resetContex() {
+ SecurityTokenProvider.instance.reset();
+ ScopeProvider.instance.reset();
+ }
+
+ public static void setContextFromToken(String token) {
+ if (token == null || token.compareTo("") == 0) {
+ resetContex();
+ } else {
+ SecurityTokenProvider.instance.set(token);
+ String scope = getContextName(token);
+ ScopeProvider.instance.set(scope);
+ }
+
+ }
+
+ public static String getCurrentContextName() {
+ String token = SecurityTokenProvider.instance.get();
+ return getContextName(token);
+ }
+
+ public static UUID getContextUUID(String token) throws ResourceRegistryException {
+ ContextCache contextCache = ContextCache.getInstance();
+ String contextFullName = getContextName(token);
+ UUID contextUUID = contextCache.getUUIDByFullName(contextFullName);
+ return contextUUID;
+ }
+
+ public static String getContextName(String token) {
+ try {
+ return authorizationProxy.get(token).getContext();
+ } catch (Exception e) {
+ logger.error("Error retrieving context form token {}, it should never happen", token, e);
+ return null;
+ }
+ }
+
+ public static SortedSet getContextFullNamesFromTokens(Set tokens){
+ SortedSet contextFullNames = new TreeSet<>();
+ for(String token : tokens) {
+ String contextFullName = getContextName(token);
+ contextFullNames.add(contextFullName);
+ }
+ return contextFullNames;
+ }
+
+ public static SortedSet getContextUUIDFromTokens(Set tokens) throws ResourceRegistryException {
+ SortedSet contextsUUID = new TreeSet<>();
+ ContextCache contextCache = ContextCache.getInstance();
+ for(String token : tokens) {
+ String contextFullName = getContextName(token);
+ UUID contextUUID = contextCache.getUUIDByFullName(contextFullName);
+ contextsUUID.add(contextUUID);
+ }
+ return contextsUUID;
+ }
+
+}
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/EServiceHandler.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/EServiceHandler.java
new file mode 100644
index 0000000..a84e7ea
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/EServiceHandler.java
@@ -0,0 +1,275 @@
+package org.gcube.smartgears.handler.resourceregistry;
+
+import static org.gcube.common.events.Observes.Kind.resilient;
+import static org.gcube.smartgears.handlers.ProfileEvents.addToContext;
+import static org.gcube.smartgears.handlers.ProfileEvents.removeFromContext;
+import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.activation;
+import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.failure;
+import static org.gcube.smartgears.lifecycle.application.ApplicationLifecycle.stop;
+import static org.gcube.smartgears.utils.Utils.rethrowUnchecked;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
+import org.gcube.common.events.Observes;
+import org.gcube.informationsystem.model.reference.entities.Resource;
+import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
+import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
+import org.gcube.resourcemanagement.model.reference.entities.facets.StateFacet;
+import org.gcube.resourcemanagement.model.reference.entities.resources.EService;
+import org.gcube.smartgears.context.application.ApplicationContext;
+import org.gcube.smartgears.handler.resourceregistry.resourcemanager.EServiceManager;
+import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent.Start;
+import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle;
+import org.gcube.smartgears.lifecycle.application.ApplicationState;
+import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
+import org.gcube.smartgears.utils.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the {@link EService} {@link Resource} of the application.
+ *
+ * The manager:
+ *
+ * - creates the {@link EService} {@link Resource} and the facets it
+ * {@link ConsistsOf} when the application starts for the first time;
+ * - update the {@link StateFacet} when the application becomes active,
+ * and at any lifecycle change thereafter;
+ *
+ *
+ *
+ * @author Luca Frosini (ISTI-CNR)
+ */
+public class EServiceHandler {
+
+ private static final Logger logger = LoggerFactory.getLogger(EServiceHandler.class);
+
+ private ApplicationContext applicationContext;
+ private ScheduledFuture> periodicUpdates;
+
+ protected EServiceManager eServiceManager;
+
+ public EServiceHandler() {
+ super();
+ }
+
+ public void onStart(Start event) {
+ try {
+ logger.info("{} onStart started", this.getClass().getSimpleName());
+ this.applicationContext = event.context();
+ init();
+ registerObservers();
+ schedulePeriodicUpdates();
+ logger.info("{} onStart terminated", this.getClass().getSimpleName());
+ } catch (Throwable re) {
+ logger.error("onStart failed", re);
+ }
+ }
+
+ protected void removeResourceFromOldContexts(Set startContexts, Set resourceContexts) {
+ Set contextsToRemove = new HashSet<>(resourceContexts);
+ contextsToRemove.removeAll(startContexts);
+ for(UUID contextToRemove : contextsToRemove) {
+ try {
+ eServiceManager.removeFromContext(contextToRemove);
+ }catch (Exception e) {
+ try {
+ String contextFullName = ContextCache.getInstance().getContextFullNameByUUID(contextToRemove);
+ logger.warn("Unable to remove {} from Context {} UUID {}", EService.NAME, contextFullName, contextsToRemove, e);
+ }catch (Exception ex) {
+ logger.warn("Unable to remove {} from Context with UUID {}.", EService.NAME, contextsToRemove, e);
+ }
+ }
+ }
+ }
+
+ private void init() {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
+ boolean create = true;
+
+ Set startTokens = applicationContext.configuration().startTokens();
+
+ String firstToken = startTokens.iterator().next();
+ ContextUtility.setContextFromToken(firstToken);
+ eServiceManager = new EServiceManager(applicationContext);
+
+
+ Set startContextsUUID = new HashSet<>();
+ for (String token : startTokens) {
+ UUID contextUUID = ContextUtility.getContextUUID(token);
+ startContextsUUID.add(contextUUID);
+ if (create) {
+ eServiceManager.createEService();
+ create = false;
+ } else {
+ eServiceManager.addToContext(contextUUID);
+ }
+ }
+
+ Set resourceContextsUUID = eServiceManager.getContextsUUID().keySet();
+ removeResourceFromOldContexts(startContextsUUID, resourceContextsUUID);
+
+ } catch (Throwable e) {
+ rethrowUnchecked(e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ logger.info("{} init() terminated", this.getClass().getSimpleName());
+ }
+
+ private void registerObservers() {
+
+ applicationContext.events().subscribe(new Object() {
+
+ @Observes({ activation, stop, failure })
+ void onChanged(ApplicationLifecycle lc) {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
+ if(previousToken==null) {
+ String token = applicationContext.configuration().startTokens().iterator().next();
+ ContextUtility.setContextFromToken(token);
+ }
+ eServiceManager.updateFacets();
+ } catch (Exception e) {
+ logger.error("Failed to update {} State", EService.NAME, e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ }
+
+ @Observes(value = addToContext)
+ void addTo(String token) {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
+ ContextUtility.setContextFromToken(token);
+ UUID contextUUID = ContextUtility.getContextUUID(token);
+ eServiceManager.addToContext(contextUUID);
+ } catch (Exception e) {
+ logger.error("Failed to add {} to current context ({})", EService.NAME,
+ ContextUtility.getCurrentContextName(), e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ }
+
+ @Observes(value = removeFromContext)
+ void removeFrom(String token) {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
+ eServiceManager.removeFromCurrentContext();
+ } catch (Exception e) {
+ logger.error("Failed to remove {} from current context ({})",
+ EService.NAME, ContextUtility.getCurrentContextName(), e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+
+ }
+
+ });
+ }
+
+ private void schedulePeriodicUpdates() {
+
+ // register to cancel updates
+ applicationContext.events().subscribe(
+
+ new Object() {
+
+ // we register it in response to lifecycle events so that we can
+ // stop and resume along with application
+ @Observes(value = { activation }, kind = resilient)
+ synchronized void restartPeriodicUpdates(final ApplicationLifecycle lc) {
+
+ // already running
+ if (periodicUpdates != null) {
+ return;
+ }
+
+ String applicationName = applicationContext.name();
+
+ if (lc.state() == ApplicationState.active) {
+ logger.info("Scheduling periodic updates of {} for application {}",
+ EService.NAME, applicationName);
+ } else {
+ logger.info("Resuming periodic updates of {} for application {}",
+ EService.NAME, applicationName);
+ }
+
+ final Runnable updateTask = new Runnable() {
+ public void run() {
+ String previousToken = SecurityTokenProvider.instance.get();
+ if (previousToken == null) {
+ String token = applicationContext.configuration().startTokens().iterator().next();
+ ContextUtility.setContextFromToken(token);
+ }
+ try {
+ eServiceManager.updateFacets();
+ } catch (Exception e) {
+ logger.error("Cannot complete periodic update of {} for application {}", EService.NAME, applicationName, e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ }
+ }
+ };
+
+ periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask,
+ Constants.application_republish_frequency_in_minutes,
+ Constants.application_republish_frequency_in_minutes, TimeUnit.MINUTES);
+
+ /*
+ * The following line is used for testing purposes during development.
+ * If you uncomment this, you need to comment the line above
+ */
+// periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask, 120, 120, TimeUnit.SECONDS);
+
+ }
+
+ @Observes(value = { stop, failure }, kind = resilient)
+ synchronized void cancelPeriodicUpdates(ContainerLifecycle ignore) {
+
+ if (periodicUpdates != null) {
+
+ String applicationName = applicationContext.name();
+
+ logger.trace("Stopping periodic updates of {} for application {} ",
+ EService.NAME, applicationName);
+
+ try {
+ periodicUpdates.cancel(true);
+ periodicUpdates = null;
+ } catch (Exception e) {
+ logger.warn("Could not stop periodic updates of {} for application {}",
+ EService.NAME, applicationName, e);
+ }
+ }
+ }
+
+ });
+
+ }
+
+ @Override
+ public String toString() {
+ return Constants.RESOURCE_MANAGEMENT;
+ }
+
+}
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/HostingNodeHandler.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/HostingNodeHandler.java
new file mode 100644
index 0000000..1dd0893
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/HostingNodeHandler.java
@@ -0,0 +1,263 @@
+package org.gcube.smartgears.handler.resourceregistry;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.gcube.common.events.Observes.Kind.resilient;
+import static org.gcube.smartgears.handlers.ProfileEvents.addToContext;
+import static org.gcube.smartgears.handlers.ProfileEvents.removeFromContext;
+import static org.gcube.smartgears.lifecycle.container.ContainerLifecycle.activation;
+import static org.gcube.smartgears.lifecycle.container.ContainerLifecycle.failure;
+import static org.gcube.smartgears.lifecycle.container.ContainerLifecycle.part_activation;
+import static org.gcube.smartgears.lifecycle.container.ContainerLifecycle.shutdown;
+import static org.gcube.smartgears.lifecycle.container.ContainerLifecycle.stop;
+import static org.gcube.smartgears.lifecycle.container.ContainerState.active;
+import static org.gcube.smartgears.utils.Utils.rethrowUnchecked;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
+import org.gcube.common.events.Observes;
+import org.gcube.informationsystem.model.reference.entities.Facet;
+import org.gcube.informationsystem.model.reference.entities.Resource;
+import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
+import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
+import org.gcube.resourcemanagement.model.reference.entities.facets.StateFacet;
+import org.gcube.resourcemanagement.model.reference.entities.resources.HostingNode;
+import org.gcube.smartgears.context.Property;
+import org.gcube.smartgears.context.container.ContainerContext;
+import org.gcube.smartgears.handler.resourceregistry.resourcemanager.HostingNodeManager;
+import org.gcube.smartgears.handlers.container.ContainerHandler;
+import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent.Start;
+import org.gcube.smartgears.lifecycle.container.ContainerLifecycle;
+import org.gcube.smartgears.lifecycle.container.ContainerState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the {@link HostingNode} {@link Resource} of the application.
+ *
+ * The manager:
+ *
+ * - creates the {@link HostingNode} {@link Resource} and the facets it
+ * {@link ConsistsOf} when the container starts for the first time;
+ * - update the {@link StateFacet} when the application becomes
+ * active, and at any lifecycle change thereafter;
+ * - schedule a periodic update of {@link Facet}s containing variables
+ * information.
+ *
+ *
+ *
+ * @author Luca Frosini (ISTI-CNR)
+ */
+public class HostingNodeHandler {
+
+ private static Logger logger = LoggerFactory.getLogger(HostingNodeHandler.class);
+
+ private ContainerContext containerContext;
+ private ScheduledFuture> periodicUpdates;
+
+ protected HostingNodeManager hostingNodeManager;
+
+ public HostingNodeHandler() {
+ super();
+
+ }
+
+ public void onStart(Start event) {
+ try {
+ logger.info("{} onStart started", this.getClass().getSimpleName());
+ this.containerContext = event.context();
+ init();
+ registerObservers();
+ schedulePeriodicUpdates();
+ logger.info("{} onStart terminated", this.getClass().getSimpleName());
+ } catch (Throwable re) {
+ logger.error("onStart failed", re);
+ }
+ }
+
+ protected void removeResourceFromOldContexts(Set startContexts, Set resourceContexts) throws ResourceRegistryException {
+ Set contextsToRemove = new HashSet<>(resourceContexts);
+ contextsToRemove.removeAll(startContexts);
+ for(UUID contextToRemove : contextsToRemove) {
+ hostingNodeManager.removeFromContext(contextToRemove);
+ }
+ }
+
+ private void init() {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(HostingNodeHandler.class.getClassLoader());
+ boolean create = true;
+
+ List startTokens = containerContext.configuration().startTokens();
+
+ String firstToken = startTokens.iterator().next();
+ ContextUtility.setContextFromToken(firstToken);
+ hostingNodeManager = new HostingNodeManager(containerContext);
+
+ Set startContextsUUID = new HashSet<>();
+ for (String token : startTokens) {
+ UUID contextUUID = ContextUtility.getContextUUID(token);
+ startContextsUUID.add(contextUUID);
+ if (create) {
+ hostingNodeManager.createHostingNode();
+ containerContext.properties().add(new Property(Constants.HOSTING_NODE_MANAGER_PROPERTY, hostingNodeManager));
+ create = false;
+ } else {
+ hostingNodeManager.addToContext(contextUUID);
+ }
+ }
+
+ Set resourceContextsUUID = hostingNodeManager.getContextsUUID().keySet();
+ removeResourceFromOldContexts(startContextsUUID, resourceContextsUUID);
+
+ } catch (Throwable e) {
+ rethrowUnchecked(e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ logger.info("{} init() terminated", this.getClass().getSimpleName());
+ }
+
+ private void registerObservers() {
+
+ containerContext.events().subscribe(new Object() {
+
+ @Observes({ activation, part_activation, shutdown, stop, failure })
+ void onChanged(ContainerLifecycle cl) {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(HostingNodeHandler.class.getClassLoader());
+ if (previousToken == null) {
+ String token = containerContext.configuration().startTokens().iterator().next();
+ ContextUtility.setContextFromToken(token);
+ }
+ hostingNodeManager.updateFacets();
+ } catch (Exception e) {
+ logger.error("Failed to update {} State", HostingNode.NAME, e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ }
+
+ @Observes(value = addToContext)
+ void addTo(String token) {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(HostingNodeHandler.class.getClassLoader());
+ ContextUtility.setContextFromToken(token);
+ UUID contextUUID = ContextUtility.getContextUUID(token);
+ hostingNodeManager.addToContext(contextUUID);
+ } catch (Exception e) {
+ logger.error("Failed to update Service State", e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ }
+
+ @Observes(value = removeFromContext)
+ void removeFrom(String token) {
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ String previousToken = SecurityTokenProvider.instance.get();
+ try {
+ Thread.currentThread().setContextClassLoader(HostingNodeHandler.class.getClassLoader());
+ ContextUtility.setContextFromToken(token);
+ UUID contextUUID = ContextUtility.getContextUUID(token);
+ hostingNodeManager.removeFromContext(contextUUID);
+ } catch (Exception e) {
+ logger.error("Failed to update Service State", e);
+ } finally {
+ ContextUtility.setContextFromToken(previousToken);
+ Thread.currentThread().setContextClassLoader(contextCL);
+ }
+ }
+
+ });
+ }
+
+ private void schedulePeriodicUpdates() {
+ // register to cancel updates
+ containerContext.events().subscribe(
+
+ new Object() {
+
+ final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
+
+ // we register it in response to lifecycle events so that we can
+ // stop and resume along with application
+ @Observes(value = { activation, part_activation }, kind = resilient)
+ synchronized void restartPeriodicUpdates(ContainerLifecycle cl) {
+
+ // already running
+ if (periodicUpdates != null) {
+ return;
+ }
+
+ if (cl.state() == active) {
+ logger.info("Scheduling periodic updates of {}", HostingNode.NAME);
+ } else {
+ logger.info("Resuming periodic updates of {}", HostingNode.NAME);
+ }
+
+ final Runnable updateTask = new Runnable() {
+ public void run() {
+ String previousToken = SecurityTokenProvider.instance.get();
+ if (previousToken == null) {
+ String token = containerContext.configuration().startTokens().iterator().next();
+ ContextUtility.setContextFromToken(token);
+ }
+ try {
+ hostingNodeManager.updateFacets();
+ } catch (Exception e) {
+ logger.error("Cannot complete periodic update of {}", HostingNode.NAME, e);
+ }finally {
+ ContextUtility.setContextFromToken(previousToken);
+ }
+ }
+ };
+
+ periodicUpdates = service.scheduleAtFixedRate(updateTask, 3,
+ containerContext.configuration().publicationFrequency(), SECONDS);
+
+ }
+
+ @Observes(value = { stop, failure, shutdown }, kind = resilient)
+ synchronized void cancelPeriodicUpdates(ContainerLifecycle cl) {
+
+ if (periodicUpdates != null) {
+ logger.trace("Stopping periodic updates of {}", HostingNode.NAME);
+ try {
+ periodicUpdates.cancel(true);
+ service.shutdownNow();
+ periodicUpdates = null;
+ } catch (Exception e) {
+ logger.warn("Could not stop periodic updates of {}", HostingNode.NAME, e);
+ }
+ }
+ }
+
+ });
+
+ }
+
+ @Override
+ public String toString() {
+ return Constants.RESOURCE_MANAGEMENT;
+ }
+
+}
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/EServiceManager.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/EServiceManager.java
new file mode 100644
index 0000000..0e45143
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/EServiceManager.java
@@ -0,0 +1,410 @@
+package org.gcube.smartgears.handler.resourceregistry.resourcemanager;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.servlet.ServletRegistration;
+
+import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
+import org.gcube.informationsystem.model.impl.properties.HeaderImpl;
+import org.gcube.informationsystem.model.impl.properties.PropagationConstraintImpl;
+import org.gcube.informationsystem.model.reference.entities.Facet;
+import org.gcube.informationsystem.model.reference.entities.Resource;
+import org.gcube.informationsystem.model.reference.properties.Header;
+import org.gcube.informationsystem.model.reference.properties.PropagationConstraint;
+import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.AddConstraint;
+import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.RemoveConstraint;
+import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
+import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.AvailableInAnotherContextException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.entities.resource.ResourceNotFoundException;
+import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClient;
+import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClientFactory;
+import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisher;
+import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisherFactory;
+import org.gcube.informationsystem.utils.ElementMapper;
+import org.gcube.resourcemanagement.model.impl.entities.facets.AccessPointFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.EventFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.SoftwareFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.StateFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.resources.EServiceImpl;
+import org.gcube.resourcemanagement.model.impl.properties.ValueSchemaImpl;
+import org.gcube.resourcemanagement.model.impl.relations.consistsof.IsIdentifiedByImpl;
+import org.gcube.resourcemanagement.model.impl.relations.isrelatedto.ActivatesImpl;
+import org.gcube.resourcemanagement.model.reference.entities.facets.AccessPointFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.EventFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.MemoryFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.SoftwareFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.StateFacet;
+import org.gcube.resourcemanagement.model.reference.entities.resources.EService;
+import org.gcube.resourcemanagement.model.reference.entities.resources.HostingNode;
+import org.gcube.resourcemanagement.model.reference.properties.ValueSchema;
+import org.gcube.resourcemanagement.model.reference.relations.consistsof.HasPersistentMemory;
+import org.gcube.resourcemanagement.model.reference.relations.consistsof.HasVolatileMemory;
+import org.gcube.resourcemanagement.model.reference.relations.consistsof.IsIdentifiedBy;
+import org.gcube.resourcemanagement.model.reference.relations.isrelatedto.Activates;
+import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
+import org.gcube.smartgears.configuration.container.ContainerConfiguration;
+import org.gcube.smartgears.context.application.ApplicationContext;
+import org.gcube.smartgears.handler.resourceregistry.Constants;
+import org.gcube.smartgears.handler.resourceregistry.ContextUtility;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Luca Frosini (ISTI-CNR)
+ */
+public class EServiceManager {
+
+ private static Logger logger = LoggerFactory.getLogger(HostingNodeManager.class);
+
+ private static List servletExcludes = Arrays.asList("default", "jsp");
+
+ private ResourceRegistryPublisher resourceRegistryPublisher;
+
+ private EService eService;
+
+ private ApplicationContext applicationContext;
+
+ public EServiceManager(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ this.resourceRegistryPublisher = ResourceRegistryPublisherFactory.create();
+ }
+
+ public void addEServiceToCurrentContext() throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ String currentToken = SecurityTokenProvider.instance.get();
+ UUID contextUUID = ContextUtility.getContextUUID(currentToken);
+
+ /* Trying to get a context which is not the current to properly invoke the addToContext without forcing the operation using addResourceToCurrentContext */
+ boolean anotherContextSet = false;
+ Set startTokens = applicationContext.configuration().startTokens();
+ for (String token : startTokens) {
+ UUID anotherContextUUID = ContextUtility.getContextUUID(token);
+ if(anotherContextUUID.compareTo(contextUUID)!=0) {
+ ContextUtility.setContextFromToken(token);
+ anotherContextSet = true;
+ break;
+ }
+ }
+
+ UUID uuid = UUID.fromString(applicationContext.id());
+ try {
+ if(anotherContextSet) {
+ resourceRegistryPublisher.addResourceToContext(EService.NAME, uuid, contextUUID, false);
+ }else {
+ resourceRegistryPublisher.addResourceToCurrentContext(HostingNode.NAME, uuid, false);
+ }
+ logger.info("{} with UUID {} successfully added to context ({})", EService.NAME, uuid, ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to add {} with UUID {} to context ({})", EService.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }finally {
+ ContextUtility.setContextFromToken(currentToken);
+ }
+ }
+
+ public void addHostingNodeToCurrentContext() throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ String currentToken = SecurityTokenProvider.instance.get();
+ UUID contextUUID = ContextUtility.getContextUUID(currentToken);
+
+ /* Trying to get a context which is not the current to properly invoke the addToContext without forcing the operation using addResourceToCurrentContext */
+ boolean anotherContextSet = false;
+ Set startTokens = applicationContext.configuration().startTokens();
+ for (String token : startTokens) {
+ UUID anotherContextUUID = ContextUtility.getContextUUID(token);
+ if(anotherContextUUID.compareTo(contextUUID)!=0) {
+ ContextUtility.setContextFromToken(token);
+ anotherContextSet = true;
+ break;
+ }
+ }
+
+ UUID uuid = UUID.fromString(applicationContext.container().id());
+ try {
+ if(anotherContextSet) {
+ resourceRegistryPublisher.addResourceToContext(HostingNode.NAME, uuid, contextUUID, false);
+ }else {
+ resourceRegistryPublisher.addResourceToCurrentContext(HostingNode.NAME, uuid, false);
+ }
+ logger.info("{} with UUID {} successfully added to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }finally {
+ ContextUtility.setContextFromToken(currentToken);
+ }
+ }
+
+ public void addToContext(UUID contextUUID) throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ UUID uuid = UUID.fromString(applicationContext.container().id());
+ try {
+ resourceRegistryPublisher.addToContext(HostingNode.NAME, uuid, contextUUID, false);
+ logger.info("{} with UUID {} successfully added to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }
+ }
+
+ public void removeFromCurrentContext()
+ throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ UUID uuid = UUID.fromString(applicationContext.container().id());
+ try {
+ resourceRegistryPublisher.removeResourceFromCurrentContext(HostingNode.NAME, uuid, false);
+ logger.info("{} with UUID {} successfully removed from context ({})", HostingNode.NAME, uuid,
+ ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to remove {} with UUID {} from context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }
+ }
+
+ public void removeFromContext(UUID contextUUID)
+ throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ String contextFullName = ContextCache.getInstance().getContextFullNameByUUID(contextUUID);
+ UUID uuid = UUID.fromString(applicationContext.container().id());
+ try {
+ resourceRegistryPublisher.removeResourceFromContext(HostingNode.NAME, uuid, contextUUID, false);
+ logger.info("{} with UUID {} successfully removed from context ({})", HostingNode.NAME, uuid, contextFullName);
+ } catch (Exception e) {
+ logger.error("Unable to remove {} from context ({})", HostingNode.NAME, uuid, contextFullName, e);
+ }
+ }
+
+ private String getBaseAddress() {
+ ApplicationConfiguration configuration = applicationContext.configuration();
+ ContainerConfiguration container = applicationContext.container().configuration();
+ String baseAddress;
+ if (configuration.proxied()) {
+ String protocol = configuration.proxyAddress().protocol();
+ String port = configuration.proxyAddress().port() != null ? ":" + configuration.proxyAddress().port() : "";
+
+ baseAddress = String.format("%s://%s%s%s", protocol, configuration.proxyAddress().hostname(), port,
+ applicationContext.application().getContextPath());
+ } else {
+ String protocol = container.protocol();
+ int port = container.port();
+
+ baseAddress = String.format("%s://%s:%d%s", protocol, container.hostname(), port,
+ applicationContext.application().getContextPath());
+ }
+ return baseAddress;
+ }
+
+ public String getState() {
+ return applicationContext.lifecycle().state().remoteForm().toLowerCase();
+ }
+
+ private StateFacet getStateFacet(StateFacet stateFacet, Date date) {
+ if (stateFacet == null) {
+ stateFacet = new StateFacetImpl();
+ }
+ String state = getState();
+ stateFacet.setValue(state);
+ stateFacet.setAdditionalProperty("date", date);
+ return stateFacet;
+ }
+
+ private EventFacet getEventFacet(Date date) {
+ EventFacet eventFacet = new EventFacetImpl();
+ eventFacet.setDate(date);
+ String state = getState();
+ eventFacet.setEvent(state);
+ return eventFacet;
+ }
+
+ private EService instantiateEService() {
+ logger.info("Creating {} for {}", EService.NAME, applicationContext.name());
+
+ ApplicationConfiguration applicationConfiguration = applicationContext.configuration();
+ String id = applicationContext.id();
+
+ UUID uuid = UUID.fromString(id);
+ EService eService = new EServiceImpl();
+ Header header = new HeaderImpl(uuid);
+ eService.setHeader(header);
+
+ SoftwareFacet softwareFacet = new SoftwareFacetImpl();
+ softwareFacet.setDescription(applicationConfiguration.description());
+ softwareFacet.setGroup(applicationConfiguration.serviceClass());
+ softwareFacet.setName(applicationConfiguration.name());
+ softwareFacet.setVersion(applicationConfiguration.version());
+
+ IsIdentifiedBy isIdentifiedBy = new IsIdentifiedByImpl(
+ eService, softwareFacet);
+ eService.addFacet(isIdentifiedBy);
+
+ String baseAddress = getBaseAddress();
+ for (ServletRegistration servlet : applicationContext.application().getServletRegistrations().values()) {
+ if (!servletExcludes.contains(servlet.getName())) {
+ for (String mapping : servlet.getMappings()) {
+
+ String address = baseAddress
+ + (mapping.endsWith("*") ? mapping.substring(0, mapping.length() - 2) : mapping);
+
+ AccessPointFacet accessPointFacet = new AccessPointFacetImpl();
+ accessPointFacet.setEntryName(servlet.getName());
+ accessPointFacet.setEndpoint(URI.create(address));
+ ValueSchema valueSchema = new ValueSchemaImpl();
+ valueSchema.setValue("gcube-token");
+
+ accessPointFacet.setAuthorization(valueSchema);
+
+ eService.addFacet(accessPointFacet);
+ }
+ }
+ }
+
+ Date date = Calendar.getInstance().getTime();
+
+ StateFacet stateFacet = getStateFacet(null, date);
+ eService.addFacet(stateFacet);
+
+ EventFacet eventFacet = getEventFacet(date);;
+ eService.addFacet(eventFacet);
+
+ return eService;
+ }
+
+ public EService createEService() throws ResourceRegistryException {
+ ResourceRegistryClient resourceRegistryClient = ResourceRegistryClientFactory.create();
+ UUID eServiceUUID = UUID.fromString(applicationContext.id());
+ try {
+ ResourceRegistryClientFactory.includeContextsInInstanceHeader(true);
+ eService = resourceRegistryClient.getInstance(EService.class, eServiceUUID);
+ updateFacets();
+ } catch (NotFoundException e) {
+ eService = instantiateEService();
+ eService = createActivatesRelation(eService).getTarget();
+ } catch (AvailableInAnotherContextException e) {
+ addHostingNodeToCurrentContext();
+ try {
+ eService = resourceRegistryClient.getInstance(EService.class, eServiceUUID);
+ } catch (AvailableInAnotherContextException ex) {
+ addEServiceToCurrentContext();
+ eService = resourceRegistryClient.getInstance(EService.class, eServiceUUID);
+ // addToContext() is executed on HostingNode.
+ // If the EService is still not available we need to create activates
+ // relation because does not exists otherwise the EService should
+ // already be in the context due to propagation constraint.
+ eService = createActivatesRelation(eService).getTarget();
+ }
+ updateFacets();
+ } catch (ResourceRegistryException e) {
+ throw e;
+ }
+ return eService;
+ }
+
+ public EService updateFacets() throws ResourceRegistryException {
+ logger.debug("Updating {} for {}", EService.NAME, applicationContext.configuration().name());
+
+ StateFacet stateFacet = null;
+ EventFacet eventFacet = null;
+
+ Date date = Calendar.getInstance().getTime();
+
+ List> consistsOfToRemove = new ArrayList<>();
+
+ List> consistsOfList = eService.getConsistsOf();
+ for (ConsistsOf extends Resource, ? extends Facet> c : consistsOfList) {
+ if (c.getTarget() instanceof StateFacet) {
+ stateFacet = (StateFacet) c.getTarget();
+ stateFacet = getStateFacet(stateFacet, date);
+ continue;
+ }
+
+ if(c.getTarget() instanceof EventFacet) {
+ eventFacet = (EventFacet) c.getTarget();
+ String value = eventFacet.getEvent();
+ if(value.compareTo(getState())==0) {
+ // This facet must be updated (the date must be updated) so it must not be removed from udpate
+ eventFacet.setDate(date);
+ continue;
+ }else {
+ // This is not the event facet to be updated
+ // Setting the variable to null so it will be created if the event does not already exists.
+ eventFacet = null;
+ }
+ }
+
+ consistsOfToRemove.add(c);
+
+ }
+
+ // Resource Update has effect only on specified facets.
+ // Removing the ones that have not to be changed.
+ consistsOfList.removeAll(consistsOfToRemove);
+
+
+ if(eventFacet == null) {
+ eventFacet = getEventFacet(date);
+ eService.addFacet(eventFacet);
+ }
+
+ try {
+ logger.trace("Updating {} for {} : {}", EService.NAME, applicationContext.configuration().name(), ElementMapper.marshal(eService));
+ }catch (Exception e) {
+
+ }
+
+ try {
+ eService = resourceRegistryPublisher.updateResource(eService);
+ }catch (ResourceRegistryException e) {
+ logger.error("Error trying to publish hosting node", e);
+ }
+
+ return eService;
+ }
+
+ private Activates createActivatesRelation(EService eService)
+ throws ResourceRegistryException {
+
+ HostingNode hostingNode = ((HostingNodeManager) applicationContext.container().properties().lookup(Constants.HOSTING_NODE_MANAGER_PROPERTY).value()).getHostingNode();
+
+ PropagationConstraint propagationConstraint = new PropagationConstraintImpl();
+ propagationConstraint.setRemoveConstraint(RemoveConstraint.cascade);
+ propagationConstraint.setAddConstraint(AddConstraint.propagate);
+ Activates activates = new ActivatesImpl<>(hostingNode, eService, propagationConstraint);
+
+ try {
+ logger.trace("Going to create {} and {} for application {} : {}", Activates.NAME, EService.NAME, applicationContext.configuration().name(), ElementMapper.marshal(activates));
+ }catch (Exception e) {
+
+ }
+
+ try {
+ activates = resourceRegistryPublisher.createIsRelatedTo(activates);
+ hostingNode.attachResource(activates);
+ } catch (NotFoundException e) {
+ logger.error("THIS IS REALLY STRANGE. YOU SHOULD NOT BE HERE. Error while creating {}.", activates, e);
+ throw e;
+ } catch (ResourceRegistryException e) {
+ logger.error("Error while creating {}", activates, e);
+ throw e;
+ }
+
+ return activates;
+
+ }
+
+// public void removeEService() throws ResourceRegistryException {
+// try {
+// resourceRegistryPublisher.delete(eService);
+// } catch (ResourceRegistryException e) {
+// logger.error("Unable to delete {}. Going to set the state to {}", applicationContext.name(), getState());
+// updateFacets();
+// }
+// }
+
+ public Map getContextsUUID() throws Exception {
+ return resourceRegistryPublisher.getResourceContexts(eService);
+ }
+
+}
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/HostingNodeManager.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/HostingNodeManager.java
new file mode 100644
index 0000000..59a60ae
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/HostingNodeManager.java
@@ -0,0 +1,659 @@
+package org.gcube.smartgears.handler.resourceregistry.resourcemanager;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.gcube.com.fasterxml.jackson.databind.JsonNode;
+import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
+import org.gcube.informationsystem.model.impl.properties.HeaderImpl;
+import org.gcube.informationsystem.model.reference.entities.Facet;
+import org.gcube.informationsystem.model.reference.entities.Resource;
+import org.gcube.informationsystem.model.reference.properties.Header;
+import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
+import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.AvailableInAnotherContextException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.entities.resource.ResourceNotFoundException;
+import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClient;
+import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClientFactory;
+import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisher;
+import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisherFactory;
+import org.gcube.informationsystem.utils.ElementMapper;
+import org.gcube.resourcemanagement.model.impl.entities.facets.CPUFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.EventFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.LocationFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.MemoryFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.NetworkingFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.SimplePropertyFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.SoftwareFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.facets.StateFacetImpl;
+import org.gcube.resourcemanagement.model.impl.entities.resources.HostingNodeImpl;
+import org.gcube.resourcemanagement.model.impl.relations.consistsof.HasPersistentMemoryImpl;
+import org.gcube.resourcemanagement.model.impl.relations.consistsof.HasVolatileMemoryImpl;
+import org.gcube.resourcemanagement.model.impl.relations.consistsof.IsIdentifiedByImpl;
+import org.gcube.resourcemanagement.model.reference.entities.facets.CPUFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.EventFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.LocationFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.MemoryFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.MemoryFacet.MemoryUnit;
+import org.gcube.resourcemanagement.model.reference.entities.facets.NetworkingFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.SimplePropertyFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.SoftwareFacet;
+import org.gcube.resourcemanagement.model.reference.entities.facets.StateFacet;
+import org.gcube.resourcemanagement.model.reference.entities.resources.HostingNode;
+import org.gcube.resourcemanagement.model.reference.relations.consistsof.HasPersistentMemory;
+import org.gcube.resourcemanagement.model.reference.relations.consistsof.HasVolatileMemory;
+import org.gcube.resourcemanagement.model.reference.relations.consistsof.IsIdentifiedBy;
+import org.gcube.smartgears.configuration.container.ContainerConfiguration;
+import org.gcube.smartgears.configuration.container.Site;
+import org.gcube.smartgears.configuration.library.SmartGearsConfiguration;
+import org.gcube.smartgears.context.container.ContainerContext;
+import org.gcube.smartgears.handler.resourceregistry.ContextUtility;
+import org.gcube.smartgears.lifecycle.container.ContainerState;
+import org.gcube.smartgears.provider.ProviderFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Luca Frosini (ISTI-CNR)
+ */
+public class HostingNodeManager {
+
+ private static Logger logger = LoggerFactory.getLogger(HostingNodeManager.class);
+
+ public static final String MEMORY_TYPE = "memoryType";
+ public static final String MEMORY_TYPE_RAM = "RAM";
+ public static final String MEMORY_TYPE_JVM = "JVM";
+ public static final String JVM_MAX_MEMORY = "jvmMaxMemory";
+
+ public static final String MESSAGE = "message";
+
+ private ContainerContext containerContext;
+ private ResourceRegistryPublisher resourceRegistryPublisher;
+ private HostingNode hostingNode;
+
+ public HostingNodeManager(ContainerContext containerContext) {
+ this.containerContext = containerContext;
+ this.resourceRegistryPublisher = ResourceRegistryPublisherFactory.create();
+ }
+
+ public HostingNode getHostingNode() {
+ return hostingNode;
+ }
+
+ public void addToCurrentContext() throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ String currentToken = SecurityTokenProvider.instance.get();
+ UUID contextUUID = ContextUtility.getContextUUID(currentToken);
+
+ /* Trying to get a context which is not the current to properly invoke the addToContext without forcing the operation using addResourceToCurrentContext */
+ boolean anotherContextSet = false;
+ List startTokens = containerContext.configuration().startTokens();
+ for (String token : startTokens) {
+ UUID anotherContextUUID = ContextUtility.getContextUUID(token);
+ if(anotherContextUUID.compareTo(contextUUID)!=0) {
+ ContextUtility.setContextFromToken(token);
+ anotherContextSet = true;
+ break;
+ }
+ }
+
+ UUID uuid = UUID.fromString(containerContext.id());
+ try {
+ if(anotherContextSet) {
+ resourceRegistryPublisher.addToContext(HostingNode.NAME, uuid, contextUUID, false);
+ }else {
+ resourceRegistryPublisher.addResourceToCurrentContext(HostingNode.NAME, uuid, false);
+ }
+ logger.info("{} with UUID {} successfully added to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }
+ }
+
+ public void addToContext(UUID contextUUID) throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ UUID uuid = UUID.fromString(containerContext.id());
+ try {
+ resourceRegistryPublisher.addToContext(HostingNode.NAME, uuid, contextUUID, false);
+ logger.info("{} with UUID {} successfully added to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }
+ }
+
+ public void removeFromCurrentContext()
+ throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ UUID uuid = UUID.fromString(containerContext.id());
+ try {
+ resourceRegistryPublisher.removeResourceFromCurrentContext(HostingNode.NAME, uuid, false);
+ logger.info("{} with UUID {} successfully removed from context ({})", HostingNode.NAME, uuid,
+ ContextUtility.getCurrentContextName());
+ } catch (Exception e) {
+ logger.error("Unable to remove {} with UUID {} from context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
+ }
+ }
+
+ public void removeFromContext(UUID contextUUID)
+ throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
+ String contextFullName = ContextCache.getInstance().getContextFullNameByUUID(contextUUID);
+ UUID uuid = UUID.fromString(containerContext.id());
+ try {
+ resourceRegistryPublisher.removeResourceFromContext(HostingNode.NAME, uuid, contextUUID, false);
+ logger.info("{} with UUID {} successfully removed from context ({})", HostingNode.NAME, uuid, contextFullName);
+ } catch (Exception e) {
+ logger.error("Unable to remove {} from context ({})", HostingNode.NAME, uuid, contextFullName, e);
+ }
+ }
+
+ public HostingNode updateFacets() throws ResourceRegistryException {
+ logger.debug("Updating {}", HostingNode.NAME);
+
+ MemoryFacet ramFacet = null;
+ MemoryFacet jvmMemoryFacet = null;
+ MemoryFacet disk = null;
+ StateFacet stateFacet = null;
+ EventFacet eventFacet = null;
+
+ Date date = Calendar.getInstance().getTime();
+
+ List> consistsOfToRemove = new ArrayList<>();
+
+ List> consistsOfList = hostingNode.getConsistsOf();
+ for (ConsistsOf extends Resource, ? extends Facet> c : consistsOfList) {
+ if (c.getTarget() instanceof StateFacet) {
+ stateFacet = (StateFacet) c.getTarget();
+ stateFacet = getStateFacet(stateFacet, date);
+ continue;
+ }
+
+ if (c instanceof HasVolatileMemory) {
+ String memoryType = (String) c.getAdditionalProperty(MEMORY_TYPE);
+ if (memoryType.compareTo(MEMORY_TYPE_RAM) == 0) {
+ ramFacet = (MemoryFacet) c.getTarget();
+ ramFacet = getRamInfo(ramFacet);
+ continue;
+ }
+
+ if (memoryType.compareTo(MEMORY_TYPE_JVM) == 0) {
+ jvmMemoryFacet = (MemoryFacet) c.getTarget();
+ jvmMemoryFacet = getJVMMemoryInfo(jvmMemoryFacet);
+ continue;
+ }
+
+ }
+
+ if (c instanceof HasPersistentMemory) {
+ disk = (MemoryFacet) c.getTarget();
+ disk = getDiskSpace(disk);
+ continue;
+ }
+
+ if(c.getTarget() instanceof EventFacet) {
+ eventFacet = (EventFacet) c.getTarget();
+ String value = eventFacet.getEvent();
+ if(value.compareTo(getState())==0) {
+ // This facet must be updated (the date must be updated) so it must not be removed from udpate
+ eventFacet.setDate(date);
+ continue;
+ }else {
+ // This is not the event facet to be updated
+ // Setting the variable to null so it will be created if the event does not already exists.
+ eventFacet = null;
+ }
+ }
+
+ consistsOfToRemove.add(c);
+
+ }
+
+ // Resource Update has effect only on specified facets.
+ // Removing the ones that have not to be changed.
+ consistsOfList.removeAll(consistsOfToRemove);
+
+ if(eventFacet == null) {
+ eventFacet = getEventFacet(date);
+ hostingNode.addFacet(eventFacet);
+ }
+
+ try {
+ hostingNode = resourceRegistryPublisher.updateResource(hostingNode);
+ } catch (ResourceRegistryException e) {
+ logger.error("error trying to publish hosting node", e);
+ }
+
+ return hostingNode;
+ }
+
+ public static SoftwareFacet getOperativeSystem() {
+ SoftwareFacet osSoftwareFacet = new SoftwareFacetImpl();
+ OperatingSystemMXBean mxbean = ManagementFactory.getOperatingSystemMXBean();
+ String osName = mxbean.getName();
+ osSoftwareFacet.setGroup(osName); // softwareFacet.setGroup(System.getProperty("os.name"));
+ osSoftwareFacet.setName(mxbean.getArch()); // softwareFacet.setName(System.getProperty("os.arch"));
+ osSoftwareFacet.setVersion(mxbean.getVersion()); // softwareFacet.setVersion(System.getProperty("os.version"));
+
+ JsonNode jsonNode = ElementMapper.getObjectMapper().valueToTree(osSoftwareFacet);
+ Set fieldNames = new TreeSet<>();
+ Iterator it = jsonNode.fieldNames();
+ while (it.hasNext()) fieldNames.add(it.next());
+
+ if(osName.compareTo("Linux")==0) {
+ // Adding Linux Distribution Info
+ LinuxDistributionInfo linuxDistributionInfo = new LinuxDistributionInfo();
+ Map map = linuxDistributionInfo.getInfo();
+ Set keys = map.keySet();
+ for(String key : keys) {
+ String k = key;
+ if(fieldNames.contains(key)) {
+ k = "linuxDistribution-" + k;
+ }
+ osSoftwareFacet.setAdditionalProperty(k, map.get(key));
+ }
+ }
+
+ return osSoftwareFacet;
+ }
+
+ private HostingNode instantiateHostingNode() {
+ logger.info("Creating {}", HostingNode.NAME);
+
+ ContainerConfiguration containerConfiguration = containerContext.configuration();
+ String id = containerContext.id();
+
+ UUID uuid = UUID.fromString(id);
+ HostingNode hostingNode = new HostingNodeImpl();
+ Header header = new HeaderImpl(uuid);
+ hostingNode.setHeader(header);
+
+ NetworkingFacet networkingFacet = new NetworkingFacetImpl();
+ try {
+ networkingFacet.setIPAddress(InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ logger.warn("unable to detect the IP address of the host");
+ }
+ String hostname = containerConfiguration.hostname();
+ networkingFacet.setHostName(hostname);
+ networkingFacet.setDomainName(getDomain(hostname));
+
+ networkingFacet.setAdditionalProperty("Port", containerConfiguration.port());
+ IsIdentifiedBy isIdentifiedBy = new IsIdentifiedByImpl<>(hostingNode,
+ networkingFacet, null);
+ hostingNode.addFacet(isIdentifiedBy);
+
+ List cpuFacets = getCPUFacets();
+ for (CPUFacet cpuFacet : cpuFacets) {
+ hostingNode.addFacet(cpuFacet);
+ }
+
+ SoftwareFacet osSoftwareFacet = getOperativeSystem();
+ hostingNode.addFacet(osSoftwareFacet);
+
+
+ SmartGearsConfiguration config = ProviderFactory.provider().smartgearsConfiguration();
+ SoftwareFacet smartgearsSoftwareFacet = new SoftwareFacetImpl();
+ smartgearsSoftwareFacet.setGroup("gCube");
+ smartgearsSoftwareFacet.setName("SmartGears");
+ smartgearsSoftwareFacet.setVersion(config.version());
+ hostingNode.addFacet(smartgearsSoftwareFacet);
+
+ SoftwareFacet smartgearsDistributionSoftwareFacet = new SoftwareFacetImpl();
+ smartgearsDistributionSoftwareFacet.setGroup("gCube");
+ smartgearsDistributionSoftwareFacet.setName("SmartGearsDistribution");
+ String smartgearsDistributionVersion = containerConfiguration.properties().get("SmartGearsDistribution");
+ smartgearsDistributionSoftwareFacet.setVersion(smartgearsDistributionVersion);
+ smartgearsDistributionSoftwareFacet.setAdditionalProperty("publication-frequency",
+ String.valueOf(containerConfiguration.publicationFrequency()));
+ hostingNode.addFacet(smartgearsDistributionSoftwareFacet);
+
+
+ SoftwareFacet javaSoftwareFacet = new SoftwareFacetImpl();
+ javaSoftwareFacet.setGroup(System.getProperty("java.vendor"));
+ javaSoftwareFacet.setName("Java");
+ javaSoftwareFacet.setVersion(System.getProperty("java.version"));
+ javaSoftwareFacet.setAdditionalProperty("java.vendor.url", System.getProperty("java.vendor.url"));
+ javaSoftwareFacet.setAdditionalProperty("java.specification.version", System.getProperty("java.specification.version"));
+ hostingNode.addFacet(javaSoftwareFacet);
+
+ SimplePropertyFacet simplePropertyFacet = addEnvironmentVariables(containerConfiguration);
+ hostingNode.addFacet(simplePropertyFacet);
+
+ Date date = Calendar.getInstance().getTime();
+
+ StateFacet stateFacet = getStateFacet(null, date);
+ hostingNode.addFacet(stateFacet);
+
+ EventFacet eventFacet = getEventFacet(date);
+ hostingNode.addFacet(eventFacet);
+
+ MemoryFacet ramFacet = getRamInfo(null);
+ HasVolatileMemory hasVolatileRAMMemory = new HasVolatileMemoryImpl(
+ hostingNode, ramFacet, null);
+ hasVolatileRAMMemory.setAdditionalProperty(MEMORY_TYPE, MEMORY_TYPE_RAM);
+ hostingNode.addFacet(hasVolatileRAMMemory);
+
+ MemoryFacet jvmMemoryFacet = getJVMMemoryInfo(null);
+ HasVolatileMemory hasVolatileJVMMemory = new HasVolatileMemoryImpl(
+ hostingNode, jvmMemoryFacet, null);
+ hasVolatileJVMMemory.setAdditionalProperty(MEMORY_TYPE, MEMORY_TYPE_JVM);
+ hostingNode.addFacet(hasVolatileJVMMemory);
+
+ MemoryFacet diskFacet = getDiskSpace(null);
+ HasPersistentMemory hasPersistentMemory = new HasPersistentMemoryImpl(
+ hostingNode, diskFacet, null);
+ hostingNode.addFacet(hasPersistentMemory);
+
+ LocationFacet locationFacet = new LocationFacetImpl();
+ Site site = containerConfiguration.site();
+ locationFacet.setCountry(site.country());
+ locationFacet.setLocation(site.location());
+ locationFacet.setLatitude(site.latitude());
+ locationFacet.setLongitude(site.longitude());
+ hostingNode.addFacet(locationFacet);
+
+ logger.info("{} with UUID {} instantiated", HostingNode.NAME, uuid);
+ return hostingNode;
+ }
+
+ public HostingNode createHostingNode() throws ResourceRegistryException {
+ ResourceRegistryClient resourceRegistryClient = ResourceRegistryClientFactory.create();
+ UUID uuid = UUID.fromString(containerContext.id());
+ try {
+ hostingNode = resourceRegistryClient.getInstance(HostingNode.class, uuid);
+ hostingNode = updateFacets();
+ } catch (NotFoundException e) {
+ hostingNode = instantiateHostingNode();
+ hostingNode = resourceRegistryPublisher.createResource(hostingNode);
+ } catch (AvailableInAnotherContextException e) {
+ addToCurrentContext();
+ hostingNode = resourceRegistryClient.getInstance(HostingNode.class, uuid);
+ } catch (ResourceRegistryException e) {
+ logger.error("", e);
+ }
+ return hostingNode;
+ }
+
+ public String getState() {
+ return containerContext.lifecycle().state().remoteForm().toLowerCase();
+ }
+
+
+ private StateFacet getStateFacet(StateFacet stateFacet, Date date) {
+ if (stateFacet == null) {
+ stateFacet = new StateFacetImpl();
+ }
+ String state = getState();
+ stateFacet.setValue(state);
+ stateFacet.setAdditionalProperty("date", date);
+ return stateFacet;
+ }
+
+ private EventFacet getEventFacet(Date date) {
+ EventFacet eventFacet = new EventFacetImpl();
+ eventFacet.setDate(date);
+ String state = getState();
+ eventFacet.setEvent(state);
+ return eventFacet;
+ }
+
+ private MemoryFacet getDiskSpace(MemoryFacet memoryFacet) {
+ if (memoryFacet == null) {
+ memoryFacet = new MemoryFacetImpl();
+ }
+
+ long free = 0;
+ long total = 0;
+ try {
+ FileStore fileStore = Files
+ .getFileStore(Paths.get(containerContext.configuration().persistence().location()));
+ free = fileStore.getUsableSpace() / 1048576; // 1048576 = 1024*1024
+ // user to convert
+ // bytes in MByte
+ total = fileStore.getTotalSpace() / 1048576; // 1048576 = 1024*1024
+ // user to convert
+ // bytes in MByte
+ } catch (IOException ioe) {
+ logger.warn("Unable to detect disk space information", ioe);
+ memoryFacet.setAdditionalProperty(MESSAGE, "Unable to detect disk space information.");
+ }
+
+ memoryFacet.setUnit(MemoryUnit.MB);
+ memoryFacet.setSize(total);
+ memoryFacet.setUsed(total - free);
+
+ return memoryFacet;
+ }
+
+ private static final long BYTE_TO_MB = 1024 * 1024;
+
+ private MemoryFacet getRamInfo(MemoryFacet memoryFacet) {
+ if (memoryFacet == null) {
+ memoryFacet = new MemoryFacetImpl();
+ }
+
+ /*
+ * OperatingSystemMXBean mxbean = ManagementFactory.getOperatingSystemMXBean();
+ * com.sun.management.OperatingSystemMXBean sunmxbean =
+ * (com.sun.management.OperatingSystemMXBean) mxbean; long freeMemory =
+ * sunmxbean.getFreePhysicalMemorySize() / 1048576; // in MB long totalMemory =
+ * sunmxbean.getTotalPhysicalMemorySize() / 1048576; // in MB
+ */
+
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ long freeMemory;
+ try {
+ freeMemory = Long.parseLong(mBeanServer
+ .getAttribute(new ObjectName("java.lang", "type", "OperatingSystem"), "FreePhysicalMemorySize")
+ .toString()) / BYTE_TO_MB;
+ } catch (NumberFormatException | InstanceNotFoundException | AttributeNotFoundException
+ | MalformedObjectNameException | ReflectionException | MBeanException e) {
+ logger.warn(
+ "Unable to get free memory from Operating System. Going to get JVM Memory. Better than nothing");
+ long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
+ freeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;
+ }
+ long totalMemory;
+ try {
+ totalMemory = Long.parseLong(mBeanServer
+ .getAttribute(new ObjectName("java.lang", "type", "OperatingSystem"), "TotalPhysicalMemorySize")
+ .toString()) / BYTE_TO_MB;
+ } catch (NumberFormatException | InstanceNotFoundException | AttributeNotFoundException
+ | MalformedObjectNameException | ReflectionException | MBeanException e) {
+ logger.warn("Unable to total memory from Operating System. Going to get JVM Memory. Better than nothing");
+ totalMemory = Runtime.getRuntime().maxMemory();
+ }
+
+ memoryFacet.setUnit(MemoryUnit.MB);
+ memoryFacet.setSize(totalMemory);
+ memoryFacet.setUsed(totalMemory - freeMemory);
+
+ return memoryFacet;
+ }
+
+ private MemoryFacet getJVMMemoryInfo(MemoryFacet memoryFacet) {
+ if (memoryFacet == null) {
+ memoryFacet = new MemoryFacetImpl();
+ }
+
+ /* 1048576 = 1024*1024 used to convert bytes in MByte */
+ long jvmFreeMemory = Runtime.getRuntime().freeMemory() / 1048576;
+ long jvmTotalMemory = Runtime.getRuntime().totalMemory() / 1048576;
+ long jvmMaxMemory = Runtime.getRuntime().maxMemory() / 1048576;
+
+ memoryFacet.setUnit(MemoryUnit.MB);
+ memoryFacet.setSize(jvmTotalMemory);
+ memoryFacet.setUsed(jvmTotalMemory - jvmFreeMemory);
+ memoryFacet.setAdditionalProperty(JVM_MAX_MEMORY, jvmMaxMemory);
+
+ return memoryFacet;
+ }
+
+ private static String sanitizeKey(String key) {
+ return key.trim().replace(" ", "_");
+ }
+
+ private SimplePropertyFacet addEnvironmentVariables(ContainerConfiguration containerConfiguration) {
+
+ Map map = new HashMap();
+ map.putAll(containerConfiguration.properties());
+ map.putAll(System.getenv());
+
+ SimplePropertyFacet simplePropertyFacet = new SimplePropertyFacetImpl();
+ simplePropertyFacet.setName("ENVIRONMENT_VARIABLES");
+ simplePropertyFacet.setValue("");
+
+ for (Map.Entry entry : map.entrySet()) {
+ String varname = entry.getKey();
+ if ((varname.compareToIgnoreCase("CLASSPATH") == 0) || (varname.compareToIgnoreCase("PATH") == 0)
+ || (varname.contains("SSH")) || (varname.contains("MAIL"))
+ || (varname.compareToIgnoreCase("LS_COLORS") == 0)) {
+ continue;
+ }
+ simplePropertyFacet.setAdditionalProperty(sanitizeKey(entry.getKey()), entry.getValue());
+ }
+
+ return simplePropertyFacet;
+ }
+
+ private static String getDomain(String hostname) {
+ try {
+ Pattern pattern = Pattern.compile("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})");
+ Matcher regexMatcher = pattern.matcher(hostname);
+ if (regexMatcher.matches()) { // it's an IP address, nothing to trim
+ return hostname;
+ }
+ return hostname.substring(hostname.indexOf(".") + 1);
+ } catch (Exception e) {
+ logger.warn("Error while getting domain from hostname");
+ return hostname;
+ }
+ }
+
+ public static final String CPU_PROCESSOR = "processor";
+ public static final String CPU_VENDOR_ID = "vendor_id";
+ public static final String CPU_MODEL_NAME = "model name";
+ public static final String CPU_CPU_MHZ = "cpu MHz";
+ public static final String CPU_MODEL_T = "model\t";
+ public static final String CPU_MODEL_B = "model\b";
+ public static final String CPU_MODEL_NUMBER = "modelNumber";
+
+ public static List getCPUFacets() {
+
+ List cpuFacets = new ArrayList<>();
+
+ File file = new File("/proc/cpuinfo");
+
+ if (!file.exists()) {
+ logger.warn("cannot acquire CPU info (no /proc/cpuinfo)");
+ return cpuFacets;
+ }
+
+ BufferedReader input = null;
+
+ try {
+ input = new BufferedReader(new FileReader(file));
+
+ String line = null;
+
+ CPUFacet cpuFacet = null;
+
+ while ((line = input.readLine()) != null) {
+
+ if ((line.startsWith(CPU_PROCESSOR))) { // add the current
+ // processor to the map
+ cpuFacet = new CPUFacetImpl();
+ cpuFacets.add(cpuFacet);
+ }
+
+ try {
+ if (line.contains(CPU_VENDOR_ID)) {
+ cpuFacet.setVendor(line.split(":")[1].trim());
+ continue;
+ }
+ } catch (Exception e) {
+ continue;
+ }
+
+ try {
+ if (line.contains(CPU_MODEL_NAME)) {
+ cpuFacet.setModel(line.split(":")[1].trim());
+ continue;
+ }
+ } catch (Exception e) {
+ continue;
+ }
+
+ try {
+ if (line.contains(CPU_CPU_MHZ)) {
+ cpuFacet.setClockSpeed(line.split(":")[1].trim());
+ continue;
+ }
+ } catch (Exception e) {
+ continue;
+ }
+
+ try {
+ if ((line.contains(CPU_MODEL_T)) || (line.contains(CPU_MODEL_B))) {
+ cpuFacet.setAdditionalProperty(CPU_MODEL_NUMBER, line.split(":")[1].trim());
+ continue;
+ }
+ } catch (Exception e) {
+ continue;
+ }
+
+ try {
+ String[] nameValue = line.split(":");
+ cpuFacet.setAdditionalProperty(sanitizeKey(nameValue[0]), line.split(":")[1].trim());
+ } catch (Exception e) {
+
+ }
+
+ }
+ } catch (Exception e) {
+ logger.warn("unable to acquire CPU info", e);
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ logger.warn("unable to close stream", e);
+ }
+ }
+ }
+ return cpuFacets;
+ }
+
+ public Map getContextsUUID() throws Exception {
+ return resourceRegistryPublisher.getResourceContexts(hostingNode);
+ }
+
+}
diff --git a/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/LinuxDistributionInfo.java b/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/LinuxDistributionInfo.java
new file mode 100644
index 0000000..db149ca
--- /dev/null
+++ b/src/main/java/org/gcube/smartgears/handler/resourceregistry/resourcemanager/LinuxDistributionInfo.java
@@ -0,0 +1,93 @@
+package org.gcube.smartgears.handler.resourceregistry.resourcemanager;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Luca Frosini (ISTI-CNR)
+ */
+public class LinuxDistributionInfo {
+
+ private static final Logger logger = LoggerFactory.getLogger(LinuxDistributionInfo.class);
+
+ public static final String LSB_RELEASE_COMMAND = "lsb_release -a";
+ public static final String OS_RELEASE_FILE_PATH = "/etc/os-release";
+
+ protected Map info;
+
+ protected Map getInfoViaLsbReleaseCommand() throws IOException {
+ logger.trace("Going to exec {}", LSB_RELEASE_COMMAND);
+ Process process = Runtime.getRuntime().exec(LSB_RELEASE_COMMAND);
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ Map map = parseBufferedReader(bufferedReader);
+ bufferedReader.close();
+ return map;
+ }
+
+ private Map parseBufferedReader(BufferedReader bufferedReader) throws IOException {
+ Map map = new HashMap<>();
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ String[] nameValue = parseLine(line);
+ map.put(nameValue[0], nameValue[1]);
+ }
+ return map;
+ }
+
+ private String[] parseLine(String line) {
+ String[] splitted = line.split("=");
+ if (splitted.length < 2) {
+ splitted = line.split(":");
+ }
+ String[] ret = new String[2];
+ ret[0] = splitted[0].trim();
+ ret[1] = splitted[1].trim().replace("\"", "");
+ return ret;
+ }
+
+ private Map getInfoViaFile(File file) throws IOException {
+ logger.trace("Going to read file {}", file.getAbsolutePath());
+ BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
+ Map map = parseBufferedReader(bufferedReader);
+ bufferedReader.close();
+ return map;
+
+ }
+
+ protected Map getInfoViaOsReleaseFile() throws IOException {
+ File osReleaseFile = new File(OS_RELEASE_FILE_PATH);
+ return getInfoViaFile(osReleaseFile);
+ }
+
+ private Map retriveInfo() {
+ try {
+ return getInfoViaLsbReleaseCommand();
+ } catch (IOException e) {
+
+ }
+
+ try {
+ return getInfoViaOsReleaseFile();
+ }catch (IOException e) {
+
+ }
+
+ return null;
+ }
+
+ public Map getInfo() {
+ if (info == null) {
+ info = retriveInfo();
+ }
+ return info;
+ }
+
+}