package org.gcube.smartgears.provider; import static org.gcube.smartgears.Constants.configuration_file_path; import static org.gcube.smartgears.Constants.container_configuraton_file_path; import static org.gcube.smartgears.Constants.ghn_home_env; import static org.gcube.smartgears.Constants.ghn_home_property; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import jakarta.servlet.ServletContext; import org.gcube.common.events.Hub; import org.gcube.common.events.impl.DefaultHub; import org.gcube.common.security.credentials.Credentials; import org.gcube.smartgears.configuration.SmartgearsConfiguration; import org.gcube.smartgears.configuration.application.ApplicationConfiguration; import org.gcube.smartgears.configuration.application.ApplicationConfigurationBinder; import org.gcube.smartgears.configuration.application.ApplicationHandlers; import org.gcube.smartgears.configuration.container.ContainerConfiguration; import org.gcube.smartgears.configuration.container.ContainerConfigurationBinder; import org.gcube.smartgears.context.Properties; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.application.DefaultApplicationContext; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.context.container.DefaultContainerContext; import org.gcube.smartgears.extensions.ApplicationExtension; import org.gcube.smartgears.extensions.resource.RemoteResource; import org.gcube.smartgears.handlers.container.ContainerHandler; import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle; import org.gcube.smartgears.lifecycle.container.ContainerLifecycle; import org.gcube.smartgears.publishing.Publisher; import org.gcube.smartgears.publishing.SmartgearsProfilePublisher; import org.gcube.smartgears.security.AuthorizationProvider; import org.gcube.smartgears.security.AuthorizationProviderFactory; import org.gcube.smartgears.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ClassInfoList; import io.github.classgraph.ScanResult; /** * Default implementation of the {@link Provider} interface. * * @author Fabio Simeoni * */ public class DefaultProvider implements Provider { private static Logger log = LoggerFactory.getLogger(Provider.class); private ContainerContext containerContext; // TODO: do the same with applicationContext (with a map) private File configFile = null; protected DefaultProvider(File configFile) { this.configFile = configFile; } List publishers; protected DefaultProvider() { }; @Override public ContainerContext containerContext() { if (containerContext == null) { ContainerConfiguration configuration = containerConfiguration(); Hub hub = new DefaultHub(); ContainerLifecycle lifecycle = new ContainerLifecycle(hub); AuthorizationProviderFactory authfactory = configuration.authorizationConfiguration() .getAuthProviderFactory(); Credentials credentials = configuration.authorizationConfiguration().getCredentials(); AuthorizationProvider authProvider = authfactory.connect(credentials); containerContext = new DefaultContainerContext(configuration, hub, lifecycle, authProvider, new Properties()); } return containerContext; } @Override public List containerHandlers() { try { ContainerConfigurationBinder binder = new ContainerConfigurationBinder(); ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); if (currentClassLoader.getParent() != null && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())) { log.trace("probably i'm in a webapp classloader"); currentClassLoader = currentClassLoader.getParent(); } List defaultHandlers = binder.bindHandlers(currentClassLoader); return defaultHandlers; } catch (RuntimeException e) { throw new RuntimeException("cannot install container handlers (see cause) ", e); } } @Override public ApplicationContext contextFor(ContainerContext context, ServletContext application) { ApplicationConfiguration embedded = configurationFor(application); // shouldn't happen: management shouldn't have started at all if (embedded == null) throw new AssertionError("application @ " + application.getContextPath() + " is not distributed with " + configuration_file_path + " and there is no external configuration for it in " + container_configuraton_file_path); Hub hub = new DefaultHub(); ApplicationLifecycle lifecycle = new ApplicationLifecycle(hub, embedded.name()); return new DefaultApplicationContext(context, application, embedded, hub, lifecycle, new Properties()); } @Override public ApplicationHandlers handlersFor(ApplicationContext context) { try { ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); // searching for smartegars related application handlers in the common // classloader ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); if (currentClassLoader.getParent() != null && !currentClassLoader.getParent().equals(ClassLoader.getSystemClassLoader())) { log.trace("probably i'm in a webapp classloader"); currentClassLoader = currentClassLoader.getParent(); } ApplicationHandlers defaultHandlers = binder.bindHandlers(currentClassLoader); return defaultHandlers; } catch (RuntimeException e) { throw new RuntimeException("cannot install handlers for application @ " + context.name() + " (see cause) ", e); } } public List extensionsFor(ApplicationContext context){ return List.of(new RemoteResource()); } // helpers private ApplicationConfiguration configurationFor(ServletContext application) { try { InputStream config = application.getResourceAsStream(configuration_file_path); if (config == null) return null; ApplicationConfigurationBinder binder = new ApplicationConfigurationBinder(); return binder.load(config); } catch (RuntimeException e) { throw new RuntimeException("invalid configuration (see cause)", e); } } private ContainerConfiguration containerConfiguration() { if (configFile == null) { String home = Utils.home(); if (home == null) throw new IllegalStateException("invalid node configuration: the environment variable " + ghn_home_env + " or the system property " + ghn_home_property + " must be defined"); File homeDir = new File(home); if (!(homeDir.exists() && homeDir.isDirectory() && homeDir.canRead() && homeDir.canWrite())) throw new IllegalStateException("invalid node configuration: home " + home + " does not exist or is not a directory or cannot be accessed in read/write mode"); configFile = new File(homeDir, container_configuraton_file_path); log.trace("reading container configuration @ {} ", configFile.getAbsolutePath()); } if (!(configFile.exists() && configFile.canRead())) throw new IllegalStateException("invalid node configuration: file " + configFile.getAbsolutePath() + " does not exist or cannot be accessed"); ContainerConfiguration configuration; try (InputStream stream = new FileInputStream(configFile)) { configuration = new ContainerConfigurationBinder().load(stream); } catch (Exception e) { throw new IllegalStateException( "invalid node configuration: file " + configFile.getAbsolutePath() + " is invalid", e); } return configuration; } @Override public synchronized List publishers() { if (this.publishers == null) { Set> annotatedPublishers; try (ScanResult result = new ClassGraph().enableClassInfo().enableAnnotationInfo() .addClassLoader(Thread.currentThread().getContextClassLoader()).scan()) { ClassInfoList classInfos = result.getClassesWithAnnotation(SmartgearsProfilePublisher.class.getName()); annotatedPublishers = classInfos.stream().map(ClassInfo::loadClass) .filter(c -> Publisher.class.isAssignableFrom(c)).collect(Collectors.toSet()); } /* * Collection urls = * ClasspathHelper.forClassLoader(Thread.currentThread().getContextClassLoader() * ); urls.removeIf(url -> url.toString().endsWith(".so") || * url.toString().endsWith(".zip") ); * * * ConfigurationBuilder reflectionConf = new * ConfigurationBuilder().addUrls(urls).setScanners(new * TypeAnnotationsScanner(), new SubTypesScanner()); * * Reflections reflection = new Reflections(reflectionConf); * * = reflection.getTypesAnnotatedWith(SmartgearsProfilePublisher.class); */ List foundPublishers = new ArrayList(); for (Class annotatedPublisher : annotatedPublishers) { try { foundPublishers.add((Publisher) annotatedPublisher.getDeclaredConstructor().newInstance()); log.info("added class {} to publishers", annotatedPublisher); } catch (Throwable e) { log.error("publisher class {} cannot be instantiated", annotatedPublisher.getCanonicalName(), e); } } this.publishers = foundPublishers; if (foundPublishers.isEmpty()) log.warn("no publishers found in classloader"); } return this.publishers; } @Override public SmartgearsConfiguration smartgearsConfiguration() { ContainerConfigurationBinder binder = new ContainerConfigurationBinder(); return binder.loadSmartgearsProperty(); } /* * @Override public AuthorizationProvider authorizationProvider() { return * containerContext.authorizationProvider(); } */ }