common-smartgears/src/main/java/org/gcube/smartgears/Bootstrap.java

183 lines
5.2 KiB
Java
Raw Normal View History

package org.gcube.smartgears;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.context.container.ContainerContext;
import org.gcube.smartgears.managers.ApplicationManager;
import org.gcube.smartgears.managers.ContainerManager;
import org.gcube.smartgears.provider.ProviderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
2023-02-01 17:18:13 +01:00
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
2023-02-01 17:18:13 +01:00
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
/**
* Bootstraps management of all deployed applications which require it.
*
* @author Fabio Simeoni
*
*/
public class Bootstrap implements ServletContainerInitializer {
private static Logger log = LoggerFactory.getLogger(Bootstrap.class);
private static boolean smartgearsHasStarted = false;
private static boolean containerHasFailed = false;
private static ContainerManager manager;
private static ContainerContext context;
public Bootstrap() {
log.info("bootstrap started the container");
if (smartgearsHasStarted)
return;
smartgearsHasStarted = true;
initialiseContainer();
//this can fail the app: managed resources need a working container
startContainerIfItHasntAlreadyFailed();
}
@Override
public void onStartup(Set<Class<?>> c, ServletContext application) throws ServletException {
ApplicationManager appManager = new ApplicationManager();
log.info("check if is managed @ {}", application.getContextPath());
//act only on resources
if (isResource(application)) {
try {
log.info("starting management of application @ {}", application.getContextPath());
ApplicationContext app = appManager.start(context, application);
manager.manage(app);
context.configuration().app(app.configuration());
} catch (Throwable t) {
appManager.stop();
throw new ServletException("cannot manage application @ " + application.getContextPath()
+ " (see cause)", t);
}
} else log.info("is not managed @ {}", application.getContextPath());
}
// helpers
2023-02-06 17:34:18 +01:00
@SuppressWarnings("resource")
private void initialiseContainer() {
2024-02-02 10:54:19 +01:00
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
try {
2024-02-02 10:54:19 +01:00
// TODO Ask why is needed?
Thread.currentThread().setContextClassLoader(ContainerManager.class.getClassLoader());
log.trace("smartgears is starting");
/* Get the ContainerContext. Look at DefaultProvider */
context = ProviderFactory.provider().containerContext();
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
2023-02-01 17:18:13 +01:00
new ClassLoaderMetrics().bindTo(registry);
new JvmMemoryMetrics().bindTo(registry);
2023-02-01 17:18:13 +01:00
new JvmGcMetrics().bindTo(registry);
new ProcessorMetrics().bindTo(registry);
new JvmThreadMetrics().bindTo(registry);
2023-02-01 17:18:13 +01:00
new UptimeMetrics().bindTo(registry);
new ProcessorMetrics().bindTo(registry);
Metrics.addRegistry(registry);
2024-02-02 10:54:19 +01:00
/* Validate the configuration retrieved by ContainerContext
* using gcube facilities annotation based
* ( i.e org.gcube.common.validator.annotations)
*/
context.configuration().validate();
} catch (RuntimeException e) {
containerHasFailed = true;
log.error("cannot start smartgears", e);
//we let the container continue
2024-02-02 10:54:19 +01:00
} finally {//restore the classloader of the current application
Thread.currentThread().setContextClassLoader(contextCL);
}
}
private void startContainerIfItHasntAlreadyFailed() {
if (containerHasFailed)
throw new IllegalStateException("container is not managed due to previous failure");
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
// we initialise the container in the same classloader as this
// lib, lest container bind its resources to the current webapp
try {
// TODO Ask why is needed?
2024-02-02 10:54:19 +01:00
Thread.currentThread().setContextClassLoader(ContainerManager.class.getClassLoader());
manager = ContainerManager.instance;
context = manager.start(context);
} catch (RuntimeException e) {
containerHasFailed = true;
throw new IllegalStateException("cannot manage container", e);
}
finally {//restore the classloader of the current application
Thread.currentThread().setContextClassLoader(contextCL);
}
}
private boolean isResource(ServletContext application) {
//with care: smartgears may have already failed at this stage but we want to recognise
//apps that would have been managed otherwise and give specific errors for those
return (!containerHasFailed && context.configuration().app(application.getContextPath())!=null)
||
application.getResourceAsStream(Constants.configuration_file_path) != null;
}
}