2020-10-20 16:25:30 +02:00
|
|
|
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;
|
|
|
|
|
2020-11-11 14:19:58 +01:00
|
|
|
import java.util.HashSet;
|
2020-10-20 16:25:30 +02:00
|
|
|
import java.util.Set;
|
2020-11-11 14:19:58 +01:00
|
|
|
import java.util.UUID;
|
2020-10-20 16:25:30 +02:00
|
|
|
import java.util.concurrent.ScheduledFuture;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
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.Resource;
|
|
|
|
import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
|
2020-12-21 23:10:14 +01:00
|
|
|
import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;import org.gcube.resourcemanagement.model.reference.entities.resources.EService;
|
2020-10-20 16:25:30 +02:00
|
|
|
import org.gcube.smartgears.context.Property;
|
|
|
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
|
|
|
import org.gcube.smartgears.handler.resourceregistry.resourcemanager.EServiceManager;
|
2020-10-23 10:34:38 +02:00
|
|
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent.Start;
|
2020-10-20 16:25:30 +02:00
|
|
|
import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler;
|
|
|
|
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.
|
|
|
|
* <p>
|
|
|
|
* The manager:
|
|
|
|
* <ul>
|
|
|
|
* <li>creates the {@link EService} {@link Resource} and the facets it
|
|
|
|
* {@link ConsistsOf} when the application starts for the first time;</li>
|
|
|
|
* <li>update the {@link ServiceStateFacet} when the application becomes active,
|
|
|
|
* and at any lifecycle change thereafter;</li>
|
|
|
|
* </ul>
|
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @author Luca Frosini
|
|
|
|
*/
|
2020-10-23 10:34:38 +02:00
|
|
|
@XmlRootElement(name = Constants.RESOURCE_MANAGEMENT)
|
2020-10-20 16:25:30 +02:00
|
|
|
public class EServiceHandler extends ApplicationLifecycleHandler {
|
|
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(EServiceHandler.class);
|
|
|
|
|
|
|
|
private ApplicationContext applicationContext;
|
|
|
|
private ScheduledFuture<?> periodicUpdates;
|
|
|
|
|
|
|
|
protected EServiceManager eServiceManager;
|
2020-10-22 12:10:37 +02:00
|
|
|
|
2020-10-20 16:25:30 +02:00
|
|
|
public EServiceHandler() {
|
|
|
|
super();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-10-23 10:34:38 +02:00
|
|
|
public void onStart(Start event) {
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
|
|
|
logger.info("{} onStart started", this.getClass().getSimpleName());
|
2020-10-23 10:34:38 +02:00
|
|
|
this.applicationContext = event.context();
|
2020-10-20 16:25:30 +02:00
|
|
|
init();
|
|
|
|
registerObservers();
|
|
|
|
schedulePeriodicUpdates();
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.info("{} onStart terminated", this.getClass().getSimpleName());
|
2020-10-20 16:25:30 +02:00
|
|
|
} catch (Throwable re) {
|
|
|
|
logger.error("onStart failed", re);
|
|
|
|
}
|
|
|
|
}
|
2020-11-11 14:19:58 +01:00
|
|
|
|
|
|
|
protected void removeResourceFromOldContexts(Set<UUID> startContexts, Set<UUID> resourceContexts) {
|
|
|
|
Set<UUID> 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-20 16:25:30 +02:00
|
|
|
|
|
|
|
private void init() {
|
|
|
|
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
|
|
|
|
String previousToken = SecurityTokenProvider.instance.get();
|
|
|
|
try {
|
|
|
|
Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
|
|
|
|
boolean create = true;
|
|
|
|
Set<String> startTokens = applicationContext.configuration().startTokens();
|
2020-11-11 14:19:58 +01:00
|
|
|
|
|
|
|
Set<UUID> startContextsUUID = new HashSet<>();
|
|
|
|
ContextCache contextCache = ContextCache.getInstance();
|
2020-10-20 16:25:30 +02:00
|
|
|
for (String token : startTokens) {
|
|
|
|
ContextUtility.setContextFromToken(token);
|
2020-11-11 14:19:58 +01:00
|
|
|
String contextFullName = ContextUtility.getContextName(token);
|
|
|
|
UUID contextUUID = contextCache.getUUIDByFullName(contextFullName);
|
|
|
|
startContextsUUID.add(contextUUID);
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
|
|
|
if (create) {
|
2020-11-23 16:53:08 +01:00
|
|
|
eServiceManager = new EServiceManager(applicationContext);
|
2020-10-23 10:34:38 +02:00
|
|
|
eServiceManager.createEService();
|
2020-10-22 12:10:37 +02:00
|
|
|
applicationContext.properties()
|
|
|
|
.add(new Property(Constants.ESERVICE_MANAGER_PROPERTY, eServiceManager));
|
2020-10-20 16:25:30 +02:00
|
|
|
create = false;
|
|
|
|
} else {
|
2020-10-23 10:34:38 +02:00
|
|
|
eServiceManager.addToContext();
|
2020-10-20 16:25:30 +02:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.error("Unable to add {} to current context ({})", eServiceManager.getEService(),
|
2020-10-20 16:25:30 +02:00
|
|
|
ContextUtility.getContextName(token), e);
|
|
|
|
}
|
|
|
|
}
|
2020-11-11 14:19:58 +01:00
|
|
|
|
|
|
|
Set<UUID> resourceContextsUUID = eServiceManager.getContextsUUID();
|
|
|
|
removeResourceFromOldContexts(startContextsUUID, resourceContextsUUID);
|
|
|
|
|
2020-10-20 16:25:30 +02:00
|
|
|
} 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() {
|
|
|
|
|
2020-10-26 14:25:54 +01:00
|
|
|
@Observes({ activation, stop, failure })
|
2020-10-20 16:25:30 +02:00
|
|
|
void onChanged(ApplicationLifecycle lc) {
|
|
|
|
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
|
2020-10-23 10:34:38 +02:00
|
|
|
String previousToken = SecurityTokenProvider.instance.get();
|
|
|
|
if (previousToken == null) {
|
|
|
|
ContextUtility
|
|
|
|
.setContextFromToken(applicationContext.configuration().startTokens().iterator().next());
|
2020-10-22 12:10:37 +02:00
|
|
|
}
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
|
|
|
Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
|
2020-10-23 10:34:38 +02:00
|
|
|
eServiceManager.updateServiceStateFacet();
|
2020-10-20 16:25:30 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("Failed to update {} State", EService.NAME, e);
|
|
|
|
} finally {
|
2020-10-23 10:34:38 +02:00
|
|
|
ContextUtility.setContextFromToken(previousToken);
|
2020-10-20 16:25:30 +02:00
|
|
|
Thread.currentThread().setContextClassLoader(contextCL);
|
|
|
|
}
|
|
|
|
}
|
2020-10-26 14:25:54 +01:00
|
|
|
|
|
|
|
/*
|
2020-10-20 16:25:30 +02:00
|
|
|
@Observes({ stop, failure })
|
|
|
|
void onStop(ApplicationLifecycle lc) {
|
|
|
|
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
|
2020-10-23 10:34:38 +02:00
|
|
|
String previousToken = SecurityTokenProvider.instance.get();
|
|
|
|
if (previousToken == null) {
|
|
|
|
ContextUtility
|
|
|
|
.setContextFromToken(applicationContext.configuration().startTokens().iterator().next());
|
2020-10-22 12:10:37 +02:00
|
|
|
}
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
|
|
|
Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
|
2020-10-26 11:48:26 +01:00
|
|
|
eServiceManager.updateServiceStateFacet();
|
2020-10-20 16:25:30 +02:00
|
|
|
} catch (Exception e) {
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.error("Failed to update {} State", EService.NAME, e);
|
2020-10-20 16:25:30 +02:00
|
|
|
} finally {
|
2020-10-23 10:34:38 +02:00
|
|
|
ContextUtility.setContextFromToken(previousToken);
|
2020-10-20 16:25:30 +02:00
|
|
|
Thread.currentThread().setContextClassLoader(contextCL);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2020-10-26 14:25:54 +01:00
|
|
|
*/
|
|
|
|
|
2020-10-20 16:25:30 +02:00
|
|
|
@Observes(value = addToContext)
|
|
|
|
void addTo(String token) {
|
|
|
|
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
|
|
|
|
String previousToken = SecurityTokenProvider.instance.get();
|
2020-10-23 10:34:38 +02:00
|
|
|
if (previousToken == null) {
|
|
|
|
ContextUtility
|
|
|
|
.setContextFromToken(applicationContext.configuration().startTokens().iterator().next());
|
|
|
|
}
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
|
|
|
Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
|
|
|
|
ContextUtility.setContextFromToken(token);
|
2020-10-23 10:34:38 +02:00
|
|
|
eServiceManager.addToContext();
|
2020-10-20 16:25:30 +02:00
|
|
|
} catch (Exception e) {
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.error("Failed to add {} to current context ({})", EService.NAME,
|
2020-10-20 16:25:30 +02:00
|
|
|
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();
|
2020-10-23 10:34:38 +02:00
|
|
|
if (previousToken == null) {
|
|
|
|
ContextUtility
|
|
|
|
.setContextFromToken(applicationContext.configuration().startTokens().iterator().next());
|
|
|
|
}
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
|
|
|
Thread.currentThread().setContextClassLoader(EServiceHandler.class.getClassLoader());
|
|
|
|
eServiceManager.removeFromContext();
|
|
|
|
} catch (Exception e) {
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.error("Failed to remove {} from current context ({})",
|
|
|
|
EService.NAME, ContextUtility.getCurrentContextName(), e);
|
2020-10-20 16:25:30 +02:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lc.state() == ApplicationState.active) {
|
|
|
|
logger.info("scheduling periodic updates of application {} EService",
|
|
|
|
applicationContext.name());
|
|
|
|
} else {
|
|
|
|
logger.info("resuming periodic updates of application {} EService",
|
|
|
|
applicationContext.name());
|
|
|
|
}
|
|
|
|
|
|
|
|
final Runnable updateTask = new Runnable() {
|
|
|
|
public void run() {
|
2020-10-23 10:34:38 +02:00
|
|
|
String previousToken = SecurityTokenProvider.instance.get();
|
|
|
|
if (previousToken == null) {
|
|
|
|
ContextUtility.setContextFromToken(
|
|
|
|
applicationContext.configuration().startTokens().iterator().next());
|
|
|
|
}
|
2020-10-20 16:25:30 +02:00
|
|
|
try {
|
2020-10-23 10:34:38 +02:00
|
|
|
eServiceManager.updateServiceStateFacet();
|
2020-10-20 16:25:30 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("Cannot complete periodic update of EService", e);
|
2020-10-23 10:34:38 +02:00
|
|
|
} finally {
|
|
|
|
ContextUtility.setContextFromToken(previousToken);
|
2020-10-20 16:25:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
periodicUpdates = Utils.scheduledServicePool.scheduleAtFixedRate(updateTask,
|
|
|
|
Constants.application_republish_frequency_in_minutes,
|
|
|
|
Constants.application_republish_frequency_in_minutes, TimeUnit.MINUTES);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Observes(value = { stop, failure }, kind = resilient)
|
|
|
|
synchronized void cancelPeriodicUpdates(ContainerLifecycle ignore) {
|
|
|
|
|
|
|
|
if (periodicUpdates != null) {
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.trace("stopping periodic updates of EService for application {} ",
|
2020-10-20 16:25:30 +02:00
|
|
|
applicationContext.name());
|
|
|
|
|
|
|
|
try {
|
|
|
|
periodicUpdates.cancel(true);
|
|
|
|
periodicUpdates = null;
|
|
|
|
} catch (Exception e) {
|
2020-10-23 10:34:38 +02:00
|
|
|
logger.warn("could not stop periodic updates of EService for application {}",
|
2020-10-20 16:25:30 +02:00
|
|
|
applicationContext.name(), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2020-10-23 10:34:38 +02:00
|
|
|
return Constants.RESOURCE_MANAGEMENT;
|
2020-10-20 16:25:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|